From 357a71dc483c743c89a73170a45b5604bb058b8c Mon Sep 17 00:00:00 2001 From: Yurii Karabas <1998uriyyo@gmail.com> Date: Thu, 19 Nov 2020 01:47:34 +0200 Subject: [PATCH 1/2] Fix hash implementation of a typing.Literal --- Doc/library/typing.rst | 6 +++--- Lib/test/test_typing.py | 9 +++++++++ Lib/typing.py | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a8de984a5ce41b..5b66e3c2c5b639 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1706,9 +1706,9 @@ Introspection helpers For a typing object of the form ``X[Y, Z, ...]`` these functions return ``X`` and ``(Y, Z, ...)``. If ``X`` is a generic alias for a builtin or :mod:`collections` class, it gets normalized to the original class. - If ``X`` is a :class:`Union` contained in another generic type, - the order of ``(Y, Z, ...)`` may be different from the order of - the original arguments ``[Y, Z, ...]`` due to type caching. + If ``X`` is a :class:`Union` or :class:`Literal` contained in another + generic type, the order of ``(Y, Z, ...)`` may be different from the order + of the original arguments ``[Y, Z, ...]`` due to type caching. For unsupported objects return ``None`` and ``()`` correspondingly. Examples:: diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7deba0d71b7c4f..4c30c362cb01c3 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -569,6 +569,15 @@ def test_equal(self): self.assertEqual(Literal[1, 2], Literal[2, 1]) self.assertEqual(Literal[1, 2, 3], Literal[1, 2, 3, 3]) + def test_hash(self): + self.assertNotEqual(hash(Literal[0]), hash(Literal[False])) + self.assertNotEqual(hash(Literal[True]), hash(Literal[1])) + self.assertNotEqual(hash(Literal[1]), hash(Literal[2])) + self.assertNotEqual(hash(Literal[1, True]), hash(Literal[1])) + self.assertEqual(hash(Literal[1]), hash(Literal[1])) + self.assertEqual(hash(Literal[1, 2]), hash(Literal[2, 1])) + self.assertEqual(hash(Literal[1, 2, 3]), hash(Literal[1, 2, 3, 3])) + def test_args(self): self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3)) self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3)) diff --git a/Lib/typing.py b/Lib/typing.py index d310b3dd5820dc..46c54c406992f7 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -981,7 +981,7 @@ def __eq__(self, other): return set(_value_and_type_iter(self.__args__)) == set(_value_and_type_iter(other.__args__)) def __hash__(self): - return hash(tuple(_value_and_type_iter(self.__args__))) + return hash(frozenset(_value_and_type_iter(self.__args__))) class Generic: From 85a21a856a50a310f94249a0202d211416dfd9d3 Mon Sep 17 00:00:00 2001 From: Yurii Karabas <1998uriyyo@gmail.com> Date: Thu, 19 Nov 2020 09:43:08 +0200 Subject: [PATCH 2/2] Remove incorrect hash tests --- Lib/test/test_typing.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4c30c362cb01c3..8ffc7f40cebdd2 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -570,10 +570,6 @@ def test_equal(self): self.assertEqual(Literal[1, 2, 3], Literal[1, 2, 3, 3]) def test_hash(self): - self.assertNotEqual(hash(Literal[0]), hash(Literal[False])) - self.assertNotEqual(hash(Literal[True]), hash(Literal[1])) - self.assertNotEqual(hash(Literal[1]), hash(Literal[2])) - self.assertNotEqual(hash(Literal[1, True]), hash(Literal[1])) self.assertEqual(hash(Literal[1]), hash(Literal[1])) self.assertEqual(hash(Literal[1, 2]), hash(Literal[2, 1])) self.assertEqual(hash(Literal[1, 2, 3]), hash(Literal[1, 2, 3, 3]))