diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ba0800fae90e301..22a668f5b7a2b95 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2353,6 +2353,63 @@ def test_forward_equality(self): self.assertEqual(fr, typing.ForwardRef('int')) self.assertNotEqual(List['int'], List[int]) + def test_forward_equality_gth(self): + c1 = typing.ForwardRef('C') + c1_gth = typing.ForwardRef('C') + c2 = typing.ForwardRef('C') + c2_gth = typing.ForwardRef('C') + + class C: + pass + def foo(a: c1_gth, b: c2_gth): + pass + + self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': C, 'b': C}) + self.assertEqual(c1, c2) + self.assertEqual(c1, c1_gth) + self.assertEqual(c1_gth, c2_gth) + self.assertEqual(List[c1], List[c1_gth]) + self.assertNotEqual(List[c1], List[C]) + self.assertNotEqual(List[c1_gth], List[C]) + + def test_forward_equality_hash(self): + c1 = typing.ForwardRef('int') + c1_gth = typing.ForwardRef('int') + c2 = typing.ForwardRef('int') + c2_gth = typing.ForwardRef('int') + + def foo(a: c1_gth, b: c2_gth): + pass + get_type_hints(foo, globals(), locals()) + + self.assertEqual(hash(c1), hash(c2)) + self.assertEqual(hash(c1_gth), hash(c2_gth)) + self.assertNotEqual(hash(c1), hash(c1_gth)) + + def test_forward_equality_namespace(self): + class A: + pass + def namespace1(): + a = typing.ForwardRef('A') + def fun(x: a): + pass + get_type_hints(fun, globals(), locals()) + return a + + def namespace2(): + a = typing.ForwardRef('A') + + class A: + pass + def fun(x: a): + pass + + get_type_hints(fun, globals(), locals()) + return a + + self.assertEqual(namespace1(), namespace1()) + self.assertNotEqual(namespace1(), namespace2()) + def test_forward_repr(self): self.assertEqual(repr(List['int']), "typing.List[ForwardRef('int')]") diff --git a/Lib/typing.py b/Lib/typing.py index 5f1a0ad3d637430..686b386875ec368 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -230,16 +230,7 @@ def _remove_dups_flatten(parameters): else: params.append(p) # Weed out strict duplicates, preserving the first of each occurrence. - all_params = set(params) - if len(all_params) < len(params): - new_params = [] - for t in params: - if t in all_params: - new_params.append(t) - all_params.remove(t) - params = new_params - assert not all_params, all_params - return tuple(params) + return tuple(dict.fromkeys(params)) _cleanups = [] @@ -524,8 +515,10 @@ def _evaluate(self, globalns, localns): def __eq__(self, other): if not isinstance(other, ForwardRef): return NotImplemented - return (self.__forward_arg__ == other.__forward_arg__ and - self.__forward_value__ == other.__forward_value__) + if self.__forward_evaluated__ and other.__forward_evaluated__: + return (self.__forward_arg__ == other.__forward_arg__ and + self.__forward_value__ == other.__forward_value__) + return self.__forward_arg__ == other.__forward_arg__ def __hash__(self): return hash((self.__forward_arg__, self.__forward_value__)) diff --git a/Misc/NEWS.d/next/Library/2019-08-31-12-57-17.bpo-37953.Fz3V7f.rst b/Misc/NEWS.d/next/Library/2019-08-31-12-57-17.bpo-37953.Fz3V7f.rst new file mode 100644 index 000000000000000..ae355b620c49b30 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-08-31-12-57-17.bpo-37953.Fz3V7f.rst @@ -0,0 +1 @@ +Improve ForwardRef equality checks. Patch by hongweipeng.