Пример #1
0
def builtins_reversed(evaluator, sequences, obj):
    # Unpack the iterator values
    objects = tuple(iterable.get_iterator_types(sequences))
    rev = [iterable.AlreadyEvaluated([o]) for o in reversed(objects)]
    # Repack iterator values and then run it the normal way. This is
    # necessary, because `reversed` is a function and autocompletion
    # would fail in certain cases like `reversed(x).__iter__` if we
    # just returned the result directly.
    rev = iterable.AlreadyEvaluated(
        [iterable.FakeSequence(evaluator, rev, 'list')])
    return [er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))]
Пример #2
0
def builtins_reversed(evaluator, sequences, obj, arguments):
    # While we could do without this variable (just by using sequences), we
    # want static analysis to work well. Therefore we need to generated the
    # values again.
    first_arg = next(arguments.as_tuple())[0]
    ordered = list(iterable.py__iter__(evaluator, sequences, first_arg))

    rev = [iterable.AlreadyEvaluated(o) for o in reversed(ordered)]
    # Repack iterator values and then run it the normal way. This is
    # necessary, because `reversed` is a function and autocompletion
    # would fail in certain cases like `reversed(x).__iter__` if we
    # just returned the result directly.
    rev = iterable.AlreadyEvaluated(
        [iterable.FakeSequence(evaluator, rev, 'list')]
    )
    return set([er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))])
Пример #3
0
def _iterate_star_args(evaluator, array, input_node, func=None):
    from jedi.evaluate.representation import Instance
    if isinstance(array, iterable.Array):
        for field_stmt in array:  # yield from plz!
            yield field_stmt
    elif isinstance(array, iterable.Generator):
        for field_stmt in array.iter_content():
            yield iterable.AlreadyEvaluated([field_stmt])
    elif isinstance(array, Instance) and array.name.get_code() == 'tuple':
        debug.warning('Ignored a tuple *args input %s' % array)
    else:
        if func is not None:
            m = "TypeError: %s() argument after * must be a sequence, not %s" \
                % (func.name.value, array)
            analysis.add(evaluator, 'type-error-star', input_node, message=m)
Пример #4
0
    def get_index_types(self, evaluator, index_array):
        indexes = iterable.create_indexes_or_slices(self._evaluator, index_array)
        if any([isinstance(i, iterable.Slice) for i in indexes]):
            # Slice support in Jedi is very marginal, at the moment, so just
            # ignore them in case of __getitem__.
            # TODO support slices in a more general way.
            indexes = []

        try:
            method = self.get_subscope_by_name('__getitem__')
        except KeyError:
            debug.warning('No __getitem__, cannot access the array.')
            return []
        else:
            return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)])
Пример #5
0
def _iterate_star_args(evaluator, array, input_node, func=None):
    from jedi.evaluate.representation import Instance
    if isinstance(array, iterable.Array):
        # TODO ._items is not the call we want here. Replace in the future. id:131 gh:132
        for node in array._items():
            yield node
    elif isinstance(array, iterable.Generator):
        for types in array.py__iter__():
            yield iterable.AlreadyEvaluated(types)
    elif isinstance(array, Instance) and array.name.get_code() == 'tuple':
        debug.warning('Ignored a tuple *args input %s' % array)
    else:
        if func is not None:
            m = "TypeError: %s() argument after * must be a sequence, not %s" \
                % (func.name.value, array)
            analysis.add(evaluator, 'type-error-star', input_node, message=m)
Пример #6
0
    def unpack(self, func=None):
        named_args = []
        for stars, el in self._split():
            if stars == 1:
                arrays = self._evaluator.eval_element(el)
                iterators = [
                    _iterate_star_args(self._evaluator, a, el, func)
                    for a in arrays
                ]
                iterators = list(iterators)
                for values in list(zip_longest(*iterators)):
                    yield None, [v for v in values if v is not None]
            elif stars == 2:
                arrays = self._evaluator.eval_element(el)
                dicts = [
                    _star_star_dict(self._evaluator, a, el, func)
                    for a in arrays
                ]
                for dct in dicts:
                    for key, values in dct.items():
                        yield key, values
            else:
                if pr.is_node(el, 'argument'):
                    c = el.children
                    if len(c) == 3:  # Keyword argument.
                        named_args.append((c[0].value, (c[2], )))
                    else:  # Generator comprehension.
                        # Include the brackets with the parent.
                        comp = iterable.GeneratorComprehension(
                            self._evaluator, self.argument_node.parent)
                        yield None, (iterable.AlreadyEvaluated([comp]), )
                elif isinstance(el, (list, tuple)):
                    yield None, el
                else:
                    yield None, (el, )

        # Reordering var_args is necessary, because star args sometimes appear
        # after named argument, but in the actual order it's prepended.
        for key_arg in named_args:
            yield key_arg
