diff -r aab7258a31d3 Lib/enum.py --- a/Lib/enum.py Fri Feb 07 13:04:18 2014 -0500 +++ b/Lib/enum.py Fri Feb 07 11:25:55 2014 -0800 @@ -461,20 +461,23 @@ class Enum(metaclass=EnumMeta): cls = self._member_type_ val = self.value return cls.__format__(val, format_spec) def __getnewargs__(self): return (self._value_, ) def __hash__(self): return hash(self._name_) + def __reduce__(self): + return self.__class__, self.__getnewargs__() + # DynamicClassAttribute is used to provide access to the `name` and # `value` properties of enum members while keeping some measure of # protection from modification, while still allowing for an enumeration # to have members named `name` and `value`. This works because enumeration # members are not set directly on the enum class -- __getattr__ is # used to look them up. @DynamicClassAttribute def name(self): """The name of the Enum member.""" diff -r aab7258a31d3 Lib/test/test_enum.py --- a/Lib/test/test_enum.py Fri Feb 07 13:04:18 2014 -0500 +++ b/Lib/test/test_enum.py Fri Feb 07 11:25:55 2014 -0800 @@ -57,25 +57,26 @@ try: class Fruit(Enum): tomato = 1 banana = 2 cherry = 3 except Exception: pass def test_pickle_dump_load(assertion, source, target=None): if target is None: target = source - for protocol in range(2, HIGHEST_PROTOCOL+1): + for protocol in range(HIGHEST_PROTOCOL+1): assertion(loads(dumps(source, protocol=protocol)), target) -def test_pickle_exception(assertion, exception, obj): - for protocol in range(2, HIGHEST_PROTOCOL+1): +def test_pickle_exception(assertion, exception, obj, + highest_protocol=HIGHEST_PROTOCOL): + for protocol in range(highest_protocol+1): with assertion(exception): dumps(obj, protocol=protocol) class TestHelpers(unittest.TestCase): # _is_descriptor, _is_sunder, _is_dunder def test_is_descriptor(self): class foo: pass for attr in ('__get__','__set__','__delete__'): @@ -533,24 +534,42 @@ class TestEnum(unittest.TestCase): raise Answer test_pickle_dump_load(self.assertIs, Answer.him) test_pickle_dump_load(self.assertIs, Answer) def test_pickle_enum_function_with_module(self): if isinstance(Question, Exception): raise Question test_pickle_dump_load(self.assertIs, Question.who) test_pickle_dump_load(self.assertIs, Question) + def test_class_nested_enum_and_pickle_protocol_four(self): + # would normally just have this directly in the class namespace + class NestedEnum(Enum): + twigs = 'common' + shiny = 'rare' + + self.__class__.NestedEnum = NestedEnum + self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ + test_pickle_exception( + self.assertRaises, PicklingError, + self.NestedEnum.twigs, highest_protocol=3) + self.assertIs( + loads(dumps(self.NestedEnum.twigs, protocol=4)), + self.NestedEnum.twigs) + def test_exploding_pickle(self): - BadPickle = Enum('BadPickle', 'dill sweet bread-n-butter') + # the proper way to construct an enum using the function API + BadPickle = Enum( + 'BadPickle', 'dill sweet bread-n-butter', module=__name__) BadPickle.__qualname__ = 'BadPickle' # needed for pickle protocol 4 - globals()['BadPickle'] = BadPickle + globals()['BadPickle'] = BadPickle # when monkey patching globals + # now break BadPickle to test exception raising enum._make_class_unpicklable(BadPickle) # will overwrite __qualname__ test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill) test_pickle_exception(self.assertRaises, PicklingError, BadPickle) def test_string_enum(self): class SkillLevel(str, Enum): master = 'what is the sound of one hand clapping?' journeyman = 'why did the chicken cross the road?' apprentice = 'knock, knock!' self.assertEqual(SkillLevel.apprentice, 'knock, knock!')