<commit_before>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
import inspect
if sys.platform.startswith('java'):
    from java.lang import Class
    from java.util import List, Map

from robot.errors import DataError
from robot.utils import PY2
from robot.variables import is_dict_var, is_list_var, is_scalar_var

from .argumentspec import ArgumentSpec


class _ArgumentParser(object):

    def __init__(self, type='Keyword'):
        self._type = type

    def parse(self, source, name=None):
        # FIXME: Unify _get_arg_spec return value format
        try:
            return ArgumentSpec(name, self._type, **self._get_arg_spec(source))
        except TypeError:
            # Support original style *args return from _get_arg_spec
            return ArgumentSpec(name, self._type, *self._get_arg_spec(source))

    def _get_arg_spec(self, source):
        raise NotImplementedError


class PythonArgumentParser(_ArgumentParser):

    def _get_arg_spec(self, handler):
        if PY2:
            args, varargs, varkw, defaults = inspect.getargspec(handler)
            kwonlyargs = kwonlydefaults = None
        else:
            args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, _ \
                    = inspect.getfullargspec(handler)
        if inspect.ismethod(handler) or handler.__name__ == '__init__':
            args = args[1:]  # drop 'self'
        defaults = list(defaults) if defaults else []
        return {
            'positional': args, 'defaults': defaults, 'varargs': varargs,
            'kwargs': varkw, 'kwonlyargs': kwonlyargs,
            'kwonlydefaults': kwonlydefaults
        }


class JavaArgumentParser(_ArgumentParser):

    def _get_arg_spec(self, signatures):
        if not signatures:
            return self._no_signatures_arg_spec()
        elif len(signatures) == 1:
            return self._single_signature_arg_spec(signatures[0])
        else:
            return self._multi_signature_arg_spec(signatures)

    def _no_signatures_arg_spec(self):
        # Happens when a class has no public constructors
        return self._format_arg_spec()

    def _single_signature_arg_spec(self, signature):
        varargs, kwargs = self._get_varargs_and_kwargs_support(signature.args)
        positional = len(signature.args) - int(varargs) - int(kwargs)
        return self._format_arg_spec(positional, varargs=varargs, kwargs=kwargs)

    def _get_varargs_and_kwargs_support(self, args):
        if not args:
            return False, False
        if self._is_varargs_type(args[-1]):
            return True, False
        if not self._is_kwargs_type(args[-1]):
            return False, False
        if len(args) > 1 and self._is_varargs_type(args[-2]):
            return True, True
        return False, True

    def _is_varargs_type(self, arg):
        return arg is List or isinstance(arg, Class) and arg.isArray()

    def _is_kwargs_type(self, arg):
        return arg is Map

    def _multi_signature_arg_spec(self, signatures):
        mina = maxa = len(signatures[0].args)
        for sig in signatures[1:]:
            argc = len(sig.args)
            mina = min(argc, mina)
            maxa = max(argc, maxa)
        return self._format_arg_spec(maxa, maxa-mina)

    def _format_arg_spec(self, positional=0, defaults=0, varargs=False, kwargs=False):
        positional = ['arg%d' % (i+1) for i in range(positional)]
        defaults = [''] * defaults
        varargs = '*varargs' if varargs else None
        kwargs = '**kwargs' if kwargs else None
        supports_named = False
        return positional, defaults, varargs, kwargs, supports_named


class _ArgumentSpecParser(_ArgumentParser):

    def parse(self, argspec, name=None):
        result = ArgumentSpec(name, self._type)
        for arg in argspec:
            if result.kwargs:
                self._raise_invalid_spec('Only last argument can be kwargs.')
            if self._is_kwargs(arg):
                self._add_kwargs(arg, result)
                continue
            if result.varargs:
                self._raise_invalid_spec('Positional argument after varargs.')
            if self._is_varargs(arg):
                self._add_varargs(arg, result)
                continue
            if '=' in arg:
                self._add_arg_with_default(arg, result)<commit_msg>Clean-up arg spec parsing code.<commit_after>#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
