8000 [3.11] gh-105497: [Enum] Fix Flag inversion when alias/mask members e… · python/cpython@3f244b2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3f244b2

Browse files
[3.11] gh-105497: [Enum] Fix Flag inversion when alias/mask members exist. (GH-105542) (#105571)
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>
1 parent ddfe8eb commit 3f244b2

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

Lib/enum.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,12 +1446,11 @@ def _missing_(cls, value):
14461446
else:
14471447
pseudo_member._name_ = None
14481448
# use setdefault in case another thread already created a composite
1449-
# with this value, but only if all members are known
1450-
# note: zero is a special case -- add it
1451-
if not unknown:
1452-
pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
1453-
if neg_value is not None:
1454-
cls._value2member_map_[neg_value] = pseudo_member
1449+
# with this value
1450+
# note: zero is a special case -- always add it
1451+
pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
1452+
if neg_value is not None:
1453+
cls._value2member_map_[neg_value] = pseudo_member
14551454
return pseudo_member
14561455

14571456
def __contains__(self, other):
@@ -1527,8 +1526,8 @@ def __invert__(self):
15271526
# use all bits
15281527
self._inverted_ = self.__class__(~self._value_)
15291528
else:
1530-
# calculate flags not in this member
1531-
self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_)
1529+
# use canonical bits (i.e. calculate flags not in this member)
1530+
self._inverted_ = self.__class__(self._singles_mask_ ^ self._value_)
15321531
if isinstance(self._inverted_, self.__class__):
15331532
self._inverted_._inverted_ = self
15341533
return self._inverted_

Lib/test/test_enum.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,6 +2913,33 @@ class Color(Flag):
29132913
WHITE = RED|GREEN|BLUE
29142914
BLANCO = RED|GREEN|BLUE
29152915

2916+
class Complete(Flag):
2917+
A = 0x01
2918+
B = 0x02
2919+
2920+
class Partial(Flag):
2921+
A = 0x01
2922+
B = 0x02
2923+
MASK = 0xff
2924+
2925+
class CompleteInt(IntFlag):
2926+
A = 0x01
2927+
B = 0x02
2928+
2929+
class PartialInt(IntFlag):
2930+
A = 0x01
2931+
B = 0x02
2932+
MASK = 0xff
2933+
2934+
class CompleteIntStrict(IntFlag, boundary=STRICT):
2935+
A = 0x01
2936+
B = 0x02
2937+
2938+
class PartialIntStrict(IntFlag, boundary=STRICT):
2939+
A = 0x01
2940+
B = 0x02
2941+
MASK = 0xff
2942+
29162943
def test_or(self):
29172944
Perm = self.Perm
29182945
for i in Perm:
@@ -2971,6 +2998,18 @@ def test_invert(self):
29712998
Open = self.Open
29722999
self.assertIs(Open.WO & ~Open.WO, Open.RO)
29733000
self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
3001+
Complete = self.Complete
3002+
self.assertIs(~Complete.A, Complete.B)
3003+
Partial = self.Partial
3004+
self.assertIs(~Partial.A, Partial.B)
3005+
CompleteInt = self.CompleteInt
3006+
self.assertIs(~CompleteInt.A, CompleteInt.B)
3007+
PartialInt = self.PartialInt
3008+
self.assertIs(~PartialInt.A, PartialInt(254))
3009+
CompleteIntStrict = self.CompleteIntStrict
3010+
self.assertIs(~CompleteIntStrict.A, CompleteIntStrict.B)
3011+
PartialIntStrict = self.PartialIntStrict
3012+
self.assertIs(~PartialIntStrict.A, PartialIntStrict.B)
29743013

29753014
def test_bool(self):
29763015
Perm = self.Perm
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix flag inversion when alias/mask members exist.

0 commit comments

Comments
 (0)
0