Skip to content

Commit

Permalink
pythongh-93820: Fix copy() regression in enum.Flag (pythonGH-93876)
Browse files Browse the repository at this point in the history
pythonGH-26658 introduced a regression in copy / pickle protocol for combined
`enum.Flag`s. `copy.copy(re.A | re.I)` would fail with
`AttributeError: ASCII|IGNORECASE`.

`enum.Flag` now has a `__reduce_ex__()` method that reduces flags by
combined value, not by combined name.
(cherry picked from commit 05b32c1)

Co-authored-by: Christian Heimes <christian@python.org>
  • Loading branch information
tiran authored and miss-islington committed Jun 16, 2022
1 parent 6e28032 commit 00d46e7
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,9 @@ class Flag(Enum, boundary=STRICT):
Support for flags
"""

def __reduce_ex__(self, proto):
return self.__class__, (self._value_, )

_numeric_repr_ = repr

def _generate_next_value_(name, start, count, last_values):
Expand Down
28 changes: 28 additions & 0 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import copy
import enum
import doctest
import inspect
Expand Down Expand Up @@ -732,6 +733,13 @@ def test_format_specs(self):
self.assertFormatIsValue('{:5.2}', TE.third)
self.assertFormatIsValue('{:f}', TE.third)

def test_copy(self):
TE = self.MainEnum
copied = copy.copy(TE)
self.assertEqual(copied, TE)
deep = copy.deepcopy(TE)
self.assertEqual(deep, TE)


class _FlagTests:

Expand Down Expand Up @@ -2652,6 +2660,26 @@ class MyIntFlag(int, Flag):
self.assertTrue(isinstance(MyIntFlag.ONE | MyIntFlag.TWO, MyIntFlag), MyIntFlag.ONE | MyIntFlag.TWO)
self.assertTrue(isinstance(MyIntFlag.ONE | 2, MyIntFlag))

def test_int_flags_copy(self):
class MyIntFlag(IntFlag):
ONE = 1
TWO = 2
FOUR = 4

flags = MyIntFlag.ONE | MyIntFlag.TWO
copied = copy.copy(flags)
deep = copy.deepcopy(flags)
self.assertEqual(copied, flags)
self.assertEqual(deep, flags)

flags = MyIntFlag.ONE | MyIntFlag.TWO | 8
copied = copy.copy(flags)
deep = copy.deepcopy(flags)
self.assertEqual(copied, flags)
self.assertEqual(deep, flags)
self.assertEqual(copied.value, 1 | 2 | 8)


class TestOrder(unittest.TestCase):
"test usage of the `_order_` attribute"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed a regression when :func:`copy.copy`-ing :class:`enum.Flag` with
multiple flag members.

0 comments on commit 00d46e7

Please sign in to comment.