def get_on_import_stmt(evaluator, user_context, user_stmt, is_like_search=False): """ Resolve the user statement, if it is an import. Only resolve the parts until the user position. """ import_names = user_stmt.get_all_import_names() kill_count = -1 cur_name_part = None for i in import_names: if user_stmt.alias == i: continue for name_part in i.names: if name_part.end_pos >= user_context.position: if not cur_name_part: cur_name_part = name_part kill_count += 1 context = user_context.get_context() just_from = next(context) == 'from' i = imports.ImportPath(evaluator, user_stmt, is_like_search, kill_count=kill_count, direct_resolve=True, is_just_from=just_from) return i, cur_name_part
def usages_add_import_modules(evaluator, definitions, search_name): """ Adds the modules of the imports """ new = set() for d in definitions: if isinstance(d.parent, pr.Import): s = imports.ImportPath(evaluator, d.parent, direct_resolve=True) with common.ignored(IndexError): new.add(s.follow(is_goto=True)[0]) return set(definitions) | new
def _follow_statements_imports(self): # imports completion is very complicated and needs to be treated # separately in Completion. if self._definition.isinstance( pr.Import) and self._definition.alias is None: i = imports.ImportPath(self._evaluator, self._definition, True) import_path = i.import_path + (unicode(self._name), ) return imports.get_importer(self._evaluator, import_path, i._importer.module).follow( self._evaluator) return super(Completion, self)._follow_statements_imports()
def follow_inexistent_imports(defs): """ Imports can be generated, e.g. following `multiprocessing.dummy` generates an import dummy in the multiprocessing module. The Import doesn't exist -> follow. """ definitions = set(defs) for d in defs: if isinstance(d.parent, pr.Import) \ and d.start_pos == (0, 0): i = imports.ImportPath(self._evaluator, d.parent).follow(is_goto=True) definitions.remove(d) definitions |= follow_inexistent_imports(i) return definitions
def type(self): """ The type of the completion objects. Follows imports. For a further description, look at :attr:`jedi.api.classes.BaseDefinition.type`. """ if isinstance(self._definition, pr.Import): i = imports.ImportPath(self._evaluator, self._definition) if len(i.import_path) <= 1: return 'module' followed = self.follow_definition() if followed: # Caveat: Only follows the first one, ignore the other ones. # This is ok, since people are almost never interested in # variations. return followed[0].type return super(Completion, self).type
def docstring(self, raw=False, fast=True): """ :param fast: Don't follow imports that are only one level deep like ``import foo``, but follow ``from foo import bar``. This makes sense for speed reasons. Completing `import a` is slow if you use the ``foo.documentation(fast=False)`` on every object, because it parses all libraries starting with ``a``. """ definition = self._definition if isinstance(self._definition, pr.Import): i = imports.ImportPath(self._evaluator, self._definition) if len(i.import_path) > 1 or not fast: followed = self._follow_statements_imports() if followed: # TODO: Use all of the followed objects as input to Documentation. definition = followed[0] if raw: return _Help(definition).raw() else: return _Help(definition).full()
def usages(evaluator, definitions, search_name, mods): def compare_array(definitions): """ `definitions` are being compared by module/start_pos, because sometimes the id's of the objects change (e.g. executions). """ result = [] for d in definitions: module = d.get_parent_until() result.append((module, d.start_pos)) return result def check_call(call): result = [] follow = [] # There might be multiple search_name's in one call_path call_path = list(call.generate_call_path()) for i, name in enumerate(call_path): # name is `pr.NamePart`. if name == search_name: follow.append(call_path[:i + 1]) for f in follow: follow_res, search = evaluator.goto(call.parent, f) # names can change (getattr stuff), therefore filter names that # don't match `search_name`. # TODO add something like that in the future - for now usages are # completely broken anyway. #follow_res = [r for r in follow_res if str(r) == search] #print search.start_pos,search_name.start_pos #print follow_res, search, search_name, [(r, r.start_pos) for r in follow_res] follow_res = usages_add_import_modules(evaluator, follow_res, search) compare_follow_res = compare_array(follow_res) # compare to see if they match if any(r in compare_definitions for r in compare_follow_res): scope = call.parent result.append(Usage(evaluator, search, scope)) return result if not definitions: return set() compare_definitions = compare_array(definitions) mods |= set([d.get_parent_until() for d in definitions]) names = [] for m in imports.get_modules_containing_name(mods, str(search_name)): try: stmts = m.used_names[search_name] except KeyError: continue for stmt in stmts: if isinstance(stmt, pr.Import): count = 0 imps = [] for i in stmt.get_all_import_names(): for name_part in i.names: count += 1 if name_part == search_name: imps.append((count, name_part)) for used_count, name_part in imps: i = imports.ImportPath(evaluator, stmt, kill_count=count - used_count, direct_resolve=True) f = i.follow(is_goto=True) if set(f) & set(definitions): names.append(Usage(evaluator, name_part, stmt)) else: for call in helpers.scan_statement_for_calls(stmt, search_name, assignment_details=True): names += check_call(call) return names