def _imitate_items(self, arguments): lazy_values = [ LazyKnownValue( FakeTuple(self.inference_state, (LazyTreeValue(self._defining_context, key_node), LazyTreeValue(self._defining_context, value_node)))) for key_node, value_node in self.get_tree_entries() ] return ValueSet([FakeList(self.inference_state, lazy_values)])
def unpack(self, funcdef=None): named_args = [] for star_count, el in unpack_arglist(self.argument_node): if star_count == 1: 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 # an exception? yield None, get_merged_lazy_value( [v for v in values if v is not None]) elif star_count == 2: arrays = self.context.infer_node(el) for dct in arrays: 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.context, c[2]), )) else: # Generator comprehension. # Include the brackets with the parent. sync_comp_for = el.children[1] if sync_comp_for.type == 'comp_for': sync_comp_for = sync_comp_for.children[1] comp = iterable.GeneratorComprehension( self._inference_state, 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.context, el) # Reordering arguments is necessary, because star args sometimes appear # after named argument, but in the actual order it's prepended. for named_arg in named_args: yield named_arg
def exact_key_items(self): """ Returns a generator of tuples like dict.items(), where the key is resolved (as a string) and the values are still lazy values. """ for key_node, value in self.get_tree_entries(): for key in self._defining_context.infer_node(key_node): if is_string(key): yield key.get_safe_value(), LazyTreeValue(self._defining_context, value)
def _get_yield_lazy_value(self, yield_expr): if yield_expr.type == 'keyword': # `yield` just yields None. ctx = compiled.builtin_from_name(self.inference_state, 'None') yield LazyKnownValue(ctx) return node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. cn = ContextualizedNode(self, node.children[1]) yield from cn.infer().iterate(cn) else: yield LazyTreeValue(self, node)
def py__iter__(self, contextualized_node=None): """ While values returns the possible values for any array field, this function returns the value for a certain index. """ for node in self.get_tree_entries(): if node == ':' or node.type == 'subscript': # TODO this should probably use at least part of the code # of infer_subscript_list. yield LazyKnownValue( Slice(self._defining_context, None, None, None)) else: yield LazyTreeValue(self._defining_context, node) yield from check_array_additions(self._defining_context, self)
def get_executed_param_names_and_issues(function_value, arguments): """ Return a tuple of: - a list of `ExecutedParamName`s corresponding to the arguments of the function execution `function_value`, containing the inferred value of those arguments (whether explicit or default) - a list of the issues encountered while building that list For example, given: ``` def foo(a, b, c=None, d='d'): ... foo(42, c='c') ``` Then for the execution of `foo`, this will return a tuple containing: - a list with entries for each parameter a, b, c & d; the entries for a, c, & d will have their values (42, 'c' and 'd' respectively) included. - a list with a single entry about the lack of a value for `b` """ def too_many_args(argument): m = _error_argument_count(funcdef, len(unpacked_va)) # Just report an error for the first param that is not needed (like # cPython). if arguments.get_calling_nodes(): # There might not be a valid calling node so check for that first. issues.append( _add_argument_issue('type-error-too-many-arguments', argument, message=m)) else: issues.append(None) debug.warning('non-public warning: %s', m) issues = [] # List[Optional[analysis issue]] result_params = [] param_dict = {} funcdef = function_value.tree_node # Default params are part of the value where the function was defined. # This means that they might have access on class variables that the # function itself doesn't have. default_param_context = function_value.get_default_param_context() for param in funcdef.get_params(): param_dict[param.name.value] = param unpacked_va = list(arguments.unpack(funcdef)) var_arg_iterator = PushBackIterator(iter(unpacked_va)) non_matching_keys = defaultdict(lambda: []) keys_used = {} keys_only = False had_multiple_value_error = False for param in funcdef.get_params(): # The value and key can both be null. There, the defaults apply. # args / kwargs will just be empty arrays / dicts, respectively. # Wrong value count is just ignored. If you try to test cases that are # not allowed in Python, Jedi will maybe not show any completions. is_default = False key, argument = next(var_arg_iterator, (None, None)) while key is not None: keys_only = True try: key_param = param_dict[key] except KeyError: non_matching_keys[key] = argument else: if key in keys_used: had_multiple_value_error = True m = ( "TypeError: %s() got multiple values for keyword argument '%s'." % (funcdef.name, key)) for contextualized_node in arguments.get_calling_nodes(): issues.append( analysis.add(contextualized_node.context, 'type-error-multiple-values', contextualized_node.node, message=m)) else: keys_used[key] = ExecutedParamName(function_value, arguments, key_param, argument) key, argument = next(var_arg_iterator, (None, None)) try: result_params.append(keys_used[param.name.value]) continue except KeyError: pass if param.star_count == 1: # *args param lazy_value_list = [] if argument is not None: lazy_value_list.append(argument) for key, argument in var_arg_iterator: # Iterate until a key argument is found. if key: var_arg_iterator.push_back((key, argument)) break lazy_value_list.append(argument) seq = iterable.FakeTuple(function_value.inference_state, lazy_value_list) result_arg = LazyKnownValue(seq) elif param.star_count == 2: if argument is not None: too_many_args(argument) # **kwargs param dct = iterable.FakeDict(function_value.inference_state, dict(non_matching_keys)) result_arg = LazyKnownValue(dct) non_matching_keys = {} else: # normal param if argument is None: # No value: Return an empty container if param.default is None: result_arg = LazyUnknownValue() if not keys_only: for contextualized_node in arguments.get_calling_nodes( ): m = _error_argument_count(funcdef, len(unpacked_va)) issues.append( analysis.add( contextualized_node.context, 'type-error-too-few-arguments', contextualized_node.node, message=m, )) else: result_arg = LazyTreeValue(default_param_context, param.default) is_default = True else: result_arg = argument result_params.append( ExecutedParamName(function_value, arguments, param, result_arg, is_default=is_default)) if not isinstance(result_arg, LazyUnknownValue): keys_used[param.name.value] = result_params[-1] if keys_only: # All arguments should be handed over to the next function. It's not # about the values inside, it's about the names. Jedi needs to now that # there's nothing to find for certain names. for k in set(param_dict) - set(keys_used): param = param_dict[k] if not (non_matching_keys or had_multiple_value_error or param.star_count or param.default): # add a warning only if there's not another one. for contextualized_node in arguments.get_calling_nodes(): m = _error_argument_count(funcdef, len(unpacked_va)) issues.append( analysis.add(contextualized_node.context, 'type-error-too-few-arguments', contextualized_node.node, message=m)) for key, lazy_value in non_matching_keys.items(): m = "TypeError: %s() got an unexpected keyword argument '%s'." \ % (funcdef.name, key) issues.append( _add_argument_issue('type-error-keyword-argument', lazy_value, message=m)) remaining_arguments = list(var_arg_iterator) if remaining_arguments: first_key, lazy_value = remaining_arguments[0] too_many_args(lazy_value) return result_params, issues