@@ -52,6 +52,11 @@ class Name(StrEnum):
5252except Exception as exc :
5353 Answer = exc
5454
55+ try :
56+ Theory = Enum ('Theory' , 'rule law supposition' , qualname = 'spanish_inquisition' )
57+ except Exception as exc :
58+ Theory = exc
59+
5560# for doctests
5661try :
5762 class Fruit (Enum ):
@@ -61,14 +66,18 @@ class Fruit(Enum):
6166except Exception :
6267 pass
6368
64- def test_pickle_dump_load (assertion , source , target = None ):
69+ def test_pickle_dump_load (assertion , source , target = None ,
70+ * , protocol = (0 , HIGHEST_PROTOCOL )):
71+ start , stop = protocol
6572 if target is None :
6673 target = source
67- for protocol in range (2 , HIGHEST_PROTOCOL + 1 ):
74+ for protocol in range (start , stop + 1 ):
6875 assertion (loads (dumps (source , protocol = protocol )), target )
6976
70- def test_pickle_exception (assertion , exception , obj ):
71- for protocol in range (2 , HIGHEST_PROTOCOL + 1 ):
77+ def test_pickle_exception (assertion , exception , obj ,
78+ * , protocol = (0 , HIGHEST_PROTOCOL )):
79+ start , stop = protocol
80+ for protocol in range (start , stop + 1 ):
7281 with assertion (exception ):
7382 dumps (obj , protocol = protocol )
7483
@@ -101,6 +110,7 @@ def test_is_dunder(self):
101110
102111
103112class TestEnum (unittest .TestCase ):
113+
104114 def setUp (self ):
105115 class Season (Enum ):
106116 SPRING = 1
@@ -540,11 +550,31 @@ def test_pickle_enum_function_with_module(self):
540550 test_pickle_dump_load (self .assertIs , Question .who )
541551 test_pickle_dump_load (self .assertIs , Question )
542552
553+ def test_enum_function_with_qualname (self ):
554+ if isinstance (Theory , Exception ):
555+ raise Theory
556+ self .assertEqual (Theory .__qualname__ , 'spanish_inquisition' )
557+
558+ def test_class_nested_enum_and_pickle_protocol_four (self ):
559+ # would normally just have this directly in the class namespace
560+ class NestedEnum (Enum ):
561+ twigs = 'common'
562+ shiny = 'rare'
563+
564+ self .__class__ .NestedEnum = NestedEnum
565+ self .NestedEnum .__qualname__ = '%s.NestedEnum' % self .__class__ .__name__
566+ test_pickle_exception (
567+ self .assertRaises , PicklingError , self .NestedEnum .twigs ,
568+ protocol = (0 , 3 ))
569+ test_pickle_dump_load (self .assertIs , self .NestedEnum .twigs ,
570+ protocol = (4 , HIGHEST_PROTOCOL ))
571+
543572 def test_exploding_pickle (self ):
544- BadPickle = Enum ('BadPickle' , 'dill sweet bread-n-butter' )
545- BadPickle . __qualname__ = 'BadPickle' # needed for pickle protocol 4
573+ BadPickle = Enum (
574+ 'BadPickle' , 'dill sweet bread-n-butter' , module = __name__ )
546575 globals ()['BadPickle' ] = BadPickle
547- enum ._make_class_unpicklable (BadPickle ) # will overwrite __qualname__
576+ # now break BadPickle to test exception raising
577+ enum ._make_class_unpicklable (BadPickle )
548578 test_pickle_exception (self .assertRaises , TypeError , BadPickle .dill )
549579 test_pickle_exception (self .assertRaises , PicklingError , BadPickle )
550580
@@ -927,6 +957,174 @@ class NEI(NamedInt, Enum):
927957 self .assertEqual (NEI .y .value , 2 )
928958 test_pickle_dump_load (self .assertIs , NEI .y )
929959
960+ def test_subclasses_with_getnewargs_ex (self ):
961+ class NamedInt (int ):
962+ __qualname__ = 'NamedInt' # needed for pickle protocol 4
963+ def __new__ (cls , * args ):
964+ _args = args
965+ name , * args = args
966+ if len (args ) == 0 :
967+ raise TypeError ("name and value must be specified" )
968+ self = int .__new__ (cls , * args )
969+ self ._intname = name
970+ self ._args = _args
971+ return self
972+ def __getnewargs_ex__ (self ):
973+ return self ._args , {}
974+ @property
975+ def __name__ (self ):
976+ return self ._intname
977+ def __repr__ (self ):
978+ # repr() is updated to include the name and type info
979+ return "{}({!r}, {})" .format (type (self ).__name__ ,
980+ self .__name__ ,
981+ int .__repr__ (self ))
982+ def __str__ (self ):
983+ # str() is unchanged, even if it relies on the repr() fallback
984+ base = int
985+ base_str = base .__str__
986+ if base_str .__objclass__ is object :
987+ return base .__repr__ (self )
988+ return base_str (self )
989+ # for simplicity, we only define one operator that
990+ # propagates expressions
991+ def __add__ (self , other ):
992+ temp = int (self ) + int ( other )
993+ if isinstance (self , NamedInt ) and isinstance (other , NamedInt ):
994+ return NamedInt (
995+ '({0} + {1})' .format (self .__name__ , other .__name__ ),
996+ temp )
997+ else :
998+ return temp
999+
1000+ class NEI (NamedInt , Enum ):
1001+ __qualname__ = 'NEI' # needed for pickle protocol 4
1002+ x = ('the-x' , 1 )
1003+ y = ('the-y' , 2 )
1004+
1005+
1006+ self .assertIs (NEI .__new__ , Enum .__new__ )
1007+ self .assertEqual (repr (NEI .x + NEI .y ), "NamedInt('(the-x + the-y)', 3)" )
1008+ globals ()['NamedInt' ] = NamedInt
1009+ globals ()['NEI' ] = NEI
1010+ NI5 = NamedInt ('test' , 5 )
1011+ self .assertEqual (NI5 , 5 )
1012+ test_pickle_dump_load (self .assertEqual , NI5 , 5 , protocol = (4 , 4 ))
1013+ self .assertEqual (NEI .y .value , 2 )
1014+ test_pickle_dump_load (self .assertIs , NEI .y , protocol = (4 , 4 ))
1015+
1016+ def test_subclasses_with_reduce (self ):
1017+ class NamedInt (int ):
1018+ __qualname__ = 'NamedInt' # needed for pickle protocol 4
1019+ def __new__ (cls , * args ):
1020+ _args = args
1021+ name , * args = args
1022+ if len (args ) == 0 :
1023+ raise TypeError ("name and value must be specified" )
1024+ self = int .__new__ (cls , * args )
1025+ self ._intname = name
1026+ self ._args = _args
1027+ return self
1028+ def __reduce__ (self ):
1029+ return self .__class__ , self ._args
1030+ @property
1031+ def __name__ (self ):
1032+ return self ._intname
1033+ def __repr__ (self ):
1034+ # repr() is updated to include the name and type info
1035+ return "{}({!r}, {})" .format (type (self ).__name__ ,
1036+ self .__name__ ,
1037+ int .__repr__ (self ))
1038+ def __str__ (self ):
1039+ # str() is unchanged, even if it relies on the repr() fallback
1040+ base = int
1041+ base_str = base .__str__
1042+ if base_str .__objclass__ is object :
1043+ return base .__repr__ (self )
1044+ return base_str (self )
1045+ # for simplicity, we only define one operator that
1046+ # propagates expressions
1047+ def __add__ (self , other ):
1048+ temp = int (self ) + int ( other )
1049+ if isinstance (self , NamedInt ) and isinstance (other , NamedInt ):
1050+ return NamedInt (
1051+ '({0} + {1})' .format (self .__name__ , other .__name__ ),
1052+ temp )
1053+ else :
1054+ return temp
1055+
1056+ class NEI (NamedInt , Enum ):
1057+ __qualname__ = 'NEI' # needed for pickle protocol 4
1058+ x = ('the-x' , 1 )
1059+ y = ('the-y' , 2 )
1060+
1061+
1062+ self .assertIs (NEI .__new__ , Enum .__new__ )
1063+ self .assertEqual (repr (NEI .x + NEI .y ), "NamedInt('(the-x + the-y)', 3)" )
1064+ globals ()['NamedInt' ] = NamedInt
1065+ globals ()['NEI' ] = NEI
1066+ NI5 = NamedInt ('test' , 5 )
1067+ self .assertEqual (NI5 , 5 )
1068+ test_pickle_dump_load (self .assertEqual , NI5 , 5 )
1069+ self .assertEqual (NEI .y .value , 2 )
1070+ test_pickle_dump_load (self .assertIs , NEI .y )
1071+
1072+ def test_subclasses_with_reduce_ex (self ):
1073+ class NamedInt (int ):
1074+ __qualname__ = 'NamedInt' # needed for pickle protocol 4
1075+ def __new__ (cls , * args ):
1076+ _args = args
1077+ name , * args = args
1078+ if len (args ) == 0 :
1079+ raise TypeError ("name and value must be specified" )
1080+ self = int .__new__ (cls , * args )
1081+ self ._intname = name
1082+ self ._args = _args
1083+ return self
1084+ def __reduce_ex__ (self , proto ):
1085+ return self .__class__ , self ._args
1086+ @property
1087+ def __name__ (self ):
1088+ return self ._intname
1089+ def __repr__ (self ):
1090+ # repr() is updated to include the name and type info
1091+ return "{}({!r}, {})" .format (type (self ).__name__ ,
1092+ self .__name__ ,
1093+ int .__repr__ (self ))
1094+ def __str__ (self ):
1095+ # str() is unchanged, even if it relies on the repr() fallback
1096+ base = int
1097+ base_str = base .__str__
1098+ if base_str .__objclass__ is object :
1099+ return base .__repr__ (self )
1100+ return base_str (self )
1101+ # for simplicity, we only define one operator that
1102+ # propagates expressions
1103+ def __add__ (self , other ):
1104+ temp = int (self ) + int ( other )
1105+ if isinstance (self , NamedInt ) and isinstance (other , NamedInt ):
1106+ return NamedInt (
1107+ '({0} + {1})' .format (self .__name__ , other .__name__ ),
1108+ temp )
1109+ else :
1110+ return temp
1111+
1112+ class NEI (NamedInt , Enum ):
1113+ __qualname__ = 'NEI' # needed for pickle protocol 4
1114+ x = ('the-x' , 1 )
1115+ y = ('the-y' , 2 )
1116+
1117+
1118+ self .assertIs (NEI .__new__ , Enum .__new__ )
1119+ self .assertEqual (repr (NEI .x + NEI .y ), "NamedInt('(the-x + the-y)', 3)" )
1120+ globals ()['NamedInt' ] = NamedInt
1121+ globals ()['NEI' ] = NEI
1122+ NI5 = NamedInt ('test' , 5 )
1123+ self .assertEqual (NI5 , 5 )
1124+ test_pickle_dump_load (self .assertEqual , NI5 , 5 )
1125+ self .assertEqual (NEI .y .value , 2 )
1126+ test_pickle_dump_load (self .assertIs , NEI .y )
1127+
9301128 def test_subclasses_without_getnewargs (self ):
9311129 class NamedInt (int ):
9321130 __qualname__ = 'NamedInt'
0 commit comments