diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 6cd5494e..17261f2d 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -695,12 +695,15 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False, :param references: If True lists all the names that are not listed by ``definitions=True``. E.g. ``a = b`` returns ``b``. """ + def def_ref_filter(_def): + is_def = _def.is_definition() + return definitions and is_def or references and not is_def + # Set line/column to a random position, because they don't matter. script = Script(source, line=1, column=0, path=path, encoding=encoding) defs = [classes.Definition(script._evaluator, name_part) - for name_part in get_module_name_parts(script._parser.module()) - if 390 < name_part.start_pos[0] < 399] - return sorted(defs, key=lambda x: (x.line, x.column)) + for name_part in get_module_name_parts(script._parser.module())] + return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column)) def preload_module(*modules): diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 3c89b91f..8b4d1696 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -699,6 +699,19 @@ class Definition(use_metaclass(CachedMetaClass, BaseDefinition)): iterable = list(iterable) return list(chain.from_iterable(iterable)) + def is_definition(self): + """ + Returns True, if defined as a name in a statement, function or class. + Returns False, if it's a reference to such a definition. + """ + if not isinstance(self._definition, pr.NamePart): + # Currently only handle NameParts. Once we have a proper API, this + # will be the standard anyway. + raise NotImplementedError + stmt_or_imp = self._definition.get_parent_until((pr.ExprStmt, pr.Import)) + exp_list = stmt_or_imp.expression_list() + return not exp_list or self._definition.start_pos < exp_list[0].start_pos + def __eq__(self, other): return self._start_pos == other._start_pos \ and self.module_path == other.module_path \ diff --git a/test/test_api/test_api_classes.py b/test/test_api/test_api_classes.py index b96a37c2..d173be0d 100644 --- a/test/test_api/test_api_classes.py +++ b/test/test_api/test_api_classes.py @@ -200,8 +200,11 @@ class TestGotoAssignments(TestCase): function. They are not really different in functionality, but really different as an implementation. """ - def test_basic(self): - refs = names('a = 1; a', references=True, definitions=False) - assert len(refs) == 1 - ass = refs[0].goto_assignments() - assert ass[0].description == '' + def test_repetition(self): + defs = names('a = 1; a', references=True, definitions=False) + # Repeat on the same variable. Shouldn't change once we're on a + # definition. + for _ in range(3): + assert len(defs) == 1 + ass = defs[0].goto_assignments() + assert ass[0].description == 'a = 1'