Пример #7
0
def get_params(evaluator, func, var_args):
    param_names = []
    param_dict = {}
    for param in func.params:
        param_dict[str(param.get_name())] = param
    unpacked_va = list(var_args.unpack(func))
    from jedi.evaluate.representation import InstanceElement
    if isinstance(func, InstanceElement):
        # Include self at this place.
        unpacked_va.insert(
            0, (None, [iterable.AlreadyEvaluated([func.instance])]))
    var_arg_iterator = common.PushBackIterator(iter(unpacked_va))

    non_matching_keys = defaultdict(lambda: [])
    keys_used = {}
    keys_only = False
    had_multiple_value_error = False
    for param in func.params:
        # The value and key can both be null. There, the defaults apply.
        # args / kwargs will just be empty arrays / dicts, respectively.
        # Wrong value count is just ignored. If you try to test cases that are
        # not allowed in Python, Jedi will maybe not show any completions.
        default = [] if param.default is None else [param.default]
        key, va_values = next(var_arg_iterator, (None, default))
        while key is not None:
            keys_only = True
            k = unicode(key)
            try:
                key_param = param_dict[unicode(key)]
            except KeyError:
                non_matching_keys[key] += va_values
            else:
                param_names.append(
                    ExecutedParam(key_param, var_args, va_values).name)

            if k in keys_used:
                had_multiple_value_error = True
                m = (
                    "TypeError: %s() got multiple values for keyword argument '%s'."
                    % (func.name, k))
                calling_va = _get_calling_var_args(evaluator, var_args)
                if calling_va is not None:
                    analysis.add(evaluator,
                                 'type-error-multiple-values',
                                 calling_va,
                                 message=m)
            else:
                try:
                    keys_used[k] = param_names[-1]
                except IndexError:
                    # TODO this is wrong stupid and whatever.
                    pass
            key, va_values = next(var_arg_iterator, (None, ()))

        values = []
        if param.stars == 1:
            # *args param
            lst_values = [iterable.MergedNodes(va_values)] if va_values else []
            for key, va_values in var_arg_iterator:
                # Iterate until a key argument is found.
                if key:
                    var_arg_iterator.push_back((key, va_values))
                    break
                if va_values:
                    lst_values.append(iterable.MergedNodes(va_values))
            seq = iterable.FakeSequence(evaluator, lst_values, 'tuple')
            values = [iterable.AlreadyEvaluated([seq])]
        elif param.stars == 2:
            # **kwargs param
            dct = iterable.FakeDict(evaluator, dict(non_matching_keys))
            values = [iterable.AlreadyEvaluated([dct])]
            non_matching_keys = {}
        else:
            # normal param
            if va_values:
                values = va_values
            else:
                # No value: Return an empty container
                values = []
                if not keys_only:
                    calling_va = var_args.get_calling_var_args()
                    if calling_va is not None:
                        m = _error_argument_count(func, len(unpacked_va))
                        analysis.add(evaluator,
                                     'type-error-too-few-arguments',
                                     calling_va,
                                     message=m)

        # Now add to result if it's not one of the previously covered cases.
        if (not keys_only or param.stars == 2):
            param_names.append(ExecutedParam(param, var_args, values).name)
            keys_used[unicode(param.get_name())] = param_names[-1]

    if keys_only:
        # All arguments should be handed over to the next function. It's not
        # about the values inside, it's about the names. Jedi needs to now that
        # there's nothing to find for certain names.
        for k in set(param_dict) - set(keys_used):
            param = param_dict[k]
            values = [] if param.default is None else [param.default]
            param_names.append(ExecutedParam(param, var_args, values).name)

            if not (non_matching_keys or had_multiple_value_error
                    or param.stars or param.default):
                # add a warning only if there's not another one.
                calling_va = _get_calling_var_args(evaluator, var_args)
                if calling_va is not None:
                    m = _error_argument_count(func, len(unpacked_va))
                    analysis.add(evaluator,
                                 'type-error-too-few-arguments',
                                 calling_va,
                                 message=m)

    for key, va_values in non_matching_keys.items():
        m = "TypeError: %s() got an unexpected keyword argument '%s'." \
            % (func.name, key)
        for value in va_values:
            analysis.add(evaluator,
                         'type-error-keyword-argument',
                         value.parent,
                         message=m)

    remaining_params = list(var_arg_iterator)
    if remaining_params:
        m = _error_argument_count(func, len(unpacked_va))
        # Just report an error for the first param that is not needed (like
        # cPython).
        first_key, first_values = remaining_params[0]
        for v in first_values:
            if first_key is not None:
                # Is a keyword argument, return the whole thing instead of just
                # the value node.
                v = v.parent
                try:
                    non_kw_param = keys_used[first_key]
                except KeyError:
                    pass
                else:
                    origin_args = non_kw_param.parent.var_args.argument_node
                    # TODO  calculate the var_args tree and check if it's in
                    # the tree (if not continue).
                    # print('\t\tnonkw', non_kw_param.parent.var_args.argument_node, )
                    if origin_args not in [
                            f.parent.parent for f in first_values
                    ]:
                        continue
            analysis.add(evaluator,
                         'type-error-too-many-arguments',
                         v,
                         message=m)
    return param_names
