issue23591: add Flags, IntFlags, and tests

This commit is contained in:
Ethan Furman 2016-08-31 00:12:15 -07:00
parent bfbaa6b206
commit ee47e5cf8a
2 changed files with 668 additions and 11 deletions

View File

@ -1,5 +1,7 @@
import sys
from types import MappingProxyType, DynamicClassAttribute
from functools import reduce
from operator import or_ as _or_
# try _collections first to reduce startup cost
try:
@ -8,7 +10,7 @@ except ImportError:
from collections import OrderedDict
__all__ = ['EnumMeta', 'Enum', 'IntEnum', 'unique']
__all__ = ['EnumMeta', 'Enum', 'IntEnum', 'Flags', 'IntFlags', 'unique']
def _is_descriptor(obj):
@ -64,7 +66,10 @@ class _EnumDict(dict):
"""
if _is_sunder(key):
if key not in ('_order_', ):
if key not in (
'_order_', '_create_pseudo_member_', '_decompose_',
'_generate_next_value_', '_missing_',
):
raise ValueError('_names_ are reserved for future Enum use')
elif _is_dunder(key):
if key == '__order__':
@ -75,7 +80,7 @@ class _EnumDict(dict):
elif not _is_descriptor(value):
if key in self:
# enum overwriting a descriptor?
raise TypeError('Key already defined as: %r' % self[key])
raise TypeError('%r already defined as: %r' % (key, self[key]))
self._member_names.append(key)
super().__setitem__(key, value)
@ -91,9 +96,15 @@ class EnumMeta(type):
"""Metaclass for Enum"""
@classmethod
def __prepare__(metacls, cls, bases):
return _EnumDict()
# create the namespace dict
enum_dict = _EnumDict()
# inherit previous flags and _generate_next_value_ function
member_type, first_enum = metacls._get_mixins_(bases)
if first_enum is not None:
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
return enum_dict
def __new__(metacls, cls, bases, classdict):
def __new__(metacls, cls, bases, classdict, **kwds):
# an Enum class is final once enumeration items have been defined; it
# cannot be mixed with other types (int, float, etc.) if it has an
# inherited __new__ unless a new __new__ is defined (or the resulting
@ -104,7 +115,7 @@ class EnumMeta(type):
# save enum items into separate mapping so they don't get baked into
# the new class
members = {k: classdict[k] for k in classdict._member_names}
enum_members = {k: classdict[k] for k in classdict._member_names}
for name in classdict._member_names:
del classdict[name]
@ -112,7 +123,7 @@ class EnumMeta(type):
_order_ = classdict.pop('_order_', None)
# check for illegal enum names (any others?)
invalid_names = set(members) & {'mro', }
invalid_names = set(enum_members) & {'mro', }
if invalid_names:
raise ValueError('Invalid enum member name: {0}'.format(
','.join(invalid_names)))
@ -156,7 +167,7 @@ class EnumMeta(type):
# a custom __new__ is doing something funky with the values -- such as
# auto-numbering ;)
for member_name in classdict._member_names:
value = members[member_name]
value = enum_members[member_name]
if not isinstance(value, tuple):
args = (value, )
else:
@ -170,7 +181,10 @@ class EnumMeta(type):
else:
enum_member = __new__(enum_class, *args)
if not hasattr(enum_member, '_value_'):
enum_member._value_ = member_type(*args)
if member_type is object:
enum_member._value_ = value
else:
enum_member._value_ = member_type(*args)
value = enum_member._value_
enum_member._name_ = member_name
enum_member.__objclass__ = enum_class
@ -344,13 +358,18 @@ class EnumMeta(type):
"""
metacls = cls.__class__
bases = (cls, ) if type is None else (type, cls)
_, first_enum = cls._get_mixins_(bases)
classdict = metacls.__prepare__(class_name, bases)
# special processing needed for names?
if isinstance(names, str):
names = names.replace(',', ' ').split()
if isinstance(names, (tuple, list)) and isinstance(names[0], str):
names = [(e, i) for (i, e) in enumerate(names, start)]
original_names, names = names, []
last_value = None
for count, name in enumerate(original_names):
last_value = first_enum._generate_next_value_(name, start, count, last_value)
names.append((name, last_value))
# Here, names is either an iterable of (name, value) or a mapping.
for item in names:
@ -492,6 +511,16 @@ class Enum(metaclass=EnumMeta):
for member in cls._member_map_.values():
if member._value_ == value:
return member
# still not found -- try _missing_ hook
return cls._missing_(value)
@staticmethod
def _generate_next_value_(name, start, count, last_value):
if not count:
return start
return last_value + 1
@classmethod
def _missing_(cls, value):
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
def __repr__(self):
@ -585,6 +614,184 @@ class IntEnum(int, Enum):
def _reduce_ex_by_name(self, proto):
return self.name
class Flags(Enum):
"""Support for flags"""
@staticmethod
def _generate_next_value_(name, start, count, last_value):
"""
Generate the next value when not given.
name: the name of the member
start: the initital start value or None
count: the number of existing members
last_value: the last value assigned or None
"""
if not count:
return start if start is not None else 1
high_bit = _high_bit(last_value)
return 2 ** (high_bit+1)
@classmethod
def _missing_(cls, value):
original_value = value
if value < 0:
value = ~value
possible_member = cls._create_pseudo_member_(value)
for member in possible_member._decompose_():
if member._name_ is None and member._value_ != 0:
raise ValueError('%r is not a valid %s' % (original_value, cls.__name__))
if original_value < 0:
possible_member = ~possible_member
return possible_member
@classmethod
def _create_pseudo_member_(cls, value):
pseudo_member = cls._value2member_map_.get(value, None)
if pseudo_member is None:
# construct a non-singleton enum pseudo-member
pseudo_member = object.__new__(cls)
pseudo_member._name_ = None
pseudo_member._value_ = value
cls._value2member_map_[value] = pseudo_member
return pseudo_member
def _decompose_(self):
"""Extract all members from the value."""
value = self._value_
members = []
cls = self.__class__
for member in sorted(cls, key=lambda m: m._value_, reverse=True):
while _high_bit(value) > _high_bit(member._value_):
unknown = self._create_pseudo_member_(2 ** _high_bit(value))
members.append(unknown)
value &= ~unknown._value_
if (
(value & member._value_ == member._value_)
and (member._value_ or not members)
):
value &= ~member._value_
members.append(member)
if not members or value:
members.append(self._create_pseudo_member_(value))
members = list(members)
return members
def __contains__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return other._value_ & self._value_ == other._value_
def __iter__(self):
if self.value == 0:
return iter([])
else:
return iter(self._decompose_())
def __repr__(self):
cls = self.__class__
if self._name_ is not None:
return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_)
members = self._decompose_()
if len(members) == 1 and members[0]._name_ is None:
return '<%s: %r>' % (cls.__name__, members[0]._value_)
else:
return '<%s.%s: %r>' % (
cls.__name__,
'|'.join([str(m._name_ or m._value_) for m in members]),
self._value_,
)
def __str__(self):
cls = self.__class__
if self._name_ is not None:
return '%s.%s' % (cls.__name__, self._name_)
members = self._decompose_()
if len(members) == 1 and members[0]._name_ is None:
return '%s.%r' % (cls.__name__, members[0]._value_)
else:
return '%s.%s' % (
cls.__name__,
'|'.join([str(m._name_ or m._value_) for m in members]),
)
def __or__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__class__(self._value_ | other._value_)
def __and__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__class__(self._value_ & other._value_)
def __xor__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
return self.__class__(self._value_ ^ other._value_)
def __invert__(self):
members = self._decompose_()
inverted_members = [m for m in self.__class__ if m not in members and not m._value_ & self._value_]
inverted = reduce(_or_, inverted_members, self.__class__(0))
return self.__class__(inverted)
class IntFlags(int, Flags):
"""Support for integer-based Flags"""
@classmethod
def _create_pseudo_member_(cls, value):
pseudo_member = cls._value2member_map_.get(value, None)
if pseudo_member is None:
# construct a non-singleton enum pseudo-member
pseudo_member = int.__new__(cls, value)
pseudo_member._name_ = None
pseudo_member._value_ = value
cls._value2member_map_[value] = pseudo_member
return pseudo_member
@classmethod
def _missing_(cls, value):
possible_member = cls._create_pseudo_member_(value)
return possible_member
def __or__(self, other):
if not isinstance(other, (self.__class__, int)):
return NotImplemented
return self.__class__(self._value_ | self.__class__(other)._value_)
def __and__(self, other):
if not isinstance(other, (self.__class__, int)):
return NotImplemented
return self.__class__(self._value_ & self.__class__(other)._value_)
def __xor__(self, other):
if not isinstance(other, (self.__class__, int)):
return NotImplemented
return self.__class__(self._value_ ^ self.__class__(other)._value_)
__ror__ = __or__
__rand__ = __and__
__rxor__ = __xor__
def __invert__(self):
# members = self._decompose_()
# inverted_members = [m for m in self.__class__ if m not in members and not m._value_ & self._value_]
# inverted = reduce(_or_, inverted_members, self.__class__(0))
return self.__class__(~self._value_)
def _high_bit(value):
"""return the highest bit set in value"""
bit = 0
while 'looking for the highest bit':
limit = 2 ** bit
if limit > value:
return bit - 1
bit += 1
def unique(enumeration):
"""Class decorator for enumerations ensuring unique member values."""
duplicates = []

