mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-16 02:27:06 +08:00
Add absolute import detection
This commit is contained in:
@@ -294,6 +294,27 @@ class Scope(Simple, IsScope):
|
|||||||
if p:
|
if p:
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
@property
|
||||||
|
def absolute_imports(self):
|
||||||
|
"""
|
||||||
|
Checks if imports in this scope are absolute.
|
||||||
|
|
||||||
|
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 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
|
||||||
|
|
||||||
|
has_import = any(_enables_absolute_import(i) for i in self.imports)
|
||||||
|
self._absolute_imports = has_import
|
||||||
|
return has_import
|
||||||
|
|
||||||
|
_absolute_imports = True if is_py3k else None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
try:
|
try:
|
||||||
name = self.path
|
name = self.path
|
||||||
@@ -306,6 +327,13 @@ class Scope(Simple, IsScope):
|
|||||||
return "<%s: %s@%s-%s>" % (type(self).__name__, name,
|
return "<%s: %s@%s-%s>" % (type(self).__name__, name,
|
||||||
self.start_pos[0], self.end_pos[0])
|
self.start_pos[0], self.end_pos[0])
|
||||||
|
|
||||||
|
def _enables_absolute_import(imp):
|
||||||
|
"""
|
||||||
|
Checks if the import is a ``__future__`` import that enables the
|
||||||
|
``absolute_import`` feature.
|
||||||
|
"""
|
||||||
|
namespace, feature = imp.from_ns.names[0], imp.namespace.names[0]
|
||||||
|
return namespace == "__future__" and feature == "absolute_import"
|
||||||
|
|
||||||
class Module(IsScope):
|
class Module(IsScope):
|
||||||
""" For isinstance checks. fast_parser.Module also inherits from this. """
|
""" For isinstance checks. fast_parser.Module also inherits from this. """
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ else:
|
|||||||
import os
|
import os
|
||||||
from os.path import abspath, dirname
|
from os.path import abspath, dirname
|
||||||
import functools
|
import functools
|
||||||
|
import pytest
|
||||||
|
|
||||||
import jedi
|
import jedi
|
||||||
|
|
||||||
@@ -60,3 +61,6 @@ def cwd_at(path):
|
|||||||
os.chdir(oldcwd)
|
os.chdir(oldcwd)
|
||||||
return wrapper
|
return wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
py3_only = pytest.mark.skipif("not is_py3k")
|
||||||
|
py2_only = pytest.mark.skipif("is_py3k")
|
||||||
|
|||||||
27
test/test_absolute_import.py
Normal file
27
test/test_absolute_import.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
from jedi.parsing import Parser
|
||||||
|
from jedi._compatibility import is_py3k; is_py3k # shut up pyflakes
|
||||||
|
from . import base
|
||||||
|
|
||||||
|
@base.py3_only
|
||||||
|
def test_py3k_imports_are_always_absolute():
|
||||||
|
"""
|
||||||
|
By default, imports in Python 3 are absolute.
|
||||||
|
"""
|
||||||
|
parser = Parser("1", "test.py")
|
||||||
|
assert parser.scope.absolute_imports
|
||||||
|
|
||||||
|
@base.py2_only
|
||||||
|
def test_py2_imports_are_not_always_absolute():
|
||||||
|
"""
|
||||||
|
By default, imports in Python 2 are not absolute.
|
||||||
|
"""
|
||||||
|
parser = Parser("1", "test.py")
|
||||||
|
assert not 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
|
||||||
Reference in New Issue
Block a user