diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 5fd11d4a..164da43b 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -8,8 +8,8 @@ import warnings from jedi._compatibility import next, unicode from jedi import settings from jedi import common -from jedi import cache from jedi.parser import representation as pr +from jedi.evaluate.cache import memoize_default from jedi.evaluate import representation as er from jedi.evaluate import iterable from jedi.evaluate import imports @@ -300,8 +300,25 @@ class BaseDefinition(object): return stripped.is_callable() + @memoize_default() + def _follow_statements_imports(self): + if self._definition.isinstance(pr.Statement): + defs = self._evaluator.eval_statement(self._definition) + elif self._definition.isinstance(pr.Import): + if self._definition.alias is None: + i = imports.ImportPath(self._evaluator, self._definition, True) + defs = imports.Importer(i.import_path + [unicode(self._name)], + i._importer.module).follow(self._evaluator) + else: + defs = imports.strip_imports(self._evaluator, [self._definition]) + else: + return [self] + + defs = [BaseDefinition(self._evaluator, d, d.start_pos) for d in defs] + return defs + @property - @cache.underscore_memoization + @memoize_default() def params(self): """ Raises an ``AttributeError``if the definition is not callable. @@ -465,7 +482,7 @@ class Completion(BaseDefinition): return followed[0].type return super(Completion, self).type - @cache.underscore_memoization + @memoize_default() def follow_definition(self): """ Return the original definitions. I strongly recommend not using it for @@ -488,7 +505,6 @@ class Completion(BaseDefinition): return [self] defs = [BaseDefinition(self._evaluator, d, d.start_pos) for d in defs] - cache.clear_caches() return defs @@ -607,7 +623,7 @@ class Definition(BaseDefinition): position = '' if self.in_builtin_module else '@%s' % (self.line) return "%s:%s%s" % (self.module_name, self.description, position) - @cache.underscore_memoization + @memoize_default() def defined_names(self): """ List sub-definitions (e.g., methods in class). diff --git a/jedi/evaluate/cache.py b/jedi/evaluate/cache.py index d686f894..bf7a5342 100644 --- a/jedi/evaluate/cache.py +++ b/jedi/evaluate/cache.py @@ -5,7 +5,7 @@ """ -def memoize_default(default, evaluator_is_first_arg=False, second_arg_is_evaluator=False): +def memoize_default(default=None, evaluator_is_first_arg=False, second_arg_is_evaluator=False): """ This is a typical memoization decorator, BUT there is one difference: To prevent recursion it sets defaults. diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 5cefcad4..6911a0e9 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -63,7 +63,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): # (No var_args) used. self.is_generated = False - @memoize_default(None) + @memoize_default() def _get_method_execution(self, func): func = InstanceElement(self._evaluator, self, func, True) return FunctionExecution(self._evaluator, func, self.var_args) @@ -203,7 +203,7 @@ class InstanceElement(use_metaclass(CachedMetaClass, pr.Base)): self.is_class_var = is_class_var @common.safe_property - @memoize_default(None) + @memoize_default() def parent(self): par = self.var.parent if isinstance(par, Class) and par == self.instance.base \ @@ -336,7 +336,7 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)): self.base_func = func self.is_decorated = is_decorated - @memoize_default(None) + @memoize_default() def _decorated_func(self): """ Returns the function, that is to be executed in the end. @@ -476,7 +476,7 @@ class FunctionExecution(Executable): raise AttributeError('Tried to access %s: %s. Why?' % (name, self)) return getattr(self.base, name) - @memoize_default(None) + @memoize_default() def _scope_copy(self, scope): """ Copies a scope (e.g. if) in an execution """ # TODO method uses different scopes than the subscopes property. diff --git a/test/test_api/test_api_classes.py b/test/test_api/test_api_classes.py index c334be93..ecb89aa0 100644 --- a/test/test_api/test_api_classes.py +++ b/test/test_api/test_api_classes.py @@ -126,16 +126,16 @@ def test_completion_documentation(): def test_signature_params(): + def check(defs): + params = defs[0].params + assert len(params) == 1 + assert params[0].name == 'bar' + s = dedent(''' def foo(bar): pass foo''') - defs = Script(s).goto_definitions() - params = defs[0].params - assert len(params) == 1 - assert params[0].name == 'bar' + check(Script(s).goto_definitions()) - defs = Script(s).goto_assignments() - with pytest.raises(AttributeError): - params = defs[0].params + check(Script(s).goto_assignments())