diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 835fc5fb..9f83ecbf 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -7,9 +7,8 @@ interesting information about completion and goto operations. import re import os import warnings -import itertools -from _compatibility import unicode +from _compatibility import unicode, reduce import cache import dynamic import recursion @@ -59,6 +58,9 @@ class BaseDefinition(object): def __init__(self, definition, start_pos): self.start_pos = start_pos self.definition = definition + """ + An instance of :class:`jedi.parsing_representation.Base` subclass. + """ self.is_keyword = isinstance(definition, keywords.Keyword) # generate a path to the definition @@ -273,44 +275,38 @@ class Definition(BaseDefinition): super(Definition, self).__init__(definition, definition.start_pos) @property - def names(self): + def name(self): """ Name of variable/function/class/module. - For example, for ``isinstance`` it returns ``['isinstance']``. - As it is possible to have multiple definition in a statement, - this attribute returns a list of string. + For example, for ``x = None`` it returns ``'x'``. - :rtype: list of str + :rtype: str or None """ d = self.definition if isinstance(d, er.InstanceElement): d = d.var - if isinstance(d, pr.Name): - d = d.parent - if isinstance(d, er.Array): - return [unicode(d.type)] + if isinstance(d, pr.Name): + return d.names[-1] if d.names else None + elif isinstance(d, er.Array): + return unicode(d.type) elif isinstance(d, (pr.Class, er.Class, er.Instance, er.Function, pr.Function)): - return [unicode(d.name)] + return unicode(d.name) elif isinstance(d, pr.Module): - return [self.module_name] + return self.module_name elif isinstance(d, pr.Import): - def getname(name): - try: - return [name.names[-1]] - except AttributeError: - return [] - return list(itertools.chain(*map(getname, d.get_defined_names()))) + try: + return d.get_defined_names()[0].names[-1] + except AttributeError, IndexError: + return None elif isinstance(d, pr.Statement): - def getname(assignment): - try: - return [assignment[1].values[0][0].name.names[-1]] - except IndexError: - return [] - return list(itertools.chain(*map(getname, d.assignment_details))) - return [] + try: + return d.assignment_details[0][1].values[0][0].name.names[-1] + except IndexError: + return None + return None @property def description(self): @@ -364,7 +360,12 @@ class Definition(BaseDefinition): :rtype: list of Definition """ - return get_definitions(self.definition) + d = self.definition + if isinstance(d, er.InstanceElement): + d = d.var + if isinstance(d, pr.Name): + d = d.parent + return get_definitions(d) def get_definitions(scope): @@ -374,15 +375,10 @@ def get_definitions(scope): :type scope: Scope :rtype: list of Definition """ - def is_definition(s): - return isinstance(s, (pr.Import, pr.Function, pr.Class)) or \ - isinstance(s, pr.Statement) and s.assignment_details - scopes = [] - scopes.extend(scope.imports) - scopes.extend(scope.statements) - scopes.extend(scope.subscopes) - dscopes = sorted(filter(is_definition, scopes), key=lambda s: s.start_pos) - return list(map(Definition, dscopes)) + tuples = evaluate.get_names_of_scope( + scope, star_search=False, include_builtin=False) + names = reduce(lambda x, y: x + y[1], tuples, []) + return list(map(Definition, sorted(names, key=lambda s: s.start_pos))) class RelatedName(BaseDefinition): diff --git a/test/regression.py b/test/regression.py index 31ed25f8..eca48d1a 100755 --- a/test/regression.py +++ b/test/regression.py @@ -402,28 +402,23 @@ class TestGetDefinitions(TestBase): pass data = None """) - assert len(definitions) == 4 - assert definitions[0].names == ['module'] - assert definitions[1].names == ['Class'] - assert definitions[2].names == ['func'] - assert definitions[3].names == ['data'] + self.assertEqual([d.name for d in definitions], + ['module', 'Class', 'func', 'data']) def test_multiple_assignment(self): definitions = api.get_definitions(""" x = y = None """) - assert len(definitions) == 1 - assert definitions[0].names == ['x', 'y'] + self.assertEqual([d.name for d in definitions], + ['x', 'y']) def test_multiple_imports(self): definitions = api.get_definitions(""" from module import a, b from another_module import * """) - assert len(definitions) == 3 - assert definitions[0].names == ['a'] - assert definitions[1].names == ['b'] - assert definitions[2].names == [] + self.assertEqual([d.name for d in definitions], + ['a', 'b']) def test_nested_definitions(self): definitions = api.get_definitions(""" @@ -433,13 +428,13 @@ class TestGetDefinitions(TestBase): def g(): pass """) - assert len(definitions) == 1 - assert definitions[0].names == ['Class'] + self.assertEqual([d.name for d in definitions], + ['Class']) subdefinitions = definitions[0].get_definitions() - assert subdefinitions[0].names == ['f'] - assert subdefinitions[1].names == ['g'] - assert subdefinitions[0].full_name == 'Class.f' - assert subdefinitions[1].full_name == 'Class.g' + self.assertEqual([d.name for d in subdefinitions], + ['f', 'g']) + self.assertEqual([d.full_name for d in subdefinitions], + ['Class.f', 'Class.g']) class TestSpeed(TestBase):