Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2389,6 +2389,9 @@ types.
disallowed in Python 3.15. To create a NamedTuple class with 0 fields,
use ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``.

.. versionchanged:: 3.14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. versionchanged:: 3.14
.. versionchanged:: next

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Added support for arbitrary multiple inheritance.

.. class:: NewType(name, tp)

Helper class to create low-overhead :ref:`distinct types <distinct>`.
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,11 @@ typing
* Remove :class:`!typing.ByteString`. It had previously raised a
:exc:`DeprecationWarning` since Python 3.12.

* Add support of multiple inheritance with :class:`~typing.NamedTuple`.
Previously, multiple inheritance was only supported if there was exactly
one other base and the base was :class:`typing.Generic`.
(Contributed by Serhiy Storchaka in :gh:`116241`.)

urllib
------

Expand Down
35 changes: 34 additions & 1 deletion Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7925,7 +7925,40 @@ class X(NamedTuple):

def test_multiple_inheritance(self):
class A:
pass
@property
def x(self):
return 4
@property
def y(self):
return 5
def __len__(self):
return 10

class X(NamedTuple, A):
x: int
self.assertEqual(X.__bases__, (tuple, A))
self.assertEqual(X.__orig_bases__, (NamedTuple, A))
self.assertEqual(X.__mro__, (X, tuple, A, object))

a = X(3)
self.assertEqual(a.x, 3)
self.assertEqual(a.y, 5)
self.assertEqual(len(a), 1)

class Y(A, NamedTuple):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a test to check the order of the members as well when doing unpacking? And maybe test class Z(X, Y, NamedTuple)? (I don't know if this leads to a MRO incompatibilty though)

x: int
self.assertEqual(Y.__bases__, (A, tuple))
self.assertEqual(Y.__orig_bases__, (A, NamedTuple))
self.assertEqual(Y.__mro__, (Y, A, tuple, object))

a = Y(3)
self.assertEqual(a.x, 3)
self.assertEqual(a.y, 5)
self.assertEqual(len(a), 10)

def test_multiple_inheritance_errors(self):
class A(NamedTuple):
x: int
with self.assertRaises(TypeError):
class X(NamedTuple, A):
x: int
Expand Down
4 changes: 0 additions & 4 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2952,10 +2952,6 @@ def annotate(format):
class NamedTupleMeta(type):
def __new__(cls, typename, bases, ns):
assert _NamedTuple in bases
for base in bases:
if base is not _NamedTuple and base is not Generic:
raise TypeError(
'can only inherit from a NamedTuple type and Generic')
bases = tuple(tuple if base is _NamedTuple else base for base in bases)
if "__annotations__" in ns:
types = ns["__annotations__"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for arbitrary multiple inheritance with :class:`typing.NamedTuple`.
Loading