Пример #8
0
 def execute_evaluated(self, obj, *args):
     """
     Execute a function with already executed arguments.
     """
     args = [iterable.AlreadyEvaluated([arg]) for arg in args]
     return self.execute(obj, args)
Пример #9
0
    def parent(self):
        """
        Creating fake statements for the interpreter.
        """
        obj = self._value
        parser_path = []
        if inspect.ismodule(obj):
            module = obj
        else:
            names = []
            try:
                o = obj.__objclass__
                names.append(obj.__name__)
                obj = o
            except AttributeError:
                pass

            try:
                module_name = obj.__module__
                names.insert(0, obj.__name__)
            except AttributeError:
                # Unfortunately in some cases like `int` there's no __module__
                module = builtins
            else:
                # TODO this import is wrong. Yields x for x.y.z instead of z
                module = __import__(module_name)
            parser_path = names
        raw_module = get_module(self._value)

        found = []
        try:
            path = module.__file__
        except AttributeError:
            pass
        else:
            path = re.sub('c$', '', path)
            if path.endswith('.py'):
                # cut the `c` from `.pyc`
                with open(path) as f:
                    source = source_to_unicode(f.read())
                mod = FastParser(load_grammar(), source, path[:-1]).module
                if parser_path:
                    assert len(parser_path) == 1
                    found = self._evaluator.find_types(mod,
                                                       parser_path[0],
                                                       search_global=True)
                else:
                    found = [er.wrap(self._evaluator, mod)]

                if not found:
                    debug.warning(
                        'Possibly an interpreter lookup for Python code failed %s',
                        parser_path)

        if not found:
            evaluated = compiled.CompiledObject(obj)
            if evaluated == builtins:
                # The builtins module is special and always cached.
                evaluated = compiled.builtin
            found = [evaluated]

        content = iterable.AlreadyEvaluated(found)
        stmt = pt.ExprStmt([
            self,
            pt.Operator(pt.zero_position_modifier, '=', (0, 0), ''), content
        ])
        stmt.parent = self._module
        return stmt
Пример #10
0
    def parent(self):
        """
        Creating fake statements for the interpreter.

        Here we are trying to link back to Python code, if possible. This means
        we try to find the python module for a name (not the builtin).
        """
        return mixed.create(self._evaluator, self._value)
        obj = self._value
        parser_path = []
        if inspect.ismodule(obj):
            module = obj
        else:
            names = []
            try:
                o = obj.__objclass__
                names.append(obj.__name__)
                obj = o
            except AttributeError:
                pass

            try:
                module_name = obj.__module__
                names.insert(0, obj.__name__)
            except AttributeError:
                # Unfortunately in some cases like `int` there's no __module__
                module = builtins
            else:
                # If we put anything into fromlist, it will just return the
                # latest name.
                module = __import__(module_name, fromlist=[''])
            parser_path = names

        found = []
        try:
            path = module.__file__
        except AttributeError:
            pass
        else:
            # Find the corresponding Python file for an interpreted one.
            path = re.sub(r'\.pyc$', '.py', path)

            if path.endswith('.py'):
                with open(path) as f:
                    source = source_to_unicode(f.read())
                mod = FastParser(load_grammar(), source, path).module
                mod = self._evaluator.wrap(mod)

                # We have to make sure that the modules that we import are also
                # part of evaluator.modules.
                for module_name, module in sys.modules.items():
                    try:
                        iterated_path = module.__file__
                    except AttributeError:
                        pass
                    else:
                        if iterated_path == path:
                            self._evaluator.modules[module_name] = mod
                            break
                else:
                    raise NotImplementedError(
                        'This should not happen, a module '
                        'should be part of sys.modules.')

                if parser_path:
                    assert len(parser_path) == 1
                    found = list(
                        self._evaluator.find_types(mod,
                                                   parser_path[0],
                                                   search_global=True))
                else:
                    found = [mod]

                if not found:
                    debug.warning(
                        'Interpreter lookup failed in global scope for %s',
                        parser_path)

        if not found:
            evaluated = compiled.create(self._evaluator, obj)
            found = [evaluated]

        if len(found) > 1:
            content = iterable.AlreadyEvaluated(found)
            stmt = pt.ExprStmt([
                self,
                pt.Operator(pt.zero_position_modifier, '=', (0, 0), ''),
                content
            ])
            stmt.parent = self._module
            return stmt
        else:
            return found[0]