[Python-checkins] bpo-46170: Improve the error message when subclassing NewType (GH-30268)

JelleZijlstra webhook-mailer at python.org
Mon Mar 7 22:50:52 EST 2022


https://github.com/python/cpython/commit/f391f9bf28f0bba7939d9f9e5a7a6396d2b0df62
commit: f391f9bf28f0bba7939d9f9e5a7a6396d2b0df62
branch: main
author: James Hilton-Balfe <gobot1234yt at gmail.com>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2022-03-07T19:50:46-08:00
summary:

bpo-46170: Improve the error message when subclassing NewType (GH-30268)

Co-authored-by: Alex Waygood <alex.waygood at gmail.com>
Co-authored-by: Nikita Sobolev <mail at sobolevn.me>
Co-authored-by: Ken Jin <28750310+Fidget-Spinner at users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2021-12-26-14-45-51.bpo-46170.AQ7kSM.rst
M Lib/test/test_typing.py
M Lib/typing.py

diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 17d78cffcb4fa..c76aa0adefeb9 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -4423,6 +4423,17 @@ def test_missing__name__(self):
                 )
         exec(code, {})
 
+    def test_error_message_when_subclassing(self):
+        with self.assertRaisesRegex(
+            TypeError,
+            re.escape(
+                "Cannot subclass an instance of NewType. Perhaps you were looking for: "
+                "`ProUserId = NewType('ProUserId', UserId)`"
+            )
+        ):
+            class ProUserId(UserId):
+                ...
+
 
 class NewTypePythonTests(NewTypeTests, BaseTestCase):
     module = py_typing
diff --git a/Lib/typing.py b/Lib/typing.py
index 360129e3db34e..721afb7a03fd9 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -2639,6 +2639,21 @@ def __init__(self, name, tp):
         if def_mod != 'typing':
             self.__module__ = def_mod
 
+    def __mro_entries__(self, bases):
+        # We defined __mro_entries__ to get a better error message
+        # if a user attempts to subclass a NewType instance. bpo-46170
+        superclass_name = self.__name__
+
+        class Dummy:
+            def __init_subclass__(cls):
+                subclass_name = cls.__name__
+                raise TypeError(
+                    f"Cannot subclass an instance of NewType. Perhaps you were looking for: "
+                    f"`{subclass_name} = NewType({subclass_name!r}, {superclass_name})`"
+                )
+
+        return (Dummy,)
+
     def __repr__(self):
         return f'{self.__module__}.{self.__qualname__}'
 
diff --git a/Misc/NEWS.d/next/Library/2021-12-26-14-45-51.bpo-46170.AQ7kSM.rst b/Misc/NEWS.d/next/Library/2021-12-26-14-45-51.bpo-46170.AQ7kSM.rst
new file mode 100644
index 0000000000000..5f266a29ce1cc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-12-26-14-45-51.bpo-46170.AQ7kSM.rst
@@ -0,0 +1 @@
+Improve the error message when you try to subclass an instance of :class:`typing.NewType`.



More information about the Python-checkins mailing list