diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index c68986fe..e95eb08e 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -94,6 +94,26 @@ class Arguments(pr.Base): new_args.append(stmt) return new_args + def eval_argument_clinic(self, arguments): + """Uses a list with argument clinic information (see PEP 436).""" + iterator = self.unpack() + for i, (name, optional, allow_kwargs) in enumerate(arguments): + key, va_values = next(iterator, (None, [])) + if key is not None: + raise NotImplementedError + if not va_values and not optional: + debug.warning('TypeError: %s expected at least %s arguments, got %s', + name, len(arguments), i) + raise ValueError + values = list(chain.from_iterable(self._evaluator.eval_element(el) + for el in va_values)) + if not values and not optional: + # For the stdlib we always want values. If we don't get them, + # that's ok, maybe something is too hard to resolve, however, + # we will not proceed with the evaluation of that function. + raise ValueError + yield values + def eval_args(self): return [self._evaluator.eval_element(el) for stars, el in self._split()] diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index f45816a1..fef96adf 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -7,6 +7,8 @@ To add a new implementation, create a function and add it to the """ import collections +import re + from jedi._compatibility import unicode from jedi.evaluate import compiled from jedi.evaluate import representation as er @@ -58,15 +60,30 @@ def argument_clinic(string, want_obj=False): """ Works like Argument Clinic (PEP 436), to validate function params. """ - args = [] - # TODO Do the splitting and checking if the input is correct. - #re. - # = string.split(', ') + clinic_args = [] + allow_kwargs = False + while string: + # Optional arguments have to begin with a bracket. And should always be + # at the end of the arguments. This is therefore not a proper argument + # clinic implementation. `range()` for exmple allows an optional start + # value at the beginning. + match = re.match('(?:(?:(\[), ?|, ?|)(\w+)|, ?/)\]*', string) + string = string[len(match.group(0)):] + if not match.group(2): # A slash -> allow named arguments + allow_kwargs = True + continue + optional = match.group(1) + word = match.group(2) + clinic_args.append((word, bool(optional), allow_kwargs)) def f(func): def wrapper(evaluator, obj, arguments): - args = arguments.eval_args() - return func(evaluator, *args) + try: + lst = list(arguments.eval_argument_clinic(clinic_args)) + except ValueError: + return [] + else: + return func(evaluator, *lst) return wrapper return f