9595 'ReadOnly' ,
9696 'Required' ,
9797 'NotRequired' ,
98+ 'NoDefault' ,
99+ 'NoExtraItems' ,
98100
99101 # Pure aliases, have always been in typing
100102 'AbstractSet' ,
121123 'MutableMapping' ,
122124 'MutableSequence' ,
123125 'MutableSet' ,
124- 'NoDefault' ,
125126 'Optional' ,
126127 'Pattern' ,
127128 'Reversible' ,
@@ -871,6 +872,59 @@ def inner(func):
871872 return inner
872873
873874
875+ if not hasattr (typing , "NoDefault" ) or not hasattr (typing , "NoExtraItems" ):
876+ class SingletonMeta (type ):
877+ def __setattr__ (cls , attr , value ):
878+ # TypeError is consistent with the behavior of NoneType
879+ raise TypeError (
880+ f"cannot set { attr !r} attribute of immutable type { cls .__name__ !r} "
881+ )
882+
883+
884+ if hasattr (typing , "NoDefault" ):
885+ NoDefault = typing .NoDefault
886+ else :
887+ class NoDefaultType (metaclass = SingletonMeta ):
888+ """The type of the NoDefault singleton."""
889+
890+ __slots__ = ()
891+
892+ def __new__ (cls ):
893+ return globals ().get ("NoDefault" ) or object .__new__ (cls )
894+
895+ def __repr__ (self ):
896+ return "typing_extensions.NoDefault"
897+
898+ def __reduce__ (self ):
899+ return "NoDefault"
900+
901+ NoDefault = NoDefaultType ()
902+ del NoDefaultType
903+
904+ if hasattr (typing , "NoExtraItems" ):
905+ NoExtraItems = typing .NoExtraItems
906+ else :
907+ class NoExtraItemsType (metaclass = SingletonMeta ):
908+ """The type of the NoExtraItems singleton."""
909+
910+ __slots__ = ()
911+
912+ def __new__ (cls ):
913+ return globals ().get ("NoExtraItems" ) or object .__new__ (cls )
914+
915+ def __repr__ (self ):
916+ return "typing_extensions.NoExtraItems"
917+
918+ def __reduce__ (self ):
919+ return "NoExtraItems"
920+
921+ NoExtraItems = NoExtraItemsType ()
922+ del NoExtraItemsType
923+
924+ if not hasattr (typing , "NoDefault" ) or not hasattr (typing , "NoExtraItems" ):
925+ del SingletonMeta
926+
927+
874928# Update this to something like >=3.13.0b1 if and when
875929# PEP 728 is implemented in CPython
876930_PEP_728_IMPLEMENTED = False
@@ -917,7 +971,7 @@ def _get_typeddict_qualifiers(annotation_type):
917971 break
918972
919973 class _TypedDictMeta (type ):
920- def __new__ (cls , name , bases , ns , * , total = True , closed = None , extra_items = None ):
974+ def __new__ (cls , name , bases , ns , * , total = True , closed = None , extra_items = NoExtraItems ):
921975 """Create new typed dict class object.
922976
923977 This method is called when TypedDict is subclassed,
@@ -929,8 +983,8 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None, extra_items=None):
929983 if type (base ) is not _TypedDictMeta and base is not typing .Generic :
930984 raise TypeError ('cannot inherit from both a TypedDict type '
931985 'and a non-TypedDict base class' )
932- if closed is not None and extra_items is not None :
933- raise TypeError ("Cannot combine closed=True and extra_items" )
986+ if closed is not None and extra_items is not NoExtraItems :
987+ raise TypeError (f "Cannot combine closed={ closed !r } and extra_items" )
934988 elif closed is None :
935989 closed = False
936990
@@ -982,9 +1036,6 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None, extra_items=None):
9821036 optional_keys .update (base_dict .get ('__optional_keys__' , ()))
9831037 readonly_keys .update (base_dict .get ('__readonly_keys__' , ()))
9841038 mutable_keys .update (base_dict .get ('__mutable_keys__' , ()))
985- base_extra_items_type = getattr (base , '__extra_items__' , None )
986- if base_extra_items_type is not None :
987- extra_items_type = base_extra_items_type
9881039 if getattr (base , "__closed__" , False ) and not closed :
9891040 if sys .version_info < (3 , 14 ):
9901041 # PEP 728 wants this to be an error, but that is not
@@ -997,7 +1048,7 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None, extra_items=None):
9971048 else :
9981049 raise TypeError ("Child of a closed TypedDict must also be closed" )
9991050
1000- if closed and extra_items_type is None :
1051+ if closed and extra_items_type is NoExtraItems :
10011052 extra_items_type = Never
10021053
10031054 # This was specified in an earlier version of PEP 728. Support
@@ -1059,7 +1110,16 @@ def __subclasscheck__(cls, other):
10591110 _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
10601111
10611112 @_ensure_subclassable (lambda bases : (_TypedDict ,))
1062- def TypedDict (typename , fields = _marker , / , * , total = True , closed = False , ** kwargs ):
1113+ def TypedDict (
1114+ typename ,
1115+ fields = _marker ,
1116+ / ,
1117+ * ,
1118+ total = True ,
1119+ closed = False ,
1120+ extra_items = NoExtraItems ,
1121+ ** kwargs
1122+ ):
10631123 """A simple typed namespace. At runtime it is equivalent to a plain dict.
10641124
10651125 TypedDict creates a dictionary type such that a type checker will expect all
@@ -1119,9 +1179,14 @@ class Point2D(TypedDict):
11191179 "using the functional syntax, pass an empty dictionary, e.g. "
11201180 ) + example + "."
11211181 warnings .warn (deprecation_msg , DeprecationWarning , stacklevel = 2 )
1182+ # Support a field called "closed"
11221183 if closed is not False and closed is not True :
11231184 kwargs ["closed" ] = closed
1124- closed = False
1185+ closed = None
1186+ # Or "extra_items"
1187+ if extra_items is not NoExtraItems :
1188+ kwargs ["extra_items" ] = extra_items
1189+ extra_items = NoExtraItems
11251190 fields = kwargs
11261191 elif kwargs :
11271192 raise TypeError ("TypedDict takes either a dict or keyword arguments,"
@@ -1143,7 +1208,7 @@ class Point2D(TypedDict):
11431208 # Setting correct module is necessary to make typed dict classes pickleable.
11441209 ns ['__module__' ] = module
11451210
1146- td = _TypedDictMeta (typename , (), ns , total = total , closed = closed )
1211+ td = _TypedDictMeta (typename , (), ns , total = total , closed = closed , extra_items = extra_items )
11471212 td .__orig_bases__ = (TypedDict ,)
11481213 return td
11491214
@@ -1466,34 +1531,6 @@ def TypeAlias(self, parameters):
14661531 )
14671532
14681533
1469- if hasattr (typing , "NoDefault" ):
1470- NoDefault = typing .NoDefault
1471- else :
1472- class NoDefaultTypeMeta (type ):
1473- def __setattr__ (cls , attr , value ):
1474- # TypeError is consistent with the behavior of NoneType
1475- raise TypeError (
1476- f"cannot set { attr !r} attribute of immutable type { cls .__name__ !r} "
1477- )
1478-
1479- class NoDefaultType (metaclass = NoDefaultTypeMeta ):
1480- """The type of the NoDefault singleton."""
1481-
1482- __slots__ = ()
1483-
1484- def __new__ (cls ):
1485- return globals ().get ("NoDefault" ) or object .__new__ (cls )
1486-
1487- def __repr__ (self ):
1488- return "typing_extensions.NoDefault"
1489-
1490- def __reduce__ (self ):
1491- return "NoDefault"
1492-
1493- NoDefault = NoDefaultType ()
1494- del NoDefaultType , NoDefaultTypeMeta
1495-
1496-
14971534def _set_default (type_param , default ):
14981535 type_param .has_default = lambda : default is not NoDefault
14991536 type_param .__default__ = default
0 commit comments