def get_filters(self, search_global=False): origin_scope = self._get_origin_scope() if search_global: position = self._position # For functions and classes the defaults don't belong to the # function and get evaluated in the context before the function. So # make sure to exclude the function/class name. if origin_scope is not None: ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef', 'lambdef') lambdef = None if ancestor == 'lambdef': # For lambdas it's even more complicated since parts will # be evaluated later. lambdef = ancestor ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef') if ancestor is not None: colon = ancestor.children[-2] if position < colon.start_pos: if lambdef is None or position < lambdef.children[-2].start_pos: position = ancestor.start_pos return get_global_filters(self._evaluator, self._context, position, origin_scope) else: return self._context.get_filters(search_global, self._position, origin_scope=origin_scope)
def get_filters(self, search_global=False): origin_scope = self._get_origin_scope() if search_global: position = self._position # For functions and classes the defaults don't belong to the # function and get evaluated in the context before the function. So # make sure to exclude the function/class name. if origin_scope is not None: ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef', 'lambdef') lambdef = None if ancestor == 'lambdef': # For lambdas it's even more complicated since parts will # be evaluated later. lambdef = ancestor ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef') if ancestor is not None: colon = ancestor.children[-2] if position is not None and position < colon.start_pos: if lambdef is None or position < lambdef.children[ -2].start_pos: position = ancestor.start_pos return get_global_filters(self._evaluator, self._context, position, origin_scope) else: return self._get_context_filters(origin_scope)
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 _iter_nodes_for_param(param_name): from parso.python.tree import search_ancestor from jedi.inference.arguments import TreeArguments execution_context = param_name.parent_context # Walk up the parso tree to get the FunctionNode we want. We use the parso # tree rather than going via the execution context so that we're agnostic of # the specific scope we're evaluating within (i.e: module or function, # etc.). function_node = tree.search_ancestor(param_name.tree_name, 'funcdef', 'lambdef') module_node = function_node.get_root_node() start = function_node.children[-1].start_pos end = function_node.children[-1].end_pos for name in module_node.get_used_names().get(param_name.string_name): if start <= name.start_pos < end: # Is used in the function argument = name.parent if argument.type == 'argument' \ and argument.children[0] == '*' * param_name.star_count: trailer = search_ancestor(argument, 'trailer') if trailer is not None: # Make sure we're in a function context = execution_context.create_context(trailer) if _goes_to_param_name(param_name, context, name): values = _to_callables(context, trailer) args = TreeArguments.create_cached( execution_context.inference_state, context=context, argument_node=trailer.children[1], trailer=trailer, ) for c in values: yield c, args
def parent(self): """ Returns the parent scope of this identifier. :rtype: Name """ if not self._name.is_value_name: return None if self.type in ('function', 'class', 'param') and self._name.tree_name is not None: # Since the parent_context doesn't really match what the user # thinks of that the parent is here, we do these cases separately. # The reason for this is the following: # - class: Nested classes parent_context is always the # parent_context of the most outer one. # - function: Functions in classes have the module as # parent_context. # - param: The parent_context of a param is not its function but # e.g. the outer class or module. cls_or_func_node = self._name.tree_name.get_definition() parent = search_ancestor(cls_or_func_node, 'funcdef', 'classdef', 'file_input') context = self._get_module_context().create_value( parent).as_context() else: context = self._name.parent_context if context is None: return None while context.name is None: # Happens for comprehension contexts context = context.parent_context return Name(self._inference_state, context.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 not types: return NO_CONTEXTS if from_import_name is not None: types = unite( t.py__getattribute__( from_import_name, name_context=context, is_goto=is_goto, analysis_errors=False ) for t in types ) if not is_goto: types = ContextSet(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 create_name(self, tree_name): definition = tree_name.get_definition() if definition and definition.type == 'param' and definition.name == tree_name: funcdef = search_ancestor(definition, 'funcdef', 'lambdef') func = self.create_value(funcdef) return AnonymousParamName(func, tree_name) else: context = self.create_context(tree_name) return TreeNameDefinition(context, tree_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 not types: return NO_CONTEXTS if from_import_name is not None: types = unite( t.py__getattribute__( from_import_name, name_context=context, is_goto=is_goto, analysis_errors=False ) for t in types ) if not is_goto: types = ContextSet.from_set(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 infer(self): param_node = search_ancestor(self.tree_name, 'param') # TODO I think this should not belong here. It's not even really true, # because classmethod and other descriptors can change it. 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 ContextSet(self.parent_context.instance) else: return self.get_param().infer()
def _get_global_filters_for_name(context, name_or_none, position): # For functions and classes the defaults don't belong to the # function and get inferred in the value before the function. So # make sure to exclude the function/class name. if name_or_none is not None: ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef', 'lambdef') lambdef = None if ancestor == 'lambdef': # For lambdas it's even more complicated since parts will # be inferred later. lambdef = ancestor ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef') if ancestor is not None: colon = ancestor.children[-2] if position is not None and position < colon.start_pos: if lambdef is None or position < lambdef.children[-2].start_pos: position = ancestor.start_pos return get_global_filters(context, position, name_or_none)
def _convert_names(self, names): for name in names: param = search_ancestor(name, 'param') # Here we don't need to check if the param is a default/annotation, # because those are not definitions and never make it to this # point. if param: yield self._convert_param(param, name) else: yield TreeNameDefinition(self.parent_context, name)
def infer(self): stmt = search_ancestor(self.tree_name, 'expr_stmt') if stmt is not None: if stmt.children[1].type == "annassign": from jedi.inference.gradual.annotation import infer_annotation values = infer_annotation( self.parent_context, stmt.children[1].children[1]).execute_annotation() if values: return values return super().infer()
def _is_a_pytest_param_and_inherited(param_name): """ Pytest params are either in a `test_*` function or have a pytest fixture with the decorator @pytest.fixture. This is a heuristic and will work in most cases. """ funcdef = search_ancestor(param_name.tree_name, 'funcdef') if funcdef is None: # A lambda return False, False decorators = funcdef.get_decorators() return _is_pytest_func(funcdef.name.value, decorators), \ funcdef.name.value == param_name.string_name
def create_instance_context(self, class_context, node): new = node while True: func_node = new new = search_ancestor(new, 'funcdef', 'classdef') if class_context.tree_node is new: func = FunctionValue.from_context(class_context, func_node) bound_method = BoundMethod(self, class_context, func) if func_node.name.value == '__init__': context = bound_method.as_context(self._arguments) else: context = bound_method.as_context() break return context.create_context(node)
def get_kind(self): tree_param = search_ancestor(self.tree_name, 'param') if tree_param.star_count == 1: # *args return Parameter.VAR_POSITIONAL if tree_param.star_count == 2: # **kwargs return Parameter.VAR_KEYWORD parent = tree_param.parent for p in parent.children: if p.type == 'param': if p.star_count: return Parameter.KEYWORD_ONLY if p == tree_param: break return Parameter.POSITIONAL_OR_KEYWORD
def get_qualified_names(self, include_module_names=False): import_node = search_ancestor(self.tree_name, 'import_name', 'import_from') # For import nodes we cannot just have names, because it's very unclear # how they would look like. For now we just ignore them in most cases. # In case of level == 1, it works always, because it's like a submodule # lookup. if import_node is not None and not (import_node.level == 1 and self.get_root_context().is_package): # TODO improve the situation for when level is present. if include_module_names and not import_node.level: return tuple(n.value for n in import_node.get_path_for_name(self.tree_name)) else: return None return super(AbstractTreeName, self).get_qualified_names(include_module_names)
def get_qualified_names(self, include_module_names=False): import_node = search_ancestor(self.tree_name, 'import_name', 'import_from') if import_node is not None: return tuple( n.value for n in import_node.get_path_for_name(self.tree_name)) parent_names = self.parent_context.get_qualified_names() if parent_names is None: return None parent_names += (self.tree_name.value, ) if include_module_names: module_names = self.get_root_context().string_names if module_names is None: return None return module_names + parent_names return parent_names
def _prepare_infer_import(module_context, tree_name): import_node = search_ancestor(tree_name, 'import_name', 'import_from') import_path = import_node.get_path_for_name(tree_name) from_import_name = None 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(module_context.inference_state, tuple(import_path), module_context, import_node.level) return from_import_name, tuple(import_path), import_node.level, importer.follow()
def _complete_params(self, leaf): stack_node = self.stack[-2] if stack_node.nonterminal == 'parameters': stack_node = self.stack[-3] if stack_node.nonterminal == 'funcdef': context = get_user_context(self._module_context, self._position) node = search_ancestor(leaf, 'error_node', 'funcdef') if node.type == 'error_node': n = node.children[0] if n.type == 'decorators': decorators = n.children elif n.type == 'decorator': decorators = [n] else: decorators = [] else: decorators = node.get_decorators() function_name = stack_node.nodes[1] return complete_param_names(context, function_name.value, decorators) return []
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 goto(self): context = self.parent_context name = self.tree_name definition = name.get_definition(import_name_always=True) if definition is not None: type_ = definition.type if type_ == 'expr_stmt': # Only take the parent, because if it's more complicated than just # a name it's something you can "goto" again. is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: return [self] elif type_ in ('import_from', 'import_name'): from jedi.inference.imports import goto_import module_names = goto_import(context, name) return module_names else: return [self] else: from jedi.inference.imports import follow_error_node_imports_if_possible values = follow_error_node_imports_if_possible(context, name) if values is not None: return [value.name for value in values] par = name.parent node_type = par.type if node_type == 'argument' and par.children[1] == '=' and par.children[ 0] == name: # Named param goto. trailer = par.parent if trailer.type == 'arglist': trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': value_set = context.infer_node(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_infer = trailer.parent.children[:i] if to_infer[0] == 'await': to_infer.pop(0) value_set = context.infer_node(to_infer[0]) from jedi.inference.syntax_tree import infer_trailer for trailer in to_infer[1:]: value_set = infer_trailer(context, value_set, trailer) param_names = [] for value in value_set: for signature in value.get_signatures(): for param_name in signature.get_param_names(): if param_name.string_name == name.value: param_names.append(param_name) return param_names elif node_type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: new_dotted = deep_ast_copy(par) new_dotted.children[index - 1:] = [] values = context.infer_node(new_dotted) return unite( value.goto(name, name_context=context) for value in values) if node_type == 'trailer' and par.children[0] == '.': values = infer_call_of_leaf(context, name, cut_own_trailer=True) return values.goto(name, name_context=context) else: stmt = search_ancestor(name, 'expr_stmt', 'lambdef') or name if stmt.type == 'lambdef': stmt = name return context.goto(name, position=stmt.start_pos)
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_index]
def _get_context_completions(self): """ Analyzes the context that a completion is made in and decides what to return. Technically this works by generating a parser stack and analysing the current stack for possible grammar nodes. Possible enhancements: - global/nonlocal search global - yield from / raise from <- could be only exceptions/generators - In args: */**: no completion - In params (also lambda): no completion before = """ grammar = self._evaluator.grammar try: self.stack = stack = helpers.get_stack_at_position( grammar, self._code_lines, self._module_node, self._position ) except helpers.OnErrorLeaf as e: self.stack = stack = None if e.error_leaf.value == '.': # After ErrorLeaf's that are dots, we will not do any # completions since this probably just confuses the user. return [] # If we don't have a context, just use global completion. return self._global_completions() allowed_transitions = \ list(stack._allowed_transition_names_and_token_types()) if 'if' in allowed_transitions: leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True) previous_leaf = leaf.get_previous_leaf() indent = self._position[1] if not (leaf.start_pos <= self._position <= leaf.end_pos): indent = leaf.start_pos[1] if previous_leaf is not None: stmt = previous_leaf while True: stmt = search_ancestor( stmt, 'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt', 'error_node', ) if stmt is None: break type_ = stmt.type if type_ == 'error_node': first = stmt.children[0] if isinstance(first, Leaf): type_ = first.value + '_stmt' # Compare indents if stmt.start_pos[1] == indent: if type_ == 'if_stmt': allowed_transitions += ['elif', 'else'] elif type_ == 'try_stmt': allowed_transitions += ['except', 'finally', 'else'] elif type_ == 'for_stmt': allowed_transitions.append('else') completion_names = [] current_line = self._code_lines[self._position[0] - 1][:self._position[1]] if not current_line or current_line[-1] in ' \t.;': completion_names += self._get_keyword_completion_names(allowed_transitions) if any(t in allowed_transitions for t in (PythonTokenTypes.NAME, PythonTokenTypes.INDENT)): # This means that we actually have to do type inference. nonterminals = [stack_node.nonterminal for stack_node in stack] nodes = [] for stack_node in stack: if stack_node.dfa.from_rule == 'small_stmt': nodes = [] else: nodes += stack_node.nodes if nodes and nodes[-1] in ('as', 'def', 'class'): # No completions for ``with x as foo`` and ``import x as foo``. # Also true for defining names as a class or function. return list(self._get_class_context_completions(is_function=True)) elif "import_stmt" in nonterminals: level, names = parse_dotted_names(nodes, "import_from" in nonterminals) only_modules = not ("import_from" in nonterminals and 'import' in nodes) completion_names += self._get_importer_names( names, level, only_modules=only_modules, ) elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.': dot = self._module_node.get_leaf_for_position(self._position) completion_names += self._trailer_completions(dot.get_previous_leaf()) else: completion_names += self._global_completions() completion_names += self._get_class_context_completions(is_function=False) if 'trailer' in nonterminals: call_signatures = self._call_signatures_method() completion_names += get_call_signature_param_names(call_signatures) return completion_names
def get_test_node_from_name(self, name): node = search_ancestor(name, "with_item") if node is None: raise ValueError( 'The name is not actually part of a with statement.') return node.children[0]
def _complete_python(self, leaf): """ Analyzes the current context of a completion and decides what to return. Technically this works by generating a parser stack and analysing the current stack for possible grammar nodes. Possible enhancements: - global/nonlocal search global - yield from / raise from <- could be only exceptions/generators - In args: */**: no completion - In params (also lambda): no completion before = """ grammar = self._inference_state.grammar self.stack = stack = None self._position = (self._original_position[0], self._original_position[1] - len(self._like_name)) cached_name = None try: self.stack = stack = helpers.get_stack_at_position( grammar, self._code_lines, leaf, self._position) except helpers.OnErrorLeaf as e: value = e.error_leaf.value if value == '.': # After ErrorLeaf's that are dots, we will not do any # completions since this probably just confuses the user. return cached_name, [] # If we don't have a value, just use global completion. return cached_name, self._complete_global_scope() allowed_transitions = \ list(stack._allowed_transition_names_and_token_types()) if 'if' in allowed_transitions: leaf = self._module_node.get_leaf_for_position( self._position, include_prefixes=True) previous_leaf = leaf.get_previous_leaf() indent = self._position[1] if not (leaf.start_pos <= self._position <= leaf.end_pos): indent = leaf.start_pos[1] if previous_leaf is not None: stmt = previous_leaf while True: stmt = search_ancestor( stmt, 'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt', 'error_node', ) if stmt is None: break type_ = stmt.type if type_ == 'error_node': first = stmt.children[0] if isinstance(first, Leaf): type_ = first.value + '_stmt' # Compare indents if stmt.start_pos[1] == indent: if type_ == 'if_stmt': allowed_transitions += ['elif', 'else'] elif type_ == 'try_stmt': allowed_transitions += [ 'except', 'finally', 'else' ] elif type_ == 'for_stmt': allowed_transitions.append('else') completion_names = [] current_line = self._code_lines[self._position[0] - 1][:self._position[1]] kwargs_only = False if any(t in allowed_transitions for t in (PythonTokenTypes.NAME, PythonTokenTypes.INDENT)): # This means that we actually have to do type inference. nonterminals = [stack_node.nonterminal for stack_node in stack] nodes = _gather_nodes(stack) if nodes and nodes[-1] in ('as', 'def', 'class'): # No completions for ``with x as foo`` and ``import x as foo``. # Also true for defining names as a class or function. return cached_name, list( self._complete_inherited(is_function=True)) elif "import_stmt" in nonterminals: level, names = parse_dotted_names( nodes, "import_from" in nonterminals) only_modules = not ("import_from" in nonterminals and 'import' in nodes) completion_names += self._get_importer_names( names, level, only_modules=only_modules, ) elif nonterminals[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.': dot = self._module_node.get_leaf_for_position(self._position) cached_name, n = self._complete_trailer( dot.get_previous_leaf()) completion_names += n elif self._is_parameter_completion(): completion_names += self._complete_params(leaf) else: # Apparently this looks like it's good enough to filter most cases # so that signature completions don't randomly appear. # To understand why this works, three things are important: # 1. trailer with a `,` in it is either a subscript or an arglist. # 2. If there's no `,`, it's at the start and only signatures start # with `(`. Other trailers could start with `.` or `[`. # 3. Decorators are very primitive and have an optional `(` with # optional arglist in them. if nodes[-1] in ['(', ','] \ and nonterminals[-1] in ('trailer', 'arglist', 'decorator'): signatures = self._signatures_callback(*self._position) if signatures: call_details = signatures[0]._call_details used_kwargs = list( call_details.iter_used_keyword_arguments()) positional_count = call_details.count_positional_arguments( ) completion_names += _get_signature_param_names( signatures, positional_count, used_kwargs, ) kwargs_only = _must_be_kwarg(signatures, positional_count, used_kwargs) if not kwargs_only: completion_names += self._complete_global_scope() completion_names += self._complete_inherited( is_function=False) if not kwargs_only: completion_names += self._complete_keywords( allowed_transitions, only_values=not (not current_line or current_line[-1] in ' \t.;' and current_line[-3:] != '...')) return cached_name, completion_names
def _get_context_completions(self): """ Analyzes the context that a completion is made in and decides what to return. Technically this works by generating a parser stack and analysing the current stack for possible grammar nodes. Possible enhancements: - global/nonlocal search global - yield from / raise from <- could be only exceptions/generators - In args: */**: no completion - In params (also lambda): no completion before = """ grammar = self._evaluator.grammar try: self.stack = helpers.get_stack_at_position( grammar, self._code_lines, self._module_node, self._position ) except helpers.OnErrorLeaf as e: self.stack = None if e.error_leaf.value == '.': # After ErrorLeaf's that are dots, we will not do any # completions since this probably just confuses the user. return [] # If we don't have a context, just use global completion. return self._global_completions() allowed_keywords, allowed_tokens = \ helpers.get_possible_completion_types(grammar._pgen_grammar, self.stack) if 'if' in allowed_keywords: leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True) previous_leaf = leaf.get_previous_leaf() indent = self._position[1] if not (leaf.start_pos <= self._position <= leaf.end_pos): indent = leaf.start_pos[1] if previous_leaf is not None: stmt = previous_leaf while True: stmt = search_ancestor( stmt, 'if_stmt', 'for_stmt', 'while_stmt', 'try_stmt', 'error_node', ) if stmt is None: break type_ = stmt.type if type_ == 'error_node': first = stmt.children[0] if isinstance(first, Leaf): type_ = first.value + '_stmt' # Compare indents if stmt.start_pos[1] == indent: if type_ == 'if_stmt': allowed_keywords += ['elif', 'else'] elif type_ == 'try_stmt': allowed_keywords += ['except', 'finally', 'else'] elif type_ == 'for_stmt': allowed_keywords.append('else') completion_names = list(self._get_keyword_completion_names(allowed_keywords)) if token.NAME in allowed_tokens or token.INDENT in allowed_tokens: # This means that we actually have to do type inference. symbol_names = list(self.stack.get_node_names(grammar._pgen_grammar)) nodes = list(self.stack.get_nodes()) if nodes and nodes[-1] in ('as', 'def', 'class'): # No completions for ``with x as foo`` and ``import x as foo``. # Also true for defining names as a class or function. return list(self._get_class_context_completions(is_function=True)) elif "import_stmt" in symbol_names: level, names = self._parse_dotted_names(nodes, "import_from" in symbol_names) only_modules = not ("import_from" in symbol_names and 'import' in nodes) completion_names += self._get_importer_names( names, level, only_modules=only_modules, ) elif symbol_names[-1] in ('trailer', 'dotted_name') and nodes[-1] == '.': dot = self._module_node.get_leaf_for_position(self._position) completion_names += self._trailer_completions(dot.get_previous_leaf()) else: completion_names += self._global_completions() completion_names += self._get_class_context_completions(is_function=False) if 'trailer' in symbol_names: call_signatures = self._call_signatures_method() completion_names += get_call_signature_param_names(call_signatures) return completion_names
def _get_param_node(self): return search_ancestor(self.tree_name, 'param')
def get_param(self): params, _ = self.parent_context.get_executed_params_and_issues() param_node = search_ancestor(self.tree_name, 'param') return params[param_node.position_index]
def is_import(self): imp = search_ancestor(self.tree_name, 'import_from', 'import_name') return imp is not None