| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1615,6 +1615,12 @@ These are not used in annotations. They are building blocks for declaring types. | |||
| 1615 | 1615 | def __repr__(self) -> str: | |
| 1616 | 1616 | return f'<Employee {self.name}, id={self.id}>' | |
| 1617 | 1617 | ||
| 1618 | + ``NamedTuple`` subclasses can be generic:: | ||
| 1619 | + | ||
| 1620 | + class Group(NamedTuple, Generic[T]): | ||
| 1621 | + key: T | ||
| 1622 | + group: list[T] | ||
| 1623 | + | ||
| 1618 | 1624 | Backward-compatible usage:: | |
| 1619 | 1625 | ||
| 1620 | 1626 | Employee = NamedTuple('Employee', [('name', str), ('id', int)]) | |
@@ -1633,6 +1639,9 @@ These are not used in annotations. They are building blocks for declaring types. | |||
| 1633 | 1639 | Removed the ``_field_types`` attribute in favor of the more | |
| 1634 | 1640 | standard ``__annotations__`` attribute which has the same information. | |
| 1635 | 1641 | ||
| 1642 | + .. versionchanged:: 3.11 | ||
| 1643 | + Added support for generic namedtuples. | ||
| 1644 | + | ||
| 1636 | 1645 | .. class:: NewType(name, tp) | |
| 1637 | 1646 | ||
| 1638 | 1647 | A helper class to indicate a distinct type to a typechecker, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -715,6 +715,10 @@ For major changes, see :ref:`new-feat-related-type-hints-311`. | |||
| 715 | 715 | to clear all registered overloads of a function. | |
| 716 | 716 | (Contributed by Jelle Zijlstra in :gh:`89263`.) | |
| 717 | 717 | ||
| 718 | + * :class:`~typing.NamedTuple` subclasses can be generic. | ||
| 719 | + (Contributed by Serhiy Storchaka in :issue:`43923`.) | ||
| 720 | + | ||
| 721 | + | ||
| 718 | 722 | unicodedata | |
| 719 | 723 | ----------- | |
| 720 | 724 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5678,6 +5678,45 @@ class A: | |||
| 5678 | 5678 | with self.assertRaises(TypeError): | |
| 5679 | 5679 | class X(NamedTuple, A): | |
| 5680 | 5680 | x: int | |
| 5681 | + with self.assertRaises(TypeError): | ||
| 5682 | + class X(NamedTuple, tuple): | ||
| 5683 | + x: int | ||
| 5684 | + with self.assertRaises(TypeError): | ||
| 5685 | + class X(NamedTuple, NamedTuple): | ||
| 5686 | + x: int | ||
| 5687 | + class A(NamedTuple): | ||
| 5688 | + x: int | ||
| 5689 | + with self.assertRaises(TypeError): | ||
| 5690 | + class X(NamedTuple, A): | ||
| 5691 | + y: str | ||
| 5692 | + | ||
| 5693 | + def test_generic(self): | ||
| 5694 | + class X(NamedTuple, Generic[T]): | ||
| 5695 | + x: T | ||
| 5696 | + self.assertEqual(X.__bases__, (tuple, Generic)) | ||
| 5697 | + self.assertEqual(X.__orig_bases__, (NamedTuple, Generic[T])) | ||
| 5698 | + self.assertEqual(X.__mro__, (X, tuple, Generic, object)) | ||
| 5699 | + | ||
| 5700 | + class Y(Generic[T], NamedTuple): | ||
| 5701 | + x: T | ||
| 5702 | + self.assertEqual(Y.__bases__, (Generic, tuple)) | ||
| 5703 | + self.assertEqual(Y.__orig_bases__, (Generic[T], NamedTuple)) | ||
| 5704 | + self.assertEqual(Y.__mro__, (Y, Generic, tuple, object)) | ||
| 5705 | + | ||
| 5706 | + for G in X, Y: | ||
| 5707 | + with self.subTest(type=G): | ||
| 5708 | + self.assertEqual(G.__parameters__, (T,)) | ||
| 5709 | + A = G[int] | ||
| 5710 | + self.assertIs(A.__origin__, G) | ||
| 5711 | + self.assertEqual(A.__args__, (int,)) | ||
| 5712 | + self.assertEqual(A.__parameters__, ()) | ||
| 5713 | + | ||
| 5714 | + a = A(3) | ||
| 5715 | + self.assertIs(type(a), G) | ||
| 5716 | + self.assertEqual(a.x, 3) | ||
| 5717 | + | ||
| 5718 | + with self.assertRaises(TypeError): | ||
| 5719 | + G[int, str] | ||
| 5681 | 5720 | ||
| 5682 | 5721 | def test_namedtuple_keyword_usage(self): | |
| 5683 | 5722 | LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2764,7 +2764,12 @@ def _make_nmtuple(name, types, module, defaults = ()): | |||
| 2764 | 2764 | class NamedTupleMeta(type): | |
| 2765 | 2765 | ||
| 2766 | 2766 | def __new__(cls, typename, bases, ns): | |
| 2767 | - assert bases[0] is _NamedTuple | ||
| 2767 | + assert _NamedTuple in bases | ||
| 2768 | + for base in bases: | ||
| 2769 | + if base is not _NamedTuple and base is not Generic: | ||
| 2770 | + raise TypeError( | ||
| 2771 | + 'can only inherit from a NamedTuple type and Generic') | ||
| 2772 | + bases = tuple(tuple if base is _NamedTuple else base for base in bases) | ||
| 2768 | 2773 | types = ns.get('__annotations__', {}) | |
| 2769 | 2774 | default_names = [] | |
| 2770 | 2775 | for field_name in types: | |
@@ -2778,12 +2783,18 @@ def __new__(cls, typename, bases, ns): | |||
| 2778 | 2783 | nm_tpl = _make_nmtuple(typename, types.items(), | |
| 2779 | 2784 | defaults=[ns[n] for n in default_names], | |
| 2780 | 2785 | module=ns['__module__']) | |
| 2786 | + nm_tpl.__bases__ = bases | ||
| 2787 | + if Generic in bases: | ||
| 2788 | + class_getitem = Generic.__class_getitem__.__func__ | ||
| 2789 | + nm_tpl.__class_getitem__ = classmethod(class_getitem) | ||
| 2781 | 2790 | # update from user namespace without overriding special namedtuple attributes | |
| 2782 | 2791 | for key in ns: | |
| 2783 | 2792 | if key in _prohibited: | |
| 2784 | 2793 | raise AttributeError("Cannot overwrite NamedTuple attribute " + key) | |
| 2785 | 2794 | elif key not in _special and key not in nm_tpl._fields: | |
| 2786 | 2795 | setattr(nm_tpl, key, ns[key]) | |
| 2796 | + if Generic in bases: | ||
| 2797 | + nm_tpl.__init_subclass__() | ||
| 2787 | 2798 | return nm_tpl | |
| 2788 | 2799 | ||
| 2789 | 2800 | ||
@@ -2821,9 +2832,7 @@ class Employee(NamedTuple): | |||
| 2821 | 2832 | _NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {}) | |
| 2822 | 2833 | ||
| 2823 | 2834 | def _namedtuple_mro_entries(bases): | |
| 2824 | - if len(bases) > 1: | ||
| 2825 | - raise TypeError("Multiple inheritance with NamedTuple is not supported") | ||
| 2826 | - assert bases[0] is NamedTuple | ||
| 2835 | + assert NamedTuple in bases | ||
| 2827 | 2836 | return (_NamedTuple,) | |
| 2828 | 2837 | ||
| 2829 | 2838 | NamedTuple.__mro_entries__ = _namedtuple_mro_entries | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + Add support for generic :class:`typing.NamedTuple`. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments