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)
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
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()
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()
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
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
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
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
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
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
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
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
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
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
def get_param(self): params = self.parent_context.get_params() param_node = search_ancestor(self.tree_name, 'param') return params[param_node.position_index]
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])
def get_parent_function(self): """ Returns the function/lambda of a parameter. """ return search_ancestor(self, 'funcdef', 'lambdef')
def get_param(self): params = self.parent_context.get_params() param_node = search_ancestor(self.tree_name, 'param') return params[param_node.position_nr]
def get_parent_function(self): """ Returns the function/lambda a paramter is defined in. """ return search_ancestor(self, ('funcdef', 'lambdef'))