mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
issue23591: add Flags, IntFlags, and tests
This commit is contained in:
parent
bfbaa6b206
commit
ee47e5cf8a
2 changed files with 668 additions and 11 deletions
227
Lib/enum.py
227
Lib/enum.py
|
@ -1,5 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
from types import MappingProxyType, DynamicClassAttribute
|
from types import MappingProxyType, DynamicClassAttribute
|
||||||
|
from functools import reduce
|
||||||
|
from operator import or_ as _or_
|
||||||
|
|
||||||
# try _collections first to reduce startup cost
|
# try _collections first to reduce startup cost
|
||||||
try:
|
try:
|
||||||
|
@ -8,7 +10,7 @@ except ImportError:
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['EnumMeta', 'Enum', 'IntEnum', 'unique']
|
__all__ = ['EnumMeta', 'Enum', 'IntEnum', 'Flags', 'IntFlags', 'unique']
|
||||||
|
|
||||||
|
|
||||||
def _is_descriptor(obj):
|
def _is_descriptor(obj):
|
||||||
|
@ -64,7 +66,10 @@ class _EnumDict(dict):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if _is_sunder(key):
|
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')
|
raise ValueError('_names_ are reserved for future Enum use')
|
||||||
elif _is_dunder(key):
|
elif _is_dunder(key):
|
||||||
if key == '__order__':
|
if key == '__order__':
|
||||||
|
@ -75,7 +80,7 @@ class _EnumDict(dict):
|
||||||
elif not _is_descriptor(value):
|
elif not _is_descriptor(value):
|
||||||
if key in self:
|
if key in self:
|
||||||
# enum overwriting a descriptor?
|
# 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)
|
self._member_names.append(key)
|
||||||
super().__setitem__(key, value)
|
super().__setitem__(key, value)
|
||||||
|
|
||||||
|
@ -91,9 +96,15 @@ class EnumMeta(type):
|
||||||
"""Metaclass for Enum"""
|
"""Metaclass for Enum"""
|
||||||
@classmethod
|
@classmethod
|
||||||
def __prepare__(metacls, cls, bases):
|
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
|
# 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
|
# cannot be mixed with other types (int, float, etc.) if it has an
|
||||||
# inherited __new__ unless a new __new__ is defined (or the resulting
|
# 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
|
# save enum items into separate mapping so they don't get baked into
|
||||||
# the new class
|
# 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:
|
for name in classdict._member_names:
|
||||||
del classdict[name]
|
del classdict[name]
|
||||||
|
|
||||||
|
@ -112,7 +123,7 @@ class EnumMeta(type):
|
||||||
_order_ = classdict.pop('_order_', None)
|
_order_ = classdict.pop('_order_', None)
|
||||||
|
|
||||||
# check for illegal enum names (any others?)
|
# check for illegal enum names (any others?)
|
||||||
invalid_names = set(members) & {'mro', }
|
invalid_names = set(enum_members) & {'mro', }
|
||||||
if invalid_names:
|
if invalid_names:
|
||||||
raise ValueError('Invalid enum member name: {0}'.format(
|
raise ValueError('Invalid enum member name: {0}'.format(
|
||||||
','.join(invalid_names)))
|
','.join(invalid_names)))
|
||||||
|
@ -156,7 +167,7 @@ class EnumMeta(type):
|
||||||
# a custom __new__ is doing something funky with the values -- such as
|
# a custom __new__ is doing something funky with the values -- such as
|
||||||
# auto-numbering ;)
|
# auto-numbering ;)
|
||||||
for member_name in classdict._member_names:
|
for member_name in classdict._member_names:
|
||||||
value = members[member_name]
|
value = enum_members[member_name]
|
||||||
if not isinstance(value, tuple):
|
if not isinstance(value, tuple):
|
||||||
args = (value, )
|
args = (value, )
|
||||||
else:
|
else:
|
||||||
|
@ -170,7 +181,10 @@ class EnumMeta(type):
|
||||||
else:
|
else:
|
||||||
enum_member = __new__(enum_class, *args)
|
enum_member = __new__(enum_class, *args)
|
||||||
if not hasattr(enum_member, '_value_'):
|
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_
|
value = enum_member._value_
|
||||||
enum_member._name_ = member_name
|
enum_member._name_ = member_name
|
||||||
enum_member.__objclass__ = enum_class
|
enum_member.__objclass__ = enum_class
|
||||||
|
@ -344,13 +358,18 @@ class EnumMeta(type):
|
||||||
"""
|
"""
|
||||||
metacls = cls.__class__
|
metacls = cls.__class__
|
||||||
bases = (cls, ) if type is None else (type, cls)
|
bases = (cls, ) if type is None else (type, cls)
|
||||||
|
_, first_enum = cls._get_mixins_(bases)
|
||||||
classdict = metacls.__prepare__(class_name, bases)
|
classdict = metacls.__prepare__(class_name, bases)
|
||||||
|
|
||||||
# special processing needed for names?
|
# special processing needed for names?
|
||||||
if isinstance(names, str):
|
if isinstance(names, str):
|
||||||
names = names.replace(',', ' ').split()
|
names = names.replace(',', ' ').split()
|
||||||
if isinstance(names, (tuple, list)) and isinstance(names[0], str):
|
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.
|
# Here, names is either an iterable of (name, value) or a mapping.
|
||||||
for item in names:
|
for item in names:
|
||||||
|
@ -492,6 +511,16 @@ class Enum(metaclass=EnumMeta):
|
||||||
for member in cls._member_map_.values():
|
for member in cls._member_map_.values():
|
||||||
if member._value_ == value:
|
if member._value_ == value:
|
||||||
return member
|
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__))
|
raise ValueError("%r is not a valid %s" % (value, cls.__name__))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -585,6 +614,184 @@ class IntEnum(int, Enum):
|
||||||
def _reduce_ex_by_name(self, proto):
|
def _reduce_ex_by_name(self, proto):
|
||||||
return self.name
|
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):
|
def unique(enumeration):
|
||||||
"""Class decorator for enumerations ensuring unique member values."""
|
"""Class decorator for enumerations ensuring unique member values."""
|
||||||
duplicates = []
|
duplicates = []
|
||||||
|
|
|
@ -3,7 +3,7 @@ import inspect
|
||||||
import pydoc
|
import pydoc
|
||||||
import unittest
|
import unittest
|
||||||
from collections import OrderedDict
|
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 io import StringIO
|
||||||
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
|
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
|
||||||
from test import support
|
from test import support
|
||||||
|
@ -1633,6 +1633,456 @@ class TestOrder(unittest.TestCase):
|
||||||
verde = green
|
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):
|
class TestUnique(unittest.TestCase):
|
||||||
|
|
||||||
def test_unique_clean(self):
|
def test_unique_clean(self):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue