2
2
import collections
3
3
import collections .abc
4
4
from collections import defaultdict
5
- from functools import lru_cache , wraps
5
+ from functools import lru_cache , wraps , reduce
6
6
import gc
7
7
import inspect
8
8
import itertools
9
+ import operator
9
10
import pickle
10
11
import re
11
12
import sys
@@ -1770,6 +1771,26 @@ def test_union_union(self):
1770
1771
v = Union [u , Employee ]
1771
1772
self .assertEqual (v , Union [int , float , Employee ])
1772
1773
1774
+ def test_union_of_unhashable (self ):
1775
+ class UnhashableMeta (type ):
1776
+ __hash__ = None
1777
+
1778
+ class A (metaclass = UnhashableMeta ): ...
1779
+ class B (metaclass = UnhashableMeta ): ...
1780
+
1781
+ self .assertEqual (Union [A , B ].__args__ , (A , B ))
1782
+ union1 = Union [A , B ]
1783
+ with self .assertRaises (TypeError ):
1784
+ hash (union1 )
1785
+
1786
+ union2 = Union [int , B ]
1787
+ with self .assertRaises (TypeError ):
1788
+ hash (union2 )
1789
+
1790
+ union3 = Union [A , int ]
1791
+ with self .assertRaises (TypeError ):
1792
+ hash (union3 )
1793
+
1773
1794
def test_repr (self ):
1774
1795
self .assertEqual (repr (Union ), 'typing.Union' )
1775
1796
u = Union [Employee , int ]
@@ -5295,10 +5316,8 @@ def some(self):
5295
5316
self .assertFalse (hasattr (WithOverride .some , "__override__" ))
5296
5317
5297
5318
def test_multiple_decorators (self ):
5298
- import functools
5299
-
5300
5319
def with_wraps (f ): # similar to `lru_cache` definition
5301
- @functools . wraps (f )
5320
+ @wraps (f )
5302
5321
def wrapper (* args , ** kwargs ):
5303
5322
return f (* args , ** kwargs )
5304
5323
return wrapper
@@ -8183,6 +8202,76 @@ def test_flatten(self):
8183
8202
self .assertEqual (A .__metadata__ , (4 , 5 ))
8184
8203
self .assertEqual (A .__origin__ , int )
8185
8204
8205
+ def test_deduplicate_from_union (self ):
8206
+ # Regular:
8207
+ self .assertEqual (get_args (Annotated [int , 1 ] | int ),
8208
+ (Annotated [int , 1 ], int ))
8209
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], int ]),
8210
+ (Annotated [int , 1 ], int ))
8211
+ self .assertEqual (get_args (Annotated [int , 1 ] | Annotated [int , 2 ] | int ),
8212
+ (Annotated [int , 1 ], Annotated [int , 2 ], int ))
8213
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], Annotated [int , 2 ], int ]),
8214
+ (Annotated [int , 1 ], Annotated [int , 2 ], int ))
8215
+ self .assertEqual (get_args (Annotated [int , 1 ] | Annotated [str , 1 ] | int ),
8216
+ (Annotated [int , 1 ], Annotated [str , 1 ], int ))
8217
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], Annotated [str , 1 ], int ]),
8218
+ (Annotated [int , 1 ], Annotated [str , 1 ], int ))
8219
+
8220
+ # Duplicates:
8221
+ self .assertEqual (Annotated [int , 1 ] | Annotated [int , 1 ] | int ,
8222
+ Annotated [int , 1 ] | int )
8223
+ self .assertEqual (Union [Annotated [int , 1 ], Annotated [int , 1 ], int ],
8224
+ Union [Annotated [int , 1 ], int ])
8225
+
8226
+ # Unhashable metadata:
8227
+ self .assertEqual (get_args (str | Annotated [int , {}] | Annotated [int , set ()] | int ),
8228
+ (str , Annotated [int , {}], Annotated [int , set ()], int ))
8229
+ self .assertEqual (get_args (Union [str , Annotated [int , {}], Annotated [int , set ()], int ]),
8230
+ (str , Annotated [int , {}], Annotated [int , set ()], int ))
8231
+ self .assertEqual (get_args (str | Annotated [int , {}] | Annotated [str , {}] | int ),
8232
+ (str , Annotated [int , {}], Annotated [str , {}], int ))
8233
+ self .assertEqual (get_args (Union [str , Annotated [int , {}], Annotated [str , {}], int ]),
8234
+ (str , Annotated [int , {}], Annotated [str , {}], int ))
8235
+
8236
+ self .assertEqual (get_args (Annotated [int , 1 ] | str | Annotated [str , {}] | int ),
8237
+ (Annotated [int , 1 ], str , Annotated [str , {}], int ))
8238
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], str , Annotated [str , {}], int ]),
8239
+ (Annotated [int , 1 ], str , Annotated [str , {}], int ))
8240
+
8241
+ import dataclasses
8242
+ @dataclasses .dataclass
8243
+ class ValueRange :
8244
+ lo : int
8245
+ hi : int
8246
+ v = ValueRange (1 , 2 )
8247
+ self .assertEqual (get_args (Annotated [int , v ] | None ),
8248
+ (Annotated [int , v ], types .NoneType ))
8249
+ self .assertEqual (get_args (Union [Annotated [int , v ], None ]),
8250
+ (Annotated [int , v ], types .NoneType ))
8251
+ self .assertEqual (get_args (Optional [Annotated [int , v ]]),
8252
+ (Annotated [int , v ], types .NoneType ))
8253
+
8254
+ # Unhashable metadata duplicated:
8255
+ self .assertEqual (Annotated [int , {}] | Annotated [int , {}] | int ,
8256
+ Annotated [int , {}] | int )
8257
+ self .assertEqual (Annotated [int , {}] | Annotated [int , {}] | int ,
8258
+ int | Annotated [int , {}])
8259
+ self .assertEqual (Union [Annotated [int , {}], Annotated [int , {}], int ],
8260
+ Union [Annotated [int , {}], int ])
8261
+ self .assertEqual (Union [Annotated [int , {}], Annotated [int , {}], int ],
8262
+ Union [int , Annotated [int , {}]])
8263
+
8264
+ def test_order_in_union (self ):
8265
+ expr1 = Annotated [int , 1 ] | str | Annotated [str , {}] | int
8266
+ for args in itertools .permutations (get_args (expr1 )):
8267
+ with self .subTest (args = args ):
8268
+ self .assertEqual (expr1 , reduce (operator .or_ , args ))
8269
+
8270
+ expr2 = Union [Annotated [int , 1 ], str , Annotated [str , {}], int ]
8271
+ for args in itertools .permutations (get_args (expr2 )):
8272
+ with self .subTest (args = args ):
8273
+ self .assertEqual (expr2 , Union [args ])
8274
+
8186
8275
def test_specialize (self ):
8187
8276
L = Annotated [List [T ], "my decoration" ]
8188
8277
LI = Annotated [List [int ], "my decoration" ]
@@ -8203,6 +8292,16 @@ def test_hash_eq(self):
8203
8292
{Annotated [int , 4 , 5 ], Annotated [int , 4 , 5 ], Annotated [T , 4 , 5 ]},
8204
8293
{Annotated [int , 4 , 5 ], Annotated [T , 4 , 5 ]}
8205
8294
)
8295
+ # Unhashable `metadata` raises `TypeError`:
8296
+ a1 = Annotated [int , []]
8297
+ with self .assertRaises (TypeError ):
8298
+ hash (a1 )
8299
+
8300
+ class A :
8301
+ __hash__ = None
8302
+ a2 = Annotated [int , A ()]
8303
+ with self .assertRaises (TypeError ):
8304
+ hash (a2 )
8206
8305
8207
8306
def test_instantiate (self ):
8208
8307
class C :
0 commit comments