Beispiel #1
0
 def _convert_names(self, names):
     for name in names:
         param = search_ancestor(name, 'param')
         if param:
             yield self.param_name(self.context, name)
         else:
             yield TreeNameDefinition(self.context, name)
Beispiel #2
0
    def _get_class_context_completions(self, is_function=True):
        """
        Autocomplete inherited methods when overriding in child class.
        """
        leaf = self._module_node.get_leaf_for_position(self._position,
                                                       include_prefixes=True)
        cls = tree.search_ancestor(leaf, 'classdef')
        if isinstance(cls, (tree.Class, tree.Function)):
            # Complete the methods that are defined in the super classes.
            random_context = self._module_context.create_context(
                cls, node_is_context=True)
        else:
            return

        if cls.start_pos[1] >= leaf.start_pos[1]:
            return

        filters = random_context.get_filters(search_global=False,
                                             is_instance=True)
        # The first dict is the dictionary of class itself.
        next(filters)
        for filter in filters:
            for name in filter.values():
                if (name.api_type == 'function') == is_function:
                    yield name
Beispiel #3
0
 def _convert_names(self, names):
     for name in names:
         param = search_ancestor(name, 'param')
         if param:
             yield self.param_name(self.context, name)
         else:
             yield TreeNameDefinition(self.context, name)
Beispiel #4
0
 def infer(self):
     param_node = search_ancestor(self.tree_name, 'param')
     if param_node.position_nr == 0:
         # This is a speed optimization, to return the self param (because
         # it's known). This only affects anonymous instances.
         return set([self.parent_context.instance])
     else:
         return self.get_param().infer()
Beispiel #5
0
 def infer(self):
     param_node = search_ancestor(self.tree_name, 'param')
     if param_node.position_index == 0:
         # This is a speed optimization, to return the self param (because
         # it's known). This only affects anonymous instances.
         return set([self.parent_context.instance])
     else:
         return self.get_param().infer()
Beispiel #6
0
def infer_import(context, tree_name, is_goto=False):
    module_context = context.get_root_context()
    import_node = search_ancestor(tree_name, ('import_name', 'import_from'))
    import_path = import_node.get_path_for_name(tree_name)
    from_import_name = None
    evaluator = context.evaluator
    try:
        from_names = import_node.get_from_names()
    except AttributeError:
        # Is an import_name
        pass
    else:
        if len(from_names) + 1 == len(import_path):
            # We have to fetch the from_names part first and then check
            # if from_names exists in the modules.
            from_import_name = import_path[-1]
            import_path = from_names

    importer = Importer(evaluator, tuple(import_path),
                        module_context, import_node.level)

    types = importer.follow()

    #if import_node.is_nested() and not self.nested_resolve:
    #    scopes = [NestedImportModule(module, import_node)]

    if from_import_name is not None:
        types = unite(
            t.py__getattribute__(
                from_import_name.value if isinstance(from_import_name, tree.Name) else from_import_name,
                name_context=context,
                is_goto=is_goto
            ) for t in types
        )

        if not types:
            path = import_path + [from_import_name]
            importer = Importer(evaluator, tuple(path),
                                module_context, import_node.level)
            types = importer.follow()
            # goto only accepts `Name`
            if is_goto:
                types = set(s.name for s in types)
    else:
        # goto only accepts `Name`
        if is_goto:
            types = set(s.name for s in types)

    debug.dbg('after import: %s', types)
    return types
Beispiel #7
0
def get_call_signature_param_names(call_signatures):
    # add named params
    for call_sig in call_signatures:
        for p in call_sig.params:
            # Allow protected access, because it's a public API.
            tree_name = p._name.tree_name
            # Compiled modules typically don't allow keyword arguments.
            if tree_name is not None:
                # Allow access on _definition here, because it's a
                # public API and we don't want to make the internal
                # Name object public.
                tree_param = tree.search_ancestor(tree_name, 'param')
                if tree_param.stars == 0:  # no *args/**kwargs
                    yield p._name
