[Python-checkins] cpython (merge 3.6 -> default): Issue #28556: Allow keyword syntax for NamedTuple (Ivan Levkivskyi) (upstream
guido.van.rossum
python-checkins at python.org
Tue Nov 15 12:49:36 EST 2016
https://hg.python.org/cpython/rev/a3de2d0f49ea
changeset: 105130:a3de2d0f49ea
parent: 105127:91e0cf7f8e30
parent: 105129:38ec88a4e282
user: Guido van Rossum <guido at python.org>
date: Tue Nov 15 09:48:12 2016 -0800
summary:
Issue #28556: Allow keyword syntax for NamedTuple (Ivan Levkivskyi) (upstream #321) (3.6->3.7)
files:
Lib/test/test_typing.py | 14 +++
Lib/typing.py | 100 ++++++++++++++-------------
2 files changed, 65 insertions(+), 49 deletions(-)
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -1865,6 +1865,20 @@
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)
+ nick = LocalEmployee('Nick', 25)
+ self.assertIsInstance(nick, tuple)
+ self.assertEqual(nick.name, 'Nick')
+ self.assertEqual(LocalEmployee.__name__, 'LocalEmployee')
+ self.assertEqual(LocalEmployee._fields, ('name', 'age'))
+ self.assertEqual(LocalEmployee._field_types, dict(name=str, age=int))
+ with self.assertRaises(TypeError):
+ NamedTuple('Name', [('x', int)], y=str)
+ with self.assertRaises(TypeError):
+ NamedTuple('Name', x=1, y='a')
+
def test_pickle(self):
global Emp # pickle wants to reference the class by name
Emp = NamedTuple('Emp', [('name', str), ('id', int)])
diff --git a/Lib/typing.py b/Lib/typing.py
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1875,6 +1875,8 @@
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 @@
return nm_tpl
-if sys.version_info[:2] >= (3, 6):
- class NamedTupleMeta(type):
-
- def __new__(cls, typename, bases, ns, *, _root=False):
- if _root:
- return super().__new__(cls, typename, bases, ns)
- types = ns.get('__annotations__', {})
- return _make_nmtuple(typename, types.items())
-
- class NamedTuple(metaclass=NamedTupleMeta, _root=True):
- """Typed version of namedtuple.
-
- Usage::
-
- class Employee(NamedTuple):
- name: str
- id: int
-
- This is equivalent to::
-
- Employee = collections.namedtuple('Employee', ['name', 'id'])
-
- 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.) Backward-compatible usage::
-
- Employee = NamedTuple('Employee', [('name', str), ('id', int)])
- """
-
- def __new__(self, typename, fields):
- return _make_nmtuple(typename, fields)
-else:
- def NamedTuple(typename, fields):
- """Typed version of namedtuple.
-
- Usage::
-
- Employee = typing.NamedTuple('Employee', [('name', str), 'id', int)])
-
- This is equivalent to::
-
- Employee = collections.namedtuple('Employee', ['name', 'id'])
-
- 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.)
- """
+_PY36 = sys.version_info[:2] >= (3, 6)
+
+
+class NamedTupleMeta(type):
+
+ def __new__(cls, typename, bases, ns):
+ if ns.get('_root', False):
+ return super().__new__(cls, typename, bases, ns)
+ if not _PY36:
+ raise TypeError("Class syntax for NamedTuple is only supported"
+ " in Python 3.6+")
+ types = ns.get('__annotations__', {})
+ return _make_nmtuple(typename, types.items())
+
+class NamedTuple(metaclass=NamedTupleMeta):
+ """Typed version of namedtuple.
+
+ Usage in Python versions >= 3.6::
+
+ class Employee(NamedTuple):
+ name: str
+ id: int
+
+ This is equivalent to::
+
+ Employee = collections.namedtuple('Employee', ['name', 'id'])
+
+ 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)
+
+ In Python versions <= 3.5 use::
+
+ Employee = NamedTuple('Employee', [('name', str), ('id', int)])
+ """
+ _root = True
+
+ def __new__(self, typename, fields=None, **kwargs):
+ if kwargs and not _PY36:
+ raise TypeError("Keyword syntax for NamedTuple is only supported"
+ " in Python 3.6+")
+ if fields is None:
+ fields = kwargs.items()
+ elif kwargs:
+ raise TypeError("Either list of fields or keywords"
+ " can be provided to NamedTuple, not both")
return _make_nmtuple(typename, fields)
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list