diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 94b5f2b0..1f1537e6 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -194,7 +194,7 @@ class Evaluator(object): if_stmt = if_stmt.parent if if_stmt.type in ('if_stmt', 'for_stmt'): break - if if_stmt.is_scope(): + if parser_utils.is_scope(if_stmt): if_stmt = None break predefined_if_name_dict = context.predefined_names.get(if_stmt) @@ -537,7 +537,7 @@ class Evaluator(object): while True: node = node.parent - if node.is_scope(): + if parser_utils.is_scope(node): return node elif node.type in ('argument', 'testlist_comp'): if node.children[1].type == 'comp_for': @@ -553,7 +553,7 @@ class Evaluator(object): return base_context is_funcdef = scope_node.type in ('funcdef', 'lambdef') - parent_scope = scope_node.get_parent_scope() + parent_scope = parser_utils.get_parent_scope(scope_node) parent_context = from_scope_node(parent_scope, child_is_funcdef=is_funcdef) if is_funcdef: @@ -586,7 +586,7 @@ class Evaluator(object): base_node = base_context.tree_node - if node_is_context and node.is_scope(): + if node_is_context and parser_utils.is_scope(node): scope_node = node else: if node.parent.type in ('funcdef', 'classdef'): diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 6f294ff7..53977fd2 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -24,6 +24,7 @@ from jedi.evaluate.cache import memoize_default from jedi.evaluate import imports from jedi.evaluate.param import TreeArguments, create_default_param from jedi.common import to_list, unite +from jedi.parser_utils import get_parent_scope MAX_PARAM_SEARCHES = 20 @@ -103,7 +104,7 @@ def _search_function_executions(evaluator, module_context, funcdef): func_string_name = funcdef.name.value compare_node = funcdef if func_string_name == '__init__': - cls = funcdef.get_parent_scope() + cls = get_parent_scope(funcdef) if isinstance(cls, tree.Class): func_string_name = cls.name.value compare_node = cls diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index 3b9950a2..198389a1 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -7,6 +7,7 @@ from abc import abstractmethod from jedi.parser.tree import search_ancestor from jedi.evaluate import flow_analysis from jedi.common import to_list, unite +from jedi.parser_utils import get_parent_scope class AbstractNameDefinition(object): @@ -189,7 +190,7 @@ class ParserTreeFilter(AbstractUsedNamesFilter): if parent.type == 'trailer': return False base_node = parent if parent.type in ('classdef', 'funcdef') else name - return base_node.get_parent_scope() == self._parser_scope + return get_parent_scope(base_node) == self._parser_scope def _check_flows(self, names): for name in sorted(names, key=lambda name: name.start_pos, reverse=True): diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 74bc1ee8..1eb94c67 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -32,6 +32,7 @@ from jedi.evaluate import param from jedi.evaluate import helpers from jedi.evaluate.filters import get_global_filters from jedi.evaluate.context import ContextualizedName, ContextualizedNode +from jedi.parser_utils import is_scope, get_parent_scope class NameFinder(object): @@ -106,7 +107,7 @@ class NameFinder(object): if self._context.predefined_names: # TODO is this ok? node might not always be a tree.Name node = self._name - while node is not None and not node.is_scope(): + while node is not None and not is_scope(node): node = node.parent if node.type in ("if_stmt", "for_stmt", "comp_for"): try: @@ -160,7 +161,7 @@ class NameFinder(object): if base_node.type == 'comp_for': return types while True: - flow_scope = flow_scope.get_parent_scope(include_flows=True) + flow_scope = get_parent_scope(flow_scope, include_flows=True) n = _check_flow_information(self._name_context, flow_scope, self._name, self._position) if n is not None: @@ -298,7 +299,7 @@ def _check_flow_information(context, flow, search_name, pos): return None result = None - if flow.is_scope(): + if is_scope(flow): # Check for asserts. module_node = flow.get_root_node() try: diff --git a/jedi/evaluate/flow_analysis.py b/jedi/evaluate/flow_analysis.py index 06de185a..670b7a71 100644 --- a/jedi/evaluate/flow_analysis.py +++ b/jedi/evaluate/flow_analysis.py @@ -1,4 +1,6 @@ -from jedi.parser_utils import get_flow_branch_keyword +from jedi.parser_utils import get_flow_branch_keyword, is_scope, get_parent_scope + + class Status(object): lookup_table = {} @@ -32,14 +34,14 @@ UNSURE = Status(None, 'unsure') def _get_flow_scopes(node): while True: - node = node.get_parent_scope(include_flows=True) - if node is None or node.is_scope(): + node = get_parent_scope(node, include_flows=True) + if node is None or is_scope(node): return yield node def reachability_check(context, context_scope, node, origin_scope=None): - first_flow_scope = node.get_parent_scope(include_flows=True) + first_flow_scope = get_parent_scope(node, include_flows=True) if origin_scope is not None: origin_flow_scopes = list(_get_flow_scopes(origin_scope)) node_flow_scopes = list(_get_flow_scopes(node)) @@ -95,7 +97,7 @@ def _break_check(context, context_scope, flow_scope, node): return reachable if context_scope != flow_scope and context_scope != flow_scope.parent: - flow_scope = flow_scope.get_parent_scope(include_flows=True) + flow_scope = get_parent_scope(flow_scope, include_flows=True) return reachable & _break_check(context, context_scope, flow_scope, node) else: return reachable diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index 12739bbc..d85e94f8 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -3,6 +3,7 @@ from itertools import chain from contextlib import contextmanager from jedi.parser.python import tree +from jedi.parser_utils import get_parent_scope def deep_ast_copy(obj): @@ -143,7 +144,7 @@ def get_module_names(module, all_scopes): # parent_scope. There's None as a parent, because nodes in the module # node have the parent module and not suite as all the others. # Therefore it's important to catch that case. - names = [n for n in names if n.get_parent_scope().parent in (module, None)] + names = [n for n in names if get_parent_scope(n).parent in (module, None)] return names diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index d0cd812a..9b131f84 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -11,6 +11,7 @@ from jedi.cache import memoize_method from jedi.evaluate import representation as er from jedi.evaluate.dynamic import search_params from jedi.evaluate import iterable +from jedi.parser_utils import get_parent_scope class AbstractInstanceContext(Context): @@ -151,7 +152,7 @@ class AbstractInstanceContext(Context): def create_instance_context(self, class_context, node): if node.parent.type in ('funcdef', 'classdef'): node = node.parent - scope = node.get_parent_scope() + scope = get_parent_scope(node) if scope == class_context.tree_node: return class_context else: @@ -189,7 +190,7 @@ class CompiledInstance(AbstractInstanceContext): return compiled.CompiledContextName(self, self.class_context.name.string_name) def create_instance_context(self, class_context, node): - if node.get_parent_scope().type == 'classdef': + if get_parent_scope(node).type == 'classdef': return class_context else: return super(CompiledInstance, self).create_instance_context(class_context, node) @@ -332,7 +333,7 @@ class InstanceClassFilter(filters.ParserTreeFilter): while node is not None: if node == self._parser_scope or node == self.context: return True - node = node.get_parent_scope() + node = get_parent_scope(node) return False def _access_possible(self, name): diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 9e7ab312..fb505780 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -276,7 +276,7 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext)): def py__class__(self): # This differentiation is only necessary for Python2. Python3 does not # use a different method class. - if isinstance(self.tree_node.get_parent_scope(), tree.Class): + if isinstance(parser_utils.get_parent_scope(self.tree_node), tree.Class): name = 'METHOD_CLASS' else: name = 'FUNCTION_CLASS' diff --git a/jedi/parser/python/tree.py b/jedi/parser/python/tree.py index f8924d28..a07ace95 100644 --- a/jedi/parser/python/tree.py +++ b/jedi/parser/python/tree.py @@ -59,19 +59,6 @@ class DocstringMixin(object): class PythonMixin(object): - def get_parent_scope(self, include_flows=False): - """ - Returns the underlying scope. - """ - scope = self.parent - while scope is not None: - if include_flows and isinstance(scope, Flow): - return scope - if scope.is_scope(): - break - scope = scope.parent - return scope - def get_definition(self): if self.type in ('newline', 'endmarker'): raise ValueError('Cannot get the indentation of whitespace or indentation.') @@ -90,10 +77,6 @@ class PythonMixin(object): break return scope - def is_scope(self): - # Default is not being a scope. Just inherit from Scope. - return False - def get_name_of_position(self, position): for c in self.children: if isinstance(c, Leaf): @@ -267,9 +250,6 @@ class Scope(PythonBaseNode, DocstringMixin): return scan(self.children) - def is_scope(self): - return True - def get_suite(self): """ Returns the part that is executed by the function. @@ -1057,9 +1037,6 @@ class CompFor(PythonBaseNode): type = 'comp_for' __slots__ = () - def is_scope(self): - return True - def get_defined_names(self): """ Returns the a list of `Name` that the comprehension defines. diff --git a/jedi/parser_utils.py b/jedi/parser_utils.py index 47a9a17c..df340f6b 100644 --- a/jedi/parser_utils.py +++ b/jedi/parser_utils.py @@ -217,3 +217,21 @@ def get_following_comment_same_line(node): comment = comment[:comment.index("\n")] return comment + +def is_scope(node): + return node.type in ('file_input', 'classdef', 'funcdef', 'lambdef', 'comp_for') + + +def get_parent_scope(node, include_flows=False): + """ + Returns the underlying scope. + """ + scope = node.parent + while scope is not None: + if include_flows and isinstance(scope, tree.Flow): + return scope + if is_scope(scope): + break + scope = scope.parent + return scope +