import inspect
if sys.platform.startswith('java'):
    from java.lang import Class
    from java.util import List, Map

from robot.errors import DataError
from robot.utils import PY2
from robot.variables import is_dict_var, is_list_var, is_scalar_var

from .argumentspec import ArgumentSpec


class _ArgumentParser(object):

    def __init__(self, type='Keyword'):
        self._type = type

    def parse(self, source, name=None):
        raise NotImplementedError


class PythonArgumentParser(_ArgumentParser):

    def parse(self, handler, name=None):
        if PY2:
            args, varargs, varkw, defaults = inspect.getargspec(handler)
            kwonlyargs = kwonlydefaults = None
        else:
            args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, _ \
                    = inspect.getfullargspec(handler)
        if inspect.ismethod(handler) or handler.__name__ == '__init__':
            args = args[1:]  # drop 'self'
        defaults = list(defaults) if defaults else []
        return ArgumentSpec(name, self._type,
                            positional=args,
                            defaults=defaults,
                            varargs=varargs,
                            kwargs=varkw,
                            kwonlyargs=kwonlyargs,
                            kwonlydefaults=kwonlydefaults)


class JavaArgumentParser(_ArgumentParser):

    def parse(self, signatures, name=None):
        if not signatures:
            return self._no_signatures_arg_spec(name)
        elif len(signatures) == 1:
            return self._single_signature_arg_spec(signatures[0], name)
        else:
            return self._multi_signature_arg_spec(signatures, name)

    def _no_signatures_arg_spec(self, name):
        # Happens when a class has no public constructors
        return self._format_arg_spec(name)

    def _single_signature_arg_spec(self, signature, name):
        varargs, kwargs = self._get_varargs_and_kwargs_support(signature.args)
        positional = len(signature.args) - int(varargs) - int(kwargs)
        return self._format_arg_spec(name, positional, varargs=varargs,
                                     kwargs=kwargs)

    def _get_varargs_and_kwargs_support(self, args):
        if not args:
            return False, False
        if self._is_varargs_type(args[-1]):
            return True, False
        if not self._is_kwargs_type(args[-1]):
            return False, False
        if len(args) > 1 and self._is_varargs_type(args[-2]):
            return True, True
        return False, True

    def _is_varargs_type(self, arg):
        return arg is List or isinstance(arg, Class) and arg.isArray()

    def _is_kwargs_type(self, arg):
        return arg is Map

    def _multi_signature_arg_spec(self, signatures, name):
        mina = maxa = len(signatures[0].args)
        for sig in signatures[1:]:
            argc = len(sig.args)
            mina = min(argc, mina)
            maxa = max(argc, maxa)
        return self._format_arg_spec(name, maxa, maxa-mina)

    def _format_arg_spec(self, name, positional=0, defaults=0, varargs=False,
                         kwargs=False):
        positional = ['arg%d' % (i+1) for i in range(positional)]
        defaults = [''] * defaults
        return ArgumentSpec(name, self._type,
                            positional=positional,
                            defaults=defaults,
                            varargs='*varargs' if varargs else None,
                            kwargs='**kwargs' if kwargs else None,
                            supports_named=False)


class _ArgumentSpecParser(_ArgumentParser):

    def parse(self, argspec, name=None):
        result = ArgumentSpec(name, self._type)
        for arg in argspec:
            if result.kwargs:
                self._raise_invalid_spec('Only last argument can be kwargs.')
            if self._is_kwargs(arg):
                self._add_kwargs(arg, result)
                continue
            if result.varargs:
                self._raise_invalid_spec('Positional argument after varargs.')
            if self._is_varargs(arg):
                self._add_varargs(arg, result)
                continue
            if '=' in arg:
                self._add_arg_with_default(arg, result)
{'fraction_non_alphanumeric': 0.08282766990291263, 'fraction_numerical': 0.006067961165048544, 'mean_word_length': 2.3982817869415807, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5003159', 'n_tokens_mistral': 2804, 'n_tokens_neox': 2716, 'n_words': 784}