diff --git a/jedi/imports.py b/jedi/imports.py index 3c08c9a3..aa055795 100644 --- a/jedi/imports.py +++ b/jedi/imports.py @@ -91,11 +91,6 @@ class ImportPath(pr.Base): and len(self.import_stmt.namespace.names) > 1 \ and not self.direct_resolve - @property - def is_absolute(self): - module = self.import_stmt.get_parent_until(pr.IsScope) - return module.absolute_imports - def get_nested_import(self, parent): """ See documentation of `self.is_nested_import`. @@ -257,7 +252,8 @@ class ImportPath(pr.Base): return importing - if self.file_path and not self.is_absolute: + parent = self.import_stmt.get_parent_until() + if self.file_path and not parent.explicit_absolute_import: sys_path_mod = list(self.sys_path_with_modifications()) sys_path_mod.insert(0, self.file_path) else: diff --git a/jedi/parsing_representation.py b/jedi/parsing_representation.py index 59b11bca..21cce274 100644 --- a/jedi/parsing_representation.py +++ b/jedi/parsing_representation.py @@ -155,6 +155,7 @@ class Scope(Simple, IsScope): # returns will be in "normal" modules. self.returns = [] self.is_generator = False + self._explicit_absolute_imports = None def add_scope(self, sub, decorators): sub.parent = self.use_as_parent @@ -295,26 +296,23 @@ class Scope(Simple, IsScope): return p @property - def absolute_imports(self): + def explicit_absolute_import(self): """ - Checks if imports in this scope are absolute. + Checks if imports in this scope are explicitly absolute, i.e. there + is a ``__future__`` import. - In Python 3, this is always true. In Python 2, this is true if there - is a ``absolute_import`` ``__future__`` import. + The result of this property is cached; the first time it is + called will cause it to walk through all the imports in the + parse tree. - The result of this property is cached; the first time it is called on - Python 2 will cause it to walk through all the imports in the parse - tree. """ - if self._absolute_imports is not None: - return self._absolute_imports + if self._explicit_absolute_imports is not None: + return self._explicit_absolute_imports has_import = any(_enables_absolute_import(i) for i in self.imports) - self._absolute_imports = has_import + self._explicit_absolute_imports = has_import return has_import - _absolute_imports = True if is_py3k else None - def __repr__(self): try: name = self.path diff --git a/test/test_absolute_import.py b/test/test_absolute_import.py index 343ce970..8d7e9e00 100644 --- a/test/test_absolute_import.py +++ b/test/test_absolute_import.py @@ -3,22 +3,20 @@ from jedi.parsing import Parser from . import base -@base.py3_only -def test_py3k_imports_are_always_absolute(): +def test_explicit_absolute_imports(): """ - By default, imports in Python 3 are absolute. + Detect modules with ``from __future__ import absolute_import``. """ - parser = Parser("1", "test.py") - assert parser.scope.absolute_imports + parser = Parser("from __future__ import absolute_import", "test.py") + assert parser.scope.explicit_absolute_import -@base.py2_only -def test_py2_imports_are_not_always_absolute(): +def test_no_explicit_absolute_imports(): """ - By default, imports in Python 2 are not absolute. + Detect modules without ``from __future__ import absolute_import``. """ parser = Parser("1", "test.py") - assert not parser.scope.absolute_imports + assert not parser.scope.explicit_absolute_import def test_dont_break_imports_without_namespaces(): @@ -28,16 +26,7 @@ def test_dont_break_imports_without_namespaces(): """ src = "from __future__ import absolute_import\nimport xyzzy" parser = Parser(src, "test.py") - assert parser.scope.absolute_imports - - -def test_imports_are_absolute_in_modules_with_future_import(): - """ - In any module with the ``absolute_import`` ``__future__`` import, all - imports are absolute. - """ - parser = Parser("from __future__ import absolute_import", "test.py") - assert parser.scope.absolute_imports + assert parser.scope.explicit_absolute_import @base.cwd_at("test/absolute_import")