1
1
import contextlib
2
2
import collections
3
3
from collections import defaultdict
4
- from functools import lru_cache , wraps
4
+ from functools import lru_cache , wraps , reduce
5
5
import inspect
6
6
import itertools
7
7
import gc
8
+ import operator
8
9
import pickle
9
10
import re
10
11
import sys
@@ -1705,6 +1706,26 @@ def test_union_union(self):
1705
1706
v = Union [u , Employee ]
1706
1707
self .assertEqual (v , Union [int , float , Employee ])
1707
1708
1709
+ def test_union_of_unhashable (self ):
1710
+ class UnhashableMeta (type ):
1711
+ __hash__ = None
1712
+
1713
+ class A (metaclass = UnhashableMeta ): ...
1714
+ class B (metaclass = UnhashableMeta ): ...
1715
+
1716
+ self .assertEqual (Union [A , B ].__args__ , (A , B ))
1717
+ union1 = Union [A , B ]
1718
+ with self .assertRaises (TypeError ):
1719
+ hash (union1 )
1720
+
1721
+ union2 = Union [int , B ]
1722
+ with self .assertRaises (TypeError ):
1723
+ hash (union2 )
1724
+
1725
+ union3 = Union [A , int ]
1726
+ with self .assertRaises (TypeError ):
1727
+ hash (union3 )
1728
+
1708
1729
def test_repr (self ):
1709
1730
self .assertEqual (repr (Union ), 'typing.Union' )
1710
1731
u = Union [Employee , int ]
@@ -7374,6 +7395,76 @@ def test_flatten(self):
7374
7395
self .assertEqual (A .__metadata__ , (4 , 5 ))
7375
7396
self .assertEqual (A .__origin__ , int )
7376
7397
7398
+ def test_deduplicate_from_union (self ):
7399
+ # Regular:
7400
+ self .assertEqual (get_args (Annotated [int , 1 ] | int ),
7401
+ (Annotated [int , 1 ], int ))
7402
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], int ]),
7403
+ (Annotated [int , 1 ], int ))
7404
+ self .assertEqual (get_args (Annotated [int , 1 ] | Annotated [int , 2 ] | int ),
7405
+ (Annotated [int , 1 ], Annotated [int , 2 ], int ))
7406
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], Annotated [int , 2 ], int ]),
7407
+ (Annotated [int , 1 ], Annotated [int , 2 ], int ))
7408
+ self .assertEqual (get_args (Annotated [int , 1 ] | Annotated [str , 1 ] | int ),
7409
+ (Annotated [int , 1 ], Annotated [str , 1 ], int ))
7410
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], Annotated [str , 1 ], int ]),
7411
+ (Annotated [int , 1 ], Annotated [str , 1 ], int ))
7412
+
7413
+ # Duplicates:
7414
+ self .assertEqual (Annotated [int , 1 ] | Annotated [int , 1 ] | int ,
7415
+ Annotated [int , 1 ] | int )
7416
+ self .assertEqual (Union [Annotated [int , 1 ], Annotated [int , 1 ], int ],
7417
+ Union [Annotated [int , 1 ], int ])
7418
+
7419
+ # Unhashable metadata:
7420
+ self .assertEqual (get_args (str | Annotated [int , {}] | Annotated [int , set ()] | int ),
7421
+ (str , Annotated [int , {}], Annotated [int , set ()], int ))
7422
+ self .assertEqual (get_args (Union [str , Annotated [int , {}], Annotated [int , set ()], int ]),
7423
+ (str , Annotated [int , {}], Annotated [int , set ()], int ))
7424
+ self .assertEqual (get_args (str | Annotated [int , {}] | Annotated [str , {}] | int ),
7425
+ (str , Annotated [int , {}], Annotated [str , {}], int ))
7426
+ self .assertEqual (get_args (Union [str , Annotated [int , {}], Annotated [str , {}], int ]),
7427
+ (str , Annotated [int , {}], Annotated [str , {}], int ))
7428
+
7429
+ self .assertEqual (get_args (Annotated [int , 1 ] | str | Annotated [str , {}] | int ),
7430
+ (Annotated [int , 1 ], str , Annotated [str , {}], int ))
7431
+ self .assertEqual (get_args (Union [Annotated [int , 1 ], str , Annotated [str , {}], int ]),
7432
+ (Annotated [int , 1 ], str , Annotated [str , {}], int ))
7433
+
7434
+ import dataclasses
7435
+ @dataclasses .dataclass
7436
+ class ValueRange :
7437
+ lo : int
7438
+ hi : int
7439
+ v = ValueRange (1 , 2 )
7440
+ self .assertEqual (get_args (Annotated [int , v ] | None ),
7441
+ (Annotated [int , v ], types .NoneType ))
7442
+ self .assertEqual (get_args (Union [Annotated [int , v ], None ]),
7443
+ (Annotated [int , v ], types .NoneType ))
7444
+ self .assertEqual (get_args (Optional [Annotated [int , v ]]),
7445
+ (Annotated [int , v ], types .NoneType ))
7446
+
7447
+ # Unhashable metadata duplicated:
7448
+ self .assertEqual (Annotated [int , {}] | Annotated [int , {}] | int ,
7449
+ Annotated [int , {}] | int )
7450
+ self .assertEqual (Annotated [int , {}] | Annotated [int , {}] | int ,
7451
+ int | Annotated [int , {}])
7452
+ self .assertEqual (Union [Annotated [int , {}], Annotated [int , {}], int ],
7453
+ Union [Annotated [int , {}], int ])
7454
+ self .assertEqual (Union [Annotated [int , {}], Annotated [int , {}], int ],
7455
+ Union [int , Annotated [int , {}]])
7456
+
7457
+ def test_order_in_union (self ):
7458
+ expr1 = Annotated [int , 1 ] | str | Annotated [str , {}] | int
7459
+ for args in itertools .permutations (get_args (expr1 )):
7460
+ with self .subTest (args = args ):
7461
+ self .assertEqual (expr1 , reduce (operator .or_ , args ))
7462
+
7463
+ expr2 = Union [Annotated [int , 1 ], str , Annotated [str , {}], int ]
7464
+ for args in itertools .permutations (get_args (expr2 )):
7465
+ with self .subTest (args = args ):
7466
+ self .assertEqual (expr2 , Union [args ])
7467
+
7377
7468
def test_specialize (self ):
7378
7469
L = Annotated [List [T ], "my decoration" ]
7379
7470
LI = Annotated [List [int ], "my decoration" ]
@@ -7394,6 +7485,16 @@ def test_hash_eq(self):
7394
7485
{Annotated [int , 4 , 5 ], Annotated [int , 4 , 5 ], Annotated [T , 4 , 5 ]},
7395
7486
{Annotated [int , 4 , 5 ], Annotated [T , 4 , 5 ]}
7396
7487
)
7488
+ # Unhashable `metadata` raises `TypeError`:
7489
+ a1 = Annotated [int , []]
7490
+ with self .assertRaises (TypeError ):
7491
+ hash (a1 )
7492
+
7493
+ class A :
7494
+ __hash__ = None
7495
+ a2 = Annotated [int , A ()]
7496
+ with self .assertRaises (TypeError ):
7497
+ hash (a2 )
7397
7498
7398
7499
def test_instantiate (self ):
7399
7500
class C :
0 commit comments