mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 23:34:45 +08:00
@@ -223,9 +223,9 @@ class Script(object):
|
|||||||
|
|
||||||
:rtype: list of :class:`classes.Definition`
|
:rtype: list of :class:`classes.Definition`
|
||||||
"""
|
"""
|
||||||
def filter_follow_imports(names):
|
def filter_follow_imports(names, follow_classes):
|
||||||
for name in names:
|
for name in names:
|
||||||
if isinstance(name, (imports.ImportName, TreeNameDefinition)):
|
if isinstance(name, follow_classes):
|
||||||
for context in name.infer():
|
for context in name.infer():
|
||||||
yield context.name
|
yield context.name
|
||||||
else:
|
else:
|
||||||
@@ -233,7 +233,13 @@ class Script(object):
|
|||||||
|
|
||||||
names = self._goto()
|
names = self._goto()
|
||||||
if follow_imports:
|
if follow_imports:
|
||||||
names = filter_follow_imports(names)
|
# TODO really, sure? TreeNameDefinition? Should probably not follow
|
||||||
|
# that.
|
||||||
|
follow_classes = (imports.ImportName, TreeNameDefinition)
|
||||||
|
else:
|
||||||
|
follow_classes = (imports.SubModuleName,)
|
||||||
|
|
||||||
|
names = filter_follow_imports(names, follow_classes)
|
||||||
|
|
||||||
defs = [classes.Definition(self._evaluator, d) for d in set(names)]
|
defs = [classes.Definition(self._evaluator, d) for d in set(names)]
|
||||||
return helpers.sorted_definitions(defs)
|
return helpers.sorted_definitions(defs)
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class Evaluator(object):
|
|||||||
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
|
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
|
||||||
|
|
||||||
def find_types(self, context, name_or_str, name_context, position=None,
|
def find_types(self, context, name_or_str, name_context, position=None,
|
||||||
search_global=False, is_goto=False):
|
search_global=False, is_goto=False, analysis_errors=True):
|
||||||
"""
|
"""
|
||||||
This is the search function. The most important part to debug.
|
This is the search function. The most important part to debug.
|
||||||
`remove_statements` and `filter_statements` really are the core part of
|
`remove_statements` and `filter_statements` really are the core part of
|
||||||
@@ -127,7 +127,8 @@ class Evaluator(object):
|
|||||||
:param position: Position of the last statement -> tuple of line, column
|
:param position: Position of the last statement -> tuple of line, column
|
||||||
:return: List of Names. Their parents are the types.
|
:return: List of Names. Their parents are the types.
|
||||||
"""
|
"""
|
||||||
f = finder.NameFinder(self, context, name_context, name_or_str, position)
|
f = finder.NameFinder(self, context, name_context, name_or_str,
|
||||||
|
position, analysis_errors=analysis_errors)
|
||||||
filters = f.get_filters(search_global)
|
filters = f.get_filters(search_global)
|
||||||
if is_goto:
|
if is_goto:
|
||||||
return f.filter_name(filters)
|
return f.filter_name(filters)
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ class Context(object):
|
|||||||
|
|
||||||
@Python3Method
|
@Python3Method
|
||||||
def py__getattribute__(self, name_or_str, name_context=None, position=None,
|
def py__getattribute__(self, name_or_str, name_context=None, position=None,
|
||||||
search_global=False, is_goto=False):
|
search_global=False, is_goto=False,
|
||||||
|
analysis_errors=True):
|
||||||
if name_context is None:
|
if name_context is None:
|
||||||
name_context = self
|
name_context = self
|
||||||
return self.evaluator.find_types(
|
return self.evaluator.find_types(
|
||||||
self, name_or_str, name_context, position, search_global, is_goto)
|
self, name_or_str, name_context, position, search_global, is_goto,
|
||||||
|
analysis_errors)
|
||||||
|
|
||||||
def create_context(self, node, node_is_context=False, node_is_object=False):
|
def create_context(self, node, node_is_context=False, node_is_object=False):
|
||||||
return self.evaluator.create_context(self, node, node_is_context, node_is_object)
|
return self.evaluator.create_context(self, node, node_is_context, node_is_object)
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ from jedi.evaluate import analysis
|
|||||||
from jedi.evaluate import flow_analysis
|
from jedi.evaluate import flow_analysis
|
||||||
from jedi.evaluate import param
|
from jedi.evaluate import param
|
||||||
from jedi.evaluate import helpers
|
from jedi.evaluate import helpers
|
||||||
from jedi.evaluate.filters import get_global_filters
|
from jedi.evaluate.filters import get_global_filters, TreeNameDefinition
|
||||||
from jedi.evaluate.context import ContextualizedName, ContextualizedNode
|
from jedi.evaluate.context import ContextualizedName, ContextualizedNode
|
||||||
from jedi.parser_utils import is_scope, get_parent_scope
|
from jedi.parser_utils import is_scope, get_parent_scope
|
||||||
|
|
||||||
|
|
||||||
class NameFinder(object):
|
class NameFinder(object):
|
||||||
def __init__(self, evaluator, context, name_context, name_or_str, position=None):
|
def __init__(self, evaluator, context, name_context, name_or_str,
|
||||||
|
position=None, analysis_errors=True):
|
||||||
self._evaluator = evaluator
|
self._evaluator = evaluator
|
||||||
# Make sure that it's not just a syntax tree node.
|
# Make sure that it's not just a syntax tree node.
|
||||||
self._context = context
|
self._context = context
|
||||||
@@ -48,6 +49,7 @@ class NameFinder(object):
|
|||||||
self._string_name = name_or_str
|
self._string_name = name_or_str
|
||||||
self._position = position
|
self._position = position
|
||||||
self._found_predefined_types = None
|
self._found_predefined_types = None
|
||||||
|
self._analysis_errors = analysis_errors
|
||||||
|
|
||||||
@debug.increase_indent
|
@debug.increase_indent
|
||||||
def find(self, filters, attribute_lookup):
|
def find(self, filters, attribute_lookup):
|
||||||
@@ -65,7 +67,7 @@ class NameFinder(object):
|
|||||||
|
|
||||||
types = self._names_to_types(names, attribute_lookup)
|
types = self._names_to_types(names, attribute_lookup)
|
||||||
|
|
||||||
if not names and not types \
|
if not names and self._analysis_errors and not types \
|
||||||
and not (isinstance(self._name, tree.Name) and
|
and not (isinstance(self._name, tree.Name) and
|
||||||
isinstance(self._name.parent.parent, tree.Param)):
|
isinstance(self._name.parent.parent, tree.Param)):
|
||||||
if isinstance(self._name, tree.Name):
|
if isinstance(self._name, tree.Name):
|
||||||
@@ -122,7 +124,19 @@ class NameFinder(object):
|
|||||||
for filter in filters:
|
for filter in filters:
|
||||||
names = filter.get(self._string_name)
|
names = filter.get(self._string_name)
|
||||||
if names:
|
if names:
|
||||||
|
if len(names) == 1:
|
||||||
|
n, = names
|
||||||
|
if isinstance(n, TreeNameDefinition):
|
||||||
|
# Something somewhere went terribly wrong. This
|
||||||
|
# typically happens when using goto on an import in an
|
||||||
|
# __init__ file. I think we need a better solution, but
|
||||||
|
# it's kind of hard, because for Jedi it's not clear
|
||||||
|
# that that name has not been defined, yet.
|
||||||
|
if n.tree_name == self._name:
|
||||||
|
if self._name.get_definition().type == 'import_from':
|
||||||
|
continue
|
||||||
break
|
break
|
||||||
|
|
||||||
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name,
|
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name,
|
||||||
self._context, names, self._position)
|
self._context, names, self._position)
|
||||||
return list(names)
|
return list(names)
|
||||||
|
|||||||
@@ -65,9 +65,10 @@ def infer_import(context, tree_name, is_goto=False):
|
|||||||
if from_import_name is not None:
|
if from_import_name is not None:
|
||||||
types = unite(
|
types = unite(
|
||||||
t.py__getattribute__(
|
t.py__getattribute__(
|
||||||
from_import_name.value if isinstance(from_import_name, tree.Name) else from_import_name,
|
from_import_name,
|
||||||
name_context=context,
|
name_context=context,
|
||||||
is_goto=is_goto
|
is_goto=is_goto,
|
||||||
|
analysis_errors=False
|
||||||
) for t in types
|
) for t in types
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
addopts = --doctest-modules
|
addopts = --doctest-modules
|
||||||
|
|
||||||
# Ignore broken files in blackbox test directories
|
# Ignore broken files in blackbox test directories
|
||||||
norecursedirs = .* docs completion refactor absolute_import namespace_package scripts extensions speed static_analysis not_in_sys_path buildout_project sample_venvs init_extension_module
|
norecursedirs = .* docs completion refactor absolute_import namespace_package scripts extensions speed static_analysis not_in_sys_path buildout_project sample_venvs init_extension_module simple_import
|
||||||
|
|
||||||
# Activate `clean_jedi_cache` fixture for all tests. This should be
|
# Activate `clean_jedi_cache` fixture for all tests. This should be
|
||||||
# fine as long as we are using `clean_jedi_cache` as a session scoped
|
# fine as long as we are using `clean_jedi_cache` as a session scoped
|
||||||
|
|||||||
5
test/test_api/simple_import/__init__.py
Normal file
5
test/test_api/simple_import/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from simple_import import module
|
||||||
|
|
||||||
|
|
||||||
|
def in_function():
|
||||||
|
from simple_import import module2
|
||||||
0
test/test_api/simple_import/module.py
Normal file
0
test/test_api/simple_import/module.py
Normal file
0
test/test_api/simple_import/module2.py
Normal file
0
test/test_api/simple_import/module2.py
Normal file
@@ -2,6 +2,7 @@
|
|||||||
Test all things related to the ``jedi.api`` module.
|
Test all things related to the ``jedi.api`` module.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
from jedi import api
|
from jedi import api
|
||||||
@@ -205,3 +206,16 @@ def test_goto_assignments_follow_imports():
|
|||||||
|
|
||||||
definition, = script.goto_assignments()
|
definition, = script.goto_assignments()
|
||||||
assert (definition.line, definition.column) == start_pos
|
assert (definition.line, definition.column) == start_pos
|
||||||
|
|
||||||
|
|
||||||
|
def test_goto_module():
|
||||||
|
def check(line, expected):
|
||||||
|
script = api.Script(path=path, line=line)
|
||||||
|
module, = script.goto_assignments()
|
||||||
|
assert module.module_path == expected
|
||||||
|
|
||||||
|
base_path = os.path.join(os.path.dirname(__file__), 'simple_import')
|
||||||
|
path = os.path.join(base_path, '__init__.py')
|
||||||
|
|
||||||
|
check(1, os.path.join(base_path, 'module.py'))
|
||||||
|
check(5, os.path.join(base_path, 'module2.py'))
|
||||||
|
|||||||
Reference in New Issue
Block a user