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

ethanfurman webhook-mailer at python.org
Fri Jun 9 11:56:12 EDT 2023


https://github.com/python/cpython/commit/59f009e5898a006cdc8f5249be589de6edfe5cd0
commit: 59f009e5898a006cdc8f5249be589de6edfe5cd0
branch: main
author: Ethan Furman <ethan at stoneleaf.us>
committer: ethanfurman <ethan at stoneleaf.us>
date: 2023-06-09T08:56:05-07:00
summary:

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.

files:
A Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst
M Lib/enum.py
M Lib/test/test_enum.py

diff --git a/Lib/enum.py b/Lib/enum.py
index a22bcca4fd87..47e31b17c2a4 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -1439,12 +1439,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):
@@ -1520,8 +1519,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_
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index 02dc7c1ff683..54b7d18d4541 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -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:
@@ -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
diff --git a/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst b/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst
new file mode 100644
index 000000000000..2d4e2091b507
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-06-08-17-49-46.gh-issue-105497.K6Q8nU.rst
@@ -0,0 +1 @@
+Fix flag inversion when alias/mask members exist.



More information about the Python-checkins mailing list