@@ -32,6 +32,27 @@ def create_bound_method():
3232 return C ().method
3333
3434
35+ class Object :
36+ def __init__ (self , arg ):
37+ self .arg = arg
38+ def __repr__ (self ):
39+ return "<Object %r>" % self .arg
40+ def __eq__ (self , other ):
41+ if isinstance (other , Object ):
42+ return self .arg == other .arg
43+ return NotImplemented
44+ def __lt__ (self , other ):
45+ if isinstance (other , Object ):
46+ return self .arg < other .arg
47+ return NotImplemented
48+ def __hash__ (self ):
49+ return hash (self .arg )
50+
51+ class RefCycle :
52+ def __init__ (self ):
53+ self .cycle = self
54+
55+
3556class TestBase (unittest .TestCase ):
3657
3758 def setUp (self ):
@@ -692,6 +713,69 @@ class A(object):
692713 self .assertEqual (a (), None )
693714 self .assertEqual (l , [a ])
694715
716+ def test_equality (self ):
717+ # Alive weakrefs defer equality testing to their underlying object.
718+ x = Object (1 )
719+ y = Object (1 )
720+ z = Object (2 )
721+ a = weakref .ref (x )
722+ b = weakref .ref (y )
723+ c = weakref .ref (z )
724+ d = weakref .ref (x )
725+ # Note how we directly test the operators here, to stress both
726+ # __eq__ and __ne__.
727+ self .assertTrue (a == b )
728+ self .assertFalse (a != b )
729+ self .assertFalse (a == c )
730+ self .assertTrue (a != c )
731+ self .assertTrue (a == d )
732+ self .assertFalse (a != d )
733+ del x , y , z
734+ gc .collect ()
735+ for r in a , b , c :
736+ # Sanity check
737+ self .assertIs (r (), None )
738+ # Dead weakrefs compare by identity: whether `a` and `d` are the
739+ # same weakref object is an implementation detail, since they pointed
740+ # to the same original object and didn't have a callback.
741+ # (see issue #16453).
742+ self .assertFalse (a == b )
743+ self .assertTrue (a != b )
744+ self .assertFalse (a == c )
745+ self .assertTrue (a != c )
746+ self .assertEqual (a == d , a is d )
747+ self .assertEqual (a != d , a is not d )
748+
749+ def test_ordering (self ):
750+ # weakrefs cannot be ordered, even if the underlying objects can.
751+ ops = [operator .lt , operator .gt , operator .le , operator .ge ]
752+ x = Object (1 )
753+ y = Object (1 )
754+ a = weakref .ref (x )
755+ b = weakref .ref (y )
756+ for op in ops :
757+ self .assertRaises (TypeError , op , a , b )
758+ # Same when dead.
759+ del x , y
760+ gc .collect ()
761+ for op in ops :
762+ self .assertRaises (TypeError , op , a , b )
763+
764+ def test_hashing (self ):
765+ # Alive weakrefs hash the same as the underlying object
766+ x = Object (42 )
767+ y = Object (42 )
768+ a = weakref .ref (x )
769+ b = weakref .ref (y )
770+ self .assertEqual (hash (a ), hash (42 ))
771+ del x , y
772+ gc .collect ()
773+ # Dead weakrefs:
774+ # - retain their hash is they were hashed when alive;
775+ # - otherwise, cannot be hashed.
776+ self .assertEqual (hash (a ), hash (42 ))
777+ self .assertRaises (TypeError , hash , b )
778+
695779
696780class SubclassableWeakrefTestCase (TestBase ):
697781
@@ -796,27 +880,6 @@ def callback(w):
796880 self .assertEqual (self .cbcalled , 0 )
797881
798882
799- class Object :
800- def __init__ (self , arg ):
801- self .arg = arg
802- def __repr__ (self ):
803- return "<Object %r>" % self .arg
804- def __eq__ (self , other ):
805- if isinstance (other , Object ):
806- return self .arg == other .arg
807- return NotImplemented
808- def __lt__ (self , other ):
809- if isinstance (other , Object ):
810- return self .arg < other .arg
811- return NotImplemented
812- def __hash__ (self ):
813- return hash (self .arg )
814-
815- class RefCycle :
816- def __init__ (self ):
817- self .cycle = self
818-
819-
820883class MappingTestCase (TestBase ):
821884
822885 COUNT = 10
0 commit comments