summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2016-09-02 16:32:32 -0700
committerEthan Furman <ethan@stoneleaf.us>2016-09-02 16:32:32 -0700
commit25d94bbf05f37151e7e6e3a2e1cd5af4a3e5f68c (patch)
tree910a33c185d1f732a9a7545a3e9460672b10318e
parent044395306702fc47e63b43d5ad961a127c19b262 (diff)
downloadcpython-git-25d94bbf05f37151e7e6e3a2e1cd5af4a3e5f68c.tar.gz
issue23591: bool(empty_flags) == False; more docs & tests
-rw-r--r--Doc/library/enum.rst62
-rw-r--r--Lib/enum.py3
-rw-r--r--Lib/test/test_enum.py16
3 files changed, 78 insertions, 3 deletions
diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst
index 72218b9545..7a5bb5ffd4 100644
--- a/Doc/library/enum.rst
+++ b/Doc/library/enum.rst
@@ -546,6 +546,10 @@ members also subclass :class:`int` and can be used wherever an :class:`int` is.
Any operation on an :class:`IntFlag` member besides the bit-wise operations
will lose the :class:`IntFlag` membership.
+.. versionadded:: 3.6
+
+Sample :class:`IntFlag` class::
+
>>> from enum import IntFlag
>>> class Perm(IntFlag):
... R = 4
@@ -560,19 +564,71 @@ will lose the :class:`IntFlag` membership.
>>> Perm.R in RW
True
-.. versionadded:: 3.6
+It is also possible to name the combinations::
+
+ >>> class Perm(IntFlag):
+ ... R = 4
+ ... W = 2
+ ... X = 1
+ ... RWX = 7
+ >>> Perm.RWX
+ <Perm.RWX: 7>
+ >>> ~Perm.RWX
+ <Perm.0: 0>
+
+Another important difference between :class:`IntFlag` and :class:`Enum` is that
+if no flags are set (the value is 0), its boolean evaluation is :data:`False`::
+
+ >>> Perm.R & Perm.X
+ <Perm.0: 0>
+ >>> bool(Perm.R & Perm.X)
+ False
+
+Because :class:`IntFlag` members are also subclasses of :class:`int` they can
+be combined with them::
+
+ >>> Perm.X | 8
+ <Perm.8|X: 9>
Flag
^^^^
The last variation is :class:`Flag`. Like :class:`IntFlag`, :class:`Flag`
-members can be combined using the bitwise operators (^, \|, ^, ~). Unlike
+members can be combined using the bitwise operators (&, \|, ^, ~). Unlike
:class:`IntFlag`, they cannot be combined with, nor compared against, any
-other :class:`Flag` enumeration nor :class:`int`.
+other :class:`Flag` enumeration, nor :class:`int`.
.. versionadded:: 3.6
+Like :class:`IntFlag`, if a combination of :class:`Flag` members results in no
+flags being set, the boolean evaluation is :data:`False`::
+
+ >>> from enum import Flag
+ >>> class Color(Flag):
+ ... red = 1
+ ... blue = 2
+ ... green = 4
+ ...
+ >>> Color.red & Color.green
+ <Color.0: 0>
+ >>> bool(Color.red & Color.green)
+ False
+
+Giving a name to the "no flags set" condition does not change its boolean
+value::
+
+ >>> class Color(Flag):
+ ... black = 0
+ ... red = 1
+ ... blue = 2
+ ... green = 4
+ ...
+ >>> Color.black
+ <Color.black: 0>
+ >>> bool(Color.black)
+ False
+
.. note::
For the majority of new code, :class:`Enum` and :class:`Flag` are strongly
diff --git a/Lib/enum.py b/Lib/enum.py
index 8d23933d3e..1e028a364f 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -714,6 +714,9 @@ class Flag(Enum):
'|'.join([str(m._name_ or m._value_) for m in members]),
)
+ def __bool__(self):
+ return bool(self._value_)
+
def __or__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index cfe1b18e9a..cf704edb1b 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -1767,6 +1767,14 @@ class TestFlag(unittest.TestCase):
self.assertIs(Open.WO & ~Open.WO, Open.RO)
self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
+ def test_bool(self):
+ Perm = self.Perm
+ for f in Perm:
+ self.assertTrue(f)
+ Open = self.Open
+ for f in Open:
+ self.assertEqual(bool(f.value), bool(f))
+
def test_programatic_function_string(self):
Perm = Flag('Perm', 'R W X')
lst = list(Perm)
@@ -2137,6 +2145,14 @@ class TestIntFlag(unittest.TestCase):
self.assertFalse(W in RX)
self.assertFalse(X in RW)
+ def test_bool(self):
+ Perm = self.Perm
+ for f in Perm:
+ self.assertTrue(f)
+ Open = self.Open
+ for f in Open:
+ self.assertEqual(bool(f.value), bool(f))
+
class TestUnique(unittest.TestCase):
def test_unique_clean(self):