diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index b3e1121b..cd9c8d7d 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -192,6 +192,9 @@ class Script(object): self._inference_state.module_cache.add(names, ValueSet([module])) return module + def _get_module_context(self): + return self._get_module().as_context() + def __repr__(self): return '<%s: %s %r>' % ( self.__class__.__name__, @@ -209,7 +212,7 @@ class Script(object): """ with debug.increase_indent_cm('completions'): completion = Completion( - self._inference_state, self._get_module(), self._code_lines, + self._inference_state, self._get_module_context(), self._code_lines, self._pos, self.call_signatures ) return completion.completions() @@ -239,9 +242,9 @@ class Script(object): if leaf is None: return [] - value = self._inference_state.create_value(self._get_module(), leaf) + context = self._inference_state.create_context(self._get_module_context(), leaf) - values = helpers.infer_goto_definition(self._inference_state, value, leaf) + values = helpers.infer_goto_definition(self._inference_state, context, leaf) values = convert_values( values, only_stubs=only_stubs, @@ -299,8 +302,8 @@ class Script(object): # Without a name we really just want to jump to the result e.g. # executed by `foo()`, if we the cursor is after `)`. return self.goto_definitions(only_stubs=only_stubs, prefer_stubs=prefer_stubs) - value = self._inference_state.create_value(self._get_module(), tree_name) - names = list(self._inference_state.goto(value, tree_name)) + context = self._inference_state.create_context(self._get_module_context(), tree_name) + names = list(self._inference_state.goto(context, tree_name)) if follow_imports: names = filter_follow_imports(names, lambda name: name.is_import()) @@ -340,7 +343,7 @@ class Script(object): # Must be syntax return [] - names = usages.usages(self._get_module(), tree_name) + names = usages.usages(self._get_module_context(), tree_name) definitions = [classes.Definition(self._inference_state, n) for n in names] if not include_builtins: @@ -368,8 +371,8 @@ class Script(object): if call_details is None: return [] - value = self._inference_state.create_value( - self._get_module(), + value = self._inference_state.create_context( + self._get_module_context(), call_details.bracket_leaf ) definitions = helpers.cache_call_signatures( @@ -389,10 +392,10 @@ class Script(object): def _analysis(self): self._inference_state.is_analysis = True self._inference_state.analysis_modules = [self._module_node] - module = self._get_module() + module = self._get_module_context() try: for node in get_executable_nodes(self._module_node): - value = module.create_value(node) + value = module.create_context(node) if node.type in ('funcdef', 'classdef'): # Resolve the decorators. tree_name_to_values(self._inference_state, value, node.children[1]) @@ -505,13 +508,13 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False, else: cls = TreeNameDefinition return cls( - module_value.create_value(name), + module_context.create_context(name), name ) # Set line/column to a random position, because they don't matter. script = Script(source, line=1, column=0, path=path, encoding=encoding, environment=environment) - module_value = script._get_module() + module_context = script._get_module_context() defs = [ classes.Definition( script._inference_state, diff --git a/jedi/api/completion.py b/jedi/api/completion.py index bc87728c..f26b4e8d 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -52,11 +52,11 @@ def filter_names(inference_state, completion_names, stack, like_name): yield new -def get_user_scope(module_value, position): +def get_user_context(module_context, position): """ Returns the scope in which the user resides. This includes flows. """ - user_stmt = get_statement_of_position(module_value.tree_node, position) + user_stmt = get_statement_of_position(module_context.tree_node, position) if user_stmt is None: def scan(scope): for s in scope.children: @@ -68,12 +68,12 @@ def get_user_scope(module_value, position): return scan(s) return None - scanned_node = scan(module_value.tree_node) + scanned_node = scan(module_context.tree_node) if scanned_node: - return module_value.create_value(scanned_node, node_is_value=True) - return module_value + return module_context.create_context(scanned_node, node_is_value=True) + return module_context else: - return module_value.create_value(user_stmt) + return module_context.create_context(user_stmt) def get_flow_scope_node(module_node, position): @@ -85,10 +85,11 @@ def get_flow_scope_node(module_node, position): class Completion: - def __init__(self, inference_state, module, code_lines, position, call_signatures_callback): + def __init__(self, inference_state, module_context, code_lines, position, + call_signatures_callback): self._inference_state = inference_state - self._module_value = module - self._module_node = module.tree_node + self._module_context = module_context + self._module_node = module_context.tree_node self._code_lines = code_lines # The first step of completions is to get the name @@ -104,7 +105,7 @@ class Completion: string, start_leaf = _extract_string_while_in_string(leaf, self._position) if string is not None: completions = list(file_name_completions( - self._inference_state, self._module_value, start_leaf, string, + self._inference_state, self._module_context, start_leaf, string, self._like_name, self._call_signatures_callback, self._code_lines, self._original_position )) @@ -237,7 +238,7 @@ class Completion: yield keywords.KeywordName(self._inference_state, k) def _global_completions(self): - value = get_user_scope(self._module_value, self._position) + value = get_user_context(self._module_context, self._position) debug.dbg('global completion scope: %s', value) flow_scope_node = get_flow_scope_node(self._module_node, self._position) filters = get_global_filters( @@ -252,9 +253,9 @@ class Completion: return completion_names def _trailer_completions(self, previous_leaf): - user_value = get_user_scope(self._module_value, self._position) - inferred_value = self._inference_state.create_value( - self._module_value, previous_leaf + user_value = get_user_context(self._module_context, self._position) + inferred_value = self._inference_state.create_context( + self._module_context, previous_leaf ) values = infer_call_of_leaf(inferred_value, previous_leaf) completion_names = [] @@ -276,7 +277,7 @@ class Completion: def _get_importer_names(self, names, level=0, only_modules=True): names = [n.value for n in names] - i = imports.Importer(self._inference_state, names, self._module_value, level) + i = imports.Importer(self._inference_state, names, self._module_context, level) return i.completion_names(self._inference_state, only_modules=only_modules) def _get_class_value_completions(self, is_function=True): @@ -287,7 +288,7 @@ class Completion: cls = tree.search_ancestor(leaf, 'classdef') if isinstance(cls, (tree.Class, tree.Function)): # Complete the methods that are defined in the super classes. - random_value = self._module_value.create_value( + random_value = self._module_context.create_context( cls, node_is_value=True ) diff --git a/jedi/api/file_name.py b/jedi/api/file_name.py index 9a5f5b11..43164d36 100644 --- a/jedi/api/file_name.py +++ b/jedi/api/file_name.py @@ -7,12 +7,12 @@ from jedi.inference.helpers import get_str_or_none from jedi.parser_utils import get_string_quote -def file_name_completions(inference_state, module_value, start_leaf, string, +def file_name_completions(inference_state, module_context, start_leaf, string, like_name, call_signatures_callback, code_lines, position): # First we want to find out what can actually be changed as a name. like_name_length = len(os.path.basename(string) + like_name) - addition = _get_string_additions(module_value, start_leaf) + addition = _get_string_additions(module_context, start_leaf) if addition is None: return string = addition + string @@ -25,7 +25,7 @@ def file_name_completions(inference_state, module_value, start_leaf, string, sigs = call_signatures_callback() is_in_os_path_join = sigs and all(s.full_name == 'os.path.join' for s in sigs) if is_in_os_path_join: - to_be_added = _add_os_path_join(module_value, start_leaf, sigs[0].bracket_start) + to_be_added = _add_os_path_join(module_context, start_leaf, sigs[0].bracket_start) if to_be_added is None: is_in_os_path_join = False else: @@ -60,7 +60,7 @@ def file_name_completions(inference_state, module_value, start_leaf, string, ) -def _get_string_additions(module_value, start_leaf): +def _get_string_additions(module_context, start_leaf): def iterate_nodes(): node = addition.parent was_addition = True @@ -77,7 +77,7 @@ def _get_string_additions(module_value, start_leaf): addition = start_leaf.get_previous_leaf() if addition != '+': return '' - value = module_value.create_value(start_leaf) + value = module_context.create_context(start_leaf) return _add_strings(value, reversed(list(iterate_nodes()))) @@ -104,14 +104,14 @@ class FileName(AbstractArbitraryName): is_value_name = False -def _add_os_path_join(module_value, start_leaf, bracket_start): +def _add_os_path_join(module_context, start_leaf, bracket_start): def check(maybe_bracket, nodes): if maybe_bracket.start_pos != bracket_start: return None if not nodes: return '' - value = module_value.create_value(nodes[0]) + value = module_context.create_context(nodes[0]) return _add_strings(value, nodes, add_slash=True) or '' if start_leaf.type == 'error_leaf': diff --git a/jedi/inference/__init__.py b/jedi/inference/__init__.py index e42f2af3..9b3f2876 100644 --- a/jedi/inference/__init__.py +++ b/jedi/inference/__init__.py @@ -111,11 +111,11 @@ class InferenceState(object): self.reset_recursion_limitations() self.allow_different_encoding = True - def import_module(self, import_names, parent_module_value=None, + def import_module(self, import_names, parent_module_context=None, sys_path=None, prefer_stubs=True): if sys_path is None: sys_path = self.get_sys_path() - return imports.import_module(self, import_names, parent_module_value, + return imports.import_module(self, import_names, parent_module_context, sys_path, prefer_stubs=prefer_stubs) @staticmethod @@ -150,9 +150,9 @@ class InferenceState(object): """Convenience function""" return self.project._get_sys_path(self, environment=self.environment, **kwargs) - def infer_element(self, value, element): - if isinstance(value, CompForValue): - return infer_node(value, element) + def infer_element(self, context, element): + if isinstance(context, CompForValue): + return infer_node(context, element) if_stmt = element while if_stmt is not None: @@ -162,7 +162,7 @@ class InferenceState(object): if parser_utils.is_scope(if_stmt): if_stmt = None break - predefined_if_name_dict = value.predefined_names.get(if_stmt) + predefined_if_name_dict = context.predefined_names.get(if_stmt) # TODO there's a lot of issues with this one. We actually should do # this in a different way. Caching should only be active in certain # cases and this all sucks. @@ -182,7 +182,7 @@ class InferenceState(object): str_element_names = [e.value for e in element_names] if any(i.value in str_element_names for i in if_names): for if_name in if_names: - definitions = self.goto_definitions(value, if_name) + definitions = self.goto_definitions(context, if_name) # Every name that has multiple different definitions # causes the complexity to rise. The complexity should # never fall below 1. @@ -210,65 +210,65 @@ class InferenceState(object): if len(name_dicts) > 1: result = NO_VALUES for name_dict in name_dicts: - with helpers.predefine_names(value, if_stmt, name_dict): - result |= infer_node(value, element) + with helpers.predefine_names(context, if_stmt, name_dict): + result |= infer_node(context, element) return result else: - return self._infer_element_if_inferred(value, element) + return self._infer_element_if_inferred(context, element) else: if predefined_if_name_dict: - return infer_node(value, element) + return infer_node(context, element) else: - return self._infer_element_if_inferred(value, element) + return self._infer_element_if_inferred(context, element) - def _infer_element_if_inferred(self, value, element): + def _infer_element_if_inferred(self, context, element): """ TODO This function is temporary: Merge with infer_element. """ parent = element while parent is not None: parent = parent.parent - predefined_if_name_dict = value.predefined_names.get(parent) + predefined_if_name_dict = context.predefined_names.get(parent) if predefined_if_name_dict is not None: - return infer_node(value, element) - return self._infer_element_cached(value, element) + return infer_node(context, element) + return self._infer_element_cached(context, element) @inference_state_function_cache(default=NO_VALUES) - def _infer_element_cached(self, value, element): - return infer_node(value, element) + def _infer_element_cached(self, context, element): + return infer_node(context, element) - def goto_definitions(self, value, name): + def goto_definitions(self, context, name): def_ = name.get_definition(import_name_always=True) if def_ is not None: type_ = def_.type is_classdef = type_ == 'classdef' if is_classdef or type_ == 'funcdef': if is_classdef: - c = ClassValue(self, value, name.parent) + c = ClassValue(self, context, name.parent) else: - c = FunctionValue.from_value(value, name.parent) + c = FunctionValue.from_value(context, name.parent) return ValueSet([c]) if type_ == 'expr_stmt': is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: - return infer_expr_stmt(value, def_, name) + return infer_expr_stmt(context, def_, name) if type_ == 'for_stmt': - container_types = value.infer_node(def_.children[3]) - cn = ValueualizedNode(value, def_.children[3]) + container_types = context.infer_node(def_.children[3]) + cn = ValueualizedNode(context, def_.children[3]) for_types = iterate_values(container_types, cn) - c_node = ValueualizedName(value, name) + c_node = ValueualizedName(context, name) return check_tuple_assignments(c_node, for_types) if type_ in ('import_from', 'import_name'): - return imports.infer_import(value, name) + return imports.infer_import(context, name) else: - result = self._follow_error_node_imports_if_possible(value, name) + result = self._follow_error_node_imports_if_possible(context, name) if result is not None: return result - return helpers.infer_call_of_leaf(value, name) + return helpers.infer_call_of_leaf(context, name) - def _follow_error_node_imports_if_possible(self, value, name): + def _follow_error_node_imports_if_possible(self, context, name): error_node = tree.search_ancestor(name, 'error_node') if error_node is not None: # Get the first command start of a started simple_stmt. The error @@ -292,10 +292,10 @@ class InferenceState(object): is_import_from=is_import_from, until_node=name, ) - return imports.Importer(self, names, value.get_root_value(), level).follow() + return imports.Importer(self, names, context.get_root_context(), level).follow() return None - def goto(self, value, name): + def goto(self, context, name): definition = name.get_definition(import_name_always=True) if definition is not None: type_ = definition.type @@ -304,16 +304,16 @@ class InferenceState(object): # a name it's something you can "goto" again. is_simple_name = name.parent.type not in ('power', 'trailer') if is_simple_name: - return [TreeNameDefinition(value, name)] + return [TreeNameDefinition(context, name)] elif type_ == 'param': - return [ParamName(value, name)] + return [ParamName(context, name)] elif type_ in ('import_from', 'import_name'): - module_names = imports.infer_import(value, name, is_goto=True) + module_names = imports.infer_import(context, name, is_goto=True) return module_names else: - return [TreeNameDefinition(value, name)] + return [TreeNameDefinition(context, name)] else: - values = self._follow_error_node_imports_if_possible(value, name) + values = self._follow_error_node_imports_if_possible(context, name) if values is not None: return [value.name for value in values] @@ -326,15 +326,15 @@ class InferenceState(object): trailer = trailer.parent if trailer.type != 'classdef': if trailer.type == 'decorator': - value_set = value.infer_node(trailer.children[1]) + value_set = context.infer_node(trailer.children[1]) else: i = trailer.parent.children.index(trailer) to_infer = trailer.parent.children[:i] if to_infer[0] == 'await': to_infer.pop(0) - value_set = value.infer_node(to_infer[0]) + value_set = context.infer_node(to_infer[0]) for trailer in to_infer[1:]: - value_set = infer_trailer(value, value_set, trailer) + value_set = infer_trailer(context, value_set, trailer) param_names = [] for value in value_set: for signature in value.get_signatures(): @@ -347,28 +347,28 @@ class InferenceState(object): if index > 0: new_dotted = helpers.deep_ast_copy(par) new_dotted.children[index - 1:] = [] - values = value.infer_node(new_dotted) + values = context.infer_node(new_dotted) return unite( value.py__getattribute__(name, name_value=value, is_goto=True) for value in values ) if node_type == 'trailer' and par.children[0] == '.': - values = helpers.infer_call_of_leaf(value, name, cut_own_trailer=True) - return values.py__getattribute__(name, name_value=value, is_goto=True) + values = helpers.infer_call_of_leaf(context, name, cut_own_trailer=True) + return values.py__getattribute__(name, name_context=context, is_goto=True) else: stmt = tree.search_ancestor( name, 'expr_stmt', 'lambdef' ) or name if stmt.type == 'lambdef': stmt = name - return value.py__getattribute__( + return context.py__getattribute__( name, position=stmt.start_pos, search_global=True, is_goto=True ) - def create_value(self, base_value, node, node_is_value=False, node_is_object=False): + def create_context(self, base_context, node, node_is_value=False, node_is_object=False): def parent_scope(node): while True: node = node.parent @@ -386,14 +386,14 @@ class InferenceState(object): def from_scope_node(scope_node, is_nested=True, node_is_object=False): if scope_node == base_node: - return base_value + return base_context is_funcdef = scope_node.type in ('funcdef', 'lambdef') parent_scope = parser_utils.get_parent_scope(scope_node) parent_context = from_scope_node(parent_scope) if is_funcdef: - func = FunctionValue.from_value(parent_context, scope_node) + func = FunctionValue.from_context(parent_context, scope_node) if parent_context.is_class(): instance = AnonymousInstance( self, parent_context.parent_context, parent_context) @@ -413,7 +413,7 @@ class InferenceState(object): return CompForValue.from_comp_for(parent_context, scope_node) raise Exception("There's a scope that was not managed.") - base_node = base_value.tree_node + base_node = base_context.tree_node if node_is_value and parser_utils.is_scope(node): scope_node = node diff --git a/jedi/inference/analysis.py b/jedi/inference/analysis.py index 8aa2b63c..cfe7e704 100644 --- a/jedi/inference/analysis.py +++ b/jedi/inference/analysis.py @@ -77,17 +77,17 @@ class Warning(Error): pass -def add(node_value, error_name, node, message=None, typ=Error, payload=None): +def add(node_context, error_name, node, message=None, typ=Error, payload=None): exception = CODES[error_name][1] - if _check_for_exception_catch(node_value, node, exception, payload): + if _check_for_exception_catch(node_context, node, exception, payload): return # TODO this path is probably not right - module_value = node_value.get_root_value() - module_path = module_value.py__file__() + module_context = node_context.get_root_context() + module_path = module_context.py__file__() issue_instance = typ(error_name, module_path, node.start_pos, message) debug.warning(str(issue_instance), format=False) - node_value.inference_state.analysis.append(issue_instance) + node_context.inference_state.analysis.append(issue_instance) return issue_instance @@ -95,7 +95,7 @@ def _check_for_setattr(instance): """ Check if there's any setattr method inside an instance. If so, return True. """ - module = instance.get_root_value() + module = instance.get_root_context() node = module.tree_node if node is None: # If it's a compiled module or doesn't have a tree_node @@ -112,7 +112,7 @@ def _check_for_setattr(instance): for n in stmt_names) -def add_attribute_error(name_value, lookup_value, name): +def add_attribute_error(name_context, lookup_value, name): message = ('AttributeError: %s has no attribute %s.' % (lookup_value, name)) from jedi.inference.value.instance import CompiledInstanceName # Check for __getattr__/__getattribute__ existance and issue a warning @@ -132,10 +132,10 @@ def add_attribute_error(name_value, lookup_value, name): typ = Warning payload = lookup_value, name - add(name_value, 'attribute-error', name, message, typ, payload) + add(name_context, 'attribute-error', name, message, typ, payload) -def _check_for_exception_catch(node_value, jedi_name, exception, payload=None): +def _check_for_exception_catch(node_context, jedi_name, exception, payload=None): """ Checks if a jedi object (e.g. `Statement`) sits inside a try/catch and doesn't count as an error (if equal to `exception`). @@ -167,7 +167,7 @@ def _check_for_exception_catch(node_value, jedi_name, exception, payload=None): if node is None: return True # An exception block that catches everything. else: - except_classes = node_value.infer_node(node) + except_classes = node_context.infer_node(node) for cls in except_classes: from jedi.inference.value import iterable if isinstance(cls, iterable.Sequence) and \ @@ -192,18 +192,19 @@ def _check_for_exception_catch(node_value, jedi_name, exception, payload=None): arglist = trailer.children[1] assert arglist.type == 'arglist' from jedi.inference.arguments import TreeArguments - args = list(TreeArguments(node_value.inference_state, node_value, arglist).unpack()) + args = TreeArguments(node_context.inference_state, node_context, arglist) + unpacked_args = list(args.unpack()) # Arguments should be very simple - assert len(args) == 2 + assert len(unpacked_args) == 2 # Check name - key, lazy_value = args[1] + key, lazy_value = unpacked_args[1] names = list(lazy_value.infer()) assert len(names) == 1 and is_string(names[0]) assert force_unicode(names[0].get_safe_value()) == payload[1].value # Check objects - key, lazy_value = args[0] + key, lazy_value = unpacked_args[0] objects = lazy_value.infer() return payload[0] in objects except AssertionError: diff --git a/jedi/inference/arguments.py b/jedi/inference/arguments.py index 34803e51..9272b471 100644 --- a/jedi/inference/arguments.py +++ b/jedi/inference/arguments.py @@ -50,7 +50,7 @@ def repack_with_argument_clinic(string, keep_arguments_param=False, keep_callbac clinic_args = list(_parse_argument_clinic(string)) def decorator(func): - def wrapper(value, *args, **kwargs): + def wrapper(context, *args, **kwargs): if keep_arguments_param: arguments = kwargs['arguments'] else: @@ -59,14 +59,14 @@ def repack_with_argument_clinic(string, keep_arguments_param=False, keep_callbac kwargs.pop('callback', None) try: args += tuple(_iterate_argument_clinic( - value.inference_state, + context.inference_state, arguments, clinic_args )) except ParamIssue: return NO_VALUES else: - return func(value, *args, **kwargs) + return func(context, *args, **kwargs) return wrapper return decorator @@ -152,7 +152,7 @@ class _AbstractArgumentsMixin(object): class AbstractArguments(_AbstractArgumentsMixin): - value = None + context = None argument_node = None trailer = None @@ -198,12 +198,12 @@ def unpack_arglist(arglist): class TreeArguments(AbstractArguments): - def __init__(self, inference_state, value, argument_node, trailer=None): + def __init__(self, inference_state, context, argument_node, trailer=None): """ :param argument_node: May be an argument_node or a list of nodes. """ self.argument_node = argument_node - self.value = value + self.context = context self._inference_state = inference_state self.trailer = trailer # Can be None, e.g. in a class definition. @@ -216,8 +216,8 @@ class TreeArguments(AbstractArguments): named_args = [] for star_count, el in unpack_arglist(self.argument_node): if star_count == 1: - arrays = self.value.infer_node(el) - iterators = [_iterate_star_args(self.value, a, el, funcdef) + arrays = self.context.infer_node(el) + iterators = [_iterate_star_args(self.context, a, el, funcdef) for a in arrays] for values in list(zip_longest(*iterators)): # TODO zip_longest yields None, that means this would raise @@ -226,15 +226,15 @@ class TreeArguments(AbstractArguments): [v for v in values if v is not None] ) elif star_count == 2: - arrays = self.value.infer_node(el) + arrays = self.context.infer_node(el) for dct in arrays: - for key, values in _star_star_dict(self.value, dct, el, funcdef): + for key, values in _star_star_dict(self.context, dct, el, funcdef): yield key, values else: if el.type == 'argument': c = el.children if len(c) == 3: # Keyword argument. - named_args.append((c[0].value, LazyTreeValue(self.value, c[2]),)) + named_args.append((c[0].value, LazyTreeValue(self.context, c[2]),)) else: # Generator comprehension. # Include the brackets with the parent. sync_comp_for = el.children[1] @@ -242,13 +242,13 @@ class TreeArguments(AbstractArguments): sync_comp_for = sync_comp_for.children[1] comp = iterable.GeneratorComprehension( self._inference_state, - defining_value=self.value, + defining_context=self.context, sync_comp_for_node=sync_comp_for, entry_node=el.children[0], ) yield None, LazyKnownValue(comp) else: - yield None, LazyTreeValue(self.value, el) + yield None, LazyTreeValue(self.context, el) # Reordering arguments is necessary, because star args sometimes appear # after named argument, but in the actual order it's prepended. @@ -269,7 +269,7 @@ class TreeArguments(AbstractArguments): if not star_count or not isinstance(name, tree.Name): continue - yield TreeNameDefinition(self.value, name) + yield TreeNameDefinition(self.context, name) def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self.argument_node) @@ -302,9 +302,9 @@ class TreeArguments(AbstractArguments): break if arguments.argument_node is not None: - return [ValueualizedNode(arguments.value, arguments.argument_node)] + return [ValueualizedNode(arguments.context, arguments.argument_node)] if arguments.trailer is not None: - return [ValueualizedNode(arguments.value, arguments.trailer)] + return [ValueualizedNode(arguments.context, arguments.trailer)] return [] @@ -325,8 +325,8 @@ class TreeArgumentsWrapper(_AbstractArgumentsMixin): self._wrapped_arguments = arguments @property - def value(self): - return self._wrapped_arguments.value + def context(self): + return self._wrapped_arguments.context @property def argument_node(self): @@ -346,13 +346,13 @@ class TreeArgumentsWrapper(_AbstractArgumentsMixin): return '<%s: %s>' % (self.__class__.__name__, self._wrapped_arguments) -def _iterate_star_args(value, array, input_node, funcdef=None): +def _iterate_star_args(context, array, input_node, funcdef=None): if not array.py__getattribute__('__iter__'): if funcdef is not None: # TODO this funcdef should not be needed. m = "TypeError: %s() argument after * must be a sequence, not %s" \ % (funcdef.name.value, array) - analysis.add(value, 'type-error-star', input_node, message=m) + analysis.add(context, 'type-error-star', input_node, message=m) try: iter_ = array.py__iter__ except AttributeError: @@ -362,7 +362,7 @@ def _iterate_star_args(value, array, input_node, funcdef=None): yield lazy_value -def _star_star_dict(value, array, input_node, funcdef): +def _star_star_dict(context, array, input_node, funcdef): from jedi.inference.value.instance import CompiledInstance if isinstance(array, CompiledInstance) and array.name.string_name == 'dict': # For now ignore this case. In the future add proper iterators and just @@ -374,5 +374,5 @@ def _star_star_dict(value, array, input_node, funcdef): if funcdef is not None: m = "TypeError: %s argument after ** must be a mapping, not %s" \ % (funcdef.name.value, array) - analysis.add(value, 'type-error-star-star', input_node, message=m) + analysis.add(context, 'type-error-star-star', input_node, message=m) return {} diff --git a/jedi/inference/base_value.py b/jedi/inference/base_value.py index 69e151f5..ee7973cd 100644 --- a/jedi/inference/base_value.py +++ b/jedi/inference/base_value.py @@ -23,7 +23,7 @@ _sentinel = object() class HelperValueMixin(object): - def get_root_value(self): + def get_root_context(self): value = self while True: if value.parent_context is None: @@ -83,9 +83,6 @@ class HelperValueMixin(object): def infer_node(self, node): return self.inference_state.infer_element(self, node) - def create_value(self, node, node_is_value=False, node_is_object=False): - return self.inference_state.create_value(self, node, node_is_value, node_is_object) - def iterate(self, valueualized_node=None, is_async=False): debug.dbg('iterate %s', self) if is_async: @@ -281,18 +278,18 @@ class TreeValue(Value): class ValueualizedNode(object): - def __init__(self, value, node): - self.value = value + def __init__(self, context, node): + self.context = context self.node = node - def get_root_value(self): - return self.value.get_root_value() + def get_root_context(self): + return self.context.get_root_context() def infer(self): - return self.value.infer_node(self.node) + return self.context.infer_node(self.node) def __repr__(self): - return '<%s: %s in %s>' % (self.__class__.__name__, self.node, self.value) + return '<%s: %s in %s>' % (self.__class__.__name__, self.node, self.context) class ValueualizedName(ValueualizedNode): diff --git a/jedi/inference/compiled/mixed.py b/jedi/inference/compiled/mixed.py index 8dd42130..eab0551d 100644 --- a/jedi/inference/compiled/mixed.py +++ b/jedi/inference/compiled/mixed.py @@ -254,27 +254,27 @@ def _create(inference_state, access_handle, parent_context, *args): if parent_context is None: # TODO this __name__ is probably wrong. - name = compiled_object.get_root_value().py__name__() + name = compiled_object.get_root_context().py__name__() string_names = tuple(name.split('.')) - module_value = ModuleValue( + module_context = ModuleValue( inference_state, module_node, file_io=file_io, string_names=string_names, code_lines=code_lines, is_package=hasattr(compiled_object, 'py__path__'), - ) + ).as_context() if name is not None: - inference_state.module_cache.add(string_names, ValueSet([module_value])) + inference_state.module_cache.add(string_names, ValueSet([module_context])) else: if parent_context.tree_node.get_root_node() != module_node: # This happens e.g. when __module__ is wrong, or when using # TypeVar('foo'), where Jedi uses 'foo' as the name and # Python's TypeVar('foo').__module__ will be typing. return ValueSet({compiled_object}) - module_value = parent_context.get_root_value() + module_context = parent_context.get_root_context() tree_values = ValueSet({ - module_value.create_value( + module_context.create_context( tree_node, node_is_value=True, node_is_object=True diff --git a/jedi/inference/context.py b/jedi/inference/context.py new file mode 100644 index 00000000..cd3e04e1 --- /dev/null +++ b/jedi/inference/context.py @@ -0,0 +1,58 @@ +from abc import abstractmethod + +from jedi.inference.filters import ParserTreeFilter + + +class AbstractContext(object): + """ + Should be defined, otherwise the API returns empty types. + """ + predefined_names = {} + + def __init__(self, value): + self.inference_state = value.inference_state + self._value = value + + @abstractmethod + def get_filters(self, until_position=None, origin_scope=None): + raise NotImplementedError + + def get_root_context(self): + return self._value.get_root_context() + + def create_context(self, node, node_is_value=False, node_is_object=False): + return self.inference_state.create_context(self, node, node_is_value, node_is_object) + + @property + def py__getattribute__(self): + return self._value.py__getattribute__ + + @property + def tree_name(self): + return self._value.tree_node + + def infer_node(self, node): + raise NotImplementedError + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self._value) + + +class FunctionContext(AbstractContext): + @abstractmethod + def get_filters(self, until_position=None, origin_scope=None): + yield ParserTreeFilter( + self.inference_state, + context=self, + until_position=until_position, + origin_scope=origin_scope + ) + + +class ModuleContext(AbstractContext): + def py__file__(self): + return self._value.py__file__() + + @property + def py__package__(self): + return self._value.py__package__ diff --git a/jedi/inference/dynamic.py b/jedi/inference/dynamic.py index 41d9ef64..ced4c79e 100644 --- a/jedi/inference/dynamic.py +++ b/jedi/inference/dynamic.py @@ -89,10 +89,10 @@ def search_params(inference_state, execution_value, funcdef): debug.dbg('Dynamic param search in %s.', string_name, color='MAGENTA') try: - module_value = execution_value.get_root_value() + module_context = execution_value.get_root_value() function_executions = _search_function_executions( inference_state, - module_value, + module_context, funcdef, string_name=string_name, ) @@ -115,7 +115,7 @@ def search_params(inference_state, execution_value, funcdef): @inference_state_function_cache(default=None) @to_list -def _search_function_executions(inference_state, module_value, funcdef, string_name): +def _search_function_executions(inference_state, module_context, funcdef, string_name): """ Returns a list of param names. """ @@ -129,8 +129,8 @@ def _search_function_executions(inference_state, module_value, funcdef, string_n found_executions = False i = 0 for for_mod_value in imports.get_modules_containing_name( - inference_state, [module_value], string_name): - if not isinstance(module_value, ModuleValue): + inference_state, [module_context], string_name): + if not isinstance(module_context, ModuleValue): return for name, trailer in _get_possible_nodes(for_mod_value, string_name): i += 1 @@ -141,7 +141,8 @@ def _search_function_executions(inference_state, module_value, funcdef, string_n if i * inference_state.dynamic_params_depth > MAX_PARAM_SEARCHES: return - random_value = inference_state.create_value(for_mod_value, name) + raise NotImplementedError + random_value = inference_state.create_context(for_mod_value, name) for function_execution in _check_name_for_execution( inference_state, random_value, compare_node, name, trailer): found_executions = True @@ -219,7 +220,8 @@ def _check_name_for_execution(inference_state, value, compare_node, name, traile execution_value = next(create_func_excs()) for name, trailer in _get_possible_nodes(module_value, params[0].string_name): if value_node.start_pos < name.start_pos < value_node.end_pos: - random_value = inference_state.create_value(execution_value, name) + raise NotImplementedError + random_value = inference_state.create_context(execution_value, name) iterator = _check_name_for_execution( inference_state, random_value, diff --git a/jedi/inference/filters.py b/jedi/inference/filters.py index 730dfcf7..489a73a8 100644 --- a/jedi/inference/filters.py +++ b/jedi/inference/filters.py @@ -159,7 +159,7 @@ class FunctionExecutionFilter(ParserTreeFilter): if param: yield self.param_name(self.value, name) else: - yield TreeNameDefinition(self.value, name) + yield TreeNameDefinition(self.context, name) class GlobalNameFilter(AbstractUsedNamesFilter): @@ -362,7 +362,7 @@ def get_global_filters(inference_state, value, until_position, origin_scope): >>> scope = next(module_node.iter_funcdefs()) >>> scope - >>> value = script._get_module().create_value(scope) + >>> value = script._get_module_context().create_context(scope) >>> filters = list(get_global_filters(value.inference_state, value, (4, 0), None)) First we get the names from the function scope. diff --git a/jedi/inference/gradual/conversion.py b/jedi/inference/gradual/conversion.py index 93a0b631..c0694e4a 100644 --- a/jedi/inference/gradual/conversion.py +++ b/jedi/inference/gradual/conversion.py @@ -90,7 +90,7 @@ def _load_stub_module(module): module.inference_state, import_names=module.string_names, python_value_set=ValueSet([module]), - parent_module_value=None, + parent_module_context=None, sys_path=module.inference_state.get_sys_path(), ) diff --git a/jedi/inference/gradual/typeshed.py b/jedi/inference/gradual/typeshed.py index a57b622b..afc9bc2e 100644 --- a/jedi/inference/gradual/typeshed.py +++ b/jedi/inference/gradual/typeshed.py @@ -89,27 +89,27 @@ def _cache_stub_file_map(version_info): def import_module_decorator(func): @wraps(func) - def wrapper(inference_state, import_names, parent_module_value, sys_path, prefer_stubs): + def wrapper(inference_state, import_names, parent_module_context, sys_path, prefer_stubs): try: python_value_set = inference_state.module_cache.get(import_names) except KeyError: - if parent_module_value is not None and parent_module_value.is_stub(): - parent_module_values = parent_module_value.non_stub_value_set + if parent_module_context is not None and parent_module_context.is_stub(): + parent_module_contexts = parent_module_context.non_stub_value_set else: - parent_module_values = [parent_module_value] + parent_module_contexts = [parent_module_context] if import_names == ('os', 'path'): # This is a huge exception, we follow a nested import # ``os.path``, because it's a very important one in Python # that is being achieved by messing with ``sys.modules`` in # ``os``. - python_parent = next(iter(parent_module_values)) + python_parent = next(iter(parent_module_contexts)) if python_parent is None: python_parent, = inference_state.import_module(('os',), prefer_stubs=False) python_value_set = python_parent.py__getattribute__('path') else: python_value_set = ValueSet.from_sets( func(inference_state, import_names, p, sys_path,) - for p in parent_module_values + for p in parent_module_contexts ) inference_state.module_cache.add(import_names, python_value_set) @@ -117,7 +117,7 @@ def import_module_decorator(func): return python_value_set stub = _try_to_load_stub_cached(inference_state, import_names, python_value_set, - parent_module_value, sys_path) + parent_module_context, sys_path) if stub is not None: return ValueSet([stub]) return python_value_set @@ -140,18 +140,18 @@ def _try_to_load_stub_cached(inference_state, import_names, *args, **kwargs): def _try_to_load_stub(inference_state, import_names, python_value_set, - parent_module_value, sys_path): + parent_module_context, sys_path): """ Trying to load a stub for a set of import_names. This is modelled to work like "PEP 561 -- Distributing and Packaging Type Information", see https://www.python.org/dev/peps/pep-0561. """ - if parent_module_value is None and len(import_names) > 1: + if parent_module_context is None and len(import_names) > 1: try: - parent_module_value = _try_to_load_stub_cached( + parent_module_context = _try_to_load_stub_cached( inference_state, import_names[:-1], NO_VALUES, - parent_module_value=None, sys_path=sys_path) + parent_module_context=None, sys_path=sys_path) except KeyError: pass @@ -195,15 +195,15 @@ def _try_to_load_stub(inference_state, import_names, python_value_set, return m # 3. Try to load typeshed - m = _load_from_typeshed(inference_state, python_value_set, parent_module_value, import_names) + m = _load_from_typeshed(inference_state, python_value_set, parent_module_context, import_names) if m is not None: return m # 4. Try to load pyi file somewhere if python_value_set was not defined. if not python_value_set: - if parent_module_value is not None: + if parent_module_context is not None: try: - method = parent_module_value.py__path__ + method = parent_module_context.py__path__ except AttributeError: check_path = [] else: @@ -229,18 +229,18 @@ def _try_to_load_stub(inference_state, import_names, python_value_set, return None -def _load_from_typeshed(inference_state, python_value_set, parent_module_value, import_names): +def _load_from_typeshed(inference_state, python_value_set, parent_module_context, import_names): import_name = import_names[-1] map_ = None if len(import_names) == 1: map_ = _cache_stub_file_map(inference_state.grammar.version_info) import_name = _IMPORT_MAP.get(import_name, import_name) - elif isinstance(parent_module_value, StubModuleValue): - if not parent_module_value.is_package: + elif isinstance(parent_module_context, StubModuleValue): + if not parent_module_context.is_package: # Only if it's a package (= a folder) something can be # imported. return None - path = parent_module_value.py__path__() + path = parent_module_context.py__path__() map_ = _merge_create_stub_map(path) if map_ is not None: diff --git a/jedi/inference/imports.py b/jedi/inference/imports.py index 73d7ff0f..fa393989 100644 --- a/jedi/inference/imports.py +++ b/jedi/inference/imports.py @@ -57,12 +57,12 @@ class ModuleCache(object): # This memoization is needed, because otherwise we will infinitely loop on # certain imports. @inference_state_method_cache(default=NO_VALUES) -def infer_import(value, tree_name, is_goto=False): - module_value = value.get_root_value() +def infer_import(context, tree_name, is_goto=False): + module_context = context.get_root_context() import_node = search_ancestor(tree_name, 'import_name', 'import_from') import_path = import_node.get_path_for_name(tree_name) from_import_name = None - inference_state = value.inference_state + inference_state = context.inference_state try: from_names = import_node.get_from_names() except AttributeError: @@ -76,7 +76,7 @@ def infer_import(value, tree_name, is_goto=False): import_path = from_names importer = Importer(inference_state, tuple(import_path), - module_value, import_node.level) + module_context, import_node.level) types = importer.follow() @@ -90,7 +90,7 @@ def infer_import(value, tree_name, is_goto=False): types = unite( t.py__getattribute__( from_import_name, - name_value=value, + name_context=context, is_goto=is_goto, analysis_errors=False ) @@ -102,7 +102,7 @@ def infer_import(value, tree_name, is_goto=False): if not types: path = import_path + [from_import_name] importer = Importer(inference_state, tuple(path), - module_value, import_node.level) + module_context, import_node.level) types = importer.follow() # goto only accepts `Name` if is_goto: @@ -183,7 +183,7 @@ def _level_to_base_import_path(project_path, directory, level): class Importer(object): - def __init__(self, inference_state, import_path, module_value, level=0): + def __init__(self, inference_state, import_path, module_context, level=0): """ An implementation similar to ``__import__``. Use `follow` to actually follow the imports. @@ -196,15 +196,15 @@ class Importer(object): :param import_path: List of namespaces (strings or Names). """ - debug.speed('import %s %s' % (import_path, module_value)) + debug.speed('import %s %s' % (import_path, module_context)) self._inference_state = inference_state self.level = level - self.module_value = module_value + self.module_context = module_context self._fixed_sys_path = None self._infer_possible = True if level: - base = module_value.py__package__() + base = module_context.py__package__() # We need to care for two cases, the first one is if it's a valid # Python import. This import has a properly defined module name # chain like `foo.bar.baz` and an import in baz is made for @@ -221,7 +221,7 @@ class Importer(object): base = base[:-level + 1] import_path = base + tuple(import_path) else: - path = module_value.py__file__() + path = module_context.py__file__() import_path = list(import_path) if path is None: # If no path is defined, our best guess is that the current @@ -245,7 +245,7 @@ class Importer(object): if base_import_path is None: if import_path: _add_error( - module_value, import_path[0], + module_context, import_path[0], message='Attempted relative import beyond top-level package.' ) else: @@ -266,11 +266,11 @@ class Importer(object): sys_path_mod = ( self._inference_state.get_sys_path() - + sys_path.check_sys_path_modifications(self.module_value) + + sys_path.check_sys_path_modifications(self.module_context) ) if self._inference_state.environment.version_info.major == 2: - file_path = self.module_value.py__file__() + file_path = self.module_context.py__file__() if file_path is not None: # Python2 uses an old strange way of importing relative imports. sys_path_mod.append(force_unicode(os.path.dirname(file_path))) @@ -292,13 +292,13 @@ class Importer(object): value_set = ValueSet.from_sets([ self._inference_state.import_module( import_names[:i+1], - parent_module_value, + parent_module_context, sys_path - ) for parent_module_value in value_set + ) for parent_module_context in value_set ]) if not value_set: message = 'No module named ' + '.'.join(import_names) - _add_error(self.module_value, name, message) + _add_error(self.module_context, name, message) return NO_VALUES return value_set @@ -310,7 +310,7 @@ class Importer(object): names = [] # add builtin module names if search_path is None and in_module is None: - names += [ImportName(self.module_value, name) + names += [ImportName(self.module_context, name) for name in self._inference_state.compiled_subprocess.get_builtin_module_names()] if search_path is None: @@ -318,7 +318,7 @@ class Importer(object): for name in iter_module_names(self._inference_state, search_path): if in_module is None: - n = ImportName(self.module_value, name) + n = ImportName(self.module_context, name) else: n = SubModuleName(in_module, name) names.append(n) @@ -341,7 +341,7 @@ class Importer(object): modname = mod.string_name if modname.startswith('flask_'): extname = modname[len('flask_'):] - names.append(ImportName(self.module_value, extname)) + names.append(ImportName(self.module_context, extname)) # Now the old style: ``flaskext.foo`` for dir in self._sys_path_with_modifications(): flaskext = os.path.join(dir, 'flaskext') @@ -374,7 +374,7 @@ class Importer(object): @plugin_manager.decorate() @import_module_decorator -def import_module(inference_state, import_names, parent_module_value, sys_path): +def import_module(inference_state, import_names, parent_module_context, sys_path): """ This method is very similar to importlib's `_gcd_import`. """ @@ -385,7 +385,7 @@ def import_module(inference_state, import_names, parent_module_value, sys_path): return ValueSet([module]) module_name = '.'.join(import_names) - if parent_module_value is None: + if parent_module_context is None: # Override the sys.path. It works only good that way. # Injecting the path directly into `find_module` did not work. file_io_or_ns, is_pkg = inference_state.compiled_subprocess.get_module_info( @@ -398,7 +398,7 @@ def import_module(inference_state, import_names, parent_module_value, sys_path): return NO_VALUES else: try: - method = parent_module_value.py__path__ + method = parent_module_context.py__path__ except AttributeError: # The module is not a package. return NO_VALUES @@ -438,7 +438,7 @@ def import_module(inference_state, import_names, parent_module_value, sys_path): is_package=is_pkg, ) - if parent_module_value is None: + if parent_module_context is None: debug.dbg('global search_module %s: %s', import_names[-1], module) else: debug.dbg('search_module %s in paths %s: %s', module_name, paths, module) diff --git a/jedi/inference/lazy_value.py b/jedi/inference/lazy_value.py index 0f06a373..fa2f9609 100644 --- a/jedi/inference/lazy_value.py +++ b/jedi/inference/lazy_value.py @@ -14,7 +14,7 @@ class AbstractLazyValue(object): class LazyKnownValue(AbstractLazyValue): - """data is a value.""" + """data is a Value.""" def infer(self): return ValueSet([self.data]) @@ -34,16 +34,16 @@ class LazyUnknownValue(AbstractLazyValue): class LazyTreeValue(AbstractLazyValue): - def __init__(self, value, node): + def __init__(self, context, node): super(LazyTreeValue, self).__init__(node) - self.value = value + self.context = context # We need to save the predefined names. It's an unfortunate side effect # that needs to be tracked otherwise results will be wrong. - self._predefined_names = dict(value.predefined_names) + self._predefined_names = dict(context.predefined_names) def infer(self): - with monkeypatch(self.value, 'predefined_names', self._predefined_names): - return self.value.infer_node(self.data) + with monkeypatch(self.context, 'predefined_names', self._predefined_names): + return self.context.infer_node(self.data) def get_merged_lazy_value(lazy_values): diff --git a/jedi/inference/names.py b/jedi/inference/names.py index dd55f6e7..ff06bf2e 100644 --- a/jedi/inference/names.py +++ b/jedi/inference/names.py @@ -32,7 +32,7 @@ class AbstractNameDefinition(object): if qualified_names is None or not include_module_names: return qualified_names - module_names = self.get_root_value().string_names + module_names = self.get_root_context().string_names if module_names is None: return None return module_names + qualified_names @@ -41,8 +41,8 @@ class AbstractNameDefinition(object): # By default, a name has no qualified names. return None - def get_root_value(self): - return self.parent_context.get_root_value() + def get_root_context(self): + return self.parent_context.get_root_context() def __repr__(self): if self.start_pos is None: @@ -87,7 +87,7 @@ class AbstractTreeName(AbstractNameDefinition): # In case of level == 1, it works always, because it's like a submodule # lookup. if import_node is not None and not (import_node.level == 1 - and self.get_root_value().is_package): + and self.get_root_context().is_package): # TODO improve the situation for when level is present. if include_module_names and not import_node.level: return tuple(n.value for n in import_node.get_path_for_name(self.tree_name)) @@ -103,7 +103,9 @@ class AbstractTreeName(AbstractNameDefinition): return parent_names + (self.tree_name.value,) def goto(self, **kwargs): - return self.parent_context.inference_state.goto(self.parent_context, self.tree_name, **kwargs) + return self.parent_context.inference_state.goto( + self.parent_context, self.tree_name, **kwargs + ) def is_import(self): imp = search_ancestor(self.tree_name, 'import_from', 'import_name') @@ -125,10 +127,10 @@ class ValueNameMixin(object): def _get_qualified_names(self): return self._value.get_qualified_names() - def get_root_value(self): + def get_root_context(self): if self.parent_context is None: # A module - return self._value - return super(ValueNameMixin, self).get_root_value() + return self._value.as_context() + return super(ValueNameMixin, self).get_root_context() @property def api_type(self): @@ -156,8 +158,11 @@ class TreeNameDefinition(AbstractTreeName): def infer(self): # Refactor this, should probably be here. from jedi.inference.syntax_tree import tree_name_to_values - parent = self.parent_context - return tree_name_to_values(parent.inference_state, parent, self.tree_name) + return tree_name_to_values( + self.parent_context.inference_state, + self.parent_context, + self.tree_name + ) @property def api_type(self): @@ -318,14 +323,14 @@ class ImportName(AbstractNameDefinition): _level = 0 def __init__(self, parent_context, string_name): - self._from_module_value = parent_context + self._from_module_context = parent_context self.string_name = string_name def get_qualified_names(self, include_module_names=False): if include_module_names: if self._level: assert self._level == 1, "Everything else is not supported for now" - module_names = self._from_module_value.string_names + module_names = self._from_module_context.string_names if module_names is None: return module_names return module_names + (self.string_name,) @@ -334,7 +339,7 @@ class ImportName(AbstractNameDefinition): @property def parent_context(self): - m = self._from_module_value + m = self._from_module_context import_values = self.infer() if not import_values: return m @@ -345,7 +350,7 @@ class ImportName(AbstractNameDefinition): @memoize_method def infer(self): from jedi.inference.imports import Importer - m = self._from_module_value + m = self._from_module_context return Importer(m.inference_state, [self.string_name], m, level=self._level).follow() def goto(self): diff --git a/jedi/inference/star_args.py b/jedi/inference/star_args.py index 3ee70787..335ebb1b 100644 --- a/jedi/inference/star_args.py +++ b/jedi/inference/star_args.py @@ -35,13 +35,14 @@ def _iter_nodes_for_param(param_name): # anyway trailer = search_ancestor(argument, 'trailer') if trailer is not None: # Make sure we're in a function - value = execution_value.create_value(trailer) - if _goes_to_param_name(param_name, value, name): - values = _to_callables(value, trailer) + raise NotImplementedError + context = execution_value.create_context(trailer) + if _goes_to_param_name(param_name, context, name): + values = _to_callables(context, trailer) args = TreeArguments.create_cached( execution_value.inference_state, - value=value, + context=context, argument_node=trailer.children[1], trailer=trailer, ) @@ -51,11 +52,11 @@ def _iter_nodes_for_param(param_name): assert False -def _goes_to_param_name(param_name, value, potential_name): +def _goes_to_param_name(param_name, context, potential_name): if potential_name.type != 'name': return False from jedi.inference.names import TreeNameDefinition - found = TreeNameDefinition(value, potential_name).goto() + found = TreeNameDefinition(context, potential_name).goto() return any(param_name.parent_context == p.parent_context and param_name.start_pos == p.start_pos for p in found) diff --git a/jedi/inference/syntax_tree.py b/jedi/inference/syntax_tree.py index 69b93984..cc688f58 100644 --- a/jedi/inference/syntax_tree.py +++ b/jedi/inference/syntax_tree.py @@ -563,7 +563,7 @@ def tree_name_to_values(inference_state, context, tree_name): expr_stmt = name.parent if expr_stmt.type == "expr_stmt" and expr_stmt.children[1].type == "annassign": - correct_scope = parser_utils.get_parent_scope(name) == value.tree_node + correct_scope = parser_utils.get_parent_scope(name) == context.tree_node if correct_scope: value_set |= annotation.infer_annotation( context, expr_stmt.children[1].children[1] @@ -576,7 +576,8 @@ def tree_name_to_values(inference_state, context, tree_name): if node is None: node = tree_name.parent if node.type == 'global_stmt': - value = inference_state.create_context(value, tree_name) + c = context.create_context(tree_name) + raise NotImplementedError finder = NameFinder(inference_state, value, value, tree_name.value) filters = finder.get_global_filters() # For global_stmt lookups, we only need the first possible scope, @@ -584,8 +585,8 @@ def tree_name_to_values(inference_state, context, tree_name): filters = [next(filters)] return finder.find(filters, attribute_lookup=False) elif node.type not in ('import_from', 'import_name'): - value = inference_state.create_value(value, tree_name) - return infer_atom(value, tree_name) + c = inference_state.create_context(context, tree_name) + return infer_atom(c, tree_name) typ = node.type if typ == 'for_stmt': diff --git a/jedi/inference/sys_path.py b/jedi/inference/sys_path.py index 35b393e5..a1f705eb 100644 --- a/jedi/inference/sys_path.py +++ b/jedi/inference/sys_path.py @@ -11,11 +11,11 @@ from jedi import settings from jedi import debug -def _abs_path(module_value, path): +def _abs_path(module_context, path): if os.path.isabs(path): return path - module_path = module_value.py__file__() + module_path = module_context.py__file__() if module_path is None: # In this case we have no idea where we actually are in the file # system. @@ -26,7 +26,7 @@ def _abs_path(module_value, path): return os.path.abspath(os.path.join(base_dir, path)) -def _paths_from_assignment(module_value, expr_stmt): +def _paths_from_assignment(module_context, expr_stmt): """ Extracts the assigned strings from an assignment that looks as follows:: @@ -60,16 +60,16 @@ def _paths_from_assignment(module_value, expr_stmt): except AssertionError: continue - cn = ValueualizedNode(module_value.create_value(expr_stmt), expr_stmt) + cn = ValueualizedNode(module_context.create_context(expr_stmt), expr_stmt) for lazy_value in cn.infer().iterate(cn): for value in lazy_value.infer(): if is_string(value): - abs_path = _abs_path(module_value, value.get_safe_value()) + abs_path = _abs_path(module_context, value.get_safe_value()) if abs_path is not None: yield abs_path -def _paths_from_list_modifications(module_value, trailer1, trailer2): +def _paths_from_list_modifications(module_context, trailer1, trailer2): """ extract the path from either "sys.path.append" or "sys.path.insert" """ # Guarantee that both are trailers, the first one a name and the second one # a function execution with at least one param. @@ -85,15 +85,15 @@ def _paths_from_list_modifications(module_value, trailer1, trailer2): if name == 'insert' and len(arg.children) in (3, 4): # Possible trailing comma. arg = arg.children[2] - for value in module_value.create_value(arg).infer_node(arg): + for value in module_context.create_context(arg).infer_node(arg): if is_string(value): - abs_path = _abs_path(module_value, value.get_safe_value()) + abs_path = _abs_path(module_context, value.get_safe_value()) if abs_path is not None: yield abs_path @inference_state_method_cache(default=[]) -def check_sys_path_modifications(module_value): +def check_sys_path_modifications(module_context): """ Detect sys.path modifications within module. """ @@ -108,12 +108,12 @@ def check_sys_path_modifications(module_value): if n.type == 'name' and n.value == 'path': yield name, power - if module_value.tree_node is None: + if module_context.tree_node is None: return [] added = [] try: - possible_names = module_value.tree_node.get_used_names()['path'] + possible_names = module_context.tree_node.get_used_names()['path'] except KeyError: pass else: @@ -122,11 +122,11 @@ def check_sys_path_modifications(module_value): if len(power.children) >= 4: added.extend( _paths_from_list_modifications( - module_value, *power.children[2:4] + module_context, *power.children[2:4] ) ) elif expr_stmt is not None and expr_stmt.type == 'expr_stmt': - added.extend(_paths_from_assignment(module_value, expr_stmt)) + added.extend(_paths_from_assignment(module_context, expr_stmt)) return added @@ -157,7 +157,7 @@ def _get_paths_from_buildout_script(inference_state, buildout_script_path): inference_state, module_node, file_io, string_names=None, code_lines=get_cached_code_lines(inference_state.grammar, buildout_script_path), - ) + ).as_context() for path in check_sys_path_modifications(module): yield path diff --git a/jedi/inference/usages.py b/jedi/inference/usages.py index 91891c41..0b0d979f 100644 --- a/jedi/inference/usages.py +++ b/jedi/inference/usages.py @@ -26,22 +26,23 @@ def _dictionarize(names): ) -def _find_names(module_value, tree_name): - value = module_value.create_value(tree_name) - name = TreeNameDefinition(value, tree_name) +def _find_names(module_context, tree_name): + context = module_context.create_context(tree_name) + name = TreeNameDefinition(context, tree_name) found_names = set(name.goto()) found_names.add(name) return _dictionarize(_resolve_names(found_names)) -def usages(module_value, tree_name): +def usages(module_context, tree_name): search_name = tree_name.value - found_names = _find_names(module_value, tree_name) + found_names = _find_names(module_context, tree_name) modules = set(d.get_root_value() for d in found_names.values()) modules = set(m for m in modules if m.is_module() and not m.is_compiled()) non_matching_usage_maps = {} - for m in imports.get_modules_containing_name(module_value.inference_state, modules, search_name): + inf = module_context.inference_state + for m in imports.get_modules_containing_name(inf, modules, search_name): for name_leaf in m.tree_node.get_used_names().get(search_name, []): new = _find_names(m, name_leaf) if any(tree_name in found_names for tree_name in new): diff --git a/jedi/inference/value/iterable.py b/jedi/inference/value/iterable.py index 69e6432f..3f94ca18 100644 --- a/jedi/inference/value/iterable.py +++ b/jedi/inference/value/iterable.py @@ -669,8 +669,8 @@ def _check_array_additions(value, sequence): from jedi.inference import arguments debug.dbg('Dynamic array search for %s' % sequence, color='MAGENTA') - module_value = value.get_root_value() - if not settings.dynamic_array_additions or isinstance(module_value, compiled.CompiledObject): + module_context = value.get_root_context() + if not settings.dynamic_array_additions or isinstance(module_context, compiled.CompiledObject): debug.dbg('Dynamic array search aborted.', color='MAGENTA') return NO_VALUES @@ -696,7 +696,7 @@ def _check_array_additions(value, sequence): added_types = set() for add_name in search_names: try: - possible_names = module_value.tree_node.get_used_names()[add_name] + possible_names = module_context.tree_node.get_used_names()[add_name] except KeyError: continue else: @@ -717,19 +717,20 @@ def _check_array_additions(value, sequence): or execution_trailer.children[1] == ')': continue - random_value = value.create_value(name) + raise NotImplementedError + random_context = value.create_context(name) with recursion.execution_allowed(value.inference_state, power) as allowed: if allowed: found = infer_call_of_leaf( - random_value, + random_context, name, cut_own_trailer=True ) if sequence in found: # The arrays match. Now add the results added_types |= find_additions( - random_value, + random_context, execution_trailer.children[1], add_name ) diff --git a/jedi/inference/value/module.py b/jedi/inference/value/module.py index 4332a249..5b222a39 100644 --- a/jedi/inference/value/module.py +++ b/jedi/inference/value/module.py @@ -190,7 +190,8 @@ class ModuleValue(ModuleMixin, TreeValue): api_type = u'module' parent_context = None - def __init__(self, inference_state, module_node, file_io, string_names, code_lines, is_package=False): + def __init__(self, inference_state, module_node, file_io, string_names, + code_lines, is_package=False): super(ModuleValue, self).__init__( inference_state, parent_context=None, diff --git a/test/run.py b/test/run.py index f898e133..a353f01e 100755 --- a/test/run.py +++ b/test/run.py @@ -123,7 +123,7 @@ import jedi from jedi import debug from jedi._compatibility import unicode, is_py3 from jedi.api.classes import Definition -from jedi.api.completion import get_user_scope +from jedi.api.completion import get_user_context from jedi import parser_utils from jedi.api.environment import get_default_environment, get_system_environment from jedi.inference.gradual.conversion import convert_values @@ -225,14 +225,13 @@ class IntegrationTestCase(object): parser = grammar36.parse(string, start_symbol='eval_input', error_recovery=False) parser_utils.move(parser.get_root_node(), self.line_nr) element = parser.get_root_node() - module_value = script._get_module() - # The value shouldn't matter for the test results. - user_value = get_user_scope(module_value, (self.line_nr, 0)) - if user_value.api_type == 'function': - user_value = user_value.get_function_execution() - element.parent = user_value.tree_node + module_context = script._get_module_context() + user_context = get_user_context(module_context, (self.line_nr, 0)) + if user_context.api_type == 'function': + user_context = user_context.get_function_execution() + element.parent = user_context.tree_node results = convert_values( - inference_state.infer_element(user_value, element), + inference_state.infer_element(user_context, element), ) if not results: raise Exception('Could not resolve %s on line %s'