mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 22:14:27 +08:00
Merge branch 'master' into typeshed
There were quite a few conflicts, because there were two rewrites of the path to dotted function.
This commit is contained in:
@@ -32,7 +32,7 @@ from jedi.evaluate import imports
|
|||||||
from jedi.evaluate import usages
|
from jedi.evaluate import usages
|
||||||
from jedi.evaluate.arguments import try_iter_content
|
from jedi.evaluate.arguments import try_iter_content
|
||||||
from jedi.evaluate.helpers import get_module_names, evaluate_call_of_leaf
|
from jedi.evaluate.helpers import get_module_names, evaluate_call_of_leaf
|
||||||
from jedi.evaluate.sys_path import calculate_dotted_path_from_sys_path
|
from jedi.evaluate.sys_path import transform_path_to_dotted
|
||||||
from jedi.evaluate.filters import TreeNameDefinition, ParamName
|
from jedi.evaluate.filters import TreeNameDefinition, ParamName
|
||||||
from jedi.evaluate.syntax_tree import tree_name_to_contexts
|
from jedi.evaluate.syntax_tree import tree_name_to_contexts
|
||||||
from jedi.evaluate.context import ModuleContext
|
from jedi.evaluate.context import ModuleContext
|
||||||
@@ -108,7 +108,6 @@ class Script(object):
|
|||||||
self._evaluator = Evaluator(
|
self._evaluator = Evaluator(
|
||||||
project, environment=environment, script_path=self.path
|
project, environment=environment, script_path=self.path
|
||||||
)
|
)
|
||||||
self._project = project
|
|
||||||
debug.speed('init')
|
debug.speed('init')
|
||||||
self._module_node, source = self._evaluator.parse_and_get_code(
|
self._module_node, source = self._evaluator.parse_and_get_code(
|
||||||
code=source,
|
code=source,
|
||||||
@@ -149,10 +148,7 @@ class Script(object):
|
|||||||
def _get_module(self):
|
def _get_module(self):
|
||||||
names = ('__main__',)
|
names = ('__main__',)
|
||||||
if self.path is not None:
|
if self.path is not None:
|
||||||
import_names = calculate_dotted_path_from_sys_path(
|
import_names = transform_path_to_dotted(self._evaluator.get_sys_path(), self.path)
|
||||||
self._evaluator.get_sys_path(),
|
|
||||||
self.path
|
|
||||||
)
|
|
||||||
if import_names is not None:
|
if import_names is not None:
|
||||||
names = import_names
|
names = import_names
|
||||||
|
|
||||||
|
|||||||
@@ -522,7 +522,7 @@ def get_modules_containing_name(evaluator, modules, name):
|
|||||||
if base_names:
|
if base_names:
|
||||||
import_names = base_names + (module_name,)
|
import_names = base_names + (module_name,)
|
||||||
else:
|
else:
|
||||||
import_names = sys_path.calculate_dotted_path_from_sys_path(e_sys_path, path)
|
import_names = sys_path.transform_path_to_dotted(e_sys_path, path)
|
||||||
|
|
||||||
module = _load_module(
|
module = _load_module(
|
||||||
evaluator, path, code,
|
evaluator, path, code,
|
||||||
|
|||||||
@@ -197,38 +197,40 @@ def _get_buildout_script_paths(search_path):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
def calculate_dotted_path_from_sys_path(sys_path, module_path):
|
def transform_path_to_dotted(sys_path, module_path):
|
||||||
"""
|
"""
|
||||||
Returns the dotted path inside a sys.path as a list of names.
|
Returns the dotted path inside a sys.path as a list of names. e.g.
|
||||||
|
|
||||||
This function is supposed to be a backup plan in case there's no idea where
|
>>> transform_path_to_dotted(["/foo"], '/foo/bar/baz.py')
|
||||||
a file is lying.
|
('bar', 'baz')
|
||||||
|
|
||||||
|
Returns None if the path doesn't really resolve to anything.
|
||||||
"""
|
"""
|
||||||
# First remove the suffix.
|
# First remove the suffix.
|
||||||
for suffix in all_suffixes():
|
for suffix in all_suffixes():
|
||||||
if module_path.endswith(suffix):
|
if module_path.endswith(suffix):
|
||||||
module_path = module_path[:-len(suffix)]
|
module_path = module_path[:-len(suffix)]
|
||||||
break
|
break
|
||||||
else:
|
# Once the suffix was removed we are using the files as we know them. This
|
||||||
# There should always be a suffix in a valid Python file on the path.
|
# means that if someone uses an ending like .vim for a Python file, .vim
|
||||||
return None
|
# will be part of the returned dotted part.
|
||||||
|
|
||||||
if module_path.endswith('__init__'):
|
if module_path.endswith(os.path.sep + '__init__'):
|
||||||
|
# -1 to remove the separator
|
||||||
module_path = module_path[:-len('__init__') - 1]
|
module_path = module_path[:-len('__init__') - 1]
|
||||||
|
|
||||||
if module_path.endswith(os.path.sep):
|
|
||||||
# The paths in sys.path may end with a slash.
|
|
||||||
module_path = module_path[:-1]
|
|
||||||
|
|
||||||
for p in sys_path:
|
for p in sys_path:
|
||||||
if module_path.startswith(p):
|
if module_path.startswith(p):
|
||||||
rest = module_path[len(p):]
|
rest = module_path[len(p):]
|
||||||
|
# On Windows a path can also use a slash.
|
||||||
if rest.startswith(os.path.sep) or rest.startswith('/'):
|
if rest.startswith(os.path.sep) or rest.startswith('/'):
|
||||||
|
# Remove a slash in cases it's still there.
|
||||||
rest = rest[1:]
|
rest = rest[1:]
|
||||||
|
|
||||||
if rest:
|
if rest:
|
||||||
split = rest.split(os.path.sep)
|
split = rest.split(os.path.sep)
|
||||||
for string in split:
|
for string in split:
|
||||||
if not string or '.' in string:
|
if not string:
|
||||||
return None
|
return None
|
||||||
return tuple(split)
|
return tuple(split)
|
||||||
return None
|
return None
|
||||||
|
|||||||
0
test/examples/issue1209/__init__.py
Normal file
0
test/examples/issue1209/__init__.py
Normal file
0
test/examples/issue1209/api/__init__.py
Normal file
0
test/examples/issue1209/api/__init__.py
Normal file
0
test/examples/issue1209/api/whatever/__init__.py
Normal file
0
test/examples/issue1209/api/whatever/__init__.py
Normal file
0
test/examples/issue1209/api/whatever/api_test1.py
Normal file
0
test/examples/issue1209/api/whatever/api_test1.py
Normal file
0
test/examples/issue1209/whatever/__init__.py
Normal file
0
test/examples/issue1209/whatever/__init__.py
Normal file
0
test/examples/issue1209/whatever/test.py
Normal file
0
test/examples/issue1209/whatever/test.py
Normal file
@@ -12,4 +12,4 @@ def test_django_default_project(Script):
|
|||||||
)
|
)
|
||||||
c, = script.completions()
|
c, = script.completions()
|
||||||
assert c.name == "SomeModel"
|
assert c.name == "SomeModel"
|
||||||
assert script._project._django is True
|
assert script._evaluator.project._django is True
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import pytest
|
|||||||
from jedi._compatibility import find_module_py33, find_module
|
from jedi._compatibility import find_module_py33, find_module
|
||||||
from jedi.evaluate import compiled
|
from jedi.evaluate import compiled
|
||||||
from jedi.evaluate import imports
|
from jedi.evaluate import imports
|
||||||
from ..helpers import cwd_at
|
from jedi.api.project import Project
|
||||||
|
from ..helpers import cwd_at, get_example_dir
|
||||||
|
|
||||||
THIS_DIR = os.path.dirname(__file__)
|
THIS_DIR = os.path.dirname(__file__)
|
||||||
|
|
||||||
@@ -272,3 +273,18 @@ def test_get_modules_containing_name(evaluator, path, goal):
|
|||||||
)
|
)
|
||||||
assert input_module is module
|
assert input_module is module
|
||||||
assert found_module.string_names == goal
|
assert found_module.string_names == goal
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'path', ('api/whatever/test_this.py', 'api/whatever/file'))
|
||||||
|
def test_relative_imports_with_multiple_similar_directories(Script, path):
|
||||||
|
dir = get_example_dir('issue1209')
|
||||||
|
script = Script(
|
||||||
|
"from .",
|
||||||
|
path=os.path.join(dir, path)
|
||||||
|
)
|
||||||
|
# TODO pass this project to the script as a param once that's possible.
|
||||||
|
script._evaluator.project = Project(dir)
|
||||||
|
name, import_ = script.completions()
|
||||||
|
assert import_.name == 'import'
|
||||||
|
assert name.name == 'api_test1'
|
||||||
|
|||||||
@@ -63,17 +63,34 @@ def test_venv_and_pths(venv_path):
|
|||||||
assert not set(sys.path).intersection(ETALON)
|
assert not set(sys.path).intersection(ETALON)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(('sys_path_', 'path', 'expected'), [
|
_s = ['/a', '/b', '/c/d/']
|
||||||
(['/foo'], '/foo/bar.py', ('bar',)),
|
|
||||||
(['/foo'], '/foo/bar/baz.py', ('bar', 'baz')),
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'sys_path_, module_path, result', [
|
||||||
|
(_s, '/a/b', ('b',)),
|
||||||
|
(_s, '/a/b/c', ('b', 'c')),
|
||||||
|
(_s, '/a/b.py', ('b',)),
|
||||||
|
(_s, '/a/b/c.py', ('b', 'c')),
|
||||||
|
(_s, '/x/b.py', None),
|
||||||
|
(_s, '/c/d/x.py', ('x',)),
|
||||||
|
(_s, '/c/d/x.py', ('x',)),
|
||||||
|
(_s, '/c/d/x/y.py', ('x', 'y')),
|
||||||
|
# If dots are in there they also resolve. These are obviously illegal
|
||||||
|
# in Python, but Jedi can handle them. Give the user a bit more freedom
|
||||||
|
# that he will have to correct eventually.
|
||||||
|
(_s, '/a/b.c.py', ('b.c',)),
|
||||||
|
(_s, '/a/b.d/foo.bar.py', ('b.d', 'foo.bar')),
|
||||||
|
|
||||||
|
(_s, '/a/.py', None),
|
||||||
|
(_s, '/a/c/.py', None),
|
||||||
|
|
||||||
(['/foo'], '/foo/bar/__init__.py', ('bar',)),
|
(['/foo'], '/foo/bar/__init__.py', ('bar',)),
|
||||||
(['/foo'], '/foo/bar/baz/__init__.py', ('bar', 'baz')),
|
(['/foo'], '/foo/bar/baz/__init__.py', ('bar', 'baz')),
|
||||||
|
|
||||||
(['/foo'], '/foo/bar.so', ('bar',)),
|
(['/foo'], '/foo/bar.so', ('bar',)),
|
||||||
(['/foo'], '/foo/bar/__init__.so', ('bar',)),
|
(['/foo'], '/foo/bar/__init__.so', ('bar',)),
|
||||||
|
|
||||||
(['/foo'], '/x/bar.py', None),
|
(['/foo'], '/x/bar.py', None),
|
||||||
(['/foo'], '/foo/bar.xyz', None),
|
(['/foo'], '/foo/bar.xyz', ('bar.xyz',)),
|
||||||
])
|
])
|
||||||
def test_calculate_dotted_path_from_sys_path(path, sys_path_, expected):
|
def test_calculate_dotted_from_path(sys_path_, module_path, result):
|
||||||
assert sys_path.calculate_dotted_path_from_sys_path(sys_path_, path) == expected
|
assert sys_path.transform_path_to_dotted(sys_path_, module_path) == result
|
||||||
|
|||||||
Reference in New Issue
Block a user