@@ -1647,6 +1647,95 @@ def test_final_forward_ref(self):
1647
1647
self .assertNotEqual (gth (Loop , globals ())['attr' ], Final [int ])
1648
1648
self .assertNotEqual (gth (Loop , globals ())['attr' ], Final )
1649
1649
1650
+ def test_annotation_and_optional_default (self ):
1651
+ annotation = Annotated [Union [int , None ], "data" ]
1652
+ NoneAlias = None
1653
+ StrAlias = str
1654
+ T_default = TypeVar ("T_default" , default = None )
1655
+ Ts = TypeVarTuple ("Ts" )
1656
+
1657
+ cases = {
1658
+ # annotation: expected_type_hints
1659
+ Annotated [None , "none" ] : Annotated [None , "none" ],
1660
+ annotation : annotation ,
1661
+ Optional [int ] : Optional [int ],
1662
+ Optional [List [str ]] : Optional [List [str ]],
1663
+ Optional [annotation ] : Optional [annotation ],
1664
+ Union [str , None , str ] : Optional [str ],
1665
+ Unpack [Tuple [int , None ]]: Unpack [Tuple [int , None ]],
1666
+ # Note: A starred *Ts will use typing.Unpack in 3.11+ see Issue #485
1667
+ Unpack [Ts ] : Unpack [Ts ],
1668
+ }
1669
+ # contains a ForwardRef, TypeVar(~prefix) or no expression
1670
+ do_not_stringify_cases = {
1671
+ () : {}, # Special-cased below to create an unannotated parameter
1672
+ int : int ,
1673
+ "int" : int ,
1674
+ None : type (None ),
1675
+ "NoneAlias" : type (None ),
1676
+ List ["str" ] : List [str ],
1677
+ Union [str , "str" ] : str ,
1678
+ Union [str , None , "str" ] : Optional [str ],
1679
+ Union [str , "NoneAlias" , "StrAlias" ]: Optional [str ],
1680
+ Union [str , "Union[None, StrAlias]" ]: Optional [str ],
1681
+ Union ["annotation" , T_default ] : Union [annotation , T_default ],
1682
+ Annotated ["annotation" , "nested" ] : Annotated [Union [int , None ], "data" , "nested" ],
1683
+ }
1684
+ if TYPING_3_10_0 : # cannot construct UnionTypes before 3.10
1685
+ do_not_stringify_cases ["str | NoneAlias | StrAlias" ] = str | None
1686
+ cases [str | None ] = Optional [str ]
1687
+ cases .update (do_not_stringify_cases )
1688
+ for (annot , expected ), none_default , as_str , wrap_optional in itertools .product (
1689
+ cases .items (), (False , True ), (False , True ), (False , True )
1690
+ ):
1691
+ # Special case:
1692
+ skip_reason = None
1693
+ annot_unchanged = annot
1694
+ if sys .version_info [:2 ] == (3 , 10 ) and annot == "str | NoneAlias | StrAlias" and none_default :
1695
+ # In 3.10 converts Optional[str | None] to Optional[str] which has a different repr
1696
+ skip_reason = "UnionType not preserved in 3.10"
1697
+ if wrap_optional :
1698
+ if annot_unchanged == ():
1699
+ continue
1700
+ annot = Optional [annot ]
1701
+ expected = {"x" : Optional [expected ]}
1702
+ else :
1703
+ expected = {"x" : expected } if annot_unchanged != () else {}
1704
+ if as_str :
1705
+ if annot_unchanged in do_not_stringify_cases or annot_unchanged == ():
1706
+ continue
1707
+ annot = str (annot )
1708
+ with self .subTest (
1709
+ annotation = annot ,
1710
+ as_str = as_str ,
1711
+ wrap_optional = wrap_optional ,
1712
+ none_default = none_default ,
1713
+ expected_type_hints = expected ,
1714
+ ):
1715
+ # Create function to check
1716
+ if annot_unchanged == ():
1717
+ if none_default :
1718
+ def func (x = None ): pass
1719
+ else :
1720
+ def func (x ): pass
1721
+ elif none_default :
1722
+ def func (x : annot = None ): pass
1723
+ else :
1724
+ def func (x : annot ): pass
1725
+ type_hints = get_type_hints (func , globals (), locals (), include_extras = True )
1726
+ # Equality
1727
+ self .assertEqual (type_hints , expected )
1728
+ # Hash
1729
+ for k in type_hints .keys ():
1730
+ self .assertEqual (hash (type_hints [k ]), hash (expected [k ]))
1731
+ # Test if UnionTypes are preserved
1732
+ self .assertIs (type (type_hints [k ]), type (expected [k ]))
1733
+ # Repr
1734
+ with self .subTest ("Check str and repr" ):
1735
+ if skip_reason == "UnionType not preserved in 3.10" :
1736
+ self .skipTest (skip_reason )
1737
+ self .assertEqual (repr (type_hints ), repr (expected ))
1738
+
1650
1739
1651
1740
class GetUtilitiesTestCase (TestCase ):
1652
1741
def test_get_origin (self ):
0 commit comments