Beispiel #8
0
def infer_import(context, tree_name, is_goto=False):
    module_context = context.get_root_context()
    import_node = search_ancestor(tree_name, 'import_name', 'import_from')
    import_path = import_node.get_path_for_name(tree_name)
    from_import_name = None
    evaluator = context.evaluator
    try:
        from_names = import_node.get_from_names()
    except AttributeError:
        # Is an import_name
        pass
    else:
        if len(from_names) + 1 == len(import_path):
            # We have to fetch the from_names part first and then check
            # if from_names exists in the modules.
            from_import_name = import_path[-1]
            import_path = from_names

    importer = Importer(evaluator, tuple(import_path),
                        module_context, import_node.level)

    types = importer.follow()

    #if import_node.is_nested() and not self.nested_resolve:
    #    scopes = [NestedImportModule(module, import_node)]

    if from_import_name is not None:
        types = unite(
            t.py__getattribute__(
                from_import_name.value if isinstance(from_import_name, tree.Name) else from_import_name,
                name_context=context,
                is_goto=is_goto
            ) for t in types
        )

        if not types:
            path = import_path + [from_import_name]
            importer = Importer(evaluator, tuple(path),
                                module_context, import_node.level)
            types = importer.follow()
            # goto only accepts `Name`
            if is_goto:
                types = set(s.name for s in types)
    else:
        # goto only accepts `Name`
        if is_goto:
            types = set(s.name for s in types)

    debug.dbg('after import: %s', types)
    return types
Beispiel #9
0
    def get_yield_values(self):
        for_parents = [(y,
                        tree.search_ancestor(
                            y,
                            ('for_stmt', 'funcdef', 'while_stmt', 'if_stmt')))
                       for y in self.tree_node.yields]

        # Calculate if the yields are placed within the same for loop.
        yields_order = []
        last_for_stmt = None
        for yield_, for_stmt in for_parents:
            # For really simple for loops we can predict the order. Otherwise
            # we just ignore it.
            parent = for_stmt.parent
            if parent.type == 'suite':
                parent = parent.parent
            if for_stmt.type == 'for_stmt' and parent == self.tree_node \
                    and for_stmt.defines_one_name():  # Simplicity for now.
                if for_stmt == last_for_stmt:
                    yields_order[-1][1].append(yield_)
                else:
                    yields_order.append((for_stmt, [yield_]))
            elif for_stmt == self.tree_node:
                yields_order.append((None, [yield_]))
            else:
                types = self.get_return_values(check_yields=True)
                if types:
                    yield context.get_merged_lazy_context(list(types))
                return
            last_for_stmt = for_stmt

        evaluator = self.evaluator
        for for_stmt, yields in yields_order:
            if for_stmt is None:
                # No for_stmt, just normal yields.
                for yield_ in yields:
                    for result in self._eval_yield(yield_):
                        yield result
            else:
                input_node = for_stmt.get_input_node()
                for_types = self.eval_node(input_node)
                ordered = iterable.py__iter__(evaluator, for_types, input_node)
                ordered = list(ordered)
                for lazy_context in ordered:
                    dct = {str(for_stmt.children[1]): lazy_context.infer()}
                    with helpers.predefine_names(self, for_stmt, dct):
                        for yield_in_same_for_stmt in yields:
                            for result in self._eval_yield(
                                    yield_in_same_for_stmt):
                                yield result
Beispiel #10
0
def get_call_signature_param_names(call_signatures):
    # add named params
    for call_sig in call_signatures:
        for p in call_sig.params:
            # Allow protected access, because it's a public API.
            tree_name = p._name.tree_name
            # Compiled modules typically don't allow keyword arguments.
            if tree_name is not None:
                # Allow access on _definition here, because it's a
                # public API and we don't want to make the internal
                # Name object public.
                tree_param = tree.search_ancestor(tree_name, 'param')
                if tree_param.stars == 0:  # no *args/**kwargs
                    yield p._name
Beispiel #11
0
def follow_param(module_context, param):
    def eval_docstring(docstring):
        return set(
            [p for param_str in _search_param_in_docstr(docstring, str(param.name))
                for p in _evaluate_for_statement_string(module_context, param_str)]
        )
    func = param.get_parent_function()
    types = eval_docstring(func.raw_doc)
    if func.name.value == '__init__':
        cls = search_ancestor(func, 'classdef')
        if cls is not None:
            types |= eval_docstring(cls.raw_doc)

    return types