View File

@ -3,7 +3,7 @@ import inspect
import pydoc
import unittest
from collections import OrderedDict
from enum import Enum, IntEnum, EnumMeta, unique
from enum import Enum, IntEnum, EnumMeta, Flags, IntFlags, unique
from io import StringIO
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
from test import support
@ -1633,6 +1633,456 @@ class TestOrder(unittest.TestCase):
verde = green
class TestFlags(unittest.TestCase):
"""Tests of the Flags."""
class Perm(Flags):
R, W, X = 4, 2, 1
class Open(Flags):
RO = 0
WO = 1
RW = 2
AC = 3
CE = 1<<19
def test_str(self):
Perm = self.Perm
self.assertEqual(str(Perm.R), 'Perm.R')
self.assertEqual(str(Perm.W), 'Perm.W')
self.assertEqual(str(Perm.X), 'Perm.X')
self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
self.assertEqual(str(Perm(0)), 'Perm.0')
self.assertEqual(str(~Perm.R), 'Perm.W|X')
self.assertEqual(str(~Perm.W), 'Perm.R|X')
self.assertEqual(str(~Perm.X), 'Perm.R|W')
self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.0')
self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
Open = self.Open
self.assertEqual(str(Open.RO), 'Open.RO')
self.assertEqual(str(Open.WO), 'Open.WO')
self.assertEqual(str(Open.AC), 'Open.AC')
self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
self.assertEqual(str(~Open.RO), 'Open.CE|AC')
self.assertEqual(str(~Open.WO), 'Open.CE|RW')
self.assertEqual(str(~Open.AC), 'Open.CE')
self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
def test_repr(self):
Perm = self.Perm
self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
self.assertEqual(repr(Perm(0)), '<Perm: 0>')
self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
Open = self.Open
self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
self.assertEqual(repr(~Open.RO), '<Open.CE|AC: 524291>')
self.assertEqual(repr(~Open.WO), '<Open.CE|RW: 524290>')
self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
def test_or(self):
Perm = self.Perm
for i in Perm:
for j in Perm:
self.assertEqual((i | j), Perm(i.value | j.value))
self.assertEqual((i | j).value, i.value | j.value)
self.assertIs(type(i | j), Perm)
for i in Perm:
self.assertIs(i | i, i)
Open = self.Open
self.assertIs(Open.RO | Open.CE, Open.CE)
def test_and(self):
Perm = self.Perm
RW = Perm.R | Perm.W
RX = Perm.R | Perm.X
WX = Perm.W | Perm.X
RWX = Perm.R | Perm.W | Perm.X
values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
for i in values:
for j in values:
self.assertEqual((i & j).value, i.value & j.value)
self.assertIs(type(i & j), Perm)
for i in Perm:
self.assertIs(i & i, i)
self.assertIs(i & RWX, i)
self.assertIs(RWX & i, i)
Open = self.Open
self.assertIs(Open.RO & Open.CE, Open.RO)
def test_xor(self):
Perm = self.Perm
for i in Perm:
for j in Perm:
self.assertEqual((i ^ j).value, i.value ^ j.value)
self.assertIs(type(i ^ j), Perm)
for i in Perm:
self.assertIs(i ^ Perm(0), i)
self.assertIs(Perm(0) ^ i, i)
Open = self.Open
self.assertIs(Open.RO ^ Open.CE, Open.CE)
self.assertIs(Open.CE ^ Open.CE, Open.RO)
def test_invert(self):
Perm = self.Perm
RW = Perm.R | Perm.W
RX = Perm.R | Perm.X
WX = Perm.W | Perm.X
RWX = Perm.R | Perm.W | Perm.X
values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
for i in values:
self.assertIs(type(~i), Perm)
self.assertEqual(~~i, i)
for i in Perm:
self.assertIs(~~i, i)
Open = self.Open
self.assertIs(Open.WO & ~Open.WO, Open.RO)
self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
def test_programatic_function_string(self):
Perm = Flags('Perm', 'R W X')
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<i
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_string_with_start(self):
Perm = Flags('Perm', 'R W X', start=8)
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 8<<i
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_string_list(self):
Perm = Flags('Perm', ['R', 'W', 'X'])
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<i
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_iterable(self):
Perm = Flags('Perm', (('R', 2), ('W', 8), ('X', 32)))
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<(2*i+1)
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_from_dict(self):
Perm = Flags('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<(2*i+1)
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
class TestIntFlags(unittest.TestCase):
"""Tests of the IntFlags."""
class Perm(IntFlags):
X = 1 << 0
W = 1 << 1
R = 1 << 2
class Open(IntFlags):
RO = 0
WO = 1
RW = 2
AC = 3
CE = 1<<19
def test_str(self):
Perm = self.Perm
self.assertEqual(str(Perm.R), 'Perm.R')
self.assertEqual(str(Perm.W), 'Perm.W')
self.assertEqual(str(Perm.X), 'Perm.X')
self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
self.assertEqual(str(Perm.R | 8), 'Perm.8|R')
self.assertEqual(str(Perm(0)), 'Perm.0')
self.assertEqual(str(Perm(8)), 'Perm.8')
self.assertEqual(str(~Perm.R), 'Perm.W|X|-8')
self.assertEqual(str(~Perm.W), 'Perm.R|X|-8')
self.assertEqual(str(~Perm.X), 'Perm.R|W|-8')
self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X|-8')
self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm.-8')
self.assertEqual(str(~(Perm.R | 8)), 'Perm.W|X|-16')
self.assertEqual(str(Perm(~0)), 'Perm.R|W|X|-8')
self.assertEqual(str(Perm(~8)), 'Perm.R|W|X|-16')
Open = self.Open
self.assertEqual(str(Open.RO), 'Open.RO')
self.assertEqual(str(Open.WO), 'Open.WO')
self.assertEqual(str(Open.AC), 'Open.AC')
self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
self.assertEqual(str(Open.WO | Open.CE), 'Open.CE|WO')
self.assertEqual(str(Open(4)), 'Open.4')
self.assertEqual(str(~Open.RO), 'Open.CE|AC|-524292')
self.assertEqual(str(~Open.WO), 'Open.CE|RW|-524292')
self.assertEqual(str(~Open.AC), 'Open.CE|-524292')
self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC|-524292')
self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW|-524292')
self.assertEqual(str(Open(~4)), 'Open.CE|AC|-524296')
def test_repr(self):
Perm = self.Perm
self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
self.assertEqual(repr(Perm.R | 8), '<Perm.8|R: 12>')
self.assertEqual(repr(Perm(0)), '<Perm: 0>')
self.assertEqual(repr(Perm(8)), '<Perm: 8>')
self.assertEqual(repr(~Perm.R), '<Perm.W|X|-8: -5>')
self.assertEqual(repr(~Perm.W), '<Perm.R|X|-8: -3>')
self.assertEqual(repr(~Perm.X), '<Perm.R|W|-8: -2>')
self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X|-8: -7>')
self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: -8>')
self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X|-16: -13>')
self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X|-8: -1>')
self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X|-16: -9>')
Open = self.Open
self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
self.assertEqual(repr(Open.WO | Open.CE), '<Open.CE|WO: 524289>')
self.assertEqual(repr(Open(4)), '<Open: 4>')
self.assertEqual(repr(~Open.RO), '<Open.CE|AC|-524292: -1>')
self.assertEqual(repr(~Open.WO), '<Open.CE|RW|-524292: -2>')
self.assertEqual(repr(~Open.AC), '<Open.CE|-524292: -4>')
self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC|-524292: -524289>')
self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW|-524292: -524290>')
self.assertEqual(repr(Open(~4)), '<Open.CE|AC|-524296: -5>')
def test_or(self):
Perm = self.Perm
for i in Perm:
for j in Perm:
self.assertEqual(i | j, i.value | j.value)
self.assertEqual((i | j).value, i.value | j.value)
self.assertIs(type(i | j), Perm)
for j in range(8):
self.assertEqual(i | j, i.value | j)
self.assertEqual((i | j).value, i.value | j)
self.assertIs(type(i | j), Perm)
self.assertEqual(j | i, j | i.value)
self.assertEqual((j | i).value, j | i.value)
self.assertIs(type(j | i), Perm)
for i in Perm:
self.assertIs(i | i, i)
self.assertIs(i | 0, i)
self.assertIs(0 | i, i)
Open = self.Open
self.assertIs(Open.RO | Open.CE, Open.CE)
def test_and(self):
Perm = self.Perm
RW = Perm.R | Perm.W
RX = Perm.R | Perm.X
WX = Perm.W | Perm.X
RWX = Perm.R | Perm.W | Perm.X
values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
for i in values:
for j in values:
self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
for j in range(8):
self.assertEqual(i & j, i.value & j)
self.assertEqual((i & j).value, i.value & j)
self.assertIs(type(i & j), Perm)
self.assertEqual(j & i, j & i.value)
self.assertEqual((j & i).value, j & i.value)
self.assertIs(type(j & i), Perm)
for i in Perm:
self.assertIs(i & i, i)
self.assertIs(i & 7, i)
self.assertIs(7 & i, i)
Open = self.Open
self.assertIs(Open.RO & Open.CE, Open.RO)
def test_xor(self):
Perm = self.Perm
for i in Perm:
for j in Perm:
self.assertEqual(i ^ j, i.value ^ j.value)
self.assertEqual((i ^ j).value, i.value ^ j.value)
self.assertIs(type(i ^ j), Perm)
for j in range(8):
self.assertEqual(i ^ j, i.value ^ j)
self.assertEqual((i ^ j).value, i.value ^ j)
self.assertIs(type(i ^ j), Perm)
self.assertEqual(j ^ i, j ^ i.value)
self.assertEqual((j ^ i).value, j ^ i.value)
self.assertIs(type(j ^ i), Perm)
for i in Perm:
self.assertIs(i ^ 0, i)
self.assertIs(0 ^ i, i)
Open = self.Open
self.assertIs(Open.RO ^ Open.CE, Open.CE)
self.assertIs(Open.CE ^ Open.CE, Open.RO)
def test_invert(self):
Perm = self.Perm
RW = Perm.R | Perm.W
RX = Perm.R | Perm.X
WX = Perm.W | Perm.X
RWX = Perm.R | Perm.W | Perm.X
values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
for i in values:
self.assertEqual(~i, ~i.value)
self.assertEqual((~i).value, ~i.value)
self.assertIs(type(~i), Perm)
self.assertEqual(~~i, i)
for i in Perm:
self.assertIs(~~i, i)
Open = self.Open
self.assertIs(Open.WO & ~Open.WO, Open.RO)
self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
def test_programatic_function_string(self):
Perm = IntFlags('Perm', 'R W X')
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<i
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e, v)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_string_with_start(self):
Perm = IntFlags('Perm', 'R W X', start=8)
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 8<<i
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e, v)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_string_list(self):
Perm = IntFlags('Perm', ['R', 'W', 'X'])
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<i
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e, v)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_iterable(self):
Perm = IntFlags('Perm', (('R', 2), ('W', 8), ('X', 32)))
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<(2*i+1)
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e, v)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
def test_programatic_function_from_dict(self):
Perm = IntFlags('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
lst = list(Perm)
self.assertEqual(len(lst), len(Perm))
self.assertEqual(len(Perm), 3, Perm)
self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
for i, n in enumerate('R W X'.split()):
v = 1<<(2*i+1)
e = Perm(v)
self.assertEqual(e.value, v)
self.assertEqual(type(e.value), int)
self.assertEqual(e, v)
self.assertEqual(e.name, n)
self.assertIn(e, Perm)
self.assertIs(type(e), Perm)
class TestUnique(unittest.TestCase):
def test_unique_clean(self):