forked from VimPlug/jedi
Fix namedtuple support
There were a couple issues: - namedtuple with one member didn't work - namedtuple content access was never possible - operator.itemgetter didn't work properly. Corrected py__bool__ for FakeSequence Fixes #730.
This commit is contained in:
@@ -511,6 +511,9 @@ class FakeSequence(_FakeArray):
|
|||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
return self._lazy_context_list
|
return self._lazy_context_list
|
||||||
|
|
||||||
|
def py__bool__(self):
|
||||||
|
return bool(len(self._lazy_context_list))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (type(self).__name__, self._lazy_context_list)
|
return "<%s of %s>" % (type(self).__name__, self._lazy_context_list)
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,23 @@ from jedi.evaluate import param
|
|||||||
from jedi.evaluate import analysis
|
from jedi.evaluate import analysis
|
||||||
from jedi.evaluate.context import LazyTreeContext, ContextualizedNode
|
from jedi.evaluate.context import LazyTreeContext, ContextualizedNode
|
||||||
|
|
||||||
|
# Now this is all part of fake tuples in Jedi. However super doesn't work on
|
||||||
|
# __init__ and __new__ doesn't work at all. So adding this to nametuples is
|
||||||
|
# just the easiest way.
|
||||||
|
_NAMEDTUPLE_INIT = """
|
||||||
|
def __init__(_cls, {arg_list}):
|
||||||
|
'A helper function for namedtuple.'
|
||||||
|
self.__iterable = ({arg_list})
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for i in self.__iterable:
|
||||||
|
yield i
|
||||||
|
|
||||||
|
def __getitem__(self, y):
|
||||||
|
return self.__iterable[y]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class NotInStdLib(LookupError):
|
class NotInStdLib(LookupError):
|
||||||
pass
|
pass
|
||||||
@@ -259,20 +276,24 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
else:
|
else:
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
base = collections._class_template
|
||||||
|
base += _NAMEDTUPLE_INIT
|
||||||
# Build source
|
# Build source
|
||||||
source = collections._class_template.format(
|
source = base.format(
|
||||||
typename=name,
|
typename=name,
|
||||||
field_names=fields,
|
field_names=tuple(fields),
|
||||||
num_fields=len(fields),
|
num_fields=len(fields),
|
||||||
arg_list=', '.join(fields),
|
arg_list = repr(tuple(fields)).replace("'", "")[1:-1],
|
||||||
repr_fmt=', '.join(collections._repr_template.format(name=name) for name in fields),
|
repr_fmt=', '.join(collections._repr_template.format(name=name) for name in fields),
|
||||||
field_defs='\n'.join(collections._field_template.format(index=index, name=name)
|
field_defs='\n'.join(collections._field_template.format(index=index, name=name)
|
||||||
for index, name in enumerate(fields))
|
for index, name in enumerate(fields))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Parse source
|
# Parse source
|
||||||
generated_class = next(evaluator.grammar.parse(source).iter_classdefs())
|
module = evaluator.grammar.parse(source)
|
||||||
return set([er.ClassContext(evaluator, generated_class, evaluator.BUILTINS)])
|
generated_class = next(module.iter_classdefs())
|
||||||
|
parent_context = er.ModuleContext(evaluator, module, '')
|
||||||
|
return set([er.ClassContext(evaluator, generated_class, parent_context)])
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('first, /')
|
@argument_clinic('first, /')
|
||||||
|
|||||||
@@ -43,3 +43,35 @@ def test_namedtuple_list():
|
|||||||
assert completions == set()
|
assert completions == set()
|
||||||
else:
|
else:
|
||||||
assert completions == set(['legs', 'length', 'large'])
|
assert completions == set(['legs', 'length', 'large'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_namedtuple_content():
|
||||||
|
source = dedent("""\
|
||||||
|
import collections
|
||||||
|
Foo = collections.namedtuple('Foo', ['bar', 'baz'])
|
||||||
|
named = Foo(baz=4, bar=3.0)
|
||||||
|
unnamed = Foo(4, '')
|
||||||
|
""")
|
||||||
|
|
||||||
|
def d(source):
|
||||||
|
x, = Script(source).goto_definitions()
|
||||||
|
return x.name
|
||||||
|
|
||||||
|
assert d(source + 'unnamed.bar') == 'int'
|
||||||
|
assert d(source + 'unnamed.baz') == 'str'
|
||||||
|
assert d(source + 'named.bar') == 'float'
|
||||||
|
assert d(source + 'named.baz') == 'int'
|
||||||
|
|
||||||
|
|
||||||
|
def test_nested_namedtuples():
|
||||||
|
"""
|
||||||
|
From issue #730.
|
||||||
|
"""
|
||||||
|
s = Script(dedent('''
|
||||||
|
import collections
|
||||||
|
Dataset = collections.namedtuple('Dataset', ['data'])
|
||||||
|
Datasets = collections.namedtuple('Datasets', ['train'])
|
||||||
|
train_x = Datasets(train=Dataset('data_value'))
|
||||||
|
train_x.train.'''
|
||||||
|
))
|
||||||
|
assert 'data' in [c.name for c in s.completions()]
|
||||||
|
|||||||
Reference in New Issue
Block a user