Beispiel #12
0
    def _eval_stmt(self, context, stmt, seek_name=None):
        """
        The starting point of the completion. A statement always owns a call
        list, which are the calls, that a statement does. In case multiple
        names are defined in the statement, `seek_name` returns the result for
        this name.

        :param stmt: A `tree.ExprStmt`.
        """
        debug.dbg('eval_statement %s (%s)', stmt, seek_name)
        rhs = stmt.get_rhs()
        types = self.eval_element(context, rhs)

        if seek_name:
            types = finder.check_tuple_assignments(self, types, seek_name)

        first_operation = stmt.first_operation()
        if first_operation not in (
                '=', None) and first_operation.type == 'operator':
            # `=` is always the last character in aug assignments -> -1
            operator = copy.copy(first_operation)
            operator.value = operator.value[:-1]
            name = str(stmt.get_defined_names()[0])
            left = context.py__getattribute__(name,
                                              position=stmt.start_pos,
                                              search_global=True)

            for_stmt = tree.search_ancestor(stmt, 'for_stmt')
            if isinstance(for_stmt, tree.ForStmt) and types \
                    and for_stmt.defines_one_name():
                # Iterate through result and add the values, that's possible
                # only in for loops without clutter, because they are
                # predictable. Also only do it, if the variable is not a tuple.
                node = for_stmt.get_input_node()
                for_iterables = self.eval_element(context, node)
                ordered = list(iterable.py__iter__(self, for_iterables, node))

                for lazy_context in ordered:
                    dct = {str(for_stmt.children[1]): lazy_context.infer()}
                    with helpers.predefine_names(context, for_stmt, dct):
                        t = self.eval_element(context, rhs)
                        left = precedence.calculate(self, context, left,
                                                    operator, t)
                types = left
            else:
                types = precedence.calculate(self, context, left, operator,
                                             types)
        debug.dbg('eval_statement result %s', types)
        return types
Beispiel #13
0
def follow_param(module_context, param):
    def eval_docstring(docstring):
        docstr = convert_docstring(docstring)
        return set([
            p for param_str in _search_param_in_docstr(docstr, str(param.name))
            for p in _evaluate_for_statement_string(module_context, param_str)
        ])

    func = param.get_parent_function()
    types = eval_docstring(func.raw_doc)
    if func.name.value == '__init__':
        cls = search_ancestor(func, 'classdef')
        if cls is not None:
            types |= eval_docstring(cls.raw_doc)

    return types
Beispiel #14
0
    def get_yield_values(self):
        for_parents = [(y, tree.search_ancestor(y, ('for_stmt', 'funcdef',
                                                    'while_stmt', 'if_stmt')))
                       for y in self.tree_node.yields]

        # Calculate if the yields are placed within the same for loop.
        yields_order = []
        last_for_stmt = None
        for yield_, for_stmt in for_parents:
            # For really simple for loops we can predict the order. Otherwise
            # we just ignore it.
            parent = for_stmt.parent
            if parent.type == 'suite':
                parent = parent.parent
            if for_stmt.type == 'for_stmt' and parent == self.tree_node \
                    and for_stmt.defines_one_name():  # Simplicity for now.
                if for_stmt == last_for_stmt:
                    yields_order[-1][1].append(yield_)
                else:
                    yields_order.append((for_stmt, [yield_]))
            elif for_stmt == self.tree_node:
                yields_order.append((None, [yield_]))
            else:
                types = self.get_return_values(check_yields=True)
                if types:
                    yield context.get_merged_lazy_context(list(types))
                return
            last_for_stmt = for_stmt

        evaluator = self.evaluator
        for for_stmt, yields in yields_order:
            if for_stmt is None:
                # No for_stmt, just normal yields.
                for yield_ in yields:
                    for result in self._eval_yield(yield_):
                        yield result
            else:
                input_node = for_stmt.get_input_node()
                for_types = self.eval_node(input_node)
                ordered = iterable.py__iter__(evaluator, for_types, input_node)
                ordered = list(ordered)
                for lazy_context in ordered:
                    dct = {str(for_stmt.children[1]): lazy_context.infer()}
                    with helpers.predefine_names(self, for_stmt, dct):
                        for yield_in_same_for_stmt in yields:
                            for result in self._eval_yield(yield_in_same_for_stmt):
                                yield result
Beispiel #15
0
def _check_flow_information(context, flow, search_name, pos):
    """ Try to find out the type of a variable just with the information that
    is given by the flows: e.g. It is also responsible for assert checks.::

        if isinstance(k, str):
            k.  # <- completion here

    ensures that `k` is a string.
    """
    if not settings.dynamic_flow_information:
        return None

    result = None
    if flow.is_scope():
        # Check for asserts.
        module_node = flow.get_root_node()
        try:
            names = module_node.get_used_names()[search_name.value]
        except KeyError:
            return None
        names = reversed([
            n for n in names
            if flow.start_pos <= n.start_pos < (pos or flow.end_pos)
        ])

        for name in names:
            ass = search_ancestor(name, 'assert_stmt')
            if ass is not None:
                result = _check_isinstance_type(context, ass.assertion,
                                                search_name)
                if result is not None:
                    return result

    if flow.type in ('if_stmt', 'while_stmt'):
        potential_ifs = [c for c in flow.children[1::4] if c != ':']
        for if_test in reversed(potential_ifs):
            if search_name.start_pos > if_test.end_pos:
                return _check_isinstance_type(context, if_test, search_name)
    return result
Beispiel #16
0
def _check_flow_information(context, flow, search_name, pos):
    """ Try to find out the type of a variable just with the information that
    is given by the flows: e.g. It is also responsible for assert checks.::

        if isinstance(k, str):
            k.  # <- completion here

    ensures that `k` is a string.
    """
    if not settings.dynamic_flow_information:
        return None

    result = None
    if is_scope(flow):
        # Check for asserts.
        module_node = flow.get_root_node()
        try:
            names = module_node.get_used_names()[search_name.value]
        except KeyError:
            return None
        names = reversed([
            n for n in names
            if flow.start_pos <= n.start_pos < (pos or flow.end_pos)
        ])

        for name in names:
            ass = search_ancestor(name, 'assert_stmt')
            if ass is not None:
                result = _check_isinstance_type(context, ass.assertion, search_name)
                if result is not None:
                    return result

    if flow.type in ('if_stmt', 'while_stmt'):
        potential_ifs = [c for c in flow.children[1::4] if c != ':']
        for if_test in reversed(potential_ifs):
            if search_name.start_pos > if_test.end_pos:
                return _check_isinstance_type(context, if_test, search_name)
    return result
Beispiel #17
0
 def get_param(self):
     params = self.parent_context.get_params()
     param_node = search_ancestor(self.tree_name, 'param')
     return params[param_node.position_index]
Beispiel #18
0
    def eval_atom(self, context, atom):
        """
        Basically to process ``atom`` nodes. The parser sometimes doesn't
        generate the node (because it has just one child). In that case an atom
        might be a name or a literal as well.
        """
        if isinstance(atom, tree.Name):
            # This is the first global lookup.
            stmt = atom.get_definition()
            if isinstance(stmt, tree.CompFor):
                stmt = tree.search_ancestor(
                    stmt, ('expr_stmt', 'lambda', 'funcdef', 'classdef'))
            if stmt is None or stmt.type != 'expr_stmt':
                # We only need to adjust the start_pos for statements, because
                # there the name cannot be used.
                stmt = atom
            return context.py__getattribute__(name_or_str=atom,
                                              position=stmt.start_pos,
                                              search_global=True)
        elif isinstance(atom, tree.Literal):
            return set([compiled.create(self, atom.eval())])
        else:
            c = atom.children
            if c[0].type == 'string':
                # Will be one string.
                types = self.eval_atom(context, c[0])
                for string in c[1:]:
                    right = self.eval_atom(context, string)
                    types = precedence.calculate(self, context, types, '+',
                                                 right)
                return types
            # Parentheses without commas are not tuples.
            elif c[0] == '(' and not len(c) == 2 \
                    and not(c[1].type == 'testlist_comp' and
                            len(c[1].children) > 1):
                return self.eval_element(context, c[1])

            try:
                comp_for = c[1].children[1]
            except (IndexError, AttributeError):
                pass
            else:
                if comp_for == ':':
                    # Dict comprehensions have a colon at the 3rd index.
                    try:
                        comp_for = c[1].children[3]
                    except IndexError:
                        pass

                if comp_for.type == 'comp_for':
                    return set([
                        iterable.Comprehension.from_atom(self, context, atom)
                    ])

            # It's a dict/list/tuple literal.
            array_node = c[1]
            try:
                array_node_c = array_node.children
            except AttributeError:
                array_node_c = []
            if c[0] == '{' and (array_node == '}' or ':' in array_node_c):
                context = iterable.DictLiteralContext(self, context, atom)
            else:
                context = iterable.SequenceLiteralContext(self, context, atom)
            return set([context])
Beispiel #19
0
 def get_parent_function(self):
     """
     Returns the function/lambda of a parameter.
     """
     return search_ancestor(self, 'funcdef', 'lambdef')
Beispiel #20
0
 def get_param(self):
     params = self.parent_context.get_params()
     param_node = search_ancestor(self.tree_name, 'param')
     return params[param_node.position_nr]
Beispiel #21
0
 def get_parent_function(self):
     """
     Returns the function/lambda a paramter is defined in.
     """
     return search_ancestor(self, ('funcdef', 'lambdef'))
Beispiel #22
0
 def get_parent_function(self):
     """
     Returns the function/lambda of a parameter.
     """
     return search_ancestor(self, 'funcdef', 'lambdef')