diff --git a/jedi/api/classes.py b/jedi/api/classes.py index f4934ed0..5f445d5c 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -494,8 +494,8 @@ class Completion(BaseDefinition): if self._definition.isinstance(pr.Import) and self._definition.alias is None: i = imports.ImportPath(self._evaluator, self._definition, True) import_path = tuple(i.import_path + [unicode(self._name)]) - return imports.Importer(self._evaluator, import_path, - i._importer.module).follow(self._evaluator) + return imports.get_importer(self._evaluator, import_path, + i._importer.module).follow(self._evaluator) return super(Completion, self)._follow_statements_imports() @memoize_default() diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 2a124278..ff65ab21 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -88,6 +88,7 @@ from jedi.evaluate import precedence class Evaluator(object): def __init__(self): self.memoize_cache = {} # for memoize decorators + self.import_cache = {} # like `sys.modules`. self.recursion_detector = recursion.RecursionDetector() self.execution_recursion_detector = recursion.ExecutionRecursionDetector() diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 781f183e..5bfe02f3 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -70,8 +70,8 @@ class ImportPath(pr.Base): import_path.pop() module = import_stmt.get_parent_until() - self._importer = Importer(self._evaluator, tuple(import_path), module, - import_stmt.relative_count) + self._importer = get_importer(self._evaluator, tuple(import_path), module, + import_stmt.relative_count) def __repr__(self): return '<%s: %s>' % (type(self).__name__, self.import_stmt) @@ -221,7 +221,20 @@ class ImportPath(pr.Base): return scopes -class Importer(use_metaclass(CachedMetaClass)): +def get_importer(evaluator, import_path, module, level=0): + """ + Checks the evaluator caches first, which resembles the ``sys.modules`` + cache and speeds up libraries like ``numpy``. + """ + try: + return evaluator.import_cache[import_path] + except KeyError: + importer = _Importer(evaluator, import_path, module, level) + evaluator.import_cache[import_path] = importer + return importer + + +class _Importer(object): def __init__(self, evaluator, import_path, module, level=0): """ An implementation similar to ``__import__``. Use `follow_file_system` @@ -235,13 +248,12 @@ class Importer(use_metaclass(CachedMetaClass)): :param import_path: List of namespaces (strings). """ - debug.speed('imp') + debug.speed('import %s' % (import_path,)) self._evaluator = evaluator self.import_path = import_path self.level = level self.module = module path = module.path - print(self.import_path) # TODO abspath self.file_path = os.path.dirname(path) if path is not None else None