diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index c4d9ee44..a76ec36d 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -229,7 +229,7 @@ class Script(object): temp, settings.dynamic_flow_information = \ settings.dynamic_flow_information, False try: - user_stmt = self._parser.user_stmt() + user_stmt = self._get_module().get_statement_for_position(self._pos) definitions = self._goto() if not definitions and isinstance(user_stmt, tree.Import): # For not defined imports (goto doesn't find something, we take diff --git a/jedi/api/completion.py b/jedi/api/completion.py index d27e4e89..a1a3ef20 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -53,6 +53,26 @@ def filter_names(evaluator, completion_names, like_name): yield new +def get_user_scope(module, position): + """ + Returns the scope in which the user resides. This includes flows. + """ + user_stmt = module.get_statement_for_position(position) + if user_stmt is None: + def scan(scope): + for s in scope.children: + if s.start_pos <= position <= s.end_pos: + if isinstance(s, (tree.Scope, tree.Flow)): + return scan(s) or s + elif s.type in ('suite', 'decorated'): + return scan(s) + return None + + return scan(module) or module + else: + return user_stmt.get_parent_scope(include_flows=True) + + class Completion: def __init__(self, evaluator, parser, code_lines, position, call_signatures_method): self._evaluator = evaluator @@ -158,7 +178,7 @@ class Completion: yield keywords.keyword(self._evaluator, k).name def _global_completions(self): - scope = self._parser.user_scope() + scope = get_user_scope(self._module, self._position) if not scope.is_scope(): # Might be a flow (if/while/etc). scope = scope.get_parent_scope() names_dicts = global_names_dict_generator( diff --git a/jedi/parser/user_context.py b/jedi/parser/user_context.py index 45daa057..5501fb45 100644 --- a/jedi/parser/user_context.py +++ b/jedi/parser/user_context.py @@ -5,7 +5,6 @@ from collections import namedtuple from jedi import cache from jedi.parser import ParserWithRecovery from jedi.parser.fast import FastParser -from jedi.parser import tree # TODO this should be part of the tokenizer not just of this user_context. Token = namedtuple('Token', ['type', 'string', 'start_pos', 'prefix']) @@ -38,25 +37,5 @@ class UserContextParser(object): self._parser_done_callback(parser) return parser - @cache.underscore_memoization - def user_scope(self): - """ - Returns the scope in which the user resides. This includes flows. - """ - user_stmt = self.module().get_statement_for_position(self._position) - if user_stmt is None: - def scan(scope): - for s in scope.children: - if s.start_pos <= self._position <= s.end_pos: - if isinstance(s, (tree.Scope, tree.Flow)): - return scan(s) or s - elif s.type in ('suite', 'decorated'): - return scan(s) - return None - - return scan(self.module()) or self.module() - else: - return user_stmt.get_parent_scope(include_flows=True) - def module(self): return self._parser().module diff --git a/test/run.py b/test/run.py index 59cb18f7..cdb499df 100755 --- a/test/run.py +++ b/test/run.py @@ -188,7 +188,10 @@ class IntegrationTestCase(object): parser = Parser(load_grammar(), string, start_symbol='eval_input') parser.position_modifier.line = self.line_nr element = parser.get_parsed_node() - element.parent = script._parser.user_scope() + element.parent = jedi.api.completion.get_user_scope( + script._get_module(), + (self.line_nr, self.column) + ) results = evaluator.eval_element(element) if not results: raise Exception('Could not resolve %s on line %s' diff --git a/test/test_parser/test_parser.py b/test/test_parser/test_parser.py index c76e494e..001d49a5 100644 --- a/test/test_parser/test_parser.py +++ b/test/test_parser/test_parser.py @@ -4,7 +4,6 @@ import sys import jedi from jedi._compatibility import u, is_py3 from jedi.parser import ParserWithRecovery, load_grammar -from jedi.parser.user_context import UserContextParser from jedi.parser import tree as pt from textwrap import dedent @@ -15,9 +14,10 @@ def test_user_statement_on_import(): " time)") for pos in [(2, 1), (2, 4)]: - p = UserContextParser(load_grammar(), s, None, pos, lambda x: 1).user_stmt() - assert isinstance(p, pt.Import) - assert [str(n) for n in p.get_defined_names()] == ['time'] + p = ParserWithRecovery(load_grammar(), s) + stmt = p.module.get_statement_for_position(pos) + assert isinstance(stmt, pt.Import) + assert [str(n) for n in stmt.get_defined_names()] == ['time'] class TestCallAndName():