2323from typing import reveal_type
2424from typing import no_type_check , no_type_check_decorator
2525from typing import Type
26- from typing import NamedTuple , TypedDict
26+ from typing import NamedTuple , NotRequired , Required , TypedDict
2727from typing import IO , TextIO , BinaryIO
2828from typing import Pattern , Match
2929from typing import Annotated , ForwardRef
@@ -3993,6 +3993,26 @@ class Options(TypedDict, total=False):
39933993 log_level : int
39943994 log_path : str
39953995
3996+ class TotalMovie (TypedDict ):
3997+ title : str
3998+ year : NotRequired [int ]
3999+
4000+ class NontotalMovie (TypedDict , total = False ):
4001+ title : Required [str ]
4002+ year : int
4003+
4004+ class AnnotatedMovie (TypedDict ):
4005+ title : Annotated [Required [str ], "foobar" ]
4006+ year : NotRequired [Annotated [int , 2000 ]]
4007+
4008+ class DeeplyAnnotatedMovie (TypedDict ):
4009+ title : Annotated [Annotated [Required [str ], "foobar" ], "another level" ]
4010+ year : NotRequired [Annotated [int , 2000 ]]
4011+
4012+ class WeirdlyQuotedMovie (TypedDict ):
4013+ title : Annotated ['Annotated[Required[str], "foobar"]' , "another level" ]
4014+ year : NotRequired ['Annotated[int, 2000]' ]
4015+
39964016class HasForeignBaseClass (mod_generics_cache .A ):
39974017 some_xrepr : 'XRepr'
39984018 other_a : 'mod_generics_cache.A'
@@ -4280,6 +4300,36 @@ def test_top_level_class_var(self):
42804300 ):
42814301 get_type_hints (ann_module6 )
42824302
4303+ def test_get_type_hints_typeddict (self ):
4304+ self .assertEqual (get_type_hints (TotalMovie ), {'title' : str , 'year' : int })
4305+ self .assertEqual (get_type_hints (TotalMovie , include_extras = True ), {
4306+ 'title' : str ,
4307+ 'year' : NotRequired [int ],
4308+ })
4309+
4310+ self .assertEqual (get_type_hints (AnnotatedMovie ), {'title' : str , 'year' : int })
4311+ self .assertEqual (get_type_hints (AnnotatedMovie , include_extras = True ), {
4312+ 'title' : Annotated [Required [str ], "foobar" ],
4313+ 'year' : NotRequired [Annotated [int , 2000 ]],
4314+ })
4315+
4316+ self .assertEqual (get_type_hints (DeeplyAnnotatedMovie ), {'title' : str , 'year' : int })
4317+ self .assertEqual (get_type_hints (DeeplyAnnotatedMovie , include_extras = True ), {
4318+ 'title' : Annotated [Required [str ], "foobar" , "another level" ],
4319+ 'year' : NotRequired [Annotated [int , 2000 ]],
4320+ })
4321+
4322+ self .assertEqual (get_type_hints (WeirdlyQuotedMovie ), {'title' : str , 'year' : int })
4323+ self .assertEqual (get_type_hints (WeirdlyQuotedMovie , include_extras = True ), {
4324+ 'title' : Annotated [Required [str ], "foobar" , "another level" ],
4325+ 'year' : NotRequired [Annotated [int , 2000 ]],
4326+ })
4327+
4328+ self .assertEqual (get_type_hints (_typed_dict_helper .VeryAnnotated ), {'a' : int })
4329+ self .assertEqual (get_type_hints (_typed_dict_helper .VeryAnnotated , include_extras = True ), {
4330+ 'a' : Annotated [Required [int ], "a" , "b" , "c" ]
4331+ })
4332+
42834333
42844334class GetUtilitiesTestCase (TestCase ):
42854335 def test_get_origin (self ):
@@ -4305,6 +4355,8 @@ class C(Generic[T]): pass
43054355 self .assertIs (get_origin (list | str ), types .UnionType )
43064356 self .assertIs (get_origin (P .args ), P )
43074357 self .assertIs (get_origin (P .kwargs ), P )
4358+ self .assertIs (get_origin (Required [int ]), Required )
4359+ self .assertIs (get_origin (NotRequired [int ]), NotRequired )
43084360
43094361 def test_get_args (self ):
43104362 T = TypeVar ('T' )
@@ -4342,6 +4394,8 @@ class C(Generic[T]): pass
43424394 self .assertEqual (get_args (Callable [Concatenate [int , P ], int ]),
43434395 (Concatenate [int , P ], int ))
43444396 self .assertEqual (get_args (list | str ), (list , str ))
4397+ self .assertEqual (get_args (Required [int ]), (int ,))
4398+ self .assertEqual (get_args (NotRequired [int ]), (int ,))
43454399
43464400
43474401class CollectionsAbcTests (BaseTestCase ):
@@ -5299,6 +5353,32 @@ class Cat(Animal):
52995353 'voice' : str ,
53005354 }
53015355
5356+ def test_required_notrequired_keys (self ):
5357+ self .assertEqual (NontotalMovie .__required_keys__ ,
5358+ frozenset ({"title" }))
5359+ self .assertEqual (NontotalMovie .__optional_keys__ ,
5360+ frozenset ({"year" }))
5361+
5362+ self .assertEqual (TotalMovie .__required_keys__ ,
5363+ frozenset ({"title" }))
5364+ self .assertEqual (TotalMovie .__optional_keys__ ,
5365+ frozenset ({"year" }))
5366+
5367+ self .assertEqual (_typed_dict_helper .VeryAnnotated .__required_keys__ ,
5368+ frozenset ())
5369+ self .assertEqual (_typed_dict_helper .VeryAnnotated .__optional_keys__ ,
5370+ frozenset ({"a" }))
5371+
5372+ self .assertEqual (AnnotatedMovie .__required_keys__ ,
5373+ frozenset ({"title" }))
5374+ self .assertEqual (AnnotatedMovie .__optional_keys__ ,
5375+ frozenset ({"year" }))
5376+
5377+ self .assertEqual (WeirdlyQuotedMovie .__required_keys__ ,
5378+ frozenset ({"title" }))
5379+ self .assertEqual (WeirdlyQuotedMovie .__optional_keys__ ,
5380+ frozenset ({"year" }))
5381+
53025382 def test_multiple_inheritance (self ):
53035383 class One (TypedDict ):
53045384 one : int
@@ -5399,6 +5479,98 @@ def test_get_type_hints(self):
53995479 )
54005480
54015481
5482+ class RequiredTests (BaseTestCase ):
5483+
5484+ def test_basics (self ):
5485+ with self .assertRaises (TypeError ):
5486+ Required [NotRequired ]
5487+ with self .assertRaises (TypeError ):
5488+ Required [int , str ]
5489+ with self .assertRaises (TypeError ):
5490+ Required [int ][str ]
5491+
5492+ def test_repr (self ):
5493+ self .assertEqual (repr (Required ), 'typing.Required' )
5494+ cv = Required [int ]
5495+ self .assertEqual (repr (cv ), 'typing.Required[int]' )
5496+ cv = Required [Employee ]
5497+ self .assertEqual (repr (cv ), f'typing.Required[{ __name__ } .Employee]' )
5498+
5499+ def test_cannot_subclass (self ):
5500+ with self .assertRaises (TypeError ):
5501+ class C (type (Required )):
5502+ pass
5503+ with self .assertRaises (TypeError ):
5504+ class C (type (Required [int ])):
5505+ pass
5506+ with self .assertRaises (TypeError ):
5507+ class C (Required ):
5508+ pass
5509+ with self .assertRaises (TypeError ):
5510+ class C (Required [int ]):
5511+ pass
5512+
5513+ def test_cannot_init (self ):
5514+ with self .assertRaises (TypeError ):
5515+ Required ()
5516+ with self .assertRaises (TypeError ):
5517+ type (Required )()
5518+ with self .assertRaises (TypeError ):
5519+ type (Required [Optional [int ]])()
5520+
5521+ def test_no_isinstance (self ):
5522+ with self .assertRaises (TypeError ):
5523+ isinstance (1 , Required [int ])
5524+ with self .assertRaises (TypeError ):
5525+ issubclass (int , Required )
5526+
5527+
5528+ class NotRequiredTests (BaseTestCase ):
5529+
5530+ def test_basics (self ):
5531+ with self .assertRaises (TypeError ):
5532+ NotRequired [Required ]
5533+ with self .assertRaises (TypeError ):
5534+ NotRequired [int , str ]
5535+ with self .assertRaises (TypeError ):
5536+ NotRequired [int ][str ]
5537+
5538+ def test_repr (self ):
5539+ self .assertEqual (repr (NotRequired ), 'typing.NotRequired' )
5540+ cv = NotRequired [int ]
5541+ self .assertEqual (repr (cv ), 'typing.NotRequired[int]' )
5542+ cv = NotRequired [Employee ]
5543+ self .assertEqual (repr (cv ), f'typing.NotRequired[{ __name__ } .Employee]' )
5544+
5545+ def test_cannot_subclass (self ):
5546+ with self .assertRaises (TypeError ):
5547+ class C (type (NotRequired )):
5548+ pass
5549+ with self .assertRaises (TypeError ):
5550+ class C (type (NotRequired [int ])):
5551+ pass
5552+ with self .assertRaises (TypeError ):
5553+ class C (NotRequired ):
5554+ pass
5555+ with self .assertRaises (TypeError ):
5556+ class C (NotRequired [int ]):
5557+ pass
5558+
5559+ def test_cannot_init (self ):
5560+ with self .assertRaises (TypeError ):
5561+ NotRequired ()
5562+ with self .assertRaises (TypeError ):
5563+ type (NotRequired )()
5564+ with self .assertRaises (TypeError ):
5565+ type (NotRequired [Optional [int ]])()
5566+
5567+ def test_no_isinstance (self ):
5568+ with self .assertRaises (TypeError ):
5569+ isinstance (1 , NotRequired [int ])
5570+ with self .assertRaises (TypeError ):
5571+ issubclass (int , NotRequired )
5572+
5573+
54025574class IOTests (BaseTestCase ):
54035575
54045576 def test_io (self ):
0 commit comments