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