def _break_check(evaluator, stmt, base_scope, element_scope): from jedi.evaluate.representation import wrap element_scope = wrap(evaluator, element_scope) base_scope = wrap(evaluator, base_scope) reachable = REACHABLE if isinstance(element_scope, pr.IfStmt): if element_scope.node_after_else(stmt): for check_node in element_scope.check_nodes(): reachable = _check_if(evaluator, check_node) if reachable in (REACHABLE, UNSURE): break reachable = reachable.invert() else: node = element_scope.node_in_which_check_node(stmt) reachable = _check_if(evaluator, node) elif isinstance(element_scope, (pr.TryStmt, pr.WhileStmt)): return UNSURE # Only reachable branches need to be examined further. if reachable in (UNREACHABLE, UNSURE): return reachable if base_scope != element_scope and base_scope != element_scope.parent: return reachable & _break_check(evaluator, stmt, base_scope, element_scope.parent) return reachable
def break_check(evaluator, base_scope, element_scope, origin_scope=None): from jedi.evaluate.representation import wrap base_scope = wrap(evaluator, base_scope) element_scope = wrap(evaluator, element_scope) # Direct parents get resolved, we filter scopes that are separate branches. # This makes sense for autocompletion and static analysis. For actual # Python it doesn't matter, because we're talking about potentially # unreachable code. s = origin_scope while s is not None: if element_scope == s: return REACHABLE s = s.parent reachable = REACHABLE if isinstance(element_scope, Flow): if element_scope.command == 'else': check_scope = element_scope while check_scope.previous is not None: check_scope = check_scope.previous reachable = _check_flow(evaluator, check_scope) if reachable in (REACHABLE, UNSURE): break reachable = reachable.invert() else: reachable = _check_flow(evaluator, element_scope) # Only reachable branches need to be examined further. if reachable in (UNREACHABLE, UNSURE): return reachable if base_scope != element_scope and base_scope != element_scope.parent: return reachable & break_check(evaluator, base_scope, element_scope.parent) return reachable
def _simple_complete(self, path, dot, like): if not path and not dot: scope = self._parser.user_scope() if not scope.is_scope(): # Might be a flow (if/while/etc). scope = scope.get_parent_scope() names_dicts = global_names_dict_generator( self._evaluator, er.wrap(self._evaluator, scope), self._pos) completion_names = [] for names_dict, pos in names_dicts: names = list(chain.from_iterable(names_dict.values())) if not names: continue completion_names += filter_definition_names( names, self._parser.user_stmt(), pos) elif self._get_under_cursor_stmt(path) is None: return [] else: scopes = list(self._prepare_goto(path, True)) completion_names = [] debug.dbg('possible completion scopes: %s', scopes) for s in scopes: names = [] for names_dict in s.names_dicts(search_global=False): names += chain.from_iterable(names_dict.values()) completion_names += filter_definition_names( names, self._parser.user_stmt()) return completion_names
def eval_statement(self, 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 `pr.ExprStmt`. """ debug.dbg('eval_statement %s (%s)', stmt, seek_name) types = self.eval_element(stmt.get_rhs()) if seek_name: types = finder.check_tuple_assignments(types, seek_name) first_operation = stmt.first_operation() if first_operation not in ('=', None) and not isinstance(stmt, er.InstanceElement): # TODO don't check for this. # `=` 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]) parent = er.wrap(self, stmt.get_parent_scope()) left = self.find_types(parent, name, stmt.start_pos, search_global=True) if isinstance(stmt.get_parent_until(pr.ForStmt), pr.ForStmt): # Iterate through result and add the values, that's possible # only in for loops without clutter, because they are # predictable. for r in types: left = precedence.calculate(self, left, operator, [r]) types = left else: types = precedence.calculate(self, left, operator, types) debug.dbg('eval_statement result %s', types) return types
def _simple_complete(self, path, dot, like): if not path and not dot: scope = self._parser.user_scope() if not scope.is_scope(): # Might be a flow (if/while/etc). scope = scope.get_parent_scope() names_dicts = global_names_dict_generator( self._evaluator, er.wrap(self._evaluator, scope), self._pos ) completion_names = [] for names_dict, pos in names_dicts: names = list(chain.from_iterable(names_dict.values())) if not names: continue completion_names += filter_definition_names(names, self._parser.user_stmt(), pos) elif self._get_under_cursor_stmt(path) is None: return [] else: scopes = list(self._prepare_goto(path, True)) completion_names = [] debug.dbg('possible completion scopes: %s', scopes) for s in scopes: names = [] for names_dict in s.names_dicts(search_global=False): names += chain.from_iterable(names_dict.values()) completion_names += filter_definition_names(names, self._parser.user_stmt()) return completion_names
def names_dict_lookup(self, names_dict, position): def get_param(scope, el): if isinstance(el.get_parent_until(pr.Param), pr.Param): return scope.param_by_name(str(el)) return el search_str = str(self.name_str) try: names = names_dict[search_str] if not names: # We want names, otherwise stop. return [] except KeyError: return [] names = filter_definition_names(names, self.name_str, position) name_scope = None # Only the names defined in the last position are valid definitions. last_names = [] for name in reversed(sorted(names, key=lambda name: name.start_pos)): stmt = name.get_definition() name_scope = er.wrap(self._evaluator, stmt.get_parent_scope()) if isinstance(self.scope, er.Instance) and not isinstance( name_scope, er.Instance): # Instances should not be checked for positioning, because we # don't know in which order the functions are called. last_names.append(name) continue if isinstance(name_scope, compiled.CompiledObject): # Let's test this. TODO need comment. shouldn't this be # filtered before? last_names.append(name) continue if isinstance(name, compiled.CompiledName) \ or isinstance(name, er.InstanceName) and isinstance(name._origin_name, compiled.CompiledName): last_names.append(name) continue if isinstance(self.name_str, pr.Name): origin_scope = self.name_str.get_parent_until(pr.Scope, reverse=True) else: origin_scope = None if isinstance(stmt.parent, compiled.CompiledObject): # TODO seriously? this is stupid. continue check = flow_analysis.break_check(self._evaluator, name_scope, stmt, origin_scope) if check is not flow_analysis.UNREACHABLE: last_names.append(name) if check is flow_analysis.REACHABLE: break if isinstance(name_scope, er.FunctionExecution): # Replace params return [get_param(name_scope, n) for n in last_names] return last_names
def names_dict_lookup(self, names_dict, position): def get_param(scope, el): if isinstance(el.get_parent_until(pr.Param), pr.Param): return scope.param_by_name(str(el)) return el search_str = str(self.name_str) try: names = names_dict[search_str] if not names: # We want names, otherwise stop. return [] except KeyError: return [] names = filter_definition_names(names, self.name_str, position) name_scope = None # Only the names defined in the last position are valid definitions. last_names = [] for name in reversed(sorted(names, key=lambda name: name.start_pos)): stmt = name.get_definition() name_scope = er.wrap(self._evaluator, stmt.get_parent_scope()) if isinstance(self.scope, er.Instance) and not isinstance(name_scope, er.Instance): # Instances should not be checked for positioning, because we # don't know in which order the functions are called. last_names.append(name) continue if isinstance(name_scope, compiled.CompiledObject): # Let's test this. TODO need comment. shouldn't this be # filtered before? last_names.append(name) continue if isinstance(name, compiled.CompiledName) \ or isinstance(name, er.InstanceName) and isinstance(name._origin_name, compiled.CompiledName): last_names.append(name) continue if isinstance(self.name_str, pr.Name): origin_scope = self.name_str.get_parent_until(pr.Scope, reverse=True) else: origin_scope = None if isinstance(stmt.parent, compiled.CompiledObject): # TODO seriously? this is stupid. continue check = flow_analysis.break_check(self._evaluator, name_scope, stmt, origin_scope) if check is not flow_analysis.UNREACHABLE: last_names.append(name) if check is flow_analysis.REACHABLE: break if isinstance(name_scope, er.FunctionExecution): # Replace params return [get_param(name_scope, n) for n in last_names] return last_names
def _clean_names(self, names): """ ``NameFinder.filter_name`` should only output names with correct wrapper parents. We don't want to see AST classes out in the evaluation, so remove them already here! """ for n in names: definition = n.parent if isinstance(definition, (pr.Function, pr.Class, pr.Module)): yield er.wrap(self._evaluator, definition).name else: yield n
def break_check(evaluator, base_scope, stmt, origin_scope=None): from jedi.evaluate.representation import wrap element_scope = wrap(evaluator, stmt.get_parent_scope(include_flows=True)) # Direct parents get resolved, we filter scopes that are separate branches. # This makes sense for autocompletion and static analysis. For actual # Python it doesn't matter, because we're talking about potentially # unreachable code. # e.g. `if 0:` would cause all name lookup within the flow make # unaccessible. This is not a "problem" in Python, because the code is # never called. In Jedi though, we still want to infer types. while origin_scope is not None: if element_scope == origin_scope: return REACHABLE origin_scope = origin_scope.parent return _break_check(evaluator, stmt, base_scope, element_scope)
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportWrapper): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set( [er.wrap(self._evaluator, self._parser.user_scope())]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: definitions = set(signature._definition for signature in self.call_signatures()) if re.match('\w[\w\d_]*$', goto_path) and not definitions: user_stmt = self._parser.user_stmt() if user_stmt is not None and user_stmt.type == 'expr_stmt': for name in user_stmt.get_defined_names(): if name.start_pos <= self._pos <= name.end_pos: # TODO scaning for a name and then using it should be # the default. definitions = set( self._evaluator.goto_definition(name)) if not definitions and goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) names = [s.name for s in definitions] defs = [classes.Definition(self._evaluator, name) for name in names] return helpers.sorted_definitions(set(defs))
def __init__(self, evaluator, name): self._evaluator = evaluator self._name = name """ An instance of :class:`jedi.parser.reprsentation.Name` subclass. """ self._definition = er.wrap(evaluator, self._name.get_definition()) self.is_keyword = isinstance(self._definition, keywords.Keyword) # generate a path to the definition self._module = name.get_parent_until() if self.in_builtin_module(): self.module_path = None else: self.module_path = self._module.path """Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``"""
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportWrapper): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set([er.wrap(self._evaluator, self._parser.user_scope())]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: definitions = set(signature._definition for signature in self.call_signatures()) if re.match('\w[\w\d_]*$', goto_path) and not definitions: user_stmt = self._parser.user_stmt() if user_stmt is not None and user_stmt.type == 'expr_stmt': for name in user_stmt.get_defined_names(): if name.start_pos <= self._pos <= name.end_pos: # TODO scaning for a name and then using it should be # the default. definitions = set(self._evaluator.goto_definition(name)) if not definitions and goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) names = [s.name for s in definitions] defs = [classes.Definition(self._evaluator, name) for name in names] return helpers.sorted_definitions(set(defs))
def _eval_param(evaluator, param, scope): res_new = [] func = param.get_parent_scope() cls = func.parent.get_parent_until((pr.Class, pr.Function)) from jedi.evaluate.param import ExecutedParam, Arguments if isinstance(cls, pr.Class) and param.position_nr == 0 \ and not isinstance(param, ExecutedParam): # This is where we add self - if it has never been # instantiated. if isinstance(scope, er.InstanceElement): res_new.append(scope.instance) else: inst = er.Instance(evaluator, er.wrap(evaluator, cls), Arguments(evaluator, ()), is_generated=True) res_new.append(inst) return res_new # Instances are typically faked, if the instance is not called from # outside. Here we check it for __init__ functions and return. if isinstance(func, er.InstanceElement) \ and func.instance.is_generated and str(func.name) == '__init__': param = func.var.params[param.position_nr] # Add docstring knowledge. doc_params = docstrings.follow_param(evaluator, param) if doc_params: return doc_params if isinstance(param, ExecutedParam): return res_new + param.eval(evaluator) else: # Param owns no information itself. res_new += dynamic.search_params(evaluator, param) if not res_new: if param.stars: t = 'tuple' if param.stars == 1 else 'dict' typ = evaluator.find_types(compiled.builtin, t)[0] res_new = evaluator.execute(typ) if param.default: res_new += evaluator.eval_element(param.default) return res_new
def get_posibilities(evaluator, module, func_name): try: names = module.used_names[func_name] except KeyError: return [] for name in names: stmt = name.get_definition() if not isinstance(stmt, (pr.ExprStmt, pr.CompFor, pr.ReturnStmt)): continue parent = name.parent if pr.is_node(parent, 'trailer'): parent = parent.parent trailer = None if pr.is_node(parent, 'power'): for t in parent.children[1:]: if t == '**': break if t.start_pos > name.start_pos and t.children[ 0] == '(': trailer = t break if trailer is not None: types = evaluator.goto_definition(name) # We have to remove decorators, because they are not the # "original" functions, this way we can easily compare. # At the same time we also have to remove InstanceElements. undec = [] for escope in types: if escope.isinstance(er.Function, er.Instance) \ and escope.decorates is not None: undec.append(escope.decorates) elif isinstance(escope, er.InstanceElement): undec.append(escope.var) else: undec.append(escope) if er.wrap(evaluator, compare) in undec: # Only if we have the correct function we execute # it, otherwise just ignore it. evaluator.eval_trailer(types, trailer) return listener.param_possibilities
def goto_definitions(self): """ Return the definitions of a the path under the cursor. goto function! This follows complicated paths and returns the end, not the first definition. The big difference between :meth:`goto_assignments` and :meth:`goto_definitions` is that :meth:`goto_assignments` doesn't follow imports and statements. Multiple objects may be returned, because Python itself is a dynamic language, which means depending on an option you can have two different versions of a function. :rtype: list of :class:`classes.Definition` """ def resolve_import_paths(scopes): for s in scopes.copy(): if isinstance(s, imports.ImportWrapper): scopes.remove(s) scopes.update(resolve_import_paths(set(s.follow()))) return scopes user_stmt = self._parser.user_stmt_with_whitespace() goto_path = self._user_context.get_path_under_cursor() context = self._user_context.get_context() definitions = set() if next(context) in ('class', 'def'): definitions = set([er.wrap(self._evaluator, self._parser.user_scope())]) else: # Fetch definition of callee, if there's no path otherwise. if not goto_path: call, _, _ = search_call_signatures(user_stmt, self._pos) if call is not None: definitions = set(self._evaluator.eval_call(call)) if not definitions: if goto_path: definitions = set(self._prepare_goto(goto_path)) definitions = resolve_import_paths(definitions) names = [s.name for s in definitions if s is not imports.ImportWrapper.GlobalNamespace] defs = [classes.Definition(self._evaluator, name) for name in names] return helpers.sorted_definitions(set(defs))
def get_posibilities(evaluator, module, func_name): try: names = module.used_names[func_name] except KeyError: return [] for name in names: parent = name.parent if pr.is_node(parent, 'trailer'): parent = parent.parent trailer = None if pr.is_node(parent, 'power'): for t in parent.children[1:]: if t == '**': break if t.start_pos > name.start_pos and t.children[0] == '(': trailer = t break if trailer is not None: types = evaluator.goto_definition(name) # We have to remove decorators, because they are not the # "original" functions, this way we can easily compare. # At the same time we also have to remove InstanceElements. undec = [] for escope in types: if escope.isinstance(er.Function, er.Instance) \ and escope.decorates is not None: undec.append(escope.decorates) elif isinstance(escope, er.InstanceElement): undec.append(escope.var) else: undec.append(escope) if er.wrap(evaluator, compare) in undec: # Only if we have the correct function we execute # it, otherwise just ignore it. evaluator.eval_trailer(types, trailer) return listener.param_possibilities
def completions(self): """ Return :class:`classes.Completion` objects. Those objects contain information about the completions, more than just names. :return: Completion objects, sorted by name and __ comes last. :rtype: list of :class:`classes.Completion` """ def get_completions(user_stmt, bs): if isinstance(user_stmt, pr.Import): context = self._user_context.get_context() next(context) # skip the path if next(context) == 'from': # completion is just "import" if before stands from .. return ((k, bs) for k in keywords.keyword_names('import')) return self._simple_complete(path, like) def completion_possible(path): """ The completion logic is kind of complicated, because we strip the last word part. To ignore certain strange patterns with dots, just use regex. """ if re.match('\d+\.\.$|\.{4}$', path): return True # check Ellipsis and float literal `1.` return not re.search(r'^\.|^\d\.$|\.\.$', path) debug.speed('completions start') path = self._user_context.get_path_until_cursor() if not completion_possible(path): return [] path, dot, like = helpers.completion_parts(path) user_stmt = self._parser.user_stmt_with_whitespace() b = compiled.builtin completions = get_completions(user_stmt, b) if not dot: # add named params for call_sig in self.call_signatures(): # Allow protected access, because it's a public API. module = call_sig._name.get_parent_until() # Compiled modules typically don't allow keyword arguments. if not isinstance(module, compiled.CompiledObject): for p in call_sig.params: # Allow access on _definition here, because it's a # public API and we don't want to make the internal # Name object public. if p._definition.stars == 0: # no *args/**kwargs completions.append((p._name, p._name)) if not path and not isinstance(user_stmt, pr.Import): # add keywords completions += ((k, b) for k in keywords.keyword_names(all=True)) needs_dot = not dot and path comps = [] comp_dct = {} for c, s in set(completions): n = str(c) if settings.case_insensitive_completion \ and n.lower().startswith(like.lower()) \ or n.startswith(like): if not filter_private_variable(s, user_stmt or self._parser.user_scope(), n): if isinstance(c.parent, (pr.Function, pr.Class)): # TODO I think this is a hack. It should be an # er.Function/er.Class before that. c = er.wrap(self._evaluator, c.parent).name new = classes.Completion(self._evaluator, c, needs_dot, len(like), s) k = (new.name, new.complete) # key if k in comp_dct and settings.no_completion_duplicates: comp_dct[k]._same_name_completions.append(new) else: comp_dct[k] = new comps.append(new) debug.speed('completions end') return sorted(comps, key=lambda x: (x.name.startswith('__'), x.name.startswith('_'), x.name.lower()))
def completion_names(self, evaluator, only_modules=False): """ :param only_modules: Indicates wheter it's possible to import a definition that is not defined in a module. """ from jedi.evaluate import finder, representation as er names = [] if self.import_path: # flask if self.str_import_path == ('flask', 'ext'): # List Flask extensions like ``flask_foo`` for mod in self._get_module_names(): modname = str(mod) if modname.startswith('flask_'): extname = modname[len('flask_'):] names.append(self._generate_name(extname)) # Now the old style: ``flaskext.foo`` for dir in self.sys_path_with_modifications(): flaskext = os.path.join(dir, 'flaskext') if os.path.isdir(flaskext): names += self._get_module_names([flaskext]) for scope in self.follow(evaluator): # Non-modules are not completable. if not scope.type == 'file_input': # not a module continue # namespace packages if isinstance(scope, pr.Module) and scope.path.endswith('__init__.py'): pkg_path = os.path.dirname(scope.path) paths = self.namespace_packages(pkg_path, self.import_path) names += self._get_module_names([pkg_path] + paths) if only_modules: # In the case of an import like `from x.` we don't need to # add all the variables. if ('os',) == self.str_import_path and not self.level: # os.path is a hardcoded exception, because it's a # ``sys.modules`` modification. names.append(self._generate_name('path')) continue for names_dict in scope.names_dicts(search_global=False): _names = list(chain.from_iterable(names_dict.values())) if not _names: continue _names = finder.filter_definition_names(_names, scope) names += _names else: # Empty import path=completion after import if not self.level: names += self._get_module_names() if self.file_path is not None: path = os.path.abspath(self.file_path) for i in range(self.level - 1): path = os.path.dirname(path) names += self._get_module_names([path]) if self.level: rel_path = os.path.join(self.get_relative_path(), '__init__.py') if os.path.exists(rel_path): module = _load_module(self._evaluator, rel_path) module = er.wrap(self._evaluator, module) for names_dict in module.names_dicts(search_global=False): names += chain.from_iterable(names_dict.values()) return names
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
def completions(self): """ Return :class:`classes.Completion` objects. Those objects contain information about the completions, more than just names. :return: Completion objects, sorted by name and __ comes last. :rtype: list of :class:`classes.Completion` """ def get_completions(user_stmt, bs): # TODO this closure is ugly. it also doesn't work with # simple_complete (used for Interpreter), somehow redo. module = self._parser.module() names, level, only_modules, unfinished_dotted = \ helpers.check_error_statements(module, self._pos) completion_names = [] if names is not None: imp_names = [n for n in names if n.end_pos < self._pos] i = imports.get_importer(self._evaluator, imp_names, module, level) completion_names = i.completion_names(self._evaluator, only_modules) # TODO this paragraph is necessary, but not sure it works. context = self._user_context.get_context() if not next(context).startswith('.'): # skip the path if next(context) == 'from': # completion is just "import" if before stands from .. if unfinished_dotted: return completion_names else: return keywords.keyword_names('import') if isinstance(user_stmt, pr.Import): module = self._parser.module() completion_names += imports.completion_names(self._evaluator, user_stmt, self._pos) return completion_names if names is None and not isinstance(user_stmt, pr.Import): if not path and not dot: # add keywords completion_names += keywords.keyword_names(all=True) # TODO delete? We should search for valid parser # transformations. completion_names += self._simple_complete(path, dot, like) return completion_names debug.speed('completions start') path = self._user_context.get_path_until_cursor() # Dots following an int are not the start of a completion but a float # literal. if re.search(r'^\d\.$', path): return [] path, dot, like = helpers.completion_parts(path) user_stmt = self._parser.user_stmt_with_whitespace() b = compiled.builtin completion_names = get_completions(user_stmt, b) if not dot: # add named params for call_sig in self.call_signatures(): # Allow protected access, because it's a public API. module = call_sig._name.get_parent_until() # Compiled modules typically don't allow keyword arguments. if not isinstance(module, compiled.CompiledObject): for p in call_sig.params: # Allow access on _definition here, because it's a # public API and we don't want to make the internal # Name object public. if p._definition.stars == 0: # no *args/**kwargs completion_names.append(p._name) needs_dot = not dot and path comps = [] comp_dct = {} for c in set(completion_names): n = str(c) if settings.case_insensitive_completion \ and n.lower().startswith(like.lower()) \ or n.startswith(like): if isinstance(c.parent, (pr.Function, pr.Class)): # TODO I think this is a hack. It should be an # er.Function/er.Class before that. c = er.wrap(self._evaluator, c.parent).name new = classes.Completion(self._evaluator, c, needs_dot, len(like)) k = (new.name, new.complete) # key if k in comp_dct and settings.no_completion_duplicates: comp_dct[k]._same_name_completions.append(new) else: comp_dct[k] = new comps.append(new) debug.speed('completions end') return sorted(comps, key=lambda x: (x.name.startswith('__'), x.name.startswith('_'), x.name.lower()))
def global_names_dict_generator(evaluator, scope, position): """ For global name lookups. Yields tuples of (names_dict, position). If the position is None, the position does not matter anymore in that scope. This function is used to include names from outer scopes. For example, when the current scope is function: >>> from jedi._compatibility import u, no_unicode_pprint >>> from jedi.parser import Parser, load_grammar >>> parser = Parser(load_grammar(), u(''' ... x = ['a', 'b', 'c'] ... def func(): ... y = None ... ''')) >>> scope = parser.module.subscopes[0] >>> scope <Function: func@3-5> `global_names_dict_generator` is a generator. First it yields names from most inner scope. >>> from jedi.evaluate import Evaluator >>> evaluator = Evaluator(load_grammar()) >>> scope = er.wrap(evaluator, scope) >>> pairs = list(global_names_dict_generator(evaluator, scope, (4, 0))) >>> no_unicode_pprint(pairs[0]) ({'func': [], 'y': [<Name: y@4,4>]}, (4, 0)) Then it yields the names from one level "lower". In this example, this is the most outer scope. As you can see, the position in the tuple is now None, because typically the whole module is loaded before the function is called. >>> no_unicode_pprint(pairs[1]) ({'func': [<Name: func@3,4>], 'x': [<Name: x@2,0>]}, None) After that we have a few underscore names that are part of the module. >>> sorted(pairs[2][0].keys()) ['__doc__', '__file__', '__name__', '__package__'] >>> pairs[3] # global names -> there are none in our example. ({}, None) >>> pairs[4] # package modules -> Also none. ({}, None) Finally, it yields names from builtin, if `include_builtin` is true (default). >>> pairs[5][0].values() #doctest: +ELLIPSIS [[<CompiledName: ...>], ...] """ in_func = False while scope is not None: if not (scope.type == 'classdef' and in_func): # Names in methods cannot be resolved within the class. for names_dict in scope.names_dicts(True): yield names_dict, position if scope.type == 'funcdef': # The position should be reset if the current scope is a function. in_func = True position = None scope = er.wrap(evaluator, scope.get_parent_scope()) # Add builtins to the global scope. for names_dict in compiled.builtin.names_dicts(True): yield names_dict, None
def __init__(self, evaluator, scope, name_str, position=None): self._evaluator = evaluator # Make sure that it's not just a syntax tree node. self.scope = er.wrap(evaluator, scope) self.name_str = name_str self.position = position
def completions(self): """ Return :class:`classes.Completion` objects. Those objects contain information about the completions, more than just names. :return: Completion objects, sorted by name and __ comes last. :rtype: list of :class:`classes.Completion` """ def get_completions(user_stmt, bs): # TODO this closure is ugly. it also doesn't work with # simple_complete (used for Interpreter), somehow redo. module = self._parser.module() names, level, only_modules, unfinished_dotted = \ helpers.check_error_statements(module, self._pos) completion_names = [] if names is not None: imp_names = [n for n in names if n.end_pos < self._pos] i = imports.get_importer(self._evaluator, imp_names, module, level) completion_names = i.completion_names(self._evaluator, only_modules) # TODO this paragraph is necessary, but not sure it works. context = self._user_context.get_context() if not next(context).startswith('.'): # skip the path if next(context) == 'from': # completion is just "import" if before stands from .. if unfinished_dotted: return completion_names else: return keywords.keyword_names('import') if isinstance(user_stmt, pr.Import): module = self._parser.module() completion_names += imports.completion_names( self._evaluator, user_stmt, self._pos) return completion_names if names is None and not isinstance(user_stmt, pr.Import): if not path and not dot: # add keywords completion_names += keywords.keyword_names(all=True) # TODO delete? We should search for valid parser # transformations. completion_names += self._simple_complete(path, dot, like) return completion_names debug.speed('completions start') path = self._user_context.get_path_until_cursor() # Dots following an int are not the start of a completion but a float # literal. if re.search(r'^\d\.$', path): return [] path, dot, like = helpers.completion_parts(path) user_stmt = self._parser.user_stmt_with_whitespace() b = compiled.builtin completion_names = get_completions(user_stmt, b) if not dot: # add named params for call_sig in self.call_signatures(): # Allow protected access, because it's a public API. module = call_sig._name.get_parent_until() # Compiled modules typically don't allow keyword arguments. if not isinstance(module, compiled.CompiledObject): for p in call_sig.params: # Allow access on _definition here, because it's a # public API and we don't want to make the internal # Name object public. if p._definition.stars == 0: # no *args/**kwargs completion_names.append(p._name) needs_dot = not dot and path comps = [] comp_dct = {} for c in set(completion_names): n = str(c) if settings.case_insensitive_completion \ and n.lower().startswith(like.lower()) \ or n.startswith(like): if isinstance(c.parent, (pr.Function, pr.Class)): # TODO I think this is a hack. It should be an # er.Function/er.Class before that. c = er.wrap(self._evaluator, c.parent).name new = classes.Completion(self._evaluator, c, needs_dot, len(like)) k = (new.name, new.complete) # key if k in comp_dct and settings.no_completion_duplicates: comp_dct[k]._same_name_completions.append(new) else: comp_dct[k] = new comps.append(new) debug.speed('completions end') return sorted( comps, key=lambda x: (x.name.startswith('__'), x.name.startswith('_'), x.name.lower()))
def completion_names(self, evaluator, only_modules=False): """ :param only_modules: Indicates wheter it's possible to import a definition that is not defined in a module. """ from jedi.evaluate import finder, representation as er names = [] if self.import_path: # flask if self.str_import_path == ('flask', 'ext'): # List Flask extensions like ``flask_foo`` for mod in self._get_module_names(): modname = str(mod) if modname.startswith('flask_'): extname = modname[len('flask_'):] names.append(self._generate_name(extname)) # Now the old style: ``flaskext.foo`` for dir in self.sys_path_with_modifications(): flaskext = os.path.join(dir, 'flaskext') if os.path.isdir(flaskext): names += self._get_module_names([flaskext]) for scope in self.follow(evaluator): # Non-modules are not completable. if not scope.type == 'file_input': # not a module continue # namespace packages if isinstance( scope, pr.Module) and scope.path.endswith('__init__.py'): pkg_path = os.path.dirname(scope.path) paths = self.namespace_packages(pkg_path, self.import_path) names += self._get_module_names([pkg_path] + paths) if only_modules: # In the case of an import like `from x.` we don't need to # add all the variables. if ('os', ) == self.str_import_path and not self.level: # os.path is a hardcoded exception, because it's a # ``sys.modules`` modification. names.append(self._generate_name('path')) continue for names_dict in scope.names_dicts(search_global=False): _names = list(chain.from_iterable(names_dict.values())) if not _names: continue _names = finder.filter_definition_names(_names, scope) names += _names else: # Empty import path=completion after import if not self.level: names += self._get_module_names() if self.file_path is not None: path = os.path.abspath(self.file_path) for i in range(self.level - 1): path = os.path.dirname(path) names += self._get_module_names([path]) if self.level: rel_path = os.path.join(self.get_relative_path(), '__init__.py') if os.path.exists(rel_path): module = _load_module(self._evaluator, rel_path) module = er.wrap(self._evaluator, module) for names_dict in module.names_dicts( search_global=False): names += chain.from_iterable(names_dict.values()) return names
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
def parent(self): scope = self._definition.get_parent_scope() scope = er.wrap(self._evaluator, scope) return Definition(self._evaluator, scope.name)
def filter_name(self, scope_names_generator): """ Filters all variables of a scope (which are defined in the `scope_names_generator`), until the name fits. """ # TODO Now this import is really ugly. Try to remove it. # It's possibly the only api dependency. from jedi.api.interpreter import InterpreterNamespace names = [] self.maybe_descriptor = isinstance(self.scope, er.Class) for name_list_scope, name_list in scope_names_generator: break_scopes = [] if not isinstance(name_list_scope, compiled.CompiledObject): # Here is the position stuff happening (sorting of variables). # Compiled objects don't need that, because there's only one # reference. name_list = sorted(name_list, key=lambda n: n.start_pos, reverse=True) for name in name_list: if unicode(self.name_str) != name.get_code(): continue stmt = name.get_definition() scope = stmt.parent if scope in break_scopes: continue # Exclude `arr[1] =` from the result set. if not self._name_is_array_assignment(name, stmt): # TODO we ignore a lot of elements here that should not be # ignored. But then again flow_analysis also stops when the # input scope is reached. This is not correct: variables # might still have conditions if defined outside of the # current scope. if isinstance(stmt, (pr.Param, pr.Import)) \ or isinstance(name_list_scope, (pr.Lambda, pr.ListComprehension, er.Instance, InterpreterNamespace)) \ or isinstance(scope, compiled.CompiledObject) \ or isinstance(stmt, pr.ExprStmt) and stmt.is_global(): # Always reachable. names.append(name) else: check = flow_analysis.break_check(self._evaluator, name_list_scope, er.wrap(self._evaluator, scope), self.scope) if check is not flow_analysis.UNREACHABLE: names.append(name) if check is flow_analysis.REACHABLE: break if names and self._is_name_break_scope(stmt): if self._does_scope_break_immediately(scope, name_list_scope): break else: break_scopes.append(scope) if names: break if isinstance(self.scope, er.Instance): # After checking the dictionary of an instance (self # attributes), an attribute maybe a descriptor. self.maybe_descriptor = True scope_txt = (self.scope if self.scope == name_list_scope else '%s-%s' % (self.scope, name_list_scope)) debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str, scope_txt, u(names), self.position) return list(self._clean_names(names))