@@ -709,10 +709,6 @@ def test_or_types_operator(self):
709
709
y = int | bool
710
710
with self .assertRaises (TypeError ):
711
711
x < y
712
- # Check that we don't crash if typing.Union does not have a tuple in __args__
713
- y = typing .Union [str , int ]
714
- y .__args__ = [str , int ]
715
- self .assertEqual (x , y )
716
712
717
713
def test_hash (self ):
718
714
self .assertEqual (hash (int | str ), hash (str | int ))
@@ -727,17 +723,40 @@ class B(metaclass=UnhashableMeta): ...
727
723
728
724
self .assertEqual ((A | B ).__args__ , (A , B ))
729
725
union1 = A | B
730
- with self .assertRaises (TypeError ):
726
+ with self .assertRaisesRegex (TypeError , "unhashable type: 'UnhashableMeta'" ):
731
727
hash (union1 )
732
728
733
729
union2 = int | B
734
- with self .assertRaises (TypeError ):
730
+ with self .assertRaisesRegex (TypeError , "unhashable type: 'UnhashableMeta'" ):
735
731
hash (union2 )
736
732
737
733
union3 = A | int
738
- with self .assertRaises (TypeError ):
734
+ with self .assertRaisesRegex (TypeError , "unhashable type: 'UnhashableMeta'" ):
739
735
hash (union3 )
740
736
737
+ def test_unhashable_becomes_hashable (self ):
738
+ is_hashable = False
739
+ class UnhashableMeta (type ):
740
+ def __hash__ (self ):
741
+ if is_hashable :
742
+ return 1
743
+ else :
744
+ raise TypeError ("not hashable" )
745
+
746
+ class A (metaclass = UnhashableMeta ): ...
747
+ class B (metaclass = UnhashableMeta ): ...
748
+
749
+ union = A | B
750
+ self .assertEqual (union .__args__ , (A , B ))
751
+
752
+ with self .assertRaisesRegex (TypeError , "not hashable" ):
753
+ hash (union )
754
+
755
+ is_hashable = True
756
+
757
+ with self .assertRaisesRegex (TypeError , "union contains 2 unhashable elements" ):
758
+ hash (union )
759
+
741
760
def test_instancecheck_and_subclasscheck (self ):
742
761
for x in (int | str , typing .Union [int , str ]):
743
762
with self .subTest (x = x ):
@@ -921,7 +940,7 @@ def forward_before(x: ForwardBefore[int]) -> None: ...
921
940
self .assertEqual (typing .get_args (typing .get_type_hints (forward_after )['x' ]),
922
941
(int , Forward ))
923
942
self .assertEqual (typing .get_args (typing .get_type_hints (forward_before )['x' ]),
924
- (int , Forward ))
943
+ (Forward , int ))
925
944
926
945
def test_or_type_operator_with_Protocol (self ):
927
946
class Proto (typing .Protocol ):
@@ -1015,9 +1034,14 @@ def __eq__(self, other):
1015
1034
return 1 / 0
1016
1035
1017
1036
bt = BadType ('bt' , (), {})
1037
+ bt2 = BadType ('bt2' , (), {})
1018
1038
# Comparison should fail and errors should propagate out for bad types.
1039
+ union1 = int | bt
1040
+ union2 = int | bt2
1041
+ with self .assertRaises (ZeroDivisionError ):
1042
+ union1 == union2
1019
1043
with self .assertRaises (ZeroDivisionError ):
1020
- list [ int ] | list [ bt ]
1044
+ bt | bt2
1021
1045
1022
1046
union_ga = (list [str ] | int , collections .abc .Callable [..., str ] | int ,
1023
1047
d | int )
@@ -1060,6 +1084,14 @@ def test_or_type_operator_reference_cycle(self):
1060
1084
self .assertLessEqual (sys .gettotalrefcount () - before , leeway ,
1061
1085
msg = 'Check for union reference leak.' )
1062
1086
1087
+ def test_instantiation (self ):
1088
+ with self .assertRaises (TypeError ):
1089
+ types .UnionType ()
1090
+ self .assertIs (int , types .UnionType [int ])
1091
+ self .assertIs (int , types .UnionType [int , int ])
1092
+ self .assertEqual (int | str , types .UnionType [int , str ])
1093
+ self .assertEqual (int | typing .ForwardRef ("str" ), types .UnionType [int , "str" ])
1094
+
1063
1095
1064
1096
class MappingProxyTests (unittest .TestCase ):
1065
1097
mappingproxy = types .MappingProxyType
0 commit comments