summaryrefslogtreecommitdiffstats
path: root/Lib/enum.py
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2021-06-10 22:52:09 (GMT)
committerGitHub <noreply@github.com>2021-06-10 22:52:09 (GMT)
commit62f1d2b3d7dda99598d053e10b785c463fdcf591 (patch)
treeca0da643fcceb26b1ed655b190794e47b6abbd00 /Lib/enum.py
parent05073036dcecefc00b0c3e7397601809da41e2f1 (diff)
downloadcpython-62f1d2b3d7dda99598d053e10b785c463fdcf591.zip
cpython-62f1d2b3d7dda99598d053e10b785c463fdcf591.tar.gz
cpython-62f1d2b3d7dda99598d053e10b785c463fdcf591.tar.bz2
bpo-44342: [Enum] changed pickling from by-value to by-name (GH-26658)
by-value lookups could fail on complex enums, necessitating a check for __reduce__ and possibly sabotaging the final enum; by-name lookups should never fail, and sabotaging is no longer necessary for class-based enum creation.
Diffstat (limited to 'Lib/enum.py')
-rw-r--r--Lib/enum.py25
1 files changed, 4 insertions, 21 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index 54633d8..5263e51 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -456,23 +456,6 @@ class EnumType(type):
classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1
classdict['_inverted_'] = None
#
- # If a custom type is mixed into the Enum, and it does not know how
- # to pickle itself, pickle.dumps will succeed but pickle.loads will
- # fail. Rather than have the error show up later and possibly far
- # from the source, sabotage the pickle protocol for this class so
- # that pickle.dumps also fails.
- #
- # However, if the new class implements its own __reduce_ex__, do not
- # sabotage -- it's on them to make sure it works correctly. We use
- # __reduce_ex__ instead of any of the others as it is preferred by
- # pickle over __reduce__, and it handles all pickle protocols.
- if '__reduce_ex__' not in classdict:
- if member_type is not object:
- methods = ('__getnewargs_ex__', '__getnewargs__',
- '__reduce_ex__', '__reduce__')
- if not any(m in member_type.__dict__ for m in methods):
- _make_class_unpicklable(classdict)
- #
# create a default docstring if one has not been provided
if '__doc__' not in classdict:
classdict['__doc__'] = 'An enumeration.'
@@ -792,7 +775,7 @@ class EnumType(type):
body['__module__'] = module
tmp_cls = type(name, (object, ), body)
cls = _simple_enum(etype=cls, boundary=boundary or KEEP)(tmp_cls)
- cls.__reduce_ex__ = _reduce_ex_by_name
+ cls.__reduce_ex__ = _reduce_ex_by_global_name
global_enum(cls)
module_globals[name] = cls
return cls
@@ -1030,7 +1013,7 @@ class Enum(metaclass=EnumType):
return hash(self._name_)
def __reduce_ex__(self, proto):
- return self.__class__, (self._value_, )
+ return getattr, (self.__class__, self._name_)
# enum.property is used to provide access to the `name` and
# `value` attributes of enum members while keeping some measure of
@@ -1091,7 +1074,7 @@ class StrEnum(str, Enum):
return name.lower()
-def _reduce_ex_by_name(self, proto):
+def _reduce_ex_by_global_name(self, proto):
return self.name
class FlagBoundary(StrEnum):
@@ -1795,6 +1778,6 @@ def _old_convert_(etype, name, module, filter, source=None, *, boundary=None):
# unless some values aren't comparable, in which case sort by name
members.sort(key=lambda t: t[0])
cls = etype(name, members, module=module, boundary=boundary or KEEP)
- cls.__reduce_ex__ = _reduce_ex_by_name
+ cls.__reduce_ex__ = _reduce_ex_by_global_name
cls.__repr__ = global_enum_repr
return cls