diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index a629d608..34c968d8 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -367,19 +367,11 @@ class Interpreter(Script): super(Interpreter, self).__init__(source, **kwds) self.namespaces = namespaces - # Don't use the fast parser, because it does crazy stuff that we don't - # need in our very simple and small code here (that is always - # changing). - self._parser = UserContextParser(self._grammar, self._source, - self._orig_path, self._pos, - self._parsed_callback, - use_fast_parser=False) - #interpreter.add_namespaces_to_parser(self._evaluator, namespaces, - #self._get_module()) + parser_module = super(Interpreter, self)._get_module() + self._module = interpreter.MixedModule(self._evaluator, parser_module, self.namespaces) def _get_module(self): - parser_module = super(Interpreter, self)._get_module() - return interpreter.MixedModule(parser_module, self.namespaces) + return self._module def defined_names(source, path=None, encoding='utf-8'): diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 50827221..07195c6b 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -16,6 +16,7 @@ from jedi.evaluate import representation as er from jedi.evaluate import iterable from jedi.evaluate import imports from jedi.evaluate import compiled +from jedi.evaluate.compiled import mixed from jedi.api import keywords from jedi.evaluate.finder import filter_definition_names @@ -148,7 +149,7 @@ class BaseDefinition(object): if isinstance(stripped, er.InstanceElement): stripped = stripped.var - if isinstance(stripped, compiled.CompiledObject): + if isinstance(stripped, (compiled.CompiledObject, mixed.MixedObject)): return stripped.api_type() elif isinstance(stripped, iterable.Array): return 'instance' diff --git a/jedi/api/interpreter.py b/jedi/api/interpreter.py index 6332854e..2511b144 100644 --- a/jedi/api/interpreter.py +++ b/jedi/api/interpreter.py @@ -15,37 +15,38 @@ from jedi.parser import load_grammar from jedi.parser.fast import FastParser from jedi.evaluate import helpers from jedi.evaluate import iterable +from jedi.evaluate.representation import ModuleWrapper from jedi.evaluate.compiled import mixed -def add_namespaces_to_parser(evaluator, namespace_dicts, parser_module): - for dct in namespace_dicts: - namespace = compiled.CompiledObject(evaluator, type('namespace', (), dct)) +class MixedModule(object): + resets_positions = True - for key, value in dct.items(): - # Name lookups in an ast tree work by checking names_dict. - # Therefore we just add fake names to that and we're done. - arr = parser_module.names_dict.setdefault(key, []) - name = mixed.MixedName(evaluator, namespace, key) - arr.append(name) - #arr.append(LazyName(evaluator, parser_module, key, value)) - - -class MixedModule(): def __init__(self, evaluator, parser_module, namespaces): self._evaluator = evaluator - self._parser_module = parser_module self._namespaces = namespaces - def names_dicts(self): - for names_dict in self._parser_module.names_dicts(): + self._namespace_objects = [type('jedi_namespace', (), n) for n in namespaces] + self._wrapped_module = ModuleWrapper(evaluator, parser_module) + # Usually we are dealing with very small code sizes when it comes to + # interpreter modules. In this case we just copy the whole syntax tree + # to be able to modify it. + self._parser_module = helpers.deep_ast_copy(parser_module) + + for child in self._parser_module.children: + child.parent = self + + def names_dicts(self, search_global): + for names_dict in self._wrapped_module.names_dicts(search_global): yield names_dict - for namespace in self._namespaces: - print('ole') - yield mixed.MixedObject(self._evaluator, namespace, self._parser_module.name) + for namespace_obj in self._namespace_objects: + m = mixed.MixedObject(self._evaluator, namespace_obj, self._parser_module.name) + for names_dict in m.names_dicts(False): + yield names_dict - yield namespace + def __getattr__(self, name): + return getattr(self._parser_module, name) class LazyName(helpers.FakeName): @@ -125,7 +126,7 @@ class LazyName(helpers.FakeName): 'should be part of sys.modules.') if parser_path: - #assert len(parser_path) == 1 + assert len(parser_path) == 1 found = list(self._evaluator.find_types(mod, parser_path[0], search_global=True)) else: diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 113d88e6..a4187cf6 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -115,6 +115,7 @@ class CompiledObject(Base): elif inspect.isbuiltin(cls) or inspect.ismethod(cls) \ or inspect.ismethoddescriptor(cls) or inspect.isfunction(cls): return 'function' + raise NotImplementedError @property def type(self): diff --git a/jedi/evaluate/compiled/mixed.py b/jedi/evaluate/compiled/mixed.py index a7b4d419..24e4e731 100644 --- a/jedi/evaluate/compiled/mixed.py +++ b/jedi/evaluate/compiled/mixed.py @@ -7,8 +7,7 @@ import inspect from jedi import common from jedi.parser.fast import FastParser from jedi.evaluate import compiled -from jedi.cache import underscore_memoization, memoize_method -from jedi.evaluate.cache import memoize_default +from jedi.cache import underscore_memoization class MixedObject(object): @@ -38,6 +37,15 @@ class MixedObject(object): assert search_global is False return [LazyMixedNamesDict(self._evaluator, self, is_instance=False)] + def api_type(self): + mappings = { + 'expr_stmt': 'statement', + 'classdef': 'class', + 'funcdef': 'function', + 'file_input': 'module', + } + return mappings[self._definition.type] + def __repr__(self): return '<%s: %s>' % (type(self).__name__, repr(self.obj)) diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index d3b8062a..0ded2dfa 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -559,6 +559,8 @@ def global_names_dict_generator(evaluator, scope, position): for names_dict in scope.names_dicts(True): yield names_dict, position + if hasattr(scope, 'resets_positions'): + position = None if scope.type == 'funcdef': # The position should be reset if the current scope is a function. in_func = True diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index 7b744d22..ae98e81c 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -34,6 +34,7 @@ def test_builtin_details(): var = get_completion('variable', locals()) f = get_completion('func', locals()) m = get_completion('keyword', locals()) + print(cls._definition.type) assert cls.type == 'class' assert var.type == 'instance' assert f.type == 'function'