cpython: 38ec88a4e282 (original) (raw)
--- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1865,6 +1865,20 @@ class NamedTupleTests(BaseTestCase): self.assertEqual(CoolEmployee._fields, ('name', 'cool')) self.assertEqual(CoolEmployee._field_types, dict(name=str, cool=int))
- @skipUnless(PY36, 'Python 3.6 required')
- def test_namedtuple_keyword_usage(self):
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)[](#l1.9)
nick = LocalEmployee('Nick', 25)[](#l1.10)
self.assertIsInstance(nick, tuple)[](#l1.11)
self.assertEqual(nick.name, 'Nick')[](#l1.12)
self.assertEqual(LocalEmployee.__name__, 'LocalEmployee')[](#l1.13)
self.assertEqual(LocalEmployee._fields, ('name', 'age'))[](#l1.14)
self.assertEqual(LocalEmployee._field_types, dict(name=str, age=int))[](#l1.15)
with self.assertRaises(TypeError):[](#l1.16)
NamedTuple('Name', [('x', int)], y=str)[](#l1.17)
with self.assertRaises(TypeError):[](#l1.18)
NamedTuple('Name', x=1, y='a')[](#l1.19)
+ def test_pickle(self): global Emp # pickle wants to reference the class by name Emp = NamedTuple('Emp', [('name', str), ('id', int)])
--- a/Lib/typing.py +++ b/Lib/typing.py @@ -1875,6 +1875,8 @@ class Type(Generic[CT_co], extra=type): def _make_nmtuple(name, types):
- msg = "NamedTuple('Name', [(f0, t0), (f1, t1), ...]); each t must be a type"
- types = [(n, _type_check(t, msg)) for n, t in types] nm_tpl = collections.namedtuple(name, [n for n, t in types]) nm_tpl._field_types = dict(types) try: @@ -1884,55 +1886,55 @@ def _make_nmtuple(name, types): return nm_tpl -if sys.version_info[:2] >= (3, 6):
def __new__(cls, typename, bases, ns, *, _root=False):[](#l2.19)
if _root:[](#l2.20)
return super().__new__(cls, typename, bases, ns)[](#l2.21)
types = ns.get('__annotations__', {})[](#l2.22)
return _make_nmtuple(typename, types.items())[](#l2.23)
Usage::[](#l2.28)
class Employee(NamedTuple):[](#l2.30)
name: str[](#l2.31)
id: int[](#l2.32)
This is equivalent to::[](#l2.34)
Employee = collections.namedtuple('Employee', ['name', 'id'])[](#l2.36)
The resulting class has one extra attribute: _field_types,[](#l2.38)
giving a dict mapping field names to types. (The field names[](#l2.39)
are in the _fields attribute, which is part of the namedtuple[](#l2.40)
API.) Backward-compatible usage::[](#l2.41)
Employee = NamedTuple('Employee', [('name', str), ('id', int)])[](#l2.43)
"""[](#l2.44)
def __new__(self, typename, fields):[](#l2.46)
return _make_nmtuple(typename, fields)[](#l2.47)
Usage::[](#l2.52)
Employee = typing.NamedTuple('Employee', [('name', str), 'id', int)])[](#l2.54)
This is equivalent to::[](#l2.56)
Employee = collections.namedtuple('Employee', ['name', 'id'])[](#l2.58)
The resulting class has one extra attribute: _field_types,[](#l2.60)
giving a dict mapping field names to types. (The field names[](#l2.61)
are in the _fields attribute, which is part of the namedtuple[](#l2.62)
API.)[](#l2.63)
"""[](#l2.64)
+_PY36 = sys.version_info[:2] >= (3, 6) + + +class NamedTupleMeta(type): +
- def new(cls, typename, bases, ns):
if ns.get('_root', False):[](#l2.71)
return super().__new__(cls, typename, bases, ns)[](#l2.72)
if not _PY36:[](#l2.73)
raise TypeError("Class syntax for NamedTuple is only supported"[](#l2.74)
" in Python 3.6+")[](#l2.75)
types = ns.get('__annotations__', {})[](#l2.76)
return _make_nmtuple(typename, types.items())[](#l2.77)
+ +class NamedTuple(metaclass=NamedTupleMeta):
class Employee(NamedTuple):[](#l2.84)
name: str[](#l2.85)
id: int[](#l2.86)
Employee = collections.namedtuple('Employee', ['name', 'id'])[](#l2.90)
- The resulting class has one extra attribute: _field_types,
- giving a dict mapping field names to types. (The field names
- are in the _fields attribute, which is part of the namedtuple
- API.) Alternative equivalent keyword syntax is also accepted::
Employee = NamedTuple('Employee', name=str, id=int)[](#l2.97)
- def new(self, typename, fields=None, **kwargs):
if kwargs and not _PY36:[](#l2.106)
raise TypeError("Keyword syntax for NamedTuple is only supported"[](#l2.107)
" in Python 3.6+")[](#l2.108)
if fields is None:[](#l2.109)
fields = kwargs.items()[](#l2.110)
elif kwargs:[](#l2.111)
raise TypeError("Either list of fields or keywords"[](#l2.112)
" can be provided to NamedTuple, not both")[](#l2.113) return _make_nmtuple(typename, fields)[](#l2.114)