From f868668f0e521b98ab1ac301bbb82057addcd1f7 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 10 Jan 2014 13:36:29 +0100 Subject: [PATCH] trying to fix the getattr mess with compiled --- jedi/evaluate/__init__.py | 5 ++++- jedi/evaluate/compiled.py | 13 +++++++++++-- jedi/evaluate/finder.py | 10 +++++----- jedi/evaluate/param.py | 3 +-- jedi/evaluate/stdlib.py | 15 ++++++++------- test/completion/classes.py | 2 +- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index f3ccbf16..60d74ef3 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -258,7 +258,10 @@ class Evaluator(object): call.stmt.parent = loop result += self.eval_statement(call.stmt) else: - if isinstance(call, pr.Lambda): + if isinstance(call, compiled.PyName): + print call, call.parent + result.append(call.parent) + elif isinstance(call, pr.Lambda): result.append(er.Function(self, call)) # With things like params, these can also be functions... elif isinstance(call, pr.Base) and call.isinstance( diff --git a/jedi/evaluate/compiled.py b/jedi/evaluate/compiled.py index 6c7ecab8..a7c4f9a9 100644 --- a/jedi/evaluate/compiled.py +++ b/jedi/evaluate/compiled.py @@ -51,7 +51,9 @@ class PyObject(Base): @underscore_memoization def _cls(self): # Ensures that a PyObject is returned that is not an instance (like list) - if not (inspect.isclass(self.obj) or inspect.ismodule(self.obj)): + if not (inspect.isclass(self.obj) or inspect.ismodule(self.obj) + or inspect.isbuiltin(self.obj) or inspect.ismethod(self.obj) + or inspect.ismethoddescriptor(self.obj)): return PyObject(self.obj.__class__, self.parent, True) return self @@ -89,9 +91,12 @@ class PyName(object): self._obj = obj self._name = name self.start_pos = 0, 0 # an illegal start_pos, to make sorting easy. + #if not type(name) is str: + # print obj, name + # raise NotImplementedError() def __repr__(self): - return '<%s: %s.%s>' % (type(self).__name__, self._obj.obj, self._name) + return '<%s: (%s).%s>' % (type(self).__name__, repr(self._obj.obj), self._name) @property @underscore_memoization @@ -218,3 +223,7 @@ magic_function_class = PyObject(type(load_module), parent=builtin) def create(obj): return PyObject(obj, builtin) + + +def name_from_string(string): + return PyName(create(string), string) diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 96e15d9f..adf90e3b 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -71,9 +71,10 @@ class NameFinder(object): if not result and isinstance(self.scope, er.Instance): # __getattr__ / __getattribute__ for r in self._check_getattr(self.scope): - new_name = copy.copy(r.name) - new_name.parent = r - result.append(new_name) + if not isinstance(r, compiled.PyObject): + new_name = copy.copy(r.name) + new_name.parent = r + result.append(new_name) debug.dbg('sfn filter "%s" in (%s-%s): %s@%s' % (self.name_str, self.scope, nscope, u(result), self.position)) @@ -82,9 +83,8 @@ class NameFinder(object): def _check_getattr(self, inst): """Checks for both __getattr__ and __getattribute__ methods""" result = [] - module = compiled.builtin # str is important to lose the NamePart! - name = pr.String(module, "'%s'" % self.name_str, (0, 0), (0, 0), inst) + name = compiled.name_from_string(self.name_str) with common.ignored(KeyError): result = inst.execute_subscope_by_name('__getattr__', [name]) if not result: diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index eb4f59eb..c363ed61 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -2,7 +2,6 @@ import copy from jedi.parser import representation as pr from jedi.evaluate import iterable -from jedi.evaluate import compiled from jedi.evaluate import common @@ -140,7 +139,7 @@ def _var_args_iterator(evaluator, var_args): continue old = stmt # generate a statement if it's not already one. - stmt = pr.Statement(compiled.builtin, [], (0, 0), None) + stmt = pr.Statement(_FakeSubModule, [], (0, 0), None) stmt._expression_list = [old] # *args diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index 4d821579..4f1feca7 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -3,6 +3,7 @@ Implementations of standard library functions, because it's not possible to understand them with Jedi. """ +from jedi._compatibility import unicode from jedi.evaluate import compiled from jedi.evaluate import representation as er from jedi.evaluate import iterable @@ -44,18 +45,18 @@ def builtins_getattr(evaluator, obj, params): objects = _follow_param(evaluator, params, 0) names = _follow_param(evaluator, params, 1) for obj in objects: - if not isinstance(obj, (er.Instance, er.Class, pr.Module)): + if not isinstance(obj, (er.Instance, er.Class, pr.Module, compiled.PyObject)): debug.warning('getattr called without instance') continue - for arr_name in names: - if not isinstance(arr_name, er.Instance): + for name in names: + s = unicode, str + print name + if isinstance(name, compiled.PyObject) and isinstance(name.obj, s): + stmts += evaluator.follow_path(iter([name.obj]), [obj], obj) + else: debug.warning('getattr called without str') continue - if len(arr_name.var_args) != 1: - debug.warning('jedi getattr is too simple') - key = arr_name.var_args[0] - stmts += evaluator.follow_path(iter([key]), [obj], obj) return stmts diff --git a/test/completion/classes.py b/test/completion/classes.py index 44967f6a..9ae49633 100644 --- a/test/completion/classes.py +++ b/test/completion/classes.py @@ -339,7 +339,7 @@ class Wrapper2(): return getattr(Base(), name) #? int() -Wrapper(Base()).ret(3) +Wrapper(Base()).ret #? int() Wrapper2(Base()).ret(3)