From 944d1d14b4299b50011804addba54294dbbea7f1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 18 Oct 2018 14:00:46 +0300 Subject: [PATCH 1/2] bpo-34963: Make the repr of the typing.NewType() result more meaningful. Add attributes __qualname__ and __module__. If the name argument is dotted, the __name__ attribute will be set to its last component. --- Lib/test/test_typing.py | 20 +++++++++++++------ Lib/typing.py | 8 ++++++++ .../2018-10-18-14-00-37.bpo-34963.LT5FWe.rst | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-10-18-14-00-37.bpo-34963.LT5FWe.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 6d8cc5319fb121..498cb7bdeed706 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2405,24 +2405,32 @@ def foo(a: A) -> Optional[BaseException]: assert foo(None) is None +UserId = NewType('UserId', int) + + class NewTypeTests(BaseTestCase): + UserName = NewType('NewTypeTests.UserName', str) def test_basic(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) self.assertIsInstance(UserId(5), int) - self.assertIsInstance(UserName('Joe'), str) + self.assertIsInstance(NewTypeTests.UserName('Joe'), str) self.assertEqual(UserId(5) + 1, 6) def test_errors(self): - UserId = NewType('UserId', int) - UserName = NewType('UserName', str) with self.assertRaises(TypeError): issubclass(UserId, int) with self.assertRaises(TypeError): - class D(UserName): + class D(UserId): pass + def test_introspection(self): + UserName = NewTypeTests.UserName + self.assertEqual(UserName.__name__, 'UserName') + self.assertEqual(UserName.__qualname__, 'NewTypeTests.UserName') + self.assertEqual(UserName.__module__, __name__) + self.assertEqual(UserName.__supertype__, str) + self.assertIn('UserName', repr(UserName)) + class NamedTupleTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index cfcbb3b7632842..e77aed105f90d9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1432,7 +1432,15 @@ def name_by_id(user_id: UserId) -> str: def new_type(x): return x + new_type.__qualname__ = name + if '.' in name: + name = name.rpartition('.')[-1] new_type.__name__ = name + new_type.__name__ = name + try: + new_type.__module__ = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass new_type.__supertype__ = tp return new_type diff --git a/Misc/NEWS.d/next/Library/2018-10-18-14-00-37.bpo-34963.LT5FWe.rst b/Misc/NEWS.d/next/Library/2018-10-18-14-00-37.bpo-34963.LT5FWe.rst new file mode 100644 index 00000000000000..067e00439a2046 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-18-14-00-37.bpo-34963.LT5FWe.rst @@ -0,0 +1 @@ +The repr of the result of :func:`typing.NewType` is more meaningful now. From 39f49f56e67f9c71fb35e0ee848a5bf5d65e72fe Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 28 Oct 2018 14:01:15 +0200 Subject: [PATCH 2/2] Remove duplicated line. --- Lib/typing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/typing.py b/Lib/typing.py index e77aed105f90d9..2cdb3925e8a9cc 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1436,7 +1436,6 @@ def new_type(x): if '.' in name: name = name.rpartition('.')[-1] new_type.__name__ = name - new_type.__name__ = name try: new_type.__module__ = sys._getframe(1).f_globals.get('__name__', '__main__') except (AttributeError, ValueError):