diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 09e9103e1b80d0..045d4696f9e60a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2482,6 +2482,10 @@ types. Using :func:`super` (and the ``__class__`` :term:`closure variable`) in methods of ``NamedTuple`` subclasses is unsupported and causes a :class:`TypeError`. + .. versionchanged:: next + Added support for arbitrary multiple inheritance. + + .. class:: NewType(name, tp) Helper class to create low-overhead :ref:`distinct types `. diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 21327b611120a2..b8394e5b96249f 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -830,9 +830,9 @@ http.server is colored by default. This can be controlled with :ref:`environment variables `. - (Contributed by Hugo van Kemenade in :gh:`146292`.) - - + (Contributed by Hugo van Kemenade in :gh:`146292`.) + + inspect ------- @@ -1239,6 +1239,11 @@ typing as it was incorrectly inferred in runtime before. (Contributed by Nikita Sobolev in :gh:`137191`.) +* 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`.) + unicodedata ----------- diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c6f08ff8a052ab..6bba31774a172e 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -8270,7 +8270,42 @@ 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) + self.assertEqual(list(a), [3]) + + class Y(A, NamedTuple): + 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) + self.assertEqual(list(a), [3]) + + def test_multiple_inheritance_errors(self): + class A(NamedTuple): + x: int with self.assertRaises(TypeError): class X(NamedTuple, A): x: int diff --git a/Lib/typing.py b/Lib/typing.py index e78fb8b71a996c..a6a26cda03f85f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -3016,10 +3016,6 @@ def __new__(cls, typename, bases, ns): if "__classcell__" in ns: raise TypeError( "uses of super() and __class__ are unsupported in methods of NamedTuple subclasses") - 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__"] diff --git a/Misc/NEWS.d/next/Library/2022-04-28-18-45-58.gh-issue-116241.hu9kRk.rst b/Misc/NEWS.d/next/Library/2022-04-28-18-45-58.gh-issue-116241.hu9kRk.rst new file mode 100644 index 00000000000000..0cbfb8ad12f6e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-28-18-45-58.gh-issue-116241.hu9kRk.rst @@ -0,0 +1 @@ +Add support for arbitrary multiple inheritance with :class:`typing.NamedTuple`.