mirror of
https://github.com/python/cpython.git
synced 2026-01-26 12:55:08 +00:00
gh-143831: Compare cells by identity in forward references (#143848)
This commit is contained in:
parent
78b1370de9
commit
59d3594ca1
@ -279,7 +279,13 @@ class ForwardRef:
|
||||
# because dictionaries are not hashable.
|
||||
and self.__globals__ is other.__globals__
|
||||
and self.__forward_is_class__ == other.__forward_is_class__
|
||||
and self.__cell__ == other.__cell__
|
||||
# Two separate cells are always considered unequal in forward refs.
|
||||
and (
|
||||
{name: id(cell) for name, cell in self.__cell__.items()}
|
||||
== {name: id(cell) for name, cell in other.__cell__.items()}
|
||||
if isinstance(self.__cell__, dict) and isinstance(other.__cell__, dict)
|
||||
else self.__cell__ is other.__cell__
|
||||
)
|
||||
and self.__owner__ == other.__owner__
|
||||
and (
|
||||
(tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None) ==
|
||||
@ -293,7 +299,10 @@ class ForwardRef:
|
||||
self.__forward_module__,
|
||||
id(self.__globals__), # dictionaries are not hashable, so hash by identity
|
||||
self.__forward_is_class__,
|
||||
tuple(sorted(self.__cell__.items())) if isinstance(self.__cell__, dict) else self.__cell__,
|
||||
( # cells are not hashable as well
|
||||
tuple(sorted([(name, id(cell)) for name, cell in self.__cell__.items()]))
|
||||
if isinstance(self.__cell__, dict) else id(self.__cell__),
|
||||
),
|
||||
self.__owner__,
|
||||
tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None,
|
||||
))
|
||||
|
||||
@ -8,6 +8,7 @@ import functools
|
||||
import itertools
|
||||
import pickle
|
||||
from string.templatelib import Template, Interpolation
|
||||
import types
|
||||
import typing
|
||||
import sys
|
||||
import unittest
|
||||
@ -1862,6 +1863,39 @@ class TestForwardRefClass(unittest.TestCase):
|
||||
self.assertNotEqual(hash(c3), hash(c4))
|
||||
self.assertEqual(hash(c3), hash(ForwardRef("int", module=__name__)))
|
||||
|
||||
def test_forward_equality_and_hash_with_cells(self):
|
||||
"""Regression test for GH-143831."""
|
||||
class A:
|
||||
def one(_) -> C1:
|
||||
"""One cell."""
|
||||
|
||||
one_f = ForwardRef("C1", owner=one)
|
||||
one_f_ga1 = get_annotations(one, format=Format.FORWARDREF)["return"]
|
||||
one_f_ga2 = get_annotations(one, format=Format.FORWARDREF)["return"]
|
||||
self.assertIsInstance(one_f_ga1.__cell__, types.CellType)
|
||||
self.assertIs(one_f_ga1.__cell__, one_f_ga2.__cell__)
|
||||
|
||||
def two(_) -> C1 | C2:
|
||||
"""Two cells."""
|
||||
|
||||
two_f_ga1 = get_annotations(two, format=Format.FORWARDREF)["return"]
|
||||
two_f_ga2 = get_annotations(two, format=Format.FORWARDREF)["return"]
|
||||
self.assertIsNot(two_f_ga1.__cell__, two_f_ga2.__cell__)
|
||||
self.assertIsInstance(two_f_ga1.__cell__, dict)
|
||||
self.assertIsInstance(two_f_ga2.__cell__, dict)
|
||||
|
||||
type C1 = None
|
||||
type C2 = None
|
||||
|
||||
self.assertNotEqual(A.one_f, A.one_f_ga1)
|
||||
self.assertNotEqual(hash(A.one_f), hash(A.one_f_ga1))
|
||||
|
||||
self.assertEqual(A.one_f_ga1, A.one_f_ga2)
|
||||
self.assertEqual(hash(A.one_f_ga1), hash(A.one_f_ga2))
|
||||
|
||||
self.assertEqual(A.two_f_ga1, A.two_f_ga2)
|
||||
self.assertEqual(hash(A.two_f_ga1), hash(A.two_f_ga2))
|
||||
|
||||
def test_forward_equality_namespace(self):
|
||||
def namespace1():
|
||||
a = ForwardRef("A")
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
:class:`annotationlib.ForwardRef` objects are now hashable when created from
|
||||
annotation scopes with closures. Previously, hashing such objects would
|
||||
throw an exception. Patch by Bartosz Sławecki.
|
||||
Loading…
x
Reference in New Issue
Block a user