mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 14:04:26 +08:00
Fix some interpreter issues
This commit is contained in:
@@ -472,14 +472,18 @@ class Interpreter(Script):
|
|||||||
self.namespaces = namespaces
|
self.namespaces = namespaces
|
||||||
self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default
|
self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default
|
||||||
|
|
||||||
def _get_module(self):
|
@cache.memoize_method
|
||||||
return interpreter.MixedModuleValue(
|
def _get_module_context(self):
|
||||||
self._inference_state,
|
tree_module_value = ModuleValue(
|
||||||
self._module_node,
|
self._inference_state, self._module_node,
|
||||||
self.namespaces,
|
|
||||||
file_io=KnownContentFileIO(self.path, self._code),
|
file_io=KnownContentFileIO(self.path, self._code),
|
||||||
|
string_names=('__main__',),
|
||||||
code_lines=self._code_lines,
|
code_lines=self._code_lines,
|
||||||
)
|
)
|
||||||
|
return interpreter.MixedModuleContext(
|
||||||
|
tree_module_value,
|
||||||
|
self.namespaces,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def names(source=None, path=None, encoding='utf-8', all_scopes=False,
|
def names(source=None, path=None, encoding='utf-8', all_scopes=False,
|
||||||
|
|||||||
@@ -2,11 +2,10 @@
|
|||||||
TODO Some parts of this module are still not well documented.
|
TODO Some parts of this module are still not well documented.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from jedi.inference.value import ModuleValue
|
|
||||||
from jedi.inference import compiled
|
from jedi.inference import compiled
|
||||||
from jedi.inference.compiled import mixed
|
from jedi.inference.compiled import mixed
|
||||||
from jedi.inference.compiled.access import create_access_path
|
from jedi.inference.compiled.access import create_access_path
|
||||||
from jedi.inference.base_value import ValueWrapper
|
from jedi.inference.context import ModuleContext
|
||||||
|
|
||||||
|
|
||||||
def _create(inference_state, obj):
|
def _create(inference_state, obj):
|
||||||
@@ -20,28 +19,20 @@ class NamespaceObject(object):
|
|||||||
self.__dict__ = dct
|
self.__dict__ = dct
|
||||||
|
|
||||||
|
|
||||||
class MixedModuleValue(ValueWrapper):
|
class MixedModuleContext(ModuleContext):
|
||||||
type = 'mixed_module'
|
def __init__(self, tree_module_value, namespaces):
|
||||||
|
super(MixedModuleContext, self).__init__(tree_module_value)
|
||||||
def __init__(self, inference_state, tree_module, namespaces, file_io, code_lines):
|
|
||||||
module_value = ModuleValue(
|
|
||||||
inference_state, tree_module,
|
|
||||||
file_io=file_io,
|
|
||||||
string_names=('__main__',),
|
|
||||||
code_lines=code_lines
|
|
||||||
)
|
|
||||||
super(MixedModuleValue, self).__init__(module_value)
|
|
||||||
self._namespace_objects = [NamespaceObject(n) for n in namespaces]
|
self._namespace_objects = [NamespaceObject(n) for n in namespaces]
|
||||||
|
|
||||||
def get_filters(self, *args, **kwargs):
|
def get_filters(self, *args, **kwargs):
|
||||||
for filter in self._wrapped_value.get_filters(*args, **kwargs):
|
for filter in self._value.as_context().get_filters(*args, **kwargs):
|
||||||
yield filter
|
yield filter
|
||||||
|
|
||||||
for namespace_obj in self._namespace_objects:
|
for namespace_obj in self._namespace_objects:
|
||||||
compiled_object = _create(self.inference_state, namespace_obj)
|
compiled_object = _create(self.inference_state, namespace_obj)
|
||||||
mixed_object = mixed.MixedObject(
|
mixed_object = mixed.MixedObject(
|
||||||
compiled_object=compiled_object,
|
compiled_object=compiled_object,
|
||||||
tree_value=self._wrapped_value
|
tree_value=self._value
|
||||||
)
|
)
|
||||||
for filter in mixed_object.get_filters(*args, **kwargs):
|
for filter in mixed_object.get_filters(*args, **kwargs):
|
||||||
yield filter
|
yield filter
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ class InferenceState(object):
|
|||||||
if is_classdef:
|
if is_classdef:
|
||||||
c = ClassValue(self, context, name.parent)
|
c = ClassValue(self, context, name.parent)
|
||||||
else:
|
else:
|
||||||
c = FunctionValue.from_value(context, name.parent)
|
c = FunctionValue.from_context(context, name.parent)
|
||||||
return ValueSet([c])
|
return ValueSet([c])
|
||||||
|
|
||||||
if type_ == 'expr_stmt':
|
if type_ == 'expr_stmt':
|
||||||
@@ -349,7 +349,7 @@ class InferenceState(object):
|
|||||||
new_dotted.children[index - 1:] = []
|
new_dotted.children[index - 1:] = []
|
||||||
values = context.infer_node(new_dotted)
|
values = context.infer_node(new_dotted)
|
||||||
return unite(
|
return unite(
|
||||||
value.goto(name, name_value=value)
|
value.goto(name, name_context=value.as_context())
|
||||||
for value in values
|
for value in values
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,21 @@ class MixedName(compiled.CompiledName):
|
|||||||
|
|
||||||
@underscore_memoization
|
@underscore_memoization
|
||||||
def infer(self):
|
def infer(self):
|
||||||
|
def access_to_value(parent_value, access):
|
||||||
|
if parent_value is None:
|
||||||
|
parent_context = None
|
||||||
|
else:
|
||||||
|
parent_context = parent_value.as_context()
|
||||||
|
|
||||||
|
if parent_context is None or isinstance(parent_context, MixedObject):
|
||||||
|
return _create(self._inference_state, access, parent_context=parent_context)
|
||||||
|
else:
|
||||||
|
return ValueSet({
|
||||||
|
create_cached_compiled_object(
|
||||||
|
parent_context.inference_state, access, parent_context
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
# TODO use logic from compiled.CompiledObjectFilter
|
# TODO use logic from compiled.CompiledObjectFilter
|
||||||
access_paths = self.parent_context.access_handle.getattr_paths(
|
access_paths = self.parent_context.access_handle.getattr_paths(
|
||||||
self.string_name,
|
self.string_name,
|
||||||
@@ -104,12 +119,7 @@ class MixedName(compiled.CompiledName):
|
|||||||
assert len(access_paths)
|
assert len(access_paths)
|
||||||
values = [None]
|
values = [None]
|
||||||
for access in access_paths:
|
for access in access_paths:
|
||||||
values = ValueSet.from_sets(
|
values = ValueSet.from_sets(access_to_value(v, access) for v in values)
|
||||||
_create(self._inference_state, access, parent_context=c)
|
|
||||||
if c is None or isinstance(c, MixedObject)
|
|
||||||
else ValueSet({create_cached_compiled_object(c.inference_state, access, c)})
|
|
||||||
for c in values
|
|
||||||
)
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -278,7 +288,8 @@ def _create(inference_state, access_handle, parent_context, *args):
|
|||||||
tree_node,
|
tree_node,
|
||||||
node_is_value=True,
|
node_is_value=True,
|
||||||
node_is_object=True
|
node_is_object=True
|
||||||
)
|
)._value
|
||||||
|
# TODO private access!
|
||||||
})
|
})
|
||||||
if tree_node.type == 'classdef':
|
if tree_node.type == 'classdef':
|
||||||
if not access_handle.is_class():
|
if not access_handle.is_class():
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from jedi.inference.compiled.access import _sentinel
|
|||||||
from jedi.inference.cache import inference_state_function_cache
|
from jedi.inference.cache import inference_state_function_cache
|
||||||
from jedi.inference.helpers import reraise_getitem_errors
|
from jedi.inference.helpers import reraise_getitem_errors
|
||||||
from jedi.inference.signature import BuiltinSignature
|
from jedi.inference.signature import BuiltinSignature
|
||||||
from jedi.inference.context import AbstractContext
|
from jedi.inference.context import CompiledContext
|
||||||
|
|
||||||
|
|
||||||
class CheckAttribute(object):
|
class CheckAttribute(object):
|
||||||
@@ -264,7 +264,7 @@ class CompiledObject(Value):
|
|||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
|
||||||
def _as_context(self):
|
def _as_context(self):
|
||||||
return AbstractContext(self)
|
return CompiledContext(self)
|
||||||
|
|
||||||
|
|
||||||
class CompiledName(AbstractNameDefinition):
|
class CompiledName(AbstractNameDefinition):
|
||||||
@@ -515,7 +515,9 @@ def _create_from_name(inference_state, compiled_object, name):
|
|||||||
value = None
|
value = None
|
||||||
for access_path in access_paths:
|
for access_path in access_paths:
|
||||||
value = create_cached_compiled_object(
|
value = create_cached_compiled_object(
|
||||||
inference_state, access_path, parent_context=value
|
inference_state,
|
||||||
|
access_path,
|
||||||
|
parent_context=None if value is None else value.as_context(),
|
||||||
)
|
)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,14 @@ class ModuleContext(AbstractContext):
|
|||||||
for f in filters: # Python 2...
|
for f in filters: # Python 2...
|
||||||
yield f
|
yield f
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string_names(self):
|
||||||
|
return self._value.string_names
|
||||||
|
|
||||||
|
@property
|
||||||
|
def code_lines(self):
|
||||||
|
return self._value.code_lines
|
||||||
|
|
||||||
def get_value(self):
|
def get_value(self):
|
||||||
"""
|
"""
|
||||||
This is the only function that converts a context back to a value.
|
This is the only function that converts a context back to a value.
|
||||||
@@ -127,6 +135,14 @@ class ModuleContext(AbstractContext):
|
|||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
|
|
||||||
|
class NamespaceContext(AbstractContext):
|
||||||
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
|
return self._value.get_filters()
|
||||||
|
|
||||||
|
def py__file__(self):
|
||||||
|
return self._value.py__file__()
|
||||||
|
|
||||||
|
|
||||||
class ClassContext(AbstractContext):
|
class ClassContext(AbstractContext):
|
||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
yield self.get_global_filter(until_position, origin_scope)
|
yield self.get_global_filter(until_position, origin_scope)
|
||||||
@@ -164,3 +180,8 @@ class CompForContext(AbstractContext):
|
|||||||
|
|
||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
yield ParserTreeFilter(self)
|
yield ParserTreeFilter(self)
|
||||||
|
|
||||||
|
|
||||||
|
class CompiledContext(AbstractContext):
|
||||||
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
|
return self._value.get_filters()
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ def infer_import(context, tree_name, is_goto=False):
|
|||||||
from_import_name,
|
from_import_name,
|
||||||
name_context=context,
|
name_context=context,
|
||||||
analysis_errors=False
|
analysis_errors=False
|
||||||
) for c in types.as_context()
|
) for c in types
|
||||||
])
|
])
|
||||||
else:
|
else:
|
||||||
types = types.py__getattribute__(
|
types = types.py__getattribute__(
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ def _iter_nodes_for_param(param_name):
|
|||||||
# anyway
|
# anyway
|
||||||
trailer = search_ancestor(argument, 'trailer')
|
trailer = search_ancestor(argument, 'trailer')
|
||||||
if trailer is not None: # Make sure we're in a function
|
if trailer is not None: # Make sure we're in a function
|
||||||
raise NotImplementedError
|
|
||||||
context = execution_context.create_context(trailer)
|
context = execution_context.create_context(trailer)
|
||||||
if _goes_to_param_name(param_name, context, name):
|
if _goes_to_param_name(param_name, context, name):
|
||||||
values = _to_callables(context, trailer)
|
values = _to_callables(context, trailer)
|
||||||
@@ -62,17 +61,17 @@ def _goes_to_param_name(param_name, context, potential_name):
|
|||||||
for p in found)
|
for p in found)
|
||||||
|
|
||||||
|
|
||||||
def _to_callables(value, trailer):
|
def _to_callables(context, trailer):
|
||||||
from jedi.inference.syntax_tree import infer_trailer
|
from jedi.inference.syntax_tree import infer_trailer
|
||||||
|
|
||||||
atom_expr = trailer.parent
|
atom_expr = trailer.parent
|
||||||
index = atom_expr.children[0] == 'await'
|
index = atom_expr.children[0] == 'await'
|
||||||
# Infer atom first
|
# Infer atom first
|
||||||
values = value.infer_node(atom_expr.children[index])
|
values = context.infer_node(atom_expr.children[index])
|
||||||
for trailer2 in atom_expr.children[index + 1:]:
|
for trailer2 in atom_expr.children[index + 1:]:
|
||||||
if trailer == trailer2:
|
if trailer == trailer2:
|
||||||
break
|
break
|
||||||
values = infer_trailer(value, values, trailer2)
|
values = infer_trailer(context, values, trailer2)
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -153,12 +153,12 @@ def _get_paths_from_buildout_script(inference_state, buildout_script_path):
|
|||||||
return
|
return
|
||||||
|
|
||||||
from jedi.inference.value import ModuleValue
|
from jedi.inference.value import ModuleValue
|
||||||
module = ModuleValue(
|
module_context = ModuleValue(
|
||||||
inference_state, module_node, file_io,
|
inference_state, module_node, file_io,
|
||||||
string_names=None,
|
string_names=None,
|
||||||
code_lines=get_cached_code_lines(inference_state.grammar, buildout_script_path),
|
code_lines=get_cached_code_lines(inference_state.grammar, buildout_script_path),
|
||||||
).as_context()
|
).as_context()
|
||||||
for path in check_sys_path_modifications(module):
|
for path in check_sys_path_modifications(module_context):
|
||||||
yield path
|
yield path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from jedi.inference.filters import DictFilter
|
|||||||
from jedi.inference.names import ValueNameMixin, AbstractNameDefinition
|
from jedi.inference.names import ValueNameMixin, AbstractNameDefinition
|
||||||
from jedi.inference.base_value import Value
|
from jedi.inference.base_value import Value
|
||||||
from jedi.inference.value.module import SubModuleDictMixin
|
from jedi.inference.value.module import SubModuleDictMixin
|
||||||
|
from jedi.inference.context import NamespaceContext
|
||||||
|
|
||||||
|
|
||||||
class ImplicitNSName(ValueNameMixin, AbstractNameDefinition):
|
class ImplicitNSName(ValueNameMixin, AbstractNameDefinition):
|
||||||
@@ -60,5 +61,8 @@ class ImplicitNamespaceValue(Value, SubModuleDictMixin):
|
|||||||
def is_stub(self):
|
def is_stub(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def as_context(self):
|
||||||
|
return NamespaceContext(self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, self._fullname)
|
return '<%s: %s>' % (self.__class__.__name__, self._fullname)
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ from ..helpers import cwd_at
|
|||||||
|
|
||||||
|
|
||||||
def check_module_test(Script, code):
|
def check_module_test(Script, code):
|
||||||
module_value = Script(code)._get_module()
|
module_context = Script(code)._get_module_context()
|
||||||
return check_sys_path_modifications(module_value)
|
return check_sys_path_modifications(module_context)
|
||||||
|
|
||||||
|
|
||||||
@cwd_at('test/examples/buildout_project/src/proj_name')
|
@cwd_at('test/examples/buildout_project/src/proj_name')
|
||||||
|
|||||||
@@ -318,12 +318,13 @@ def test_get_modules_containing_name(inference_state, path, goal, is_package):
|
|||||||
is_package=is_package,
|
is_package=is_package,
|
||||||
)
|
)
|
||||||
assert module
|
assert module
|
||||||
input_module, found_module = imports.get_modules_containing_name(
|
module_context = module.as_context()
|
||||||
|
input_module, found_module = imports.get_module_contexts_containing_name(
|
||||||
inference_state,
|
inference_state,
|
||||||
[module],
|
[module_context],
|
||||||
'string_that_only_exists_here'
|
'string_that_only_exists_here'
|
||||||
)
|
)
|
||||||
assert input_module is module
|
assert input_module is module_context
|
||||||
assert found_module.string_names == goal
|
assert found_module.string_names == goal
|
||||||
|
|
||||||
|
|
||||||
@@ -424,7 +425,7 @@ def test_level_to_import_path(level, directory, project_path, result):
|
|||||||
|
|
||||||
def test_import_name_calculation(Script):
|
def test_import_name_calculation(Script):
|
||||||
s = Script(path=os.path.join(test_dir, 'completion', 'isinstance.py'))
|
s = Script(path=os.path.join(test_dir, 'completion', 'isinstance.py'))
|
||||||
m = s._get_module()
|
m = s._get_module_context()
|
||||||
assert m.string_names == ('test', 'completion', 'isinstance')
|
assert m.string_names == ('test', 'completion', 'isinstance')
|
||||||
|
|
||||||
|
|
||||||
@@ -434,7 +435,7 @@ def test_pre_defined_imports_module(Script, environment, name):
|
|||||||
name = '__builtin__'
|
name = '__builtin__'
|
||||||
|
|
||||||
path = os.path.join(root_dir, name + '.py')
|
path = os.path.join(root_dir, name + '.py')
|
||||||
module = Script('', path=path)._get_module()
|
module = Script('', path=path)._get_module_context()
|
||||||
assert module.string_names == (name,)
|
assert module.string_names == (name,)
|
||||||
|
|
||||||
assert module.inference_state.builtins_module.py__file__() != path
|
assert module.inference_state.builtins_module.py__file__() != path
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ def test_equals(Script, environment, source):
|
|||||||
pytest.skip("Ellipsis does not exists in 2")
|
pytest.skip("Ellipsis does not exists in 2")
|
||||||
script = Script(source)
|
script = Script(source)
|
||||||
node = script._module_node.children[0]
|
node = script._module_node.children[0]
|
||||||
first, = script._get_module().infer_node(node)
|
first, = script._get_module_context().infer_node(node)
|
||||||
assert isinstance(first, CompiledObject) and first.get_safe_value() is True
|
assert isinstance(first, CompiledObject) and first.get_safe_value() is True
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ def test_paths_from_assignment(Script):
|
|||||||
def paths(src):
|
def paths(src):
|
||||||
script = Script(src, path='/foo/bar.py')
|
script = Script(src, path='/foo/bar.py')
|
||||||
expr_stmt = script._module_node.children[0]
|
expr_stmt = script._module_node.children[0]
|
||||||
return set(sys_path._paths_from_assignment(script._get_module(), expr_stmt))
|
return set(sys_path._paths_from_assignment(script._get_module_context(), expr_stmt))
|
||||||
|
|
||||||
# Normalize paths for Windows.
|
# Normalize paths for Windows.
|
||||||
path_a = os.path.abspath('/foo/a')
|
path_a = os.path.abspath('/foo/a')
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def test_string_literals(Script):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
script = Script(dedent(source))
|
script = Script(dedent(source))
|
||||||
assert script._get_module().tree_node.end_pos == (6, 0)
|
assert script._get_module_context().tree_node.end_pos == (6, 0)
|
||||||
assert script.completions()
|
assert script.completions()
|
||||||
|
|
||||||
|
|
||||||
@@ -47,4 +47,4 @@ def test_decorator_string_issue(Script):
|
|||||||
|
|
||||||
s = Script(source)
|
s = Script(source)
|
||||||
assert s.completions()
|
assert s.completions()
|
||||||
assert s._get_module().tree_node.get_code() == source
|
assert s._get_module_context().tree_node.get_code() == source
|
||||||
|
|||||||
Reference in New Issue
Block a user