Fix some interpreter issues

This commit is contained in:
Dave Halter
2019-08-20 09:09:19 +02:00
parent 217b632213
commit 39b294e085
15 changed files with 83 additions and 50 deletions

View File

@@ -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,

View File

@@ -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

View File

@@ -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
) )

View File

@@ -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():

View File

@@ -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

View File

@@ -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()

View File

@@ -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__(

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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')

View File

@@ -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

View File

@@ -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

View File

@@ -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')

View File

@@ -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