From 7c105d27e00493ef4014cc4647cf7347bfa7b5f4 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Wed, 22 Jan 2014 15:17:50 +0100 Subject: [PATCH] some tests survive the new interpreter module already --- jedi/api/__init__.py | 2 +- jedi/api/interpreter.py | 65 ++++++++++++++++++++++++++---- jedi/evaluate/compiled/__init__.py | 6 +-- jedi/evaluate/compiled/fake.py | 30 ++++++++------ jedi/parser/__init__.py | 4 +- 5 files changed, 82 insertions(+), 25 deletions(-) diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 8a32919d..6c1dfb66 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -580,7 +580,7 @@ class Interpreter(Script): self.namespaces = namespaces # Here we add the namespaces to the current parser. - interpreter.create(namespaces[0], self._parser.module()) + interpreter.create(self._evaluator, namespaces[0], self._parser.module()) def _simple_complete(self, path, like): user_stmt = self._parser.user_stmt(True) diff --git a/jedi/api/interpreter.py b/jedi/api/interpreter.py index ce169bba..7cf7b50d 100644 --- a/jedi/api/interpreter.py +++ b/jedi/api/interpreter.py @@ -1,35 +1,86 @@ +import inspect + +from jedi._compatibility import builtins +from jedi import debug +from jedi.cache import underscore_memoization from jedi.evaluate import compiled +from jedi.evaluate.compiled.fake import get_module from jedi.parser import representation as pr +from jedi.parser.fast import FastParser from jedi.evaluate import helpers class InterpreterNamespace(pr.Module): - def __init__(self, namespace, parser_module): + def __init__(self, evaluator, namespace, parser_module): self.namespace = namespace self.parser_module = parser_module + self._evaluator = evaluator def get_defined_names(self): + for name in self.parser_module.get_defined_names(): + yield name for key, value in self.namespace.items(): - yield LazyName(key, value) + yield LazyName(self._evaluator, key, value) def __getattr__(self, name): return getattr(self.parser_module, name) class LazyName(helpers.FakeName): - def __init__(self, name, parent_obj): + def __init__(self, evaluator, name, value): super(LazyName, self).__init__(name) - self._parent_obj = parent_obj + self._evaluator = evaluator + self._value = value + self._name = name @property + @underscore_memoization def parent(self): - return compiled.create(self._parent_obj) + parser_path = [] + obj = self._value + if inspect.ismodule(obj): + module = obj + else: + try: + o = obj.__objclass__ + parser_path.append(pr.NamePart(obj.__name__, None, None)) + obj = o + except AttributeError: + pass + + try: + module_name = obj.__module__ + parser_path.insert(0, pr.NamePart(obj.__name__, None, None)) + except AttributeError: + # Unfortunately in some cases like `int` there's no __module__ + module = builtins + else: + module = __import__(module_name) + raw_module = get_module(self._value) + + try: + path = module.__file__ + except AttributeError: + pass + else: + if path.endswith('.pyc'): + # cut the `c` from `.pyc` + with open(path[:-1]) as f: + mod = FastParser(f.read(), path[:-1]).module + found = self._evaluator.eval_call_path(iter(parser_path), mod, None) + if found: + return found[0] + debug.warning('Interpreter lookup for Python code failed %s', + mod) + + module = compiled.CompiledObject(raw_module) + return compiled.create(self._value, module, module) @parent.setter def parent(self, value): """Needed because of the ``representation.Simple`` super class.""" -def create(namespace, parser_module): - ns = InterpreterNamespace(namespace, parser_module) +def create(evaluator, namespace, parser_module): + ns = InterpreterNamespace(evaluator, namespace, parser_module) parser_module.statements[0].parent = ns diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index dc81999d..3570ad71 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -89,7 +89,7 @@ class CompiledObject(Base): return for name in self._parse_function_doc()[1].split(): try: - bltn_obj = _create_from_name(builtin, builtin, name) + bltn_obj = create_from_name(builtin, builtin, name) except AttributeError: continue else: @@ -141,7 +141,7 @@ class CompiledName(object): @underscore_memoization def parent(self): module = self._obj.get_parent_until() - return _create_from_name(module, self._obj, self.name) + return create_from_name(module, self._obj, self.name) @property def names(self): @@ -268,7 +268,7 @@ builtin = Builtin(_builtins) magic_function_class = CompiledObject(type(load_module), parent=builtin) -def _create_from_name(module, parent, name): +def create_from_name(module, parent, name): faked = fake.get_faked(module.obj, parent.obj, name) # only functions are necessary. if faked is not None: diff --git a/jedi/evaluate/compiled/fake.py b/jedi/evaluate/compiled/fake.py index b5956940..482daef6 100644 --- a/jedi/evaluate/compiled/fake.py +++ b/jedi/evaluate/compiled/fake.py @@ -49,21 +49,27 @@ def search_scope(scope, obj_name): return s +def get_module(obj): + if inspect.ismodule(obj): + return obj + try: + obj = obj.__objclass__ + except AttributeError: + pass + + try: + imp_plz = obj.__module__ + except AttributeError: + # Unfortunately in some cases like `int` there's no __module__ + return builtins + else: + return __import__(imp_plz) + + def _faked(module, obj, name): # Crazy underscore actions to try to escape all the internal madness. if module is None: - try: - module = obj.__objclass__ - except AttributeError: - pass - - try: - imp_plz = obj.__module__ - except AttributeError: - # Unfortunately in some cases like `int` there's no __module__ - module = builtins - else: - module = __import__(imp_plz) + module = get_module(obj) faked_mod = _load_faked_module(module) if faked_mod is None: diff --git a/jedi/parser/__init__.py b/jedi/parser/__init__.py index 2b841f1c..9a2c2835 100644 --- a/jedi/parser/__init__.py +++ b/jedi/parser/__init__.py @@ -632,7 +632,7 @@ class Parser(object): else: if token_type not in [tokenize.COMMENT, tokenize.INDENT, tokenize.NEWLINE, tokenize.NL]: - debug.warning('token not classified', tok, token_type, - self.start_pos[0]) + debug.warning('token not classified %s %s %s', tok, + token_type, self.start_pos[0]) continue self.no_docstr = False