From 39feecee04cd287b4bc72124cde5b70d3e2efa05 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 19:52:38 +0100 Subject: [PATCH 01/18] Add new API: jedi.api.get_definitions --- jedi/api.py | 19 +++++++++++++++++++ jedi/api_classes.py | 26 ++++++++++++++++++++++++++ test/regression.py | 18 ++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/jedi/api.py b/jedi/api.py index e2631507..959d19ea 100644 --- a/jedi/api.py +++ b/jedi/api.py @@ -468,6 +468,25 @@ class Script(object): api_classes._clear_caches() +def get_definitions(source, source_path=None, source_encoding='utf-8'): + """ + Get all definitions in `source` sorted by its position. + + This functions can be used for listing functions, classes and + data defined in a file. This can be useful if you want to list + them in "sidebar". Each element in the returned list also has + `get_definition` method which can be used to get sub-definitions + (e.g., methods in class). + + :rtype: list of api_classes.Definition + """ + parser = parsing.Parser( + modules.source_to_unicode(source, source_encoding), + module_path=source_path, + ) + return api_classes.get_definitions(parser.scope) + + def set_debug_function(func_cb=debug.print_to_stdout, warnings=True, notices=True, speed=True): """ diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 3a966609..5ef0c02e 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -317,6 +317,32 @@ class Definition(BaseDefinition): position = '' return "%s:%s%s" % (self.module_name, self.description, position) + def get_definitions(self): + """ + List sub-definitions (e.g., methods in class). + + :rtype: list of Definition + """ + return get_definitions(self._parser.scope) + + +def get_definitions(scope): + """ + List sub-definitions (e.g., methods in class). + + :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) + return map(Definition, sorted(filter(is_definition, scopes), + key=lambda s: s.start_pos)) + class RelatedName(BaseDefinition): """TODO: document this""" diff --git a/test/regression.py b/test/regression.py index 8f01ea14..e46062b3 100755 --- a/test/regression.py +++ b/test/regression.py @@ -391,6 +391,24 @@ class TestFeature(TestBase): self.assertEqual(quick_values, real_values) +class TestGetDefinitions(TestBase): + + def test_get_definitions_flat(self): + definitions = api.get_definitions(""" + import module + class Class: + pass + def func(): + pass + data = None + """) + desc = lambda i: definitions[i].description + assert desc(0) == 'import module' + assert desc(1) == 'class Class' + assert desc(2) == 'def func' + assert desc(3) == 'data=None' + + class TestSpeed(TestBase): def _check_speed(time_per_run, number=4, run_warm=True): """ Speed checks should typically be very tolerant. Some machines are From cbcaa851084d9ee952e92208b1346b3d114b415c Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 22:48:06 +0100 Subject: [PATCH 02/18] Add :attr:`Definition.names` --- jedi/api_classes.py | 34 ++++++++++++++++++++++++++++++++++ test/regression.py | 9 ++++----- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 5ef0c02e..6d4aac98 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -271,6 +271,40 @@ class Definition(BaseDefinition): def __init__(self, definition): super(Definition, self).__init__(definition, definition.start_pos) + @property + def names(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. + + :rtype: list of str + """ + 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)] + elif isinstance(d, (pr.Class, er.Class, er.Instance, + er.Function, pr.Function)): + return [unicode(d.name)] + elif isinstance(d, pr.Module): + return [self.module_name] + elif isinstance(d, pr.Import): + return [n.names[-1] for n in d.get_defined_names()] + elif isinstance(d, pr.Statement): + try: + return [a.values[0][0].name.names[-1] + for (_, a) in d.assignment_details] + except IndexError: + pass + return [] + @property def description(self): """ diff --git a/test/regression.py b/test/regression.py index e46062b3..5974711a 100755 --- a/test/regression.py +++ b/test/regression.py @@ -402,11 +402,10 @@ class TestGetDefinitions(TestBase): pass data = None """) - desc = lambda i: definitions[i].description - assert desc(0) == 'import module' - assert desc(1) == 'class Class' - assert desc(2) == 'def func' - assert desc(3) == 'data=None' + assert definitions[0].names == ['module'] + assert definitions[1].names == ['Class'] + assert definitions[2].names == ['func'] + assert definitions[3].names == ['data'] class TestSpeed(TestBase): From ba7d29f542bf39e3da1a008e1d7c55be8408a1cd Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 23:03:33 +0100 Subject: [PATCH 03/18] Add a test for multiple assignment --- test/regression.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/regression.py b/test/regression.py index 5974711a..f95321f1 100755 --- a/test/regression.py +++ b/test/regression.py @@ -402,11 +402,18 @@ 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'] + def test_multiple_assignment(self): + definitions = api.get_definitions(""" + x = y = None + """) + assert len(definitions) == 1 + assert definitions[0].names == ['x', 'y'] class TestSpeed(TestBase): def _check_speed(time_per_run, number=4, run_warm=True): From d0ad14adf448e2368b2a81f1833b6c0c861314a9 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 23:04:19 +0100 Subject: [PATCH 04/18] Fix Definition.names for star import --- jedi/api_classes.py | 5 ++++- test/regression.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 6d4aac98..d49ea37d 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -296,7 +296,10 @@ class Definition(BaseDefinition): elif isinstance(d, pr.Module): return [self.module_name] elif isinstance(d, pr.Import): - return [n.names[-1] for n in d.get_defined_names()] + try: + return [n.names[-1] for n in d.get_defined_names()] + except AttributeError: + pass elif isinstance(d, pr.Statement): try: return [a.values[0][0].name.names[-1] diff --git a/test/regression.py b/test/regression.py index f95321f1..3ab99616 100755 --- a/test/regression.py +++ b/test/regression.py @@ -415,6 +415,17 @@ class TestGetDefinitions(TestBase): assert len(definitions) == 1 assert definitions[0].names == ['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 == [] + + class TestSpeed(TestBase): def _check_speed(time_per_run, number=4, run_warm=True): """ Speed checks should typically be very tolerant. Some machines are From 0f67b3e0c22e59e4cd839b3fbc48fd55c2a2a905 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 23:11:34 +0100 Subject: [PATCH 05/18] More robust Definition.names --- jedi/api_classes.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index d49ea37d..fcdce8dd 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -7,6 +7,7 @@ interesting information about completion and goto operations. import re import os import warnings +import itertools from _compatibility import unicode import cache @@ -296,16 +297,19 @@ class Definition(BaseDefinition): elif isinstance(d, pr.Module): return [self.module_name] elif isinstance(d, pr.Import): - try: - return [n.names[-1] for n in d.get_defined_names()] - except AttributeError: - pass + def getname(name): + try: + return [name.names[-1]] + except AttributeError: + return [] + return list(itertools.chain(*map(getname, d.get_defined_names()))) elif isinstance(d, pr.Statement): - try: - return [a.values[0][0].name.names[-1] - for (_, a) in d.assignment_details] - except IndexError: - pass + 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 [] @property From 08f45d1f95f51cfa3be7cbf9c018d9e3069c5e88 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 23:26:17 +0100 Subject: [PATCH 06/18] Fix Definition.get_definitions --- jedi/api_classes.py | 2 +- test/regression.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index fcdce8dd..926ea9a3 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -364,7 +364,7 @@ class Definition(BaseDefinition): :rtype: list of Definition """ - return get_definitions(self._parser.scope) + return get_definitions(self.definition) def get_definitions(scope): diff --git a/test/regression.py b/test/regression.py index 3ab99616..cbe13b05 100755 --- a/test/regression.py +++ b/test/regression.py @@ -425,6 +425,20 @@ class TestGetDefinitions(TestBase): assert definitions[1].names == ['b'] assert definitions[2].names == [] + def test_nested_definitions(self): + definitions = api.get_definitions(""" + class Class: + def f(): + pass + def g(): + pass + """) + assert len(definitions) == 1 + assert definitions[0].names == ['Class'] + subdefinitions = definitions[0].get_definitions() + assert subdefinitions[0].names == ['f'] + assert subdefinitions[1].names == ['g'] + class TestSpeed(TestBase): def _check_speed(time_per_run, number=4, run_warm=True): From 89bfdd2b2dc58c4b79eec43a90f8708e73a5d971 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Wed, 13 Feb 2013 23:29:32 +0100 Subject: [PATCH 07/18] Test that full_name works with get_definitions --- test/regression.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/regression.py b/test/regression.py index cbe13b05..31ed25f8 100755 --- a/test/regression.py +++ b/test/regression.py @@ -438,6 +438,8 @@ class TestGetDefinitions(TestBase): 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' class TestSpeed(TestBase): From 1eccf2f76585a86d1622f80e1d3844438609d5aa Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Thu, 14 Feb 2013 14:04:58 +0100 Subject: [PATCH 08/18] Make sure get_definitions returns list in Python 3 --- jedi/api_classes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 926ea9a3..835fc5fb 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -381,8 +381,8 @@ def get_definitions(scope): scopes.extend(scope.imports) scopes.extend(scope.statements) scopes.extend(scope.subscopes) - return map(Definition, sorted(filter(is_definition, scopes), - key=lambda s: s.start_pos)) + dscopes = sorted(filter(is_definition, scopes), key=lambda s: s.start_pos) + return list(map(Definition, dscopes)) class RelatedName(BaseDefinition): From 3fbe7e9ff4e5205cb002f9dc4aeb408b047b9e54 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 23 Feb 2013 23:39:45 +0100 Subject: [PATCH 09/18] Rewrite get_definitions using evaluate.get_names_of_scope - Definition.names is changed to Definition.name. - TestGetDefinitions.test_nested_definitions fails. --- jedi/api_classes.py | 68 +++++++++++++++++++++------------------------ test/regression.py | 29 ++++++++----------- 2 files changed, 44 insertions(+), 53 deletions(-) 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): From 87714460a21ca417598183d9eba1f8610980ad85 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 23 Feb 2013 23:44:26 +0100 Subject: [PATCH 10/18] Add get_names_of_scope option to evaluate.get_names_of_scope Previously failing test passes now. --- jedi/api_classes.py | 2 +- jedi/evaluate.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 9f83ecbf..3c9d9f51 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -376,7 +376,7 @@ def get_definitions(scope): :rtype: list of Definition """ tuples = evaluate.get_names_of_scope( - scope, star_search=False, include_builtin=False) + scope, star_search=False, include_builtin=False, include_parent=False) names = reduce(lambda x, y: x + y[1], tuples, []) return list(map(Definition, sorted(names, key=lambda s: s.start_pos))) diff --git a/jedi/evaluate.py b/jedi/evaluate.py index 884a2ea6..4a68a64d 100644 --- a/jedi/evaluate.py +++ b/jedi/evaluate.py @@ -115,7 +115,7 @@ def get_defined_names_for_position(scope, position=None, start_scope=None): def get_names_of_scope(scope, position=None, star_search=True, - include_builtin=True): + include_builtin=True, include_parent=True): """ Get all completions (names) possible for the current scope. The star search option is only here to provide an optimization. Otherwise @@ -178,6 +178,9 @@ def get_names_of_scope(scope, position=None, star_search=True, # is a list comprehension yield scope, scope.get_set_vars(is_internal_call=True) + if not include_parent: + return + scope = scope.parent # This is used, because subscopes (Flow scopes) would distort the # results. From 71d5b0ac676b34c43f9eea432264b1cfc3f270b2 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 23 Feb 2013 23:49:09 +0100 Subject: [PATCH 11/18] Document return type of get_names_of_scope --- jedi/evaluate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jedi/evaluate.py b/jedi/evaluate.py index 4a68a64d..a5ef4918 100644 --- a/jedi/evaluate.py +++ b/jedi/evaluate.py @@ -153,6 +153,8 @@ def get_names_of_scope(scope, position=None, star_search=True, >>> pairs[2] #doctest: +ELLIPSIS (, [, ...]) + :rtype: [(pr.Scope, [pr.Name])] + :return: Return an generator that yields a pair of scope and names. """ in_func_scope = scope non_flow = scope.get_parent_until(pr.Flow, reverse=True) From 5a29fecfb2ea4c798c81e03a190b68d20aadd8ab Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sat, 23 Feb 2013 23:56:47 +0100 Subject: [PATCH 12/18] Fix Python 3 syntax error --- jedi/api_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 3c9d9f51..d57e0876 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -299,7 +299,7 @@ class Definition(BaseDefinition): elif isinstance(d, pr.Import): try: return d.get_defined_names()[0].names[-1] - except AttributeError, IndexError: + except (AttributeError, IndexError): return None elif isinstance(d, pr.Statement): try: From bc32844bd7ea7e207dfc8a66231bb3df31f87d49 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sun, 24 Feb 2013 00:10:30 +0100 Subject: [PATCH 13/18] Add TestGetDefinitions.test_dotted_assignment --- test/regression.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/regression.py b/test/regression.py index eca48d1a..0e936c6d 100755 --- a/test/regression.py +++ b/test/regression.py @@ -405,6 +405,14 @@ class TestGetDefinitions(TestBase): self.assertEqual([d.name for d in definitions], ['module', 'Class', 'func', 'data']) + def test_dotted_assignment(self): + definitions = api.get_definitions(""" + x = Class() + x.y.z = None + """) + self.assertEqual([d.name for d in definitions], + ['x']) + def test_multiple_assignment(self): definitions = api.get_definitions(""" x = y = None From d4bf14dd662c9ba78de0e1ab4c90e4584648084f Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sun, 10 Mar 2013 19:13:43 +0100 Subject: [PATCH 14/18] Use list comprehension instead of map --- jedi/api_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index d57e0876..b2314fcf 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -378,7 +378,7 @@ def get_definitions(scope): tuples = evaluate.get_names_of_scope( scope, star_search=False, include_builtin=False, include_parent=False) names = reduce(lambda x, y: x + y[1], tuples, []) - return list(map(Definition, sorted(names, key=lambda s: s.start_pos))) + return [Definition(d) for d in sorted(names, key=lambda s: s.start_pos)] class RelatedName(BaseDefinition): From 06de4d66e7a57378d1368ed44a9c23ecfcb4c334 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sun, 10 Mar 2013 19:26:49 +0100 Subject: [PATCH 15/18] Revert "Add get_names_of_scope option to evaluate.get_names_of_scope" This reverts commit 154662ea273a17f00186546bdf9d75833553d307. --- jedi/api_classes.py | 2 +- jedi/evaluate.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index b2314fcf..19d4580f 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -376,7 +376,7 @@ def get_definitions(scope): :rtype: list of Definition """ tuples = evaluate.get_names_of_scope( - scope, star_search=False, include_builtin=False, include_parent=False) + scope, star_search=False, include_builtin=False) names = reduce(lambda x, y: x + y[1], tuples, []) return [Definition(d) for d in sorted(names, key=lambda s: s.start_pos)] diff --git a/jedi/evaluate.py b/jedi/evaluate.py index a5ef4918..4dd1dd88 100644 --- a/jedi/evaluate.py +++ b/jedi/evaluate.py @@ -115,7 +115,7 @@ def get_defined_names_for_position(scope, position=None, start_scope=None): def get_names_of_scope(scope, position=None, star_search=True, - include_builtin=True, include_parent=True): + include_builtin=True): """ Get all completions (names) possible for the current scope. The star search option is only here to provide an optimization. Otherwise @@ -180,9 +180,6 @@ def get_names_of_scope(scope, position=None, star_search=True, # is a list comprehension yield scope, scope.get_set_vars(is_internal_call=True) - if not include_parent: - return - scope = scope.parent # This is used, because subscopes (Flow scopes) would distort the # results. From 36f03f4b0d53854409749845f95e2a0e9268932a Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sun, 10 Mar 2013 19:29:58 +0100 Subject: [PATCH 16/18] Use the first item returned by get_names_of_scope --- jedi/api_classes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 19d4580f..13ecd3e6 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -375,9 +375,9 @@ def get_definitions(scope): :type scope: Scope :rtype: list of Definition """ - tuples = evaluate.get_names_of_scope( - scope, star_search=False, include_builtin=False) - names = reduce(lambda x, y: x + y[1], tuples, []) + pair = next(evaluate.get_names_of_scope( + scope, star_search=False, include_builtin=False), None) + names = pair[1] if pair else [] return [Definition(d) for d in sorted(names, key=lambda s: s.start_pos)] From a02940f3c1a1f9586aa4bcc76e0171a46f1c1d9c Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sun, 10 Mar 2013 19:37:37 +0100 Subject: [PATCH 17/18] Rename api.get_definitions to defined_names Do the same for Definition.get_definitions also. --- jedi/api.py | 6 +++--- jedi/api_classes.py | 6 +++--- test/regression.py | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/jedi/api.py b/jedi/api.py index 959d19ea..9f1fdeea 100644 --- a/jedi/api.py +++ b/jedi/api.py @@ -468,14 +468,14 @@ class Script(object): api_classes._clear_caches() -def get_definitions(source, source_path=None, source_encoding='utf-8'): +def defined_names(source, source_path=None, source_encoding='utf-8'): """ Get all definitions in `source` sorted by its position. This functions can be used for listing functions, classes and data defined in a file. This can be useful if you want to list them in "sidebar". Each element in the returned list also has - `get_definition` method which can be used to get sub-definitions + `defined_names` method which can be used to get sub-definitions (e.g., methods in class). :rtype: list of api_classes.Definition @@ -484,7 +484,7 @@ def get_definitions(source, source_path=None, source_encoding='utf-8'): modules.source_to_unicode(source, source_encoding), module_path=source_path, ) - return api_classes.get_definitions(parser.scope) + return api_classes.defined_names(parser.scope) def set_debug_function(func_cb=debug.print_to_stdout, warnings=True, diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 13ecd3e6..0be7e3f5 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -354,7 +354,7 @@ class Definition(BaseDefinition): position = '' return "%s:%s%s" % (self.module_name, self.description, position) - def get_definitions(self): + def defined_names(self): """ List sub-definitions (e.g., methods in class). @@ -365,10 +365,10 @@ class Definition(BaseDefinition): d = d.var if isinstance(d, pr.Name): d = d.parent - return get_definitions(d) + return defined_names(d) -def get_definitions(scope): +def defined_names(scope): """ List sub-definitions (e.g., methods in class). diff --git a/test/regression.py b/test/regression.py index 0e936c6d..70d25d70 100755 --- a/test/regression.py +++ b/test/regression.py @@ -394,7 +394,7 @@ class TestFeature(TestBase): class TestGetDefinitions(TestBase): def test_get_definitions_flat(self): - definitions = api.get_definitions(""" + definitions = api.defined_names(""" import module class Class: pass @@ -406,7 +406,7 @@ class TestGetDefinitions(TestBase): ['module', 'Class', 'func', 'data']) def test_dotted_assignment(self): - definitions = api.get_definitions(""" + definitions = api.defined_names(""" x = Class() x.y.z = None """) @@ -414,14 +414,14 @@ class TestGetDefinitions(TestBase): ['x']) def test_multiple_assignment(self): - definitions = api.get_definitions(""" + definitions = api.defined_names(""" x = y = None """) self.assertEqual([d.name for d in definitions], ['x', 'y']) def test_multiple_imports(self): - definitions = api.get_definitions(""" + definitions = api.defined_names(""" from module import a, b from another_module import * """) @@ -429,7 +429,7 @@ class TestGetDefinitions(TestBase): ['a', 'b']) def test_nested_definitions(self): - definitions = api.get_definitions(""" + definitions = api.defined_names(""" class Class: def f(): pass @@ -438,7 +438,7 @@ class TestGetDefinitions(TestBase): """) self.assertEqual([d.name for d in definitions], ['Class']) - subdefinitions = definitions[0].get_definitions() + subdefinitions = definitions[0].defined_names() self.assertEqual([d.name for d in subdefinitions], ['f', 'g']) self.assertEqual([d.full_name for d in subdefinitions], From 871ce5ad3342b9e472e32956049299caab9c9e67 Mon Sep 17 00:00:00 2001 From: Takafumi Arakaki Date: Sun, 10 Mar 2013 20:44:15 +0100 Subject: [PATCH 18/18] Compatibility fix for Python 2.5 --- jedi/api_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jedi/api_classes.py b/jedi/api_classes.py index 0be7e3f5..a84c7fe8 100644 --- a/jedi/api_classes.py +++ b/jedi/api_classes.py @@ -8,7 +8,7 @@ import re import os import warnings -from _compatibility import unicode, reduce +from _compatibility import unicode, next import cache import dynamic import recursion