1
0
forked from VimPlug/jedi

Function **kwargs fixes.

This commit is contained in:
Dave Halter
2016-11-01 00:23:44 +01:00
parent 6d8ff9293d
commit 4aec9cadd7
2 changed files with 29 additions and 27 deletions
+24 -10
View File
@@ -33,17 +33,16 @@ from jedi.evaluate import pep0484
from jedi import common from jedi import common
from jedi.evaluate.filters import DictFilter from jedi.evaluate.filters import DictFilter
from jedi.evaluate import context from jedi.evaluate import context
from jedi.evaluate import precedence
class AbstractSequence(context.Context): class AbstractSequence(context.Context):
_array_type = None
def get_filters(self, search_global, until_position=None, origin_scope=None): def get_filters(self, search_global, until_position=None, origin_scope=None):
raise NotImplementedError raise NotImplementedError
@property @property
def name(self): def name(self):
return compiled.CompiledContextName(self, self._array_type) return compiled.CompiledContextName(self, self.array_type)
class IterableWrapper(tree.Base): class IterableWrapper(tree.Base):
@@ -269,7 +268,6 @@ class ArrayMixin(object):
def name(self): def name(self):
return FakeSequence(self._evaluator, [], self.type).name return FakeSequence(self._evaluator, [], self.type).name
@memoize_default()
def dict_values(self): def dict_values(self):
return unite(self._evaluator.eval_element(v) for k, v in self._items()) return unite(self._evaluator.eval_element(v) for k, v in self._items())
@@ -352,16 +350,16 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
self._defining_context = defining_context self._defining_context = defining_context
if self.atom.type in ('testlist_star_expr', 'testlist'): if self.atom.type in ('testlist_star_expr', 'testlist'):
self._array_type = 'tuple' self.array_type = 'tuple'
else: else:
self._array_type = ArrayLiteralContext.mapping[atom.children[0]] self.array_type = ArrayLiteralContext.mapping[atom.children[0]]
"""The builtin name of the array (list, set, tuple or dict).""" """The builtin name of the array (list, set, tuple or dict)."""
c = self.atom.children c = self.atom.children
array_node = c[1] array_node = c[1]
if self._array_type == 'dict' and array_node != '}' \ if self.array_type == 'dict' and array_node != '}' \
and (not hasattr(array_node, 'children') or ':' not in array_node.children): and (not hasattr(array_node, 'children') or ':' not in array_node.children):
self._array_type = 'set' self.array_type = 'set'
def py__getitem__(self, index): def py__getitem__(self, index):
"""Here the index is an int/str. Raises IndexError/KeyError.""" """Here the index is an int/str. Raises IndexError/KeyError."""
@@ -437,6 +435,16 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
else: else:
return [array_node] return [array_node]
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 LazyContexts.
"""
for key_node, value in self._items():
for key in self._defining_context.eval_node(key_node):
if precedence.is_string(key):
yield key.obj, context.LazyTreeContext(self._defining_context, value)
def __repr__(self): def __repr__(self):
return "<%s of %s>" % (type(self).__name__, self.atom) return "<%s of %s>" % (type(self).__name__, self.atom)
@@ -444,7 +452,7 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
class _FakeArray(ArrayLiteralContext): class _FakeArray(ArrayLiteralContext):
def __init__(self, evaluator, container, type): def __init__(self, evaluator, container, type):
# TODO is this class really needed? # TODO is this class really needed?
self._array_type = type self.array_type = type
self._evaluator = evaluator self._evaluator = evaluator
self.atom = container self.atom = container
self.parent_context = evaluator.BUILTINS self.parent_context = evaluator.BUILTINS
@@ -522,12 +530,18 @@ class FakeDict(_FakeArray):
def py__getitem__(self, index): def py__getitem__(self, index):
return self._dct[index].infer() return self._dct[index].infer()
def dict_values(self):
return unite(lazy_context.infer() for lazy_context in self._dct.values())
def _items(self): def _items(self):
raise DeprecationWarning raise DeprecationWarning
for key, values in self._dct.items(): for key, values in self._dct.items():
# TODO this is not proper. The values could be multiple values?! # TODO this is not proper. The values could be multiple values?!
yield key, values[0] yield key, values[0]
def exact_key_items(self):
return self._dct.items()
class MergedArray(_FakeArray): class MergedArray(_FakeArray):
def __init__(self, evaluator, arrays): def __init__(self, evaluator, arrays):
@@ -645,7 +659,7 @@ def py__getitem__(evaluator, context, types, trailer):
# If the index is not clearly defined, we have to get all the # If the index is not clearly defined, we have to get all the
# possiblities. # possiblities.
for typ in list(types): for typ in list(types):
if isinstance(typ, Array) and typ.type == 'dict': if isinstance(typ, AbstractSequence) and typ.type == 'dict':
types.remove(typ) types.remove(typ)
result |= typ.dict_values() result |= typ.dict_values()
return result | py__iter__types(evaluator, types) return result | py__iter__types(evaluator, types)
+5 -17
View File
@@ -140,11 +140,8 @@ class TreeArguments(AbstractArguments):
yield None, context.get_merged_lazy_context(values) yield None, context.get_merged_lazy_context(values)
elif stars == 2: elif stars == 2:
arrays = self._evaluator.eval_element(self._context, el) arrays = self._evaluator.eval_element(self._context, el)
dicts = [_star_star_dict(self._evaluator, a, el, func) for dct in arrays:
for a in arrays] for key, values in _star_star_dict(self._evaluator, dct, el, func):
for dct in dicts:
for key, values in dct.items():
raise NotImplementedError
yield key, values yield key, values
else: else:
if tree.is_node(el, 'argument'): if tree.is_node(el, 'argument'):
@@ -394,28 +391,19 @@ def _iterate_star_args(evaluator, array, input_node, func=None):
def _star_star_dict(evaluator, array, input_node, func): def _star_star_dict(evaluator, array, input_node, func):
dct = defaultdict(lambda: [])
from jedi.evaluate.representation import Instance from jedi.evaluate.representation import Instance
if isinstance(array, Instance) and array.name.get_code() == 'dict': if isinstance(array, Instance) and array.name.get_code() == 'dict':
# For now ignore this case. In the future add proper iterators and just # For now ignore this case. In the future add proper iterators and just
# make one call without crazy isinstance checks. # make one call without crazy isinstance checks.
return {} return {}
elif isinstance(array, iterable.AbstractSequence) and array.array_type == 'dict':
if isinstance(array, iterable.FakeDict): return array.exact_key_items()
return array._dct
elif isinstance(array, iterable.Array) and array.type == 'dict':
# TODO bad call to non-public API
for key_node, value in array._items():
for key in evaluator.eval_element(key_node):
if precedence.is_string(key):
dct[key.obj].append(value)
else: else:
if func is not None: if func is not None:
m = "TypeError: %s argument after ** must be a mapping, not %s" \ m = "TypeError: %s argument after ** must be a mapping, not %s" \
% (func.name.value, array) % (func.name.value, array)
analysis.add(evaluator, 'type-error-star-star', input_node, message=m) analysis.add(evaluator, 'type-error-star-star', input_node, message=m)
return dict(dct) return {}
def _error_argument_count(func, actual_count): def _error_argument_count(func, actual_count):