From 1765fadf730fec34ca677b914fcb83d1767fbbc9 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 11 Jan 2014 18:05:44 +0100 Subject: [PATCH] fix problems with self attributes - from fake modules --- jedi/debug.py | 1 + jedi/evaluate/__init__.py | 15 +++++++------- jedi/evaluate/compiled/__init__.py | 18 ++++++++++++++++ jedi/evaluate/compiled/fake.py | 26 ++++++++++++++++-------- jedi/evaluate/compiled/fake/_weakref.pym | 2 +- jedi/evaluate/representation.py | 9 ++++---- test/test_compiled.py | 5 ++++- 7 files changed, 53 insertions(+), 23 deletions(-) diff --git a/jedi/debug.py b/jedi/debug.py index 16d7af3d..b297124b 100644 --- a/jedi/debug.py +++ b/jedi/debug.py @@ -24,6 +24,7 @@ enable_notice = False # callback, interface: level, str debug_function = None ignored_modules = ['jedi.evaluate.builtin', 'jedi.parser'] +debug_indent = -1 def reset_time(): diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index bee22970..8ab470db 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -389,7 +389,7 @@ class Evaluator(object): except stdlib.NotInStdLib: pass - if isinstance(obj, compiled.PyObject): + if obj.isinstance(compiled.PyObject): if obj.is_executable_class(): return [er.Instance(self, obj, params)] else: @@ -401,9 +401,9 @@ class Evaluator(object): return obj.iter_content() else: stmts = [] - try: - obj.returns # Test if it is a function - except AttributeError: + if obj.isinstance(er.Function): + stmts = er.FunctionExecution(self, obj, params).get_return_types(evaluate_generator) + else: if hasattr(obj, 'execute_subscope_by_name'): try: stmts = obj.execute_subscope_by_name('__call__', params) @@ -411,8 +411,6 @@ class Evaluator(object): debug.warning("no __call__ func available", obj) else: debug.warning("no execution possible", obj) - else: - stmts = er.FunctionExecution(self, obj, params).get_return_types(evaluate_generator) debug.dbg('execute result: %s in %s' % (stmts, obj)) return imports.strip_imports(self, stmts) @@ -454,8 +452,9 @@ def filter_private_variable(scope, call_scope, var_name): if isinstance(var_name, (str, unicode)) and isinstance(scope, er.Instance)\ and var_name.startswith('__') and not var_name.endswith('__'): s = call_scope.get_parent_until((pr.Class, er.Instance)) - if s != scope and s != scope.base.base: - return True + if not isinstance(scope.base, compiled.PyObject): + if s != scope and s != scope.base.base: + return True return False diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index ee26a5c7..fbb9e1de 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -83,6 +83,8 @@ class PyObject(Base): return self._cls().obj.__name__ def execute_function(self, evaluator, params): + if self.type() != 'def': + return for name in self._parse_function_doc()[1].split(): try: bltn_obj = _create_from_name(builtin, builtin, name) @@ -95,6 +97,21 @@ class PyObject(Base): for result in evaluator.execute(bltn_obj, params): yield result + @property + @underscore_memoization + def subscopes(self): + """ + Returns only the faked scopes - the other ones are not important for + internal analysis. + """ + module = self.get_parent_until() + faked_subscopes = [] + for name in dir(self._cls().obj): + f = fake.get_faked(module.obj, self.obj, name) + if f: + faked_subscopes.append(f) + return faked_subscopes + def get_self_attributes(self): return [] # Instance compatibility @@ -236,6 +253,7 @@ magic_function_class = PyObject(type(load_module), parent=builtin) 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: faked.parent = parent return faked diff --git a/jedi/evaluate/compiled/fake.py b/jedi/evaluate/compiled/fake.py index 7b464487..65367b10 100644 --- a/jedi/evaluate/compiled/fake.py +++ b/jedi/evaluate/compiled/fake.py @@ -10,6 +10,7 @@ import inspect from jedi._compatibility import is_py3k, builtins from jedi.parser import Parser +from jedi.parser.representation import Class modules = {} @@ -63,7 +64,7 @@ def _load_fakes(module_name): return mixin_dct -def _load_module(module): +def _load_faked_module(module): module_name = module.__name__ if module_name == '__builtin__' and not is_py3k: module_name = 'builtins' @@ -82,7 +83,7 @@ def _load_module(module): return module -def get_faked(module, obj, name=None): +def _faked(module, obj, name=None): def from_scope(scope, obj_name): for s in scope.subscopes: if str(s.name) == obj_name: @@ -104,26 +105,35 @@ def get_faked(module, obj, name=None): else: module = __import__(imp_plz) - mod = _load_module(module) - if mod is None: + faked_mod = _load_faked_module(module) + if faked_mod is None: return # Having the module as a `parser.representation.module`, we need to scan # for methods. if name is None: if inspect.isbuiltin(obj): - return from_scope(mod, obj.__name__) + return from_scope(faked_mod, obj.__name__) elif not inspect.isclass(obj): # object is a method or descriptor - cls = from_scope(mod, obj.__objclass__.__name__) + cls = from_scope(faked_mod, obj.__objclass__.__name__) if cls is None: return return from_scope(cls, obj.__name__) else: if obj == module: - return from_scope(mod, name) + return from_scope(faked_mod, name) else: - return from_scope(mod, name) + cls = from_scope(faked_mod, obj.__name__) + if cls is None: + return + return from_scope(cls, name) + + +def get_faked(*args, **kwargs): + result = _faked(*args, **kwargs) + if not isinstance(result, Class): + return result def is_class_instance(obj): diff --git a/jedi/evaluate/compiled/fake/_weakref.pym b/jedi/evaluate/compiled/fake/_weakref.pym index 05eab2c8..8d21a2c4 100644 --- a/jedi/evaluate/compiled/fake/_weakref.pym +++ b/jedi/evaluate/compiled/fake/_weakref.pym @@ -1,7 +1,7 @@ def proxy(object, callback=None): return object -class ref(): +class weakref(): def __init__(self, object, callback=None): self.__object = object def __call__(self): diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 960c211d..df9ff143 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -87,8 +87,6 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): n.names = n.names[1:] names.append(InstanceElement(self._evaluator, self, n)) - if isinstance(self.base, compiled.PyObject): - return [] names = [] # This loop adds the names of the self object, copies them and removes # the self. @@ -115,9 +113,10 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): if n.names[0] == self_name and len(n.names) == 2: add_self_dot_name(n) - for s in self.base.get_super_classes(): - for inst in self._evaluator.execute(s): - names += inst.get_self_attributes() + if not isinstance(self.base, compiled.PyObject): + for s in self.base.get_super_classes(): + for inst in self._evaluator.execute(s): + names += inst.get_self_attributes() return names def get_subscope_by_name(self, name): diff --git a/test/test_compiled.py b/test/test_compiled.py index 287549ee..88eb8ba9 100644 --- a/test/test_compiled.py +++ b/test/test_compiled.py @@ -13,8 +13,11 @@ def test_simple(): objs = list(e.execute(upper[0])) assert len(objs) == 1 assert objs[0].obj is str - assert objs[0].instantiated is True def test_fake_loading(): assert isinstance(compiled.create(next), Function) + + string = compiled.builtin.get_subscope_by_name('str') + from_name = compiled._create_from_name(compiled.builtin, string, '__init__') + assert isinstance(from_name, Function)