From f30514de3a6a1e412931a1b45e80a89beae9585f Mon Sep 17 00:00:00 2001 From: Endill Date: Sat, 25 Apr 2020 20:25:07 +0300 Subject: [PATCH 1/5] Improve repr of typing.Optional --- Lib/typing.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/typing.py b/Lib/typing.py index 0dcf291950f7d1..963ce68fd05d91 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -683,6 +683,9 @@ def copy_with(self, params): return _GenericAlias(self.__origin__, params, name=self._name, inst=self._inst) def __repr__(self): + if (self.__origin__ == Union and len(self.__args__) == 2 + and self.__args__[1] is type(None)): + return (f'typing.Optional[{_type_repr(self.__args__[0])}]') if (self._name != 'Callable' or len(self.__args__) == 2 and self.__args__[0] is Ellipsis): if self._name: From 65443f4d389c306b27f7a0eedb8a111f3cc55e98 Mon Sep 17 00:00:00 2001 From: Endill Date: Sat, 25 Apr 2020 22:55:43 +0300 Subject: [PATCH 2/5] Handle None being the first --- Lib/typing.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/typing.py b/Lib/typing.py index 963ce68fd05d91..2b051450fe88ce 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -684,8 +684,12 @@ def copy_with(self, params): def __repr__(self): if (self.__origin__ == Union and len(self.__args__) == 2 - and self.__args__[1] is type(None)): - return (f'typing.Optional[{_type_repr(self.__args__[0])}]') + and type(None) in self.__args__): + if self.__args__[0] is not type(None): + arg = self.__args__[0] + else: + arg = self.__args__[1] + return (f'typing.Optional[{_type_repr(arg)}]') if (self._name != 'Callable' or len(self.__args__) == 2 and self.__args__[0] is Ellipsis): if self._name: From 0c82eb60ac8874e8d28861e12f0d20d56cab59cb Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 25 Apr 2020 20:00:59 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst diff --git a/Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst b/Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst new file mode 100644 index 00000000000000..e7a60a8d5f6f48 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-04-25-20-00-58.bpo-40389.FPA6f0.rst @@ -0,0 +1 @@ +``repr()`` now returns ``typing.Optional[T]`` when called for ``typing.Union`` of two types, one of which is ``NoneType``. \ No newline at end of file From 2e940ff498abc4d7271bafe0e1b05cfd3940bec0 Mon Sep 17 00:00:00 2001 From: Endill Date: Sun, 26 Apr 2020 08:38:52 +0300 Subject: [PATCH 4/5] Update tests --- Lib/test/test_typing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b3a671732167eb..258aa79ffad9e4 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1750,7 +1750,7 @@ def test_extended_generic_rules_repr(self): self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), 'Union[Tuple, Tuple[int]]') self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), - 'Callable[..., Union[int, NoneType]]') + 'Callable[..., Optional[int]]') self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), 'Callable[[], List[int]]') From 0265c29851464feb2997aa15fe25f7d01553a451 Mon Sep 17 00:00:00 2001 From: Endill Date: Sun, 26 Apr 2020 09:24:40 +0300 Subject: [PATCH 5/5] Update dataclasses test --- Lib/test/test_dataclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index e8fe455fc19b42..b20103bdce51cb 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2028,7 +2028,7 @@ def test_docstring_one_field_with_default_none(self): class C: x: Union[int, type(None)] = None - self.assertDocStrEqual(C.__doc__, "C(x:Union[int, NoneType]=None)") + self.assertDocStrEqual(C.__doc__, "C(x:Optional[int]=None)") def test_docstring_list_field(self): @dataclass