From 0acc5256eac5d366f734275b990bfd52092526f9 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 1 Jan 2016 12:43:07 +0100 Subject: [PATCH] Implement imitate_items(), which helps if you use {}.items(). --- jedi/evaluate/iterable.py | 41 ++++++++++++++++++++++++++++----------- jedi/evaluate/param.py | 6 +++--- test/completion/types.py | 5 +++++ 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index c7e6e054..69594e40 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -279,21 +279,29 @@ class Array(IterableWrapper, ArrayMixin): @memoize_default() def dict_values(self): - return unite(self._evaluator.eval_element(v) for v in self._values()) + return unite(self._evaluator.eval_element(v) for k, v in self._items()) @register_builtin_method('values', type='dict') - def py_values(self): - return set([FakeSequence(self._evaluator, [AlreadyEvaluated(self.dict_values())], 'tuple')]) + def _imitate_values(self): + items = unite(self._evaluator.eval_element(v) for k, v in self._items()) + return create_evaluated_sequence_set(self._evaluator, items, type='list') + #return set([FakeSequence(self._evaluator, [AlreadyEvaluated(items)], 'tuple')]) + + @register_builtin_method('items', type='dict') + def _imitate_items(self): + items = set(FakeSequence(self._evaluator, (k, v), 'tuple') + for k, v in self._items()) + + return create_evaluated_sequence_set(self._evaluator, items, type='list') def py__getitem__(self, index): """Here the index is an int/str. Raises IndexError/KeyError.""" if self.type == 'dict': - for key, values in self._items(): + for key, value in self._items(): for k in self._evaluator.eval_element(key): if isinstance(k, compiled.CompiledObject) \ and index == k.obj: - for value in values: - return self._evaluator.eval_element(value) + return self._evaluator.eval_element(value) raise KeyError('No key found in dictionary %s.' % self) # Can raise an IndexError @@ -353,11 +361,10 @@ class Array(IterableWrapper, ArrayMixin): op = next(iterator, None) if op is None or op == ',': kv.append(key) # A set. - elif op == ':': # A dict. - kv.append((key, [next(iterator)])) - next(iterator, None) # Possible comma. else: - raise NotImplementedError('dict/set comprehensions') + assert op == ':' # A dict. + kv.append((key, next(iterator))) + next(iterator, None) # Possible comma. return kv else: return [array_node] @@ -391,6 +398,16 @@ class FakeSequence(_FakeArray): return self._sequence_values +def create_evaluated_sequence_set(evaluator, *types_order, **kwargs): + """ + ``sequence_type`` is a named argument, that doesn't work in Python2. For backwards + compatibility reasons, we're now using kwargs. + """ + sequence_type = kwargs.get('sequence_type') + sets = tuple(AlreadyEvaluated(types) for types in types_order) + return set([FakeSequence(evaluator, sets, sequence_type)]) + + class AlreadyEvaluated(frozenset): """A simple container to add already evaluated objects to an array.""" def get_code(self, normalized=False): @@ -414,7 +431,9 @@ class FakeDict(_FakeArray): return unite(self._evaluator.eval_element(v) for v in self._dct[index]) def _items(self): - return self._dct.items() + for key, values in self._dct.items(): + # TODO this is not proper. The values could be multiple values?! + yield key, values[0] class MergedArray(_FakeArray): diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index ffcb9475..3dc515a1 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -269,7 +269,7 @@ def get_params(evaluator, func, var_args): try: key_param = param_dict[unicode(key)] except KeyError: - non_matching_keys[key] += va_values + non_matching_keys[key] = va_values else: param_names.append(ExecutedParam(key_param, var_args, va_values).name) @@ -407,10 +407,10 @@ def _star_star_dict(evaluator, array, input_node, func): return array._dct elif isinstance(array, iterable.Array) and array.type == 'dict': # TODO bad call to non-public API - for key_node, values in array._items(): + for key_node, value in array._items(): for key in evaluator.eval_element(key_node): if precedence.is_string(key): - dct[key.obj] += values + dct[key.obj].append(value) else: if func is not None: diff --git a/test/completion/types.py b/test/completion/types.py index b38f8db4..9c3125f0 100644 --- a/test/completion/types.py +++ b/test/completion/types.py @@ -86,6 +86,11 @@ d.values()[0] ##? int() list dict(d).values()[0] +#? str() float() +d.items()[0][0] +#? int() list +d.items()[0][1] + # ----------------- # set # -----------------