Skip to content

Commit

Permalink
[3.12] gh-105497: [Enum] Fix Flag inversion when alias/mask members e…
Browse files Browse the repository at this point in the history
…xist. (GH-105542) (#105572)

gh-105497: [Enum] Fix Flag inversion when alias/mask members exist. (GH-105542)

When inverting a Flag member (or boundary STRICT), only consider other canonical flags; when inverting an IntFlag member (or boundary KEEP), also consider aliases.
(cherry picked from commit 59f009e)

Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
  • Loading branch information
miss-islington and ethanfurman committed Jul 5, 2023
1 parent da672b2 commit 74d84cf
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
15 changes: 7 additions & 8 deletions Lib/enum.py
Expand Up @@ -1463,12 +1463,11 @@ def _missing_(cls, value):
else:
pseudo_member._name_ = None
# use setdefault in case another thread already created a composite
# with this value, but only if all members are known
# note: zero is a special case -- add it
if not unknown:
pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
if neg_value is not None:
cls._value2member_map_[neg_value] = pseudo_member
# with this value
# note: zero is a special case -- always add it
pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
if neg_value is not None:
cls._value2member_map_[neg_value] = pseudo_member
return pseudo_member

def __contains__(self, other):
Expand Down Expand Up @@ -1544,8 +1543,8 @@ def __invert__(self):
# use all bits
self._inverted_ = self.__class__(~self._value_)
else:
# calculate flags not in this member
self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_)
# use canonical bits (i.e. calculate flags not in this member)
self._inverted_ = self.__class__(self._singles_mask_ ^ self._value_)
if isinstance(self._inverted_, self.__class__):
self._inverted_._inverted_ = self
return self._inverted_
Expand Down
39 changes: 39 additions & 0 deletions Lib/test/test_enum.py
Expand Up @@ -3045,6 +3045,33 @@ class Color(Flag):
WHITE = RED|GREEN|BLUE
BLANCO = RED|GREEN|BLUE

class Complete(Flag):
A = 0x01
B = 0x02

class Partial(Flag):
A = 0x01
B = 0x02
MASK = 0xff

class CompleteInt(IntFlag):
A = 0x01
B = 0x02

class PartialInt(IntFlag):
A = 0x01
B = 0x02
MASK = 0xff

class CompleteIntStrict(IntFlag, boundary=STRICT):
A = 0x01
B = 0x02

class PartialIntStrict(IntFlag, boundary=STRICT):
A = 0x01
B = 0x02
MASK = 0xff

def test_or(self):
Perm = self.Perm
for i in Perm:
Expand Down Expand Up @@ -3103,6 +3130,18 @@ def test_invert(self):
Open = self.Open
self.assertIs(Open.WO & ~Open.WO, Open.RO)
self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
Complete = self.Complete
self.assertIs(~Complete.A, Complete.B)
Partial = self.Partial
self.assertIs(~Partial.A, Partial.B)
CompleteInt = self.CompleteInt
self.assertIs(~CompleteInt.A, CompleteInt.B)
PartialInt = self.PartialInt
self.assertIs(~PartialInt.A, PartialInt(254))
CompleteIntStrict = self.CompleteIntStrict
self.assertIs(~CompleteIntStrict.A, CompleteIntStrict.B)
PartialIntStrict = self.PartialIntStrict
self.assertIs(~PartialIntStrict.A, PartialIntStrict.B)

def test_bool(self):
Perm = self.Perm
Expand Down
@@ -0,0 +1 @@
Fix flag inversion when alias/mask members exist.

0 comments on commit 74d84cf

Please sign in to comment.