diff options
Diffstat (limited to 'venv/Lib/site-packages/aenum/test.py')
-rw-r--r-- | venv/Lib/site-packages/aenum/test.py | 6832 |
1 files changed, 6832 insertions, 0 deletions
diff --git a/venv/Lib/site-packages/aenum/test.py b/venv/Lib/site-packages/aenum/test.py new file mode 100644 index 00000000..224293cb --- /dev/null +++ b/venv/Lib/site-packages/aenum/test.py @@ -0,0 +1,6832 @@ +# -*- coding: utf-8 -*- + +from __future__ import division, print_function +import sys +import aenum +import doctest +import os +import shutil +import tempfile +import textwrap +import unittest +import uuid +import warnings +from aenum import EnumType, EnumMeta, Enum, IntEnum, StrEnum, LowerStrEnum, UpperStrEnum +from aenum import AutoNumberEnum, MultiValueEnum, OrderedEnum, UniqueEnum, AddValueEnum, Flag, IntFlag +from aenum import NamedTuple, TupleSize, NamedConstant, constant, NoAlias, AddValue, Unique +from aenum import STRICT, CONFORM, EJECT, KEEP +from aenum import _reduce_ex_by_name, unique, skip, extend_enum, auto, enum, MultiValue, member, nonmember, no_arg +from aenum import basestring, baseinteger, unicode, enum_property +from aenum import pyver, PY2, PY3, PY2_6, PY3_3, PY3_4, PY3_5, PY3_6, PY3_11 +from collections import OrderedDict +from datetime import timedelta +from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL +from operator import or_ as _or_, and_ as _and_, xor as _xor_, inv as _inv_ +from operator import abs as _abs_, add as _add_, floordiv as _floordiv_ +from operator import lshift as _lshift_, rshift as _rshift_, mod as _mod_ +from operator import mul as _mul_, neg as _neg_, pos as _pos_, pow as _pow_ +from operator import truediv as _truediv_, sub as _sub_ +if PY2: + from operator import div as _div_ +try: + import threading +except ImportError: + threading = None + +try: + any +except NameError: + from aenum import any + +MODULE = __name__ +SHORT_MODULE = MODULE.split('.')[-1] + +def load_tests(loader, tests, ignore): + tests.addTests(doctest.DocTestSuite(aenum)) + tests.addTests(doctest.DocFileSuite( + 'doc/aenum.rst', + package=aenum, + optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, + )) + return tests + +class TestCase(unittest.TestCase): + + def __init__(self, *args, **kwds): + regex = getattr(self, 'assertRaisesRegex', None) + if regex is None: + self.assertRaisesRegex = getattr(self, 'assertRaisesRegexp') + super(TestCase, self).__init__(*args, **kwds) + + +# for pickle tests +try: + class Stooges(Enum): + LARRY = 1 + CURLY = 2 + MOE = 3 +except Exception: + Stooges = sys.exc_info()[1] + +try: + class IntStooges(int, Enum): + LARRY = 1 + CURLY = 2 + MOE = 3 +except Exception: + IntStooges = sys.exc_info()[1] + +try: + class FloatStooges(float, Enum): + LARRY = 1.39 + CURLY = 2.72 + MOE = 3.142596 +except Exception: + FloatStooges = sys.exc_info()[1] + +try: + class FlagStooges(Flag): + LARRY = 1 + CURLY = 2 + MOE = 3 +except Exception as exc: + FlagStooges = exc + +try: + LifeForm = NamedTuple('LifeForm', 'branch genus species', module=__name__) +except Exception: + LifeForm = sys.exc_info()[1] + +try: + class DeathForm(NamedTuple): + color = 0 + rigidity = 1 + odor = 2 +except Exception: + DeathForm = sys.exc_info()[1] + +# for pickle test and subclass tests +try: + class Name(StrEnum): + BDFL = 'Guido van Rossum' + FLUFL = 'Barry Warsaw' +except Exception: + Name = sys.exc_info()[1] + +try: + Question = Enum('Question', 'who what when where why', module=__name__) +except Exception: + Question = sys.exc_info()[1] + +try: + Answer = Enum('Answer', 'him this then there because') +except Exception: + Answer = sys.exc_info()[1] + +try: + class WhatsIt(NamedTuple): + def what(self): + return self[0] + class ThatsIt(WhatsIt): + blah = 0 + bleh = 1 +except Exception: + ThatsIt = sys.exc_info()[1] + +# for doctests +try: + class Fruit(Enum): + tomato = 1 + banana = 2 + cherry = 3 +except Exception: + pass + +def test_pickle_dump_load(assertion, source, target=None, protocol=(0, HIGHEST_PROTOCOL)): + start, stop = protocol + failures = [] + for protocol in range(start, stop+1): + try: + if target is None: + assertion(loads(dumps(source, protocol=protocol)), source) + else: + assertion(loads(dumps(source, protocol=protocol)), target) + except Exception: + exc, tb = sys.exc_info()[1:] + failures.append('%2d: %s' %(protocol, exc)) + if failures: + raise ValueError('Failed with protocols: %s' % ', '.join(failures)) + +def test_pickle_exception(assertion, exception, obj, + protocol=(0, HIGHEST_PROTOCOL)): + start, stop = protocol + failures = [] + for protocol in range(start, stop+1): + try: + assertion(exception, dumps, obj, protocol=protocol) + except Exception: + exc = sys.exc_info()[1] + failures.append('%d: %s %s' % (protocol, exc.__class__.__name__, exc)) + if failures: + raise ValueError('Failed with protocols: %s' % ', '.join(failures)) + +if PY3: + from aenum.test_v3 import TestEnumV3, TestOrderV3, TestNamedTupleV3, TestStackoverflowAnswersV3, TestIssuesV3, TestExtendEnumV3 + from aenum import test_v3 + test_v3.IntStooges = IntStooges + test_v3.test_pickle_exception = test_pickle_exception + test_v3.test_pickle_dump_load = test_pickle_dump_load + +# for subclassing tests + +class classproperty(object): + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + self.fget = fget + self.fset = fset + self.fdel = fdel + if doc is None and fget is not None: + doc = fget.__doc__ + self.__doc__ = doc + + def __get__(self, instance, ownerclass): + return self.fget(ownerclass) + + +# tests +class TestOrder(TestCase): + """ + Test _order_ extra/missing members. + """ + + def test_same_members(self): + class Color(Enum): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 3 + + def test_same_members_with_aliases(self): + class Color(Enum): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 3 + verde = green + + def test_order_has_extra_members(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Enum): + _order_ = 'red green blue purple' + red = 1 + green = 2 + blue = 3 + + def test_order_has_extra_members_with_aliases(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Enum): + _order_ = 'red green blue purple' + red = 1 + green = 2 + blue = 3 + verde = green + + def test_enum_has_extra_members(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Enum): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 3 + purple = 4 + + def test_enum_has_extra_members_with_aliases(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Enum): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 3 + purple = 4 + verde = green + + def test_same_members_flag(self): + class Color(Flag): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 4 + + def test_same_members_with_aliases_flag(self): + class Color(Flag): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 4 + verde = green + + def test_order_has_extra_members_flag(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Flag): + _order_ = 'red green blue purple' + red = 1 + green = 2 + blue = 4 + + def test_order_has_extra_members_with_aliases_flag(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Flag): + _order_ = 'red green blue purple' + red = 1 + green = 2 + blue = 4 + verde = green + + def test_enum_has_extra_members_flag(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Flag): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 4 + purple = 8 + + def test_enum_has_extra_members_with_aliases_flag(self): + with self.assertRaisesRegex(TypeError, r'member order does not match _order_'): + class Color(Flag): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 4 + purple = 8 + verde = green + + +class TestAutoValue(TestCase): + + def test_bare(self): + # + class BareEnum(Enum): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(BareEnum.THREE.value, 3) + # + class BareIntEnum(IntEnum): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(BareIntEnum.THREE, 3) + # + class BareFlag(Flag): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(BareFlag.THREE.value, 4) + # + class BareIntFlag(IntFlag): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(BareIntFlag.THREE, 4) + + def test_init_only_final(self): + # + class InitEnumValue(Enum): + _init_ = 'value description' + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitEnumValue.THREE.value, 3) + self.assertEqual(InitEnumValue.THREE.description, 'a triangle') + # + class InitEnum(Enum): + _init_ = 'value description' + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitEnum.THREE.value, 3) + self.assertEqual(InitEnum.THREE.description, 'a triangle') + # + class InitIntEnum(IntEnum): + _init_ = 'value description' + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitIntEnum.THREE, 3) + self.assertEqual(InitIntEnum.THREE.description, 'a triangle') + # + class InitFlag(Flag): + _init_ = 'value description' + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitFlag.THREE.value, 4) + self.assertEqual(InitFlag.THREE.description, 'a triangle') + # + class InitIntFlag(IntFlag): + _init_ = 'value description' + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitIntFlag.THREE, 4) + self.assertEqual(InitIntFlag.THREE.description, 'a triangle') + + def test_init_only_inherit(self): + # + class InitInheritEnum(Enum): + _init_ = 'value description' + # + class InitEnum(InitInheritEnum): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitEnum.THREE.value, 3) + self.assertEqual(InitEnum.THREE.description, 'a triangle') + # + # + class InitInheritValueEnum(Enum): + _init_ = 'value description' + # + class InitEnum(InitInheritValueEnum): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitEnum.THREE.value, 3) + self.assertEqual(InitEnum.THREE.description, 'a triangle') + # + class InitIntEnum(int, InitInheritValueEnum): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitIntEnum.THREE, 3) + self.assertEqual(InitIntEnum.THREE.description, 'a triangle') + # + class InitInheritValueFlag(Flag): + _init_ = 'value description' + # + class InitFlag(InitInheritValueFlag): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitFlag.THREE.value, 4) + self.assertEqual(InitFlag.THREE.description, 'a triangle') + # + class InitIntFlag(int, InitInheritValueFlag): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitIntFlag.THREE, 4) + self.assertEqual(InitIntFlag.THREE.description, 'a triangle') + + def test_new_only_final(self): + # + class NewFinalEnum(Enum): + _order_ = 'ONE TWO THREE' + def __new__(cls, value): + member = object.__new__(cls) + member._value_ = value + member.proof = 'NFE1' + return member + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalEnum.THREE.value, 3) + self.assertEqual(NewFinalEnum.TWO.proof, 'NFE1') + # + class NewFinalIntEnum(IntEnum): + _order_ = 'ONE TWO THREE' + def __new__(cls, value): + member = int.__new__(cls, value) + member._value_ = value + member.proof = 'NFE2' + return member + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalIntEnum.THREE, 3) + self.assertEqual(NewFinalIntEnum.TWO.proof, 'NFE2') + # + class NewFinalFlag(Flag): + _order_ = 'ONE TWO THREE' + def __new__(cls, value): + member = object.__new__(cls) + member._value_ = value + member.proof = 'NFE3' + return member + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalFlag.THREE.value, 4) + self.assertEqual(NewFinalFlag.TWO.proof, 'NFE3') + # + class NewFinalIntFlag(IntFlag): + _order_ = 'ONE TWO THREE' + def __new__(cls, value): + member = int.__new__(cls, value) + member._value_ = value + member.proof = 'NFE4' + return member + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalIntFlag.THREE, 4) + self.assertEqual(NewFinalIntFlag.TWO.proof, 'NFE4') + # + class NewFinalStrEnum(str, Enum): + # + _order_ = "AllReset Bright FG_Cyan BG_Black" + # + def __new__(cls, value, code, description): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + obj.description = description + return obj + # + __str__ = str.__str__ + # + AllReset = '0', 'reset all (colors and brightness)' + Bright = '1', 'bright lights!' + FG_Cyan = '36', 'cyan' + BG_Black = '40', 'black' + self.assertEqual(NewFinalStrEnum.FG_Cyan.value, 3) + self.assertEqual(NewFinalStrEnum.BG_Black.value, 4) + self.assertEqual(NewFinalStrEnum.AllReset.code, '0') + self.assertEqual(NewFinalStrEnum.Bright.description, 'bright lights!') + # + class NewFinalStrFlag(str, Flag): + # + _order_ = "AllReset Bright FG_Cyan BG_Black" + # + def __new__(cls, value, code, description): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + obj.description = description + return obj + # + __str__ = str.__str__ + # + AllReset = '0', 'reset all (colors and brightness)' + Bright = '1', 'bright lights!' + FG_Cyan = '36', 'cyan' + BG_Black = '40', 'black' + self.assertEqual(NewFinalStrFlag.FG_Cyan.value, 4) + self.assertEqual(NewFinalStrFlag.BG_Black.value, 8) + self.assertEqual(NewFinalStrFlag.AllReset.code, '0') + self.assertEqual(NewFinalStrFlag.Bright.description, 'bright lights!') + + def test_new_only_inherited(self): + # + class NewInheritEnum(Enum): + def __new__(cls, value): + if cls._member_type_ is int: + member = int.__new__(cls, value*2) + else: + member = object.__new__(cls) + member._value_ = value * 2 + member.proof = 'NIE' + return member + # + class NewFinalEnum(NewInheritEnum): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalEnum.THREE.value, 6) + self.assertEqual(NewFinalEnum.TWO.proof, 'NIE') + # + class NewFinalIntEnum(int, NewInheritEnum): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalIntEnum.THREE, 6) + self.assertEqual(NewFinalIntEnum.TWO.proof, 'NIE') + # + class NewInheritFlag(Flag): + def __new__(cls, value): + if cls._member_type_ is int: + member = int.__new__(cls, value*2) + else: + member = object.__new__(cls) + member._value_ = value * 2 + member.proof = 'NIE' + return member + # + class NewFinalFlag(NewInheritFlag): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalFlag.THREE.value, 8) + self.assertEqual(NewFinalFlag.TWO.proof, 'NIE') + # + class NewFinalIntFlag(int, NewInheritFlag): + _order_ = 'ONE TWO THREE' + ONE = auto() + TWO = auto() + THREE = auto() + self.assertEqual(NewFinalIntFlag.THREE, 8) + self.assertEqual(NewFinalIntFlag.TWO.proof, 'NIE') + + def test_init_new_only(self): + # + class InitNewEnum(Enum): + _init_ = "value description" + _order_ = 'ONE TWO THREE' + def __new__(cls, value, *args): + member = object.__new__(cls) + member._value_ = value + member.proof = 'INE1' + return member + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewEnum.THREE.value, 3) + self.assertEqual(InitNewEnum.THREE.description, 'a triangle') + self.assertEqual(InitNewEnum.TWO.proof, 'INE1') + # + class InitNewIntEnum(IntEnum): + _init_ = "value description" + _order_ = 'ONE TWO THREE' + def __new__(cls, value, *args): + member = int.__new__(cls, value) + member._value_ = value + member.proof = 'INE2' + return member + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewIntEnum.THREE, 3) + self.assertEqual(InitNewIntEnum.THREE.description, 'a triangle') + self.assertEqual(InitNewIntEnum.TWO.proof, 'INE2') + # + class InitNewFlag(Flag): + _init_ = "value description" + _order_ = 'ONE TWO THREE' + def __new__(cls, value, *args): + member = object.__new__(cls) + member._value_ = value + member.proof = 'INE3' + return member + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewFlag.THREE.value, 4) + self.assertEqual(InitNewFlag.THREE.description, 'a triangle') + self.assertEqual(InitNewFlag.TWO.proof, 'INE3') + # + class InitNewIntFlag(IntFlag): + _init_ = "value description" + _order_ = 'ONE TWO THREE' + def __new__(cls, value, *args): + member = int.__new__(cls, value) + member._value_ = value + member.proof = 'INE4' + return member + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewIntFlag.THREE, 4) + self.assertEqual(InitNewIntFlag.THREE.description, 'a triangle') + self.assertEqual(InitNewIntFlag.TWO.proof, 'INE4') + + def test_init_new_inherit(self): + # + class InitNew(Enum): + _init_ = "value description" + def __new__(cls, value, *args): + member = object.__new__(cls) + member._value_ = value + member.proof = 'IN' + return member + # + class InitNewEnum(InitNew): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewEnum.THREE.value, 3) + self.assertEqual(InitNewEnum.THREE.description, 'a triangle') + self.assertEqual(InitNewEnum.TWO.proof, 'IN') + # + class InitNewInt(Enum): + _init_ = "value description" + def __new__(cls, value, *args): + member = int.__new__(cls, value) + member._value_ = value + member.proof = 'IN' + return member + # + class InitNewIntEnum(int, InitNewInt): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewIntEnum.THREE, 3) + self.assertEqual(InitNewIntEnum.THREE.description, 'a triangle') + self.assertEqual(InitNewIntEnum.TWO.proof, 'IN') + # + class InitNewFlagBase(Flag): + _init_ = "value description" + def __new__(cls, value, *args): + member = object.__new__(cls) + member._value_ = value + member.proof = 'IN' + return member + # + class InitNewFlag(InitNewFlagBase): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewFlag.THREE.value, 4) + self.assertEqual(InitNewFlag.THREE.description, 'a triangle') + self.assertEqual(InitNewFlag.TWO.proof, 'IN') + # + class InitNewIntFlagBase(int, Flag): + _init_ = "value description" + def __new__(cls, value, *args): + member = int.__new__(cls, value) + member._value_ = value + member.proof = 'IN' + return member + # + class InitNewIntFlag(InitNewIntFlagBase): + _order_ = 'ONE TWO THREE' + ONE = 'the loneliest number' + TWO = 'the number with you' + THREE = 'a triangle' + self.assertEqual(InitNewIntFlag.THREE, 4) + self.assertEqual(InitNewIntFlag.THREE.description, 'a triangle') + self.assertEqual(InitNewIntFlag.TWO.proof, 'IN') + + +class TestHelpers(TestCase): + # _is_descriptor, _is_sunder, _is_dunder + + def test_is_descriptor(self): + class foo: + pass + for attr in ('__get__','__set__','__delete__'): + obj = foo() + self.assertFalse(aenum._is_descriptor(obj)) + setattr(obj, attr, 1) + self.assertTrue(aenum._is_descriptor(obj)) + + def test_is_sunder(self): + for s in ('_a_', '_aa_'): + self.assertTrue(aenum._is_sunder(s)) + + for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_', + '__', '___', '____', '_____',): + self.assertFalse(aenum._is_sunder(s)) + + def test_is_dunder(self): + for s in ('__a__', '__aa__'): + self.assertTrue(aenum._is_dunder(s)) + for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_', + '__', '___', '____', '_____',): + self.assertFalse(aenum._is_dunder(s)) + + def test_auto(self): + def tester(first, op, final, second=None): + if second is None: + left = auto() + value = op(left) + left.value = first + self.assertEqual(value.value, final, + "%s %r -> %r != %r" % (op.__name__, first, value, final)) + else: + left = first + right = auto() + value = op(left, right) + right.value = second + self.assertEqual(value.value, final, + "forward: %r %s %r -> %r != %r" % (first, op.__name__, second, value.value, final)) + left = auto() + right = second + value = op(left, right) + left.value = first + self.assertEqual(value.value, final, + "reversed: %r %s %r -> %r != %r" % (second, op.__name__, first, value.value, final)) + for args in ( + (1, _abs_, abs(1)), + (-3, _abs_, abs(-3)), + (1, _add_, 1+2, 2), + (25, _floordiv_, 25 // 5, 5), + (49, _truediv_, 49 / 9, 9), + (6, _mod_, 6 % 9, 9), + (5, _lshift_, 5 << 2, 2), + (5, _rshift_, 5 >> 2, 2), + (3, _mul_, 3 * 6, 6), + (5, _neg_, -5), + (-4, _pos_, +(-4)), + (2, _pow_, 2**5, 5), + (7, _sub_, 7 - 10, 10), + (1, _or_, 1 | 2, 2), + (3, _xor_, 3 ^ 6, 6), + (3, _and_, 3 & 6, 6), + (7, _inv_, ~7), + ('a', _add_, 'a'+'b', 'b'), + ('a', _mul_, 'a' * 3, 3), + ): + tester(*args) + # operator.div is gone in 3 + if PY2: + tester(12, _div_, 12 // 5, 5) + # strings are a pain + left = auto() + right = 'eggs' + value = _mod_(left, right) + left.value = 'I see 17 %s!' + self.assertEqual(value.value, 'I see 17 %s!' % 'eggs') + + def test_constant(self): + errors = [] + def tester(first, op, final, second=None): + if second is None: + primary = constant(first) + secondary = constant(op(primary)) + if secondary.value != final: + errors.append( + "%s %r -> %r != %r" % (op.__name__, first, secondary.value, final), + ) + else: + left = constant(first) + right = second + value = op(left, right) + if value != final: + errors.append( + "forward: %r %s %r -> %r != %r" % (first, op.__name__, second, value, final), + ) + left = first + right = constant(second) + value = op(left, right) + if value != final: + errors.append( + "reversed: %r %s %r -> %r != %r" % (second, op.__name__, first, value, final), + ) + for args in ( + (1, _abs_, abs(1)), + (-3, _abs_, abs(-3)), + (1, _add_, 1+2, 2), + (25, _floordiv_, 25 // 5, 5), + (49, _truediv_, 49 / 9, 9), + (6, _mod_, 6 % 9, 9), + (5, _lshift_, 5 << 2, 2), + (5, _rshift_, 5 >> 2, 2), + (3, _mul_, 3 * 6, 6), + (5, _neg_, -5), + (-4, _pos_, +(-4)), + (2, _pow_, 2**5, 5), + (7, _sub_, 7 - 10, 10), + (1, _or_, 1 | 2, 2), + (3, _xor_, 3 ^ 6, 6), + (3, _and_, 3 & 6, 6), + (7, _inv_, ~7), + ('a', _add_, 'a'+'b', 'b'), + ('a', _mul_, 'a' * 3, 3), + ): + tester(*args) + # operator.div is gone in 3 + if PY2: + tester(12, _div_, 12 // 5, 5) + # strings are a pain + left = constant('I see 17 %s!') + right = 'eggs' + value = _mod_(left, right) + if value != 'I see 17 %s!' % 'eggs': + errors.append("'I see 17 eggs!' != %r" % value) + if errors: + print() + for error in errors: + print(error) + self.assertTrue(False) + + +class TestEnumType(TestCase): + + def test_immutability(self): + class Hah(object): + @classproperty + def all_values(cls): + return [m.value for m in cls] + class Huh(Hah, Enum): + one = 1 + two = 2 + self.assertRaisesRegex(AttributeError, 'cannot rebind property', setattr, Huh, 'value', 'boom') + self.assertRaisesRegex(AttributeError, 'cannot delete property', delattr, Huh, 'value') + self.assertRaisesRegex(AttributeError, 'cannot set attribute', setattr, Huh.one, 'value', 'boom') + self.assertRaisesRegex(AttributeError, 'cannot delete attribute', delattr, Huh.two, 'value') + self.assertEqual(Huh.one.value, 1) + self.assertEqual(Huh.two.value, 2) + self.assertEqual(Huh.all_values, [1, 2]) + setattr(Huh, 'all_values', 99) + self.assertEqual(Huh.all_values, 99) + + def test_enum_shadow_base(self): + class hohum(object): + def cyan(self): + "cyanize a color" + return self.value * 'cyan' + @property + def azure(self): + return 'azure ' + self.name + class Color(hohum, Enum): + red = 1 + green = 2 + blue = 3 + cyan = 4 + azure = 5 + self.assertEqual(len(Color), 5) + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.cyan, Color.azure]) + self.assertRaisesRegex(AttributeError, 'no attribute .cyan.', lambda: Color.blue.cyan) + self.assertEqual(Color.red.azure, 'azure red') + + +class TestEnum(TestCase): + + def setUp(self): + class Season(Enum): + SPRING = 1 + SUMMER = 2 + AUTUMN = 3 + WINTER = 4 + self.Season = Season + + class Konstants(float, Enum): + E = 2.7182818 + PI = 3.1415926 + TAU = 2 * PI + self.Konstants = Konstants + + class Grades(IntEnum): + A = 5 + B = 4 + C = 3 + D = 2 + F = 0 + self.Grades = Grades + + class Directional(str, Enum): + EAST = 'east' + WEST = 'west' + NORTH = 'north' + SOUTH = 'south' + self.Directional = Directional + + from datetime import date + class Holiday(date, Enum): + NEW_YEAR = 2013, 1, 1 + IDES_OF_MARCH = 2013, 3, 15 + self.Holiday = Holiday + + def test_set_name(self): + class Descriptor(object): + name = None + def __get__(self, instance, owner_class=None): + if instance is None: + return self + else: + return instance.__dict__[self.name] + def __set__(self, instance, value): + instance.__dict__[self.name] = value + def __set_name__(self, owner, name): + self.name = name + # + class AnEnum(Enum): + ONE = 'one' + two = Descriptor() + # + self.assertEqual(list(AnEnum), [AnEnum.ONE]) + self.assertEqual(AnEnum.two.name, 'two') + AnEnum.ONE.two = 'three' + self.assertEqual(AnEnum.ONE.two, 'three') + self.assertEqual(AnEnum.ONE.__dict__['two'], 'three') + + def test_private_names(self): + class Private(Enum): + __corporal = 'Radar' + __major_ = 'Hoolihan' + self.assertEqual(len(Private), 0) + self.assertEqual(Private._Private__corporal, 'Radar') + self.assertFalse(isinstance(Private._Private__corporal, Enum)) + self.assertEqual(Private._Private__major_, 'Hoolihan') + self.assertFalse(isinstance(Private._Private__major_, Enum)) + + def test_new_with_keywords(self): + class Huh(IntEnum): + __order__ = 'PLAIN BOLD_ITALIC HIGHLIGHT' + def __new__(cls, docstring, open=None, close=None): + value = len(cls.__members__) + member = int.__new__(cls, value) + if open and close is None: + close = open + member.open = open + member.close = close + member.__doc__ = docstring + member._value_ = value + return member + PLAIN = 'normal' + BOLD_ITALIC = '***really super important***', '***' + HIGHLIGHT = 'please ==take notice==', '==', '==' + p = Huh.PLAIN + self.assertTrue(type(p) is Huh, type(p)) + self.assertEqual( + (p.value, p.__doc__, p.open, p.close), + (0, 'normal', None, None), + ) + bi = Huh.BOLD_ITALIC + self.assertEqual( + (bi.value, bi.__doc__, bi.open, bi.close), + (1, '***really super important***', '***', '***'), + ) + h = Huh.HIGHLIGHT + self.assertEqual( + (h.value, h.__doc__, h.open, h.close), + (2, 'please ==take notice==', '==', '=='), + ) + + def test_members_is_ordereddict_if_ordered(self): + class Ordered(Enum): + __order__ = 'first second third' + first = 'bippity' + second = 'boppity' + third = 'boo' + self.assertTrue(type(Ordered.__members__) is OrderedDict) + + def test_members_is_ordereddict_if_not_ordered(self): + class Unordered(Enum): + this = 'that' + these = 'those' + self.assertTrue(type(Unordered.__members__) is OrderedDict) + + def test_enum_in_enum_out(self): + Season = self.Season + self.assertTrue(Season(Season.WINTER) is Season.WINTER) + + def test_enum_value(self): + Season = self.Season + self.assertEqual(Season.SPRING.value, 1) + + def test_intenum_value(self): + self.assertEqual(IntStooges.CURLY.value, 2) + + def test_enum(self): + Season = self.Season + lst = list(Season) + self.assertEqual(len(lst), len(Season)) + self.assertEqual(len(Season), 4, Season) + self.assertEqual( + [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst) + + for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split()): + i += 1 + e = Season(i) + self.assertEqual(e, getattr(Season, season)) + self.assertEqual(e.value, i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, season) + self.assertTrue(e in Season) + self.assertTrue(type(e) is Season) + self.assertTrue(isinstance(e, Season)) + self.assertEqual(str(e), 'Season.' + season) + self.assertEqual( + repr(e), + '<Season.%s: %s>' % (season, i), + ) + def test_enum_helper(self): + e1 = enum(1, 2, three=9) + e2 = enum(1, 2, three=9) + e3 = enum(1, 2, 9) + self.assertTrue(e1 is not e2) + self.assertEqual(e1, e2) + self.assertNotEqual(e1, e3) + self.assertNotEqual(e2, e3) + + def test_enum_in_enum(self): + # + class Level(Enum): + _order_ = 'DATA_CHECK DESIGN_CHECK ALERT' + # + def __new__(cls, *args, **kwds): + member = object.__new__(cls) + member._value_ = len(cls) + 1 # members are 1-based + return member + # + def __init__(self, prereq=None, dependent=None): + # create priority level lists + self.lower_priority_levels = list(self.__class__._member_map_.values()) + self.greater_priority_levels = [] + # update previous members' greater priority list + for member in self.lower_priority_levels: + member.greater_priority_levels.append(self) + # and save prereq and dependent + self.prerequisite = prereq and self.__class__[prereq.name] or None + self.dependent = dependent and self.__class__[dependent.name] or None + # + DATA_CHECK = enum() + DESIGN_CHECK = enum(DATA_CHECK) + ALERT = enum(None, DATA_CHECK) + # + self.assertEqual(Level.DATA_CHECK.value, 1) + self.assertEqual(Level.DATA_CHECK.prerequisite, None) + self.assertEqual(Level.DATA_CHECK.dependent, None) + self.assertEqual(Level.DESIGN_CHECK.prerequisite, Level.DATA_CHECK) + self.assertEqual(Level.DESIGN_CHECK.dependent, None) + self.assertEqual(Level.ALERT.prerequisite, None) + self.assertEqual(Level.ALERT.dependent, Level.DATA_CHECK) + + def test_value_name(self): + Season = self.Season + self.assertEqual(Season.SPRING.name, 'SPRING') + self.assertEqual(Season.SPRING.value, 1) + def set_name(obj, new_value): + obj.name = new_value + def set_value(obj, new_value): + obj.value = new_value + self.assertRaises(AttributeError, set_name, Season.SPRING, 'invierno', ) + self.assertRaises(AttributeError, set_value, Season.SPRING, 2) + + def test_attribute_deletion(self): + class Season(Enum): + SPRING = 1 + SUMMER = 2 + AUTUMN = 3 + WINTER = 4 + + def spam(cls): + pass + + self.assertTrue(hasattr(Season, 'spam')) + del Season.spam + self.assertFalse(hasattr(Season, 'spam')) + + self.assertRaises(AttributeError, delattr, Season, 'SPRING') + self.assertRaises(AttributeError, delattr, Season, 'DRY') + self.assertRaises(AttributeError, delattr, Season.SPRING, 'name') + + def test_bool_of_class(self): + class Empty(Enum): + pass + self.assertTrue(bool(Empty)) + + def test_bool_of_member(self): + class Count(Enum): + zero = 0 + one = 1 + two = 2 + for member in Count: + self.assertTrue(bool(member)) + + def test_invalid_names(self): + def create_bad_class_1(): + class Wrong(Enum): + mro = 9 + def create_bad_class_2(): + class Wrong(Enum): + _reserved_ = 3 + self.assertRaises(ValueError, create_bad_class_1) + self.assertRaises(ValueError, create_bad_class_2) + + def test_bool(self): + class Logic(Enum): + true = True + false = False + def __bool__(self): + return bool(self.value) + __nonzero__ = __bool__ + self.assertTrue(Logic.true) + self.assertFalse(Logic.false) + + def test_contains(self): + Season = self.Season + self.assertRaises(TypeError, lambda: 'AUTUMN' in Season) + self.assertTrue(Season.AUTUMN in Season) + self.assertRaises(TypeError, lambda: 3 not in Season) + val = Season(3) + self.assertTrue(val in Season) + # + class OtherEnum(Enum): + one = 1; two = 2 + self.assertTrue(OtherEnum.two not in Season) + # + class Wierd(Enum): + this = [1, 2, 3] + that = (1, 2, 3) + those = {1: 1, 2: 2, 3: 3} + self.assertTrue(Wierd.this in Wierd) + self.assertRaises(TypeError, lambda: [1, 2, 3] in Wierd) + self.assertRaises(TypeError, lambda: {1: 1, 2: 2, 3: 3} in Wierd) + + def test_member_contains(self): + self.assertRaises(TypeError, lambda: 'test' in self.Season.AUTUMN) + + if pyver >= PY2_6: # when `format` came into being + + def test_format_enum(self): + Season = self.Season + self.assertEqual('{0}'.format(Season.SPRING), + '{0}'.format(str(Season.SPRING))) + self.assertEqual( '{0:}'.format(Season.SPRING), + '{0:}'.format(str(Season.SPRING))) + self.assertEqual('{0:20}'.format(Season.SPRING), + '{0:20}'.format(str(Season.SPRING))) + self.assertEqual('{0:^20}'.format(Season.SPRING), + '{0:^20}'.format(str(Season.SPRING))) + self.assertEqual('{0:>20}'.format(Season.SPRING), + '{0:>20}'.format(str(Season.SPRING))) + self.assertEqual('{0:<20}'.format(Season.SPRING), + '{0:<20}'.format(str(Season.SPRING))) + + def test_custom_format(self): + class TestFloat(float, Enum): + one = 1.0 + two = 2.0 + def __format__(self, spec): + return 'TestFloat success!' + self.assertEqual(str(TestFloat.one), 'TestFloat.one') + self.assertEqual('{0}'.format(TestFloat.one), 'TestFloat success!') + + def test_format_with_custom_str(self): + class TestInt(int, Enum): + one = 1 + two = 2 + def __str__(self): + return self.name * 3 + self.assertEqual(str(TestInt.two), 'twotwotwo') + self.assertEqual('{0}'.format(TestInt.two), 'twotwotwo') + + def assertFormatIsValue(self, spec, member): + self.assertEqual(spec.format(member), spec.format(member.value)) + + def test_format_enum_date(self): + Holiday = self.Holiday + self.assertFormatIsValue('{0}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:20}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:^20}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:>20}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:<20}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:%Y %m}', Holiday.IDES_OF_MARCH) + self.assertFormatIsValue('{0:%Y %m %M:00}', Holiday.IDES_OF_MARCH) + + def test_format_enum_float(self): + Konstants = self.Konstants + self.assertFormatIsValue('{0}', Konstants.TAU) + self.assertFormatIsValue('{0:}', Konstants.TAU) + self.assertFormatIsValue('{0:20}', Konstants.TAU) + self.assertFormatIsValue('{0:^20}', Konstants.TAU) + self.assertFormatIsValue('{0:>20}', Konstants.TAU) + self.assertFormatIsValue('{0:<20}', Konstants.TAU) + self.assertFormatIsValue('{0:n}', Konstants.TAU) + self.assertFormatIsValue('{0:5.2}', Konstants.TAU) + self.assertFormatIsValue('{0:f}', Konstants.TAU) + + def test_format_enum_int(self): + Grades = self.Grades + self.assertFormatIsValue('{0}', Grades.C) + self.assertFormatIsValue('{0:}', Grades.C) + self.assertFormatIsValue('{0:20}', Grades.C) + self.assertFormatIsValue('{0:^20}', Grades.C) + self.assertFormatIsValue('{0:>20}', Grades.C) + self.assertFormatIsValue('{0:<20}', Grades.C) + self.assertFormatIsValue('{0:+}', Grades.C) + self.assertFormatIsValue('{0:08X}', Grades.C) + self.assertFormatIsValue('{0:b}', Grades.C) + + def test_format_enum_str(self): + Directional = self.Directional + self.assertFormatIsValue('{0}', Directional.WEST) + self.assertFormatIsValue('{0:}', Directional.WEST) + self.assertFormatIsValue('{0:20}', Directional.WEST) + self.assertFormatIsValue('{0:^20}', Directional.WEST) + self.assertFormatIsValue('{0:>20}', Directional.WEST) + self.assertFormatIsValue('{0:<20}', Directional.WEST) + + def test_hash(self): + Season = self.Season + dates = {} + dates[Season.WINTER] = '1225' + dates[Season.SPRING] = '0315' + dates[Season.SUMMER] = '0704' + dates[Season.AUTUMN] = '1031' + self.assertEqual(dates[Season.AUTUMN], '1031') + + def test_enum_duplicates(self): + class Season(Enum): + __order__ = "SPRING SUMMER AUTUMN WINTER" + SPRING = 1 + SUMMER = 2 + AUTUMN = FALL = 3 + WINTER = 4 + ANOTHER_SPRING = 1 + lst = list(Season) + self.assertEqual( + lst, + [Season.SPRING, Season.SUMMER, + Season.AUTUMN, Season.WINTER, + ]) + self.assertTrue(Season.FALL is Season.AUTUMN) + self.assertEqual(Season.FALL.value, 3) + self.assertEqual(Season.AUTUMN.value, 3) + self.assertTrue(Season(3) is Season.AUTUMN) + self.assertTrue(Season(1) is Season.SPRING) + self.assertEqual(Season.FALL.name, 'AUTUMN') + self.assertEqual( + set([k for k,v in Season.__members__.items() if v.name != k]), + set(['FALL', 'ANOTHER_SPRING']), + ) + + def test_enum_with_value_name(self): + class Huh(Enum): + _order_ = 'name value' + name = 1 + value = 2 + self.assertEqual( + list(Huh), + [Huh.name, Huh.value], + ) + self.assertTrue(type(Huh.name) is Huh) + self.assertEqual(Huh.name.name, 'name') + self.assertEqual(Huh.name.value, 1) + + def test_intenum_from_scratch(self): + class phy(int, Enum): + pi = 3 + tau = 2 * pi + self.assertTrue(phy.pi < phy.tau) + + def test_intenum_inherited(self): + class IntEnum(int, Enum): + pass + class phy(IntEnum): + pi = 3 + tau = 2 * pi + self.assertTrue(phy.pi < phy.tau) + + def test_floatenum_from_scratch(self): + class phy(float, Enum): + pi = 3.1415926 + tau = 2 * pi + self.assertTrue(phy.pi < phy.tau) + + def test_floatenum_inherited(self): + class FloatEnum(float, Enum): + pass + class phy(FloatEnum): + pi = 3.1415926 + tau = 2 * pi + self.assertTrue(phy.pi < phy.tau) + + def test_strenum_from_scratch(self): + class phy(str, Enum): + pi = 'Pi' + tau = 'Tau' + self.assertTrue(phy.pi < phy.tau) + + def test_intenum(self): + class WeekDay(IntEnum): + SUNDAY = 1 + MONDAY = 2 + TUESDAY = 3 + WEDNESDAY = 4 + THURSDAY = 5 + FRIDAY = 6 + SATURDAY = 7 + + self.assertEqual(['a', 'b', 'c'][WeekDay.MONDAY], 'c') + self.assertEqual([i for i in range(WeekDay.TUESDAY)], [0, 1, 2]) + + lst = list(WeekDay) + self.assertEqual(len(lst), len(WeekDay)) + self.assertEqual(len(WeekDay), 7) + target = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY' + target = target.split() + for i, weekday in enumerate(target): + i += 1 + e = WeekDay(i) + self.assertEqual(e, i) + self.assertEqual(int(e), i) + self.assertEqual(e.name, weekday) + self.assertTrue(e in WeekDay) + self.assertEqual(lst.index(e)+1, i) + self.assertTrue(0 < e < 8) + self.assertTrue(type(e) is WeekDay) + self.assertTrue(isinstance(e, int)) + self.assertTrue(isinstance(e, Enum)) + + def test_intenum_duplicates(self): + class WeekDay(IntEnum): + __order__ = 'SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY' + SUNDAY = 1 + MONDAY = 2 + TUESDAY = TEUSDAY = 3 + WEDNESDAY = 4 + THURSDAY = 5 + FRIDAY = 6 + SATURDAY = 7 + self.assertTrue(WeekDay.TEUSDAY is WeekDay.TUESDAY) + self.assertEqual(WeekDay(3).name, 'TUESDAY') + self.assertEqual([k for k,v in WeekDay.__members__.items() + if v.name != k], ['TEUSDAY', ]) + + def test_floatenum_fromhex(self): + h = float.hex(FloatStooges.MOE.value) + self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE) + h = float.hex(FloatStooges.MOE.value + 0.01) + with self.assertRaises(ValueError): + FloatStooges.fromhex(h) + + def test_pickle_enum(self): + if isinstance(Stooges, Exception): + raise Stooges + test_pickle_dump_load(self.assertTrue, Stooges.CURLY) + test_pickle_dump_load(self.assertTrue, Stooges) + + def test_pickle_int(self): + if isinstance(IntStooges, Exception): + raise IntStooges + test_pickle_dump_load(self.assertTrue, IntStooges.CURLY) + test_pickle_dump_load(self.assertTrue, IntStooges) + + def test_pickle_float(self): + if isinstance(FloatStooges, Exception): + raise FloatStooges + test_pickle_dump_load(self.assertTrue, FloatStooges.CURLY) + test_pickle_dump_load(self.assertTrue, FloatStooges) + + def test_pickle_enum_function(self): + if isinstance(Answer, Exception): + raise Answer + test_pickle_dump_load(self.assertTrue, Answer.him) + test_pickle_dump_load(self.assertTrue, Answer) + + def test_pickle_enum_function_with_module(self): + if isinstance(Question, Exception): + raise Question + test_pickle_dump_load(self.assertTrue, Question.who) + test_pickle_dump_load(self.assertTrue, Question) + + def test_pickle_by_name(self): + class ReplaceGlobalInt(IntEnum): + ONE = 1 + TWO = 2 + ReplaceGlobalInt.__reduce_ex__ = _reduce_ex_by_name + for proto in range(HIGHEST_PROTOCOL): + self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO') + + def test_exploding_pickle(self): + BadPickle = Enum('BadPickle', 'dill sweet bread-n-butter') + aenum._make_class_unpicklable(BadPickle) + globals()['BadPickle'] = BadPickle + test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill) + test_pickle_exception(self.assertRaises, PicklingError, BadPickle) + + def test_string_enum(self): + class SkillLevel(str, Enum): + master = 'what is the sound of one hand clapping?' + journeyman = 'why did the chicken cross the road?' + apprentice = 'knock, knock!' + self.assertEqual(SkillLevel.apprentice, 'knock, knock!') + + def test_getattr_getitem(self): + class Period(Enum): + morning = 1 + noon = 2 + evening = 3 + night = 4 + self.assertTrue(Period(2) is Period.noon) + self.assertTrue(getattr(Period, 'night') is Period.night) + self.assertTrue(Period['morning'] is Period.morning) + + def test_getattr_dunder(self): + Season = self.Season + self.assertTrue(getattr(Season, '__hash__')) + + def test_iteration_order(self): + class Season(Enum): + __order__ = 'SUMMER WINTER AUTUMN SPRING' + SUMMER = 2 + WINTER = 4 + AUTUMN = 3 + SPRING = 1 + self.assertEqual( + list(Season), + [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING], + ) + + def test_iteration_order_reversed(self): + self.assertEqual( + list(reversed(self.Season)), + [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER, + self.Season.SPRING] + ) + + def test_iteration_order_with_unorderable_values(self): + class Complex(Enum): + a = complex(7, 9) + b = complex(3.14, 2) + c = complex(1, -1) + d = complex(-77, 32) + self.assertEqual( + list(Complex), + [Complex.a, Complex.b, Complex.c, Complex.d], + ) + + def test_programatic_function_string(self): + SummerMonth = Enum('SummerMonth', 'june july august') + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_string_with_start(self): + SummerMonth = Enum('SummerMonth', 'june july august', start=10) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split(), 10): + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_string_list(self): + SummerMonth = Enum('SummerMonth', ['june', 'july', 'august']) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_string_list_with_start(self): + SummerMonth = Enum('SummerMonth', ['june', 'july', 'august'], start=20) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split(), 20): + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_iterable(self): + SummerMonth = Enum( + 'SummerMonth', + (('june', 1), ('july', 2), ('august', 3)) + ) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_from_dict(self): + SummerMonth = Enum( + 'SummerMonth', + dict((('june', 1), ('july', 2), ('august', 3))) + ) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + if PY2: + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_type(self): + SummerMonth = Enum('SummerMonth', 'june july august', type=int) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_type_with_start(self): + SummerMonth = Enum('SummerMonth', 'june july august', type=int, start=30) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split(), 30): + e = SummerMonth(i) + self.assertEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_type_from_subclass(self): + SummerMonth = IntEnum('SummerMonth', 'june july august') + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_type_from_subclass_with_start(self): + SummerMonth = IntEnum('SummerMonth', 'june july august', start=40) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate('june july august'.split(), 40): + e = SummerMonth(i) + self.assertEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_unicode(self): + SummerMonth = Enum('SummerMonth', unicode('june july august')) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_unicode_list(self): + SummerMonth = Enum('SummerMonth', [unicode('june'), unicode('july'), unicode('august')]) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_unicode_iterable(self): + SummerMonth = Enum( + 'SummerMonth', + ((unicode('june'), 1), (unicode('july'), 2), (unicode('august'), 3)) + ) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_from_unicode_dict(self): + SummerMonth = Enum( + 'SummerMonth', + dict(((unicode('june'), 1), (unicode('july'), 2), (unicode('august'), 3))) + ) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + if PY2: + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(int(e.value), i) + self.assertNotEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_unicode_type(self): + SummerMonth = Enum('SummerMonth', unicode('june july august'), type=int) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programatic_function_unicode_type_from_subclass(self): + SummerMonth = IntEnum('SummerMonth', unicode('june july august')) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(e, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_programmatic_function_unicode_class(self): + if PY2: + class_names = unicode('SummerMonth'), 'S\xfcmm\xe9rM\xf6nth'.decode('latin1') + else: + class_names = 'SummerMonth', 'S\xfcmm\xe9rM\xf6nth' + for i, class_name in enumerate(class_names): + if PY2 and i == 1: + self.assertRaises(TypeError, Enum, class_name, unicode('june july august')) + else: + SummerMonth = Enum(class_name, unicode('june july august')) + lst = list(SummerMonth) + self.assertEqual(len(lst), len(SummerMonth)) + self.assertEqual(len(SummerMonth), 3, SummerMonth) + self.assertEqual( + [SummerMonth.june, SummerMonth.july, SummerMonth.august], + lst, + ) + for i, month in enumerate(unicode('june july august').split()): + i += 1 + e = SummerMonth(i) + self.assertEqual(e.value, i) + self.assertEqual(e.name, month) + self.assertTrue(e in SummerMonth) + self.assertTrue(type(e) is SummerMonth) + + def test_subclassing(self): + if isinstance(Name, Exception): + raise Name + self.assertEqual(Name.BDFL, 'Guido van Rossum') + self.assertTrue(Name.BDFL, Name('Guido van Rossum')) + self.assertTrue(Name.BDFL is getattr(Name, 'BDFL')) + test_pickle_dump_load(self.assertTrue, Name.BDFL) + + def test_extending(self): + def bad_extension(): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + class MoreColor(Color): + cyan = 4 + magenta = 5 + yellow = 6 + self.assertRaises(TypeError, bad_extension) + + def test_exclude_methods(self): + class whatever(Enum): + this = 'that' + these = 'those' + def really(self): + return 'no, not %s' % self.value + self.assertFalse(type(whatever.really) is whatever) + self.assertEqual(whatever.this.really(), 'no, not that') + + def test_wrong_inheritance_order(self): + def wrong_inherit(): + class Wrong(Enum, str): + NotHere = 'error before this point' + self.assertRaises(TypeError, wrong_inherit) + + def test_intenum_transitivity(self): + class number(IntEnum): + one = 1 + two = 2 + three = 3 + class numero(IntEnum): + uno = 1 + dos = 2 + tres = 3 + self.assertEqual(number.one, numero.uno) + self.assertEqual(number.two, numero.dos) + self.assertEqual(number.three, numero.tres) + + def test_introspection(self): + class Number(IntEnum): + one = 100 + two = 200 + self.assertTrue(Number.one._member_type_ is int) + self.assertTrue(Number._member_type_ is int) + class String(str, Enum): + yarn = 'soft' + rope = 'rough' + wire = 'hard' + self.assertTrue(String.yarn._member_type_ is str) + self.assertTrue(String._member_type_ is str) + class Plain(Enum): + vanilla = 'white' + one = 1 + self.assertTrue(Plain.vanilla._member_type_ is object) + self.assertTrue(Plain._member_type_ is object) + + def test_wrong_enum_in_call(self): + class Monochrome(Enum): + black = 0 + white = 1 + class Gender(Enum): + male = 0 + female = 1 + self.assertRaises(ValueError, Monochrome, Gender.male) + + def test_wrong_enum_in_mixed_call(self): + class Monochrome(IntEnum): + black = 0 + white = 1 + class Gender(Enum): + male = 0 + female = 1 + self.assertRaises(ValueError, Monochrome, Gender.male) + + def test_mixed_enum_in_call_1(self): + class Monochrome(IntEnum): + black = 0 + white = 1 + class Gender(IntEnum): + male = 0 + female = 1 + self.assertTrue(Monochrome(Gender.female) is Monochrome.white) + + def test_mixed_enum_in_call_2(self): + class Monochrome(Enum): + black = 0 + white = 1 + class Gender(IntEnum): + male = 0 + female = 1 + self.assertTrue(Monochrome(Gender.male) is Monochrome.black) + + def test_flufl_enum(self): + class Fluflnum(Enum): + def __int__(self): + return int(self.value) + class MailManOptions(Fluflnum): + option1 = 1 + option2 = 2 + option3 = 3 + self.assertEqual(int(MailManOptions.option1), 1) + + def test_no_such_enum_member(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + self.assertRaises(ValueError, Color, 4) + self.assertRaises(KeyError, Color.__getitem__, 'chartreuse') + + def test_new_repr(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + def __repr__(self): + return "don't you just love shades of %s?" % self.name + self.assertEqual( + repr(Color.blue), + "don't you just love shades of blue?", + ) + + def test_inherited_repr(self): + class MyEnum(Enum): + def __repr__(self): + return "My name is %s." % self.name + class MyIntEnum(int, MyEnum): + this = 1 + that = 2 + theother = 3 + self.assertEqual(repr(MyIntEnum.that), "My name is that.") + + def test_multiple_mixin_mro(self): + class auto_enum(EnumMeta): + def __new__(metacls, cls, bases, classdict): + original_dict = classdict + temp_dict = metacls.__prepare__(cls, bases, {}) + if hasattr(original_dict, '_member_names'): + for k in original_dict._member_names: + temp_dict[k] = original_dict[k] + sunders = [k for k in original_dict.keys() if aenum._is_sunder(k)] + else: + sunders = [] + for k, v in original_dict.items(): + if aenum._is_sunder(k): + sunders.append(k) + temp_dict[k] = v + classdict = metacls.__prepare__(cls, bases, {}) + i = 0 + for k in sunders: + classdict[k] = original_dict[k] + for k in temp_dict._member_names: + v = original_dict[k] + if v == (): + v = i + else: + i = v + i += 1 + classdict[k] = v + for k, v in original_dict.items(): + if k not in temp_dict._member_names and k not in sunders: + classdict[k] = v + return super(auto_enum, metacls).__new__( + metacls, cls, bases, classdict) + + AutoNumberedEnum = auto_enum('AutoNumberedEnum', (Enum,), {}) + + AutoIntEnum = auto_enum('AutoIntEnum', (IntEnum,), {}) + + # class TestAutoNumber(AutoNumberedEnum): + # a = () + # b = 3 + # c = () + # self.assertEqual(TestAutoNumber.b.value, 3) + # + # if pyver >= 3.0: + # self.assertEqual( + # [TestAutoNumber.a.value, TestAutoNumber.b.value, TestAutoNumber.c.value], + # [0, 3, 4], + # ) + # + # class TestAutoInt(AutoIntEnum): + # a = () + # b = 3 + # c = () + # self.assertEqual(TestAutoInt.b, 3) + # + # if pyver >= 3.0: + # self.assertEqual( + # [TestAutoInt.a.value, TestAutoInt.b.value, TestAutoInt.c.value], + # [0, 3, 4], + # ) + + def test_meta_reconfigure(self): + + def identity(*args): + if len(args) == 1: + return args[0] + return args + + JSONEnum = None + + class JSONEnumMeta(EnumMeta): + + @classmethod + def __prepare__(metacls, cls, bases, init=None, start=None, settings=()): + return {} + + def __init__(cls, *args , **kwds): + super(JSONEnumMeta, cls).__init__(*args) + + def __new__(metacls, cls, bases, clsdict, init=None, start=None, settings=()): + import json + members = [] + if JSONEnum is not None: + if '_file' not in clsdict: + raise TypeError('_file is required') + if '_name' not in clsdict: + raise TypeError('_name is required') + if '_value' not in clsdict: + raise TypeError('_value is required') + name_spec = clsdict.pop('_name') + if not isinstance(name_spec, (tuple, list)): + name_spec = (name_spec, ) + value_spec = clsdict.pop('_value') + file = clsdict.pop('_file') + with open(file) as f: + json_data = json.load(f) + for data in json_data: + values = [] + name = data[name_spec[0]] + for piece in name_spec[1:]: + name = name[piece] + for order, (value_path, func) in sorted(value_spec.items()): + if not isinstance(value_path, (list, tuple)): + value_path = (value_path, ) + value = data[value_path[0]] + for piece in value_path[1:]: + value = value[piece] + if func is not None: + value = func(value) + values.append(value) + values = tuple(values) + members.append( + (name, identity(*values)) + ) + # get the real EnumDict + enum_dict = super(JSONEnumMeta, metacls).__prepare__(cls, bases, init, start, settings) + # transfer the original dict content, _items first + items = list(clsdict.items()) + items.sort(key=lambda p: (0 if p[0][0] == '_' else 1, p)) + for name, value in items: + enum_dict[name] = value + # add the members + for name, value in members: + enum_dict[name] = value + return super(JSONEnumMeta, metacls).__new__(metacls, cls, bases, enum_dict, init, start, settings) + + # for use with both Python 2/3 + JSONEnum = JSONEnumMeta('JsonEnum', (Enum, ), {}) + + test_file = os.path.join(tempdir, 'test_json.json') + with open(test_file, 'w') as f: + f.write( + '[{"name":"Afghanistan","alpha-2":"AF","country-code":"004","notes":{"description":"pretty"}},' + '{"name":"Ã…land Islands","alpha-2":"AX","country-code":"248","notes":{"description":"serene"}},' + '{"name":"Albania","alpha-2":"AL","country-code":"008","notes":{"description":"exciting"}},' + '{"name":"Algeria","alpha-2":"DZ","country-code":"012","notes":{"description":"scarce"}}]') + + class Country(JSONEnum): + _init_ = 'abbr code country_name description' + _file = test_file + _name = 'alpha-2' + _value = { + 1: ('alpha-2', None), + 2: ('country-code', lambda c: int(c)), + 3: ('name', None), + 4: (('notes','description'), lambda s: s.title()), + } + + self.assertEqual([Country.AF, Country.AX, Country.AL, Country.DZ], list(Country)) + self.assertEqual(Country.AF.abbr, 'AF') + self.assertEqual(Country.AX.code, 248) + self.assertEqual(Country.AL.country_name, 'Albania') + self.assertEqual(Country.DZ.description, 'Scarce') + + + def test_subclasses_with_getnewargs(self): + class NamedInt(int): + __qualname__ = 'NamedInt' # needed for pickle protocol 4 + def __new__(cls, *args): + _args = args + if len(args) < 1: + raise TypeError("name and value must be specified") + name, args = args[0], args[1:] + self = int.__new__(cls, *args) + self._intname = name + self._args = _args + return self + def __getnewargs__(self): + return self._args + @property + def __name__(self): + return self._intname + def __repr__(self): + # repr() is updated to include the name and type info + return "%s(%r, %s)" % (type(self).__name__, + self.__name__, + int.__repr__(self)) + def __str__(self): + # str() is unchanged, even if it relies on the repr() fallback + base = int + base_str = base.__str__ + if base_str.__objclass__ is object: + return base.__repr__(self) + return base_str(self) + # for simplicity, we only define one operator that + # propagates expressions + def __add__(self, other): + temp = int(self) + int( other) + if isinstance(self, NamedInt) and isinstance(other, NamedInt): + return NamedInt( + '(%s + %s)' % (self.__name__, other.__name__), + temp ) + else: + return temp + + class NEI(NamedInt, Enum): + __qualname__ = 'NEI' # needed for pickle protocol 4 + x = ('the-x', 1) + y = ('the-y', 2) + + self.assertTrue(NEI.__new__ is Enum.__new__) + self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") + globals()['NamedInt'] = NamedInt + globals()['NEI'] = NEI + NI5 = NamedInt('test', 5) + self.assertEqual(NI5, 5) + test_pickle_dump_load(self.assertTrue, NI5, 5) + self.assertEqual(NEI.y.value, 2) + test_pickle_dump_load(self.assertTrue, NEI.y) + + def test_subclasses_with_reduce(self): + class NamedInt(int): + __qualname__ = 'NamedInt' # needed for pickle protocol 4 + def __new__(cls, *args): + _args = args + if len(args) < 1: + raise TypeError("name and value must be specified") + name, args = args[0], args[1:] + self = int.__new__(cls, *args) + self._intname = name + self._args = _args + return self + def __reduce__(self): + return self.__class__, self._args + @property + def __name__(self): + return self._intname + def __repr__(self): + # repr() is updated to include the name and type info + return "%s(%r, %s)" % (type(self).__name__, + self.__name__, + int.__repr__(self)) + def __str__(self): + # str() is unchanged, even if it relies on the repr() fallback + base = int + base_str = base.__str__ + if base_str.__objclass__ is object: + return base.__repr__(self) + return base_str(self) + # for simplicity, we only define one operator that + # propagates expressions + def __add__(self, other): + temp = int(self) + int( other) + if isinstance(self, NamedInt) and isinstance(other, NamedInt): + return NamedInt( + '(%s + %s)' % (self.__name__, other.__name__), + temp ) + else: + return temp + + class NEI(NamedInt, Enum): + __qualname__ = 'NEI' # needed for pickle protocol 4 + x = ('the-x', 1) + y = ('the-y', 2) + + + self.assertTrue(NEI.__new__ is Enum.__new__) + self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") + globals()['NamedInt'] = NamedInt + globals()['NEI'] = NEI + NI5 = NamedInt('test', 5) + self.assertEqual(NI5, 5) + test_pickle_dump_load(self.assertEqual, NI5, 5) + self.assertEqual(NEI.y.value, 2) + test_pickle_dump_load(self.assertTrue, NEI.y) + + def test_subclasses_with_reduce_ex(self): + class NamedInt(int): + __qualname__ = 'NamedInt' # needed for pickle protocol 4 + def __new__(cls, *args): + _args = args + if len(args) < 1: + raise TypeError("name and value must be specified") + name, args = args[0], args[1:] + self = int.__new__(cls, *args) + self._intname = name + self._args = _args + return self + def __reduce_ex__(self, proto): + return self.__class__, self._args + @property + def __name__(self): + return self._intname + def __repr__(self): + # repr() is updated to include the name and type info + return "%s(%r, %s)" % (type(self).__name__, + self.__name__, + int.__repr__(self)) + def __str__(self): + # str() is unchanged, even if it relies on the repr() fallback + base = int + base_str = base.__str__ + if base_str.__objclass__ is object: + return base.__repr__(self) + return base_str(self) + # for simplicity, we only define one operator that + # propagates expressions + def __add__(self, other): + temp = int(self) + int( other) + if isinstance(self, NamedInt) and isinstance(other, NamedInt): + return NamedInt( + '(%s + %s)' % (self.__name__, other.__name__), + temp ) + else: + return temp + + class NEI(NamedInt, Enum): + __qualname__ = 'NEI' # needed for pickle protocol 4 + x = ('the-x', 1) + y = ('the-y', 2) + + + self.assertTrue(NEI.__new__ is Enum.__new__) + self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") + globals()['NamedInt'] = NamedInt + globals()['NEI'] = NEI + NI5 = NamedInt('test', 5) + self.assertEqual(NI5, 5) + test_pickle_dump_load(self.assertEqual, NI5, 5) + self.assertEqual(NEI.y.value, 2) + test_pickle_dump_load(self.assertTrue, NEI.y) + + def test_subclasses_without_direct_pickle_support(self): + class NamedInt(int): + __qualname__ = 'NamedInt' + def __new__(cls, *args): + _args = args + name, args = args[0], args[1:] + if len(args) == 0: + raise TypeError("name and value must be specified") + self = int.__new__(cls, *args) + self._intname = name + self._args = _args + return self + @property + def __name__(self): + return self._intname + def __repr__(self): + # repr() is updated to include the name and type info + return "%s(%r, %s)" % (type(self).__name__, + self.__name__, + int.__repr__(self)) + def __str__(self): + # str() is unchanged, even if it relies on the repr() fallback + base = int + base_str = base.__str__ + if base_str.__objclass__ is object: + return base.__repr__(self) + return base_str(self) + # for simplicity, we only define one operator that + # propagates expressions + def __add__(self, other): + temp = int(self) + int( other) + if isinstance(self, NamedInt) and isinstance(other, NamedInt): + return NamedInt( + '(%s + %s)' % (self.__name__, other.__name__), + temp ) + else: + return temp + + class NEI(NamedInt, Enum): + __qualname__ = 'NEI' + x = ('the-x', 1) + y = ('the-y', 2) + + self.assertTrue(NEI.__new__ is Enum.__new__) + self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") + globals()['NamedInt'] = NamedInt + globals()['NEI'] = NEI + NI5 = NamedInt('test', 5) + self.assertEqual(NI5, 5) + self.assertEqual(NEI.y.value, 2) + test_pickle_exception(self.assertRaises, TypeError, NEI.x) + test_pickle_exception(self.assertRaises, PicklingError, NEI) + + def test_subclasses_without_direct_pickle_support_using_name(self): + class NamedInt(int): + __qualname__ = 'NamedInt' + def __new__(cls, *args): + _args = args + name, args = args[0], args[1:] + if len(args) == 0: + raise TypeError("name and value must be specified") + self = int.__new__(cls, *args) + self._intname = name + self._args = _args + return self + @property + def __name__(self): + return self._intname + def __repr__(self): + # repr() is updated to include the name and type info + return "%s(%r, %s)" % (type(self).__name__, + self.__name__, + int.__repr__(self)) + def __str__(self): + # str() is unchanged, even if it relies on the repr() fallback + base = int + base_str = base.__str__ + if base_str.__objclass__ is object: + return base.__repr__(self) + return base_str(self) + # for simplicity, we only define one operator that + # propagates expressions + def __add__(self, other): + temp = int(self) + int( other) + if isinstance(self, NamedInt) and isinstance(other, NamedInt): + return NamedInt( + '(%s + %s)' % (self.__name__, other.__name__), + temp ) + else: + return temp + + class NEI(NamedInt, Enum): + __qualname__ = 'NEI' + x = ('the-x', 1) + y = ('the-y', 2) + def __reduce_ex__(self, proto): + return getattr, (self.__class__, self._name_) + + self.assertTrue(NEI.__new__ is Enum.__new__) + self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)") + globals()['NamedInt'] = NamedInt + globals()['NEI'] = NEI + NI5 = NamedInt('test', 5) + self.assertEqual(NI5, 5) + self.assertEqual(NEI.y.value, 2) + test_pickle_dump_load(self.assertTrue, NEI.y) + test_pickle_dump_load(self.assertTrue, NEI) + + def test_tuple_subclass(self): + class SomeTuple(tuple, Enum): + __qualname__ = 'SomeTuple' + first = (1, 'for the money') + second = (2, 'for the show') + third = (3, 'for the music') + self.assertTrue(type(SomeTuple.first) is SomeTuple) + self.assertTrue(isinstance(SomeTuple.second, tuple)) + self.assertEqual(SomeTuple.third, (3, 'for the music')) + globals()['SomeTuple'] = SomeTuple + test_pickle_dump_load(self.assertTrue, SomeTuple.first) + + # def test_duplicate_values_give_unique_enum_items(self): + # class NumericEnum(AutoNumberEnum): + # __order__ = 'enum_m enum_d enum_y' + # enum_m = () + # enum_d = () + # enum_y = () + # def __int__(self): + # return int(self._value_) + # self.assertEqual(int(NumericEnum.enum_d), 2) + # self.assertEqual(NumericEnum.enum_y.value, 3) + # self.assertTrue(NumericEnum(1) is NumericEnum.enum_m) + # self.assertEqual( + # list(NumericEnum), + # [NumericEnum.enum_m, NumericEnum.enum_d, NumericEnum.enum_y], + # ) + + def test_inherited_new_from_enhanced_enum(self): + class AutoNumber2(Enum): + def __new__(cls): + value = len(cls.__members__) + 1 + obj = object.__new__(cls) + obj._value_ = value + return obj + def __int__(self): + return int(self._value_) + class Color(AutoNumber2): + __order__ = 'red green blue' + red = () + green = () + blue = () + self.assertEqual(len(Color), 3, "wrong number of elements: %d (should be %d)" % (len(Color), 3)) + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + if PY3: + self.assertEqual(list(map(int, Color)), [1, 2, 3]) + + def test_inherited_new_from_mixed_enum(self): + class AutoNumber3(IntEnum): + def __new__(cls): + value = len(cls.__members__) + 11 + obj = int.__new__(cls, value) + obj._value_ = value + return obj + class Color(AutoNumber3): + __order__ = 'red green blue' + red = () + green = () + blue = () + self.assertEqual(len(Color), 3, "wrong number of elements: %d (should be %d)" % (len(Color), 3)) + Color.red + Color.green + Color.blue + self.assertEqual(Color.blue, 13) + + def test_equality(self): + class AlwaysEqual: + def __eq__(self, other): + return True + class OrdinaryEnum(Enum): + a = 1 + self.assertEqual(AlwaysEqual(), OrdinaryEnum.a) + self.assertEqual(OrdinaryEnum.a, AlwaysEqual()) + + def test_ordered_mixin(self): + class Grade(OrderedEnum): + __order__ = 'A B C D F' + A = 5 + B = 4 + C = 3 + D = 2 + F = 1 + self.assertEqual(list(Grade), [Grade.A, Grade.B, Grade.C, Grade.D, Grade.F]) + self.assertTrue(Grade.A > Grade.B) + self.assertTrue(Grade.F <= Grade.C) + self.assertTrue(Grade.D < Grade.A) + self.assertTrue(Grade.B >= Grade.B) + + def test_missing_deprecated(self): + class Label(Enum): + AnyApple = 0 + RedApple = 1 + GreenApple = 2 + @classmethod + def _missing_(cls, name): + return cls.AnyApple + + self.assertEqual(Label.AnyApple, Label(4)) + with self.assertRaises(AttributeError): + Label.redapple + with self.assertRaises(KeyError): + Label['redapple'] + + def test_missing(self): + class Label(Enum): + AnyApple = 0 + RedApple = 1 + GreenApple = 2 + @classmethod + def _missing_value_(cls, value): + return cls.AnyApple + + self.assertEqual(Label.AnyApple, Label(4)) + with self.assertRaises(AttributeError): + Label.redapple + with self.assertRaises(KeyError): + Label['redapple'] + + def test_missing_name(self): + class Label(Enum): + RedApple = 1 + GreenApple = 2 + @classmethod + def _missing_name_(cls, name): + for member in cls: + if member.name.lower() == name.lower(): + return member + + Label['redapple'] + with self.assertRaises(AttributeError): + Label.redapple + with self.assertRaises(ValueError): + Label('redapple') + + def test_missing_value_bad_input(self): + class Label(Enum): + AnyApple = 0 + RedApple = 1 + GreenApple = 2 + @classmethod + def _missing_value_(cls, value): + return cls.AnyApple + + self.assertEqual(Label.AnyApple, Label(4)) + with self.assertRaises(KeyError): + Label[True] + + def test_missing_name_bad_return(self): + class Label(Enum): + RedApple = 1 + GreenApple = 2 + @classmethod + def _missing_name_(cls, name): + return None + + with self.assertRaises(AttributeError): + Label.redapple + with self.assertRaises(ValueError): + Label('redapple') + with self.assertRaises(KeyError): + Label['redapple'] + + def test_extending2(self): + def bad_extension(): + class Shade(Enum): + def shade(self): + print(self.name) + class Color(Shade): + red = 1 + green = 2 + blue = 3 + class MoreColor(Color): + cyan = 4 + magenta = 5 + yellow = 6 + self.assertRaises(TypeError, bad_extension) + + def test_extending3(self): + class Shade(Enum): + def shade(self): + return self.name + class Color(Shade): + def hex(self): + return '%s hexlified!' % self.value + class MoreColor(Color): + cyan = 4 + magenta = 5 + yellow = 6 + self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!') + + def test_extending5(self): + class Color(Enum): + _order_ = 'red green blue value' + red = 1 + green = 2 + blue = 3 + value = 4 + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.value]) + self.assertEqual(Color.value.name, 'value') + self.assertEqual(Color.value.value, 4) + self.assertTrue(Color.value in Color) + self.assertEqual(Color(4), Color.value) + self.assertEqual(Color['value'], Color.value) + self.assertEqual(Color.red.value, 1) + + CONTINUE = 100, 'Continue', 'Request received, please continue' + SWITCHING_PROTOCOLS = (101, 'Switching Protocols', + 'Switching to new protocol; obey Upgrade header') + PROCESSING = 102, 'Processing' + + def test_no_duplicates(self): + def bad_duplicates(): + class Color1(UniqueEnum): + red = 1 + green = 2 + blue = 3 + class Color2(UniqueEnum): + red = 1 + green = 2 + blue = 3 + grene = 2 + self.assertRaises(ValueError, bad_duplicates) + + def test_no_duplicates_kinda(self): + class Silly(UniqueEnum): + one = 1 + two = 'dos' + name = 3 + class Sillier(IntEnum, UniqueEnum): + single = 1 + name = 2 + triple = 3 + value = 4 + + def test_init(self): + class Planet(Enum): + MERCURY = (3.303e+23, 2.4397e6) + VENUS = (4.869e+24, 6.0518e6) + EARTH = (5.976e+24, 6.37814e6) + MARS = (6.421e+23, 3.3972e6) + JUPITER = (1.9e+27, 7.1492e7) + SATURN = (5.688e+26, 6.0268e7) + URANUS = (8.686e+25, 2.5559e7) + NEPTUNE = (1.024e+26, 2.4746e7) + def __init__(self, mass, radius): + self.mass = mass # in kilograms + self.radius = radius # in meters + @property + def surface_gravity(self): + # universal gravitational constant (m3 kg-1 s-2) + G = 6.67300E-11 + return G * self.mass / (self.radius * self.radius) + self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80) + self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6)) + + def test_init_and_shadowing_attribute(self): + class SelectionEnum(str, Enum): + _init_ = 'db user' + def __new__(cls, *args, **kwds): + count = len(cls.__members__) + obj = str.__new__(cls, args[0]) + obj._count = count + obj._value_ = args + return obj + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (name, ) + args + class DeviceTypeSource(SelectionEnum): + _order_ = 'user system' + user = "User controlled" + system = "System controlled" + self.assertEqual(DeviceTypeSource.system.db, 'system') + self.assertEqual(DeviceTypeSource.system.user, 'System controlled') + self.assertEqual(DeviceTypeSource.user.db, 'user') + self.assertEqual(DeviceTypeSource.user.user, 'User controlled') + + def test_nonhash_value(self): + class AutoNumberInAList(Enum): + def __new__(cls): + value = [len(cls.__members__) + 1] + obj = object.__new__(cls) + obj._value_ = value + return obj + class ColorInAList(AutoNumberInAList): + __order__ = 'red green blue' + red = () + green = () + blue = () + self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue]) + self.assertEqual(ColorInAList.red.value, [1]) + self.assertEqual(ColorInAList([1]), ColorInAList.red) + + def test_number_reset_and_order_cleanup(self): + class Confused(Enum): + _order_ = 'ONE TWO THREE UNO DOS TRES FOUR' + ONE = auto() + TWO = auto() + THREE = auto() + UNO = 1 + DOS = auto() + TRES = auto() + FOUR = auto() + self.assertEqual(list(Confused), [Confused.ONE, Confused.TWO, Confused.THREE, Confused.FOUR]) + self.assertIs(Confused.TWO, Confused.DOS) + self.assertEqual(Confused.DOS._value_, 2) + self.assertEqual(Confused.TRES._value_, 3) + self.assertEqual(Confused.FOUR._value_, 4) + + def test_conflicting_types_resolved_in_new(self): + class LabelledIntEnum(int, Enum): + def __new__(cls, *args): + value, label = args + obj = int.__new__(cls, value) + obj.label = label + obj._value_ = value + return obj + + class LabelledList(LabelledIntEnum): + unprocessed = (1, "Unprocessed") + payment_complete = (2, "Payment Complete") + + self.assertEqual(LabelledList.unprocessed, 1) + self.assertEqual(LabelledList(1), LabelledList.unprocessed) + self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete]) + + def test_auto_number(self): + class Color(Enum): + _order_ = 'red blue green' + red = auto() + blue = auto() + green = auto() + + self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(Color.red.value, 1) + self.assertEqual(Color.blue.value, 2) + self.assertEqual(Color.green.value, 3) + + def test_auto_name(self): + class Color(Enum): + _order_ = 'red blue green' + def _generate_next_value_(name, start, count, last): + return name + red = auto() + blue = auto() + green = auto() + + self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(Color.red.value, 'red') + self.assertEqual(Color.blue.value, 'blue') + self.assertEqual(Color.green.value, 'green') + + def test_auto_name_inherit(self): + class AutoNameEnum(Enum): + def _generate_next_value_(name, start, count, last): + return name + class Color(AutoNameEnum): + _order_ = 'red blue green' + red = auto() + blue = auto() + green = auto() + + self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(Color.red.value, 'red') + self.assertEqual(Color.blue.value, 'blue') + self.assertEqual(Color.green.value, 'green') + + def test_auto_garbage(self): + class Color(Enum): + _order_ = 'red blue' + red = 'red' + blue = auto() + self.assertEqual(Color.blue.value, 1) + + def test_auto_garbage_corrected(self): + class Color(Enum): + _order_ = 'red blue green' + red = 'red' + blue = 2 + green = auto() + + self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(Color.red.value, 'red') + self.assertEqual(Color.blue.value, 2) + self.assertEqual(Color.green.value, 3) + + def test_duplicate_auto(self): + # + class MoreDupes(Enum): + _order_ = 'A B C' + A = auto() + B = A, + C = auto() + self.assertEqual(list(MoreDupes), [MoreDupes.A, MoreDupes.B, MoreDupes.C]) + self.assertEqual([m.value for m in MoreDupes], [1, (1, ), 2]) + # + class Dupes(Enum): + _order_ = 'first second third' + first = primero = auto() + second = auto() + third = auto() + self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) + + def test_auto_value_with_auto(self): + + class SelectionEnum(Enum): + _init_ = 'db user' + def __new__(cls, *args, **kwds): + count = len(cls.__members__) + obj = object.__new__(cls) + obj._count = count + obj._value_ = args + obj.db, obj.user = args + return obj + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (name, ) + args + + class Test(SelectionEnum): + _order_ = 'this that' + this = auto('these') + that = auto('those') + + self.assertEqual(list(Test), [Test.this, Test.that]) + self.assertEqual(Test.this.name, 'this') + self.assertEqual(Test.this.value, ('this', 'these')) + self.assertEqual(Test.this.db, 'this') + self.assertEqual(Test.this.user, 'these') + self.assertEqual(Test.that.name, 'that') + self.assertEqual(Test.that.value, ('that', 'those')) + self.assertEqual(Test.that.db, 'that') + self.assertEqual(Test.that.user, 'those') + + def test_auto_value_with_autovalue(self): + + class SelectionEnum(Enum): + _init_ = 'db user' + def __new__(cls, *args, **kwds): + count = len(cls.__members__) + obj = object.__new__(cls) + obj._count = count + obj._value_ = args + return obj + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (name, ) + args + + class Test(SelectionEnum): + _order_ = 'this that' + this = 'these' + that = 'those' + + self.assertEqual(list(Test), [Test.this, Test.that]) + self.assertEqual(Test.this.name, 'this') + self.assertEqual(Test.this.value, ('this', 'these')) + self.assertEqual(Test.this.db, 'this') + self.assertEqual(Test.this.user, 'these') + self.assertEqual(Test.that.name, 'that') + self.assertEqual(Test.that.value, ('that', 'those')) + self.assertEqual(Test.that.db, 'that') + self.assertEqual(Test.that.user, 'those') + + def test_auto_and_kwds(self): + class Item(Enum): + _order_ = 'A B' + A = auto(size=100, req={'red': True}) + B = auto(size=200, req={'red': False}) + # + def __new__(cls, value, size, req): + obj = object.__new__(cls) + obj._value_ = value + obj.size = size + obj.req= req + return obj + self.assertEqual((Item.A.value, Item.A.size, Item.A.req), (1, 100, {'red': True})) + self.assertEqual((Item.B.value, Item.B.size, Item.B.req), (2, 200, {'red': False})) + + def test_empty_with_functional_api(self): + empty = aenum.IntEnum('Foo', {}) + self.assertEqual(len(empty), 0) + + def test_auto_init(self): + class Planet(Enum): + _init_ = 'mass radius' + MERCURY = (3.303e+23, 2.4397e6) + VENUS = (4.869e+24, 6.0518e6) + EARTH = (5.976e+24, 6.37814e6) + MARS = (6.421e+23, 3.3972e6) + JUPITER = (1.9e+27, 7.1492e7) + SATURN = (5.688e+26, 6.0268e7) + URANUS = (8.686e+25, 2.5559e7) + NEPTUNE = (1.024e+26, 2.4746e7) + @property + def surface_gravity(self): + # universal gravitational constant (m3 kg-1 s-2) + G = 6.67300E-11 + return G * self.mass / (self.radius * self.radius) + self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80) + self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6)) + + def test_auto_init_with_value(self): + class Color(Enum): + _init_='value, rgb' + RED = 1, (1, 0, 0) + BLUE = 2, (0, 1, 0) + GREEN = 3, (0, 0, 1) + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.BLUE.value, 2) + self.assertEqual(Color.GREEN.value, 3) + self.assertEqual(Color.RED.rgb, (1, 0, 0)) + self.assertEqual(Color.BLUE.rgb, (0, 1, 0)) + self.assertEqual(Color.GREEN.rgb, (0, 0, 1)) + + def test_noalias(self): + class Settings(Enum): + _settings_ = NoAlias + red = 1 + rojo = 1 + self.assertFalse(Settings.red is Settings.rojo) + self.assertRaises(TypeError, Settings, 1) + + def test_auto_and_init(self): + class Field(int, Enum): + _order_ = 'TYPE START' + _init_ = 'value __doc__' + TYPE = "Char, Date, Logical, etc." + START = "Field offset in record" + self.assertEqual(Field.TYPE, 1) + self.assertEqual(Field.START, 2) + self.assertEqual(Field.TYPE.__doc__, 'Char, Date, Logical, etc.') + self.assertEqual(Field.START.__doc__, 'Field offset in record') + + def test_auto_and_start(self): + class Field(IntEnum): + _order_ = 'TYPE START' + _start_ = 0 + _init_ = 'value __doc__' + TYPE = "Char, Date, Logical, etc." + START = "Field offset in record" + self.assertEqual(Field.TYPE, 0) + self.assertEqual(Field.START, 1) + self.assertEqual(Field.TYPE.__doc__, 'Char, Date, Logical, etc.') + self.assertEqual(Field.START.__doc__, 'Field offset in record') + + def test_auto_and_init_and_some_values(self): + class Field(int, Enum): + _order_ = 'TYPE START BLAH BELCH' + _init_ = 'value __doc__' + TYPE = "Char, Date, Logical, etc." + START = "Field offset in record" + BLAH = 5, "test blah" + BELCH = 'test belch' + self.assertEqual(Field.TYPE, 1) + self.assertEqual(Field.START, 2) + self.assertEqual(Field.BLAH, 5) + self.assertEqual(Field.BELCH, 6) + self.assertEqual(Field.TYPE.__doc__, 'Char, Date, Logical, etc.') + self.assertEqual(Field.START.__doc__, 'Field offset in record') + self.assertEqual(Field.BLAH.__doc__, 'test blah') + self.assertEqual(Field.BELCH.__doc__, 'test belch') + + def test_auto_and_init_w_value_and_too_many_values(self): + with self.assertRaisesRegex(TypeError, r'Field\.BLAH: number of fields provided do not match init'): + class Field(int, Enum): + _order_ = 'TYPE START BLAH BELCH' + _init_ = 'value __doc__' + TYPE = 1, "Char, Date, Logical, etc." + START = 2, "Field offset in record" + BLAH = 5, 6, "test blah" + BELCH = 7, 'test belch' + + def test_auto_and_init_and_some_complex_values(self): + class Field(int, Enum): + _order_ = 'TYPE START BLAH BELCH' + _init_ = 'value __doc__ help' + TYPE = "Char, Date, Logical, etc.", "fields composed of character data" + START = "Field offset in record", "where the data starts in the record" + BLAH = 5, "test blah", "some help" + BELCH = 'test belch', "some more help" + self.assertEqual(Field.TYPE, 1) + self.assertEqual(Field.START, 2) + self.assertEqual(Field.BLAH, 5) + self.assertEqual(Field.BELCH, 6) + self.assertEqual(Field.TYPE.__doc__, 'Char, Date, Logical, etc.') + self.assertEqual(Field.START.__doc__, 'Field offset in record') + self.assertEqual(Field.BLAH.__doc__, 'test blah') + self.assertEqual(Field.BELCH.__doc__, 'test belch') + self.assertEqual(Field.TYPE.help, "fields composed of character data") + self.assertEqual(Field.START.help, "where the data starts in the record") + self.assertEqual(Field.BLAH.help, "some help") + self.assertEqual(Field.BELCH.help, "some more help") + + def test_auto_and_init_inherited(self): + class AutoEnum(IntEnum): + _start_ = 0 + _init_ = 'value __doc__' + class Field(AutoEnum): + _order_ = 'TYPE START BLAH BELCH' + TYPE = "Char, Date, Logical, etc." + START = "Field offset in record" + BLAH = 5, "test blah" + BELCH = 'test belch' + self.assertEqual(Field.TYPE, 0) + self.assertEqual(Field.START, 1) + self.assertEqual(Field.BLAH, 5) + self.assertEqual(Field.BELCH, 6) + self.assertEqual(Field.TYPE.__doc__, 'Char, Date, Logical, etc.') + self.assertEqual(Field.START.__doc__, 'Field offset in record') + self.assertEqual(Field.BLAH.__doc__, 'test blah') + self.assertEqual(Field.BELCH.__doc__, 'test belch') + + def test_missing_value_error(self): + with self.assertRaisesRegex(TypeError, r"_value_ not set in __new__"): + class Combined(str, Enum): + # + _init_ = 'value sequence' + _order_ = lambda m: m.sequence + # + def __new__(cls, value, *args): + enum = str.__new__(cls, value) + if '(' in value: + fis_name, segment = value.split('(', 1) + segment = segment.strip(' )') + else: + fis_name = value + segment = None + enum.fis_name = fis_name + enum.segment = segment + return enum + # + def __repr__(self): + return "<%s.%s>" % (self.__class__.__name__, self._name_) + # + key_type = 'An$(1,2)', 0 + company_id = 'An$(3,2)', 1 + code = 'An$(5,1)', 2 + description = 'Bn$', 3 + + + def test_auto_and_enum(self): + class Foo(aenum.Flag): + _order_ = 'a b c' + a = aenum.auto() + b = a | aenum.auto() + c = 2 + + self.assertEqual([Foo.a, Foo.c], list(Foo)) + self.assertEqual(Foo.a.value, 1) + self.assertEqual(Foo.b.value, 3) + + def test_multiple_arg_auto(self): + class AutoName(Enum): + def _generate_next_value_(name, start, count, last, *args, **kwds): + return (name, ) + args + # + class Planet(AutoName): + _init_ = 'value mass radius' + MERCURY = auto(3.303e+23, 2.4397e6) + VENUS = auto(4.869e+24, 6.0518e6) + self.assertEqual(Planet.MERCURY.value, 'MERCURY') + + def test_auto_w_multiple_arg(self): + class AutoName(Enum): + def _generate_next_value_(name, start, count, last, *args, **kwds): + return (name, ) + args + # + class Planet(AutoName): + _init_ = 'value mass radius' + MERCURY = auto(), 3.303e+23, 2.4397e6 # doesn't work + VENUS = auto(), 4.869e+24, 6.0518e6 # doesn't work + self.assertEqual(Planet.MERCURY.value, 'MERCURY') + + def test_auto_gnv_and_init(self): + class AutoName(Enum): + def _generate_next_value_(name, start, count, last, *args, **kwds): + return (name, ) + args + # + class Planet(AutoName): + _init_ = 'value mass radius' + MERCURY = 3.303e+23, 2.4397e6 # doesn't work + VENUS = 4.869e+24, 6.0518e6 # doesn't work + self.assertEqual(Planet.MERCURY.value, 'MERCURY') + + # def test_AutoNumberEnum_and_property(self): + # class Color(aenum.AutoNumberEnum): + # red = () + # green = () + # blue = () + # @property + # def cap_name(self): + # return self.name.title() + # self.assertEqual(Color.blue.cap_name, 'Blue') + + # def test_AutoNumberEnum(self): + # class Color(aenum.AutoNumberEnum): + # _order_ = 'red green blue' + # red = () + # green = () + # blue = () + # self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + # self.assertEqual(Color.red.value, 1) + # self.assertEqual(Color.green.value, 2) + # self.assertEqual(Color.blue.value, 3) + + def test_MultiValue_with_init_wo_value(self): + class Color(Enum): + _init_ = 'color r g b' + _order_ = 'red green blue' + _settings_ = MultiValue + red = 'red', 1, 2, 3 + green = 'green', 4, 5, 6 + blue = 'blue', 7, 8, 9 + self.assertEqual(Color.red.value, 'red') + self.assertEqual(Color.red.color, 'red') + self.assertEqual(Color.red.r, 1) + self.assertEqual(Color.red.g, 2) + self.assertEqual(Color.red.b, 3) + self.assertEqual(Color.green.value, 'green') + self.assertEqual(Color.green.color, 'green') + self.assertEqual(Color.green.r, 4) + self.assertEqual(Color.green.g, 5) + self.assertEqual(Color.green.b, 6) + self.assertEqual(Color.blue.value, 'blue') + self.assertEqual(Color.blue.color, 'blue') + self.assertEqual(Color.blue.r, 7) + self.assertEqual(Color.blue.g, 8) + self.assertEqual(Color.blue.b, 9) + self.assertIs(Color('red'), Color.red) + self.assertIs(Color(1), Color.red) + self.assertIs(Color(2), Color.red) + self.assertIs(Color(3), Color.red) + self.assertIs(Color('green'), Color.green) + self.assertIs(Color(4), Color.green) + self.assertIs(Color(5), Color.green) + self.assertIs(Color(6), Color.green) + self.assertIs(Color('blue'), Color.blue) + self.assertIs(Color(7), Color.blue) + self.assertIs(Color(8), Color.blue) + self.assertIs(Color(9), Color.blue) + + def test_MultiValue_with_init_w_value(self): + class Color(Enum): + _init_ = 'value r g b' + _order_ = 'red green blue' + _settings_ = MultiValue + red = 'red', 1, 2, 3 + green = 'green', 4, 5, 6 + blue = 'blue', 7, 8, 9 + self.assertEqual(Color.red.value, 'red') + self.assertEqual(Color.red.r, 1) + self.assertEqual(Color.red.g, 2) + self.assertEqual(Color.red.b, 3) + self.assertEqual(Color.green.value, 'green') + self.assertEqual(Color.green.r, 4) + self.assertEqual(Color.green.g, 5) + self.assertEqual(Color.green.b, 6) + self.assertEqual(Color.blue.value, 'blue') + self.assertEqual(Color.blue.r, 7) + self.assertEqual(Color.blue.g, 8) + self.assertEqual(Color.blue.b, 9) + self.assertIs(Color('red'), Color.red) + self.assertIs(Color(1), Color.red) + self.assertIs(Color(2), Color.red) + self.assertIs(Color(3), Color.red) + self.assertIs(Color('green'), Color.green) + self.assertIs(Color(4), Color.green) + self.assertIs(Color(5), Color.green) + self.assertIs(Color(6), Color.green) + self.assertIs(Color('blue'), Color.blue) + self.assertIs(Color(7), Color.blue) + self.assertIs(Color(8), Color.blue) + self.assertIs(Color(9), Color.blue) + + def test_MultiValue_with_init_wo_value_w_autonumber(self): + class Color(AutoNumberEnum): + _init_ = 'color r g b' + _order_ = 'red green blue' + _settings_ = MultiValue + red = 'red', 10, 20, 30 + green = 'green', 40, 50, 60 + blue = 'blue', 70, 80, 90 + self.assertEqual(Color.red.value, 1) + self.assertEqual(Color.red.color, 'red') + self.assertEqual(Color.red.r, 10) + self.assertEqual(Color.red.g, 20) + self.assertEqual(Color.red.b, 30) + self.assertEqual(Color.green.value, 2) + self.assertEqual(Color.green.color, 'green') + self.assertEqual(Color.green.r, 40) + self.assertEqual(Color.green.g, 50) + self.assertEqual(Color.green.b, 60) + self.assertEqual(Color.blue.value, 3) + self.assertEqual(Color.blue.color, 'blue') + self.assertEqual(Color.blue.r, 70) + self.assertEqual(Color.blue.g, 80) + self.assertEqual(Color.blue.b, 90) + self.assertIs(Color(1), Color.red) + self.assertIs(Color('red'), Color.red) + self.assertIs(Color(10), Color.red) + self.assertIs(Color(20), Color.red) + self.assertIs(Color(30), Color.red) + self.assertIs(Color(2), Color.green) + self.assertIs(Color('green'), Color.green) + self.assertIs(Color(40), Color.green) + self.assertIs(Color(50), Color.green) + self.assertIs(Color(60), Color.green) + self.assertIs(Color(3), Color.blue) + self.assertIs(Color('blue'), Color.blue) + self.assertIs(Color(70), Color.blue) + self.assertIs(Color(80), Color.blue) + self.assertIs(Color(90), Color.blue) + + def test_multivalue_and_autonumber_wo_init_wo_value(self): + class Day(Enum): + _settings_ = MultiValue, AddValue + _order_ = 'one two three' + _start_ = 7 + one = "21", "one" + two = "22", "two" + three = "23", "three" + self.assertEqual(Day.one.value, 7) + self.assertEqual(Day.two.value, 8) + self.assertEqual(Day.three.value, 9) + self.assertEqual(Day('21'), Day.one) + self.assertEqual(Day('one'), Day.one) + + def test_multivalue_and_autonumber_wo_init_w_some_value(self): + class Color(Enum): + _settings_ = MultiValue, Unique + _order_ = 'BLACK RED BLUE YELLOW GREEN MAGENTA' + _init_ = "value description" + BLACK = -1, "Text0" + RED = -50, "Text1" + BLUE = auto(), "Text2" + YELLOW = auto(), "Text3" + GREEN = -70, "Text4" + MAGENTA = auto(), "Text5" + self.assertEqual(Color.BLACK.value, -1) + self.assertEqual(Color.RED.value, -50) + self.assertEqual(Color.BLUE.value, -49) + self.assertEqual(Color.YELLOW.value, -48) + self.assertEqual(Color.GREEN.value, -70) + self.assertEqual(Color.MAGENTA.value, -69) + self.assertEqual(Color(-1), Color.BLACK) + self.assertEqual(Color('Text2'), Color.BLUE) + + def test_combine_new_settings_with_old_settings(self): + class Auto(Enum): + _settings_ = Unique + with self.assertRaises(ValueError): + class AutoUnique(Auto): + BLAH = auto() + BLUH = auto() + ICK = 1 + + def test_timedelta(self): + class Period(timedelta, Enum): + ''' + different lengths of time + ''' + _init_ = 'value period' + _settings_ = NoAlias + _ignore_ = 'Period i' + Period = vars() + for i in range(31): + Period['day_%d' % i] = i, 'day' + for i in range(15): + Period['week_%d' % i] = i*7, 'week' + for i in range(12): + Period['month_%d' % i] = i*30, 'month' + OneDay = day_1 + OneWeek = week_1 + self.assertFalse(hasattr(Period, '_ignore_')) + self.assertFalse(hasattr(Period, 'Period')) + self.assertFalse(hasattr(Period, 'i')) + self.assertTrue(isinstance(Period.day_1, timedelta)) + + def test_skip(self): + class enumA(Enum): + @skip + class enumB(Enum): + elementA = 'a' + elementB = 'b' + @skip + class enumC(Enum): + elementC = 'c' + elementD = 'd' + self.assertIs(enumA.enumB, enumA.__dict__['enumB']) + + def test_nonmember(self): + class enumA(Enum): + @nonmember + class enumB(Enum): + elementA = 'a' + elementB = 'b' + @nonmember + class enumC(Enum): + elementC = 'c' + elementD = 'd' + self.assertIs(enumA.enumB, enumA.__dict__['enumB']) + + def test_member_with_external_functions(self): + class Func(Enum): + _order_ = 'an_int a_str' + an_int = member(int) + a_str = member(str) + @classproperty + def types(cls): + return [m.value for m in list(cls)] + def __repr__(self): + return "<%s.%s>" % (self.__class__.__name__, self.name, ) + def __call__(self, *args, **kwds): + return self.value(*args, **kwds) + # + self.assertEqual([Func.an_int, Func.a_str], list(Func)) + self.assertEqual([int, str], Func.types) + self.assertEqual(Func.an_int(7), 7) + self.assertEqual(Func.a_str('BlahBlah'), 'BlahBlah') + + def test_member_with_internal_functions(self): + class Func(Enum): + _order_ = 'haha hehe' + @member + def haha(): + return 'haha' + @member + def hehe(name): + return 'hehe -- what a name! %s!' % name + @classproperty + def types(cls): + return [m.value for m in list(cls)] + def __repr__(self): + return "<%s.%s>" % (self.__class__.__name__, self.name, ) + def __call__(self, *args, **kwds): + return self.value(*args, **kwds) + # + self.assertEqual([Func.haha, Func.hehe], list(Func)) + self.assertEqual([Func.haha.value, Func.hehe.value], Func.types) + self.assertEqual(Func.haha(), 'haha') + self.assertEqual(Func.hehe('BlahBlah'), 'hehe -- what a name! BlahBlah!') + + def test_constantness_of_constants(self): + class Universe(Enum): + PI = constant(3.141596) + G = constant(6.67300E-11) + self.assertEqual(Universe.PI, 3.141596) + self.assertRaisesRegex(AttributeError, r'cannot rebind constant', setattr, Universe, 'PI', 9) + self.assertRaisesRegex(AttributeError, r'cannot delete constant', delattr, Universe, 'PI') + + def test_math_and_stuff_with_constants(self): + class Universe(Enum): + PI = constant(3.141596) + TAU = constant(2 * PI) + self.assertEqual(Universe.PI, 3.141596) + self.assertEqual(Universe.TAU, 2 * Universe.PI) + + def test_constant_with_auto_is_updated(self): + class Fruit(Flag): + _order_ = 'apple banana lemon orange' + apple = auto() + banana = auto() + lemon = auto() + orange = auto() + CitrusTypes = constant(lemon | orange) + self.assertEqual(list(Fruit), [Fruit.apple, Fruit.banana, Fruit.lemon, Fruit.orange]) + self.assertEqual(list(Fruit.CitrusTypes), [Fruit.lemon, Fruit.orange]) + self.assertTrue(Fruit.orange in Fruit.CitrusTypes) + + + def test_order_as_function(self): + # first with _init_ + class TestSequence(Enum): + _init_ = 'value, sequence' + _order_ = lambda member: member.sequence + item_id = 'An$(1,6)', 0 # Item Code + company_id = 'An$(7,2)', 1 # Company Code + warehouse_no = 'An$(9,4)', 2 # Warehouse Number + company = 'Hn$(13,6)', 3 # 4 SPACES + COMPANY + key_type = 'Cn$(19,3)', 4 # Key Type = '1**' + available = 'Zn$(1,1)', 5 # Available? + contract_item = 'Bn(2,1)', 6 # Contract Item? + sales_category = 'Fn', 7 # Sales Category + gl_category = 'Rn$(5,1)', 8 # G/L Category + warehouse_category = 'Sn$(6,1)', 9 # Warehouse Category + inv_units = 'Qn$(7,2)', 10 # Inv Units + for i, member in enumerate(TestSequence): + self.assertEqual(i, member.sequence) + ts = TestSequence + self.assertEqual(ts.item_id.name, 'item_id') + self.assertEqual(ts.item_id.value, 'An$(1,6)') + self.assertEqual(ts.item_id.sequence, 0) + self.assertEqual(ts.company_id.name, 'company_id') + self.assertEqual(ts.company_id.value, 'An$(7,2)') + self.assertEqual(ts.company_id.sequence, 1) + self.assertEqual(ts.warehouse_no.name, 'warehouse_no') + self.assertEqual(ts.warehouse_no.value, 'An$(9,4)') + self.assertEqual(ts.warehouse_no.sequence, 2) + self.assertEqual(ts.company.name, 'company') + self.assertEqual(ts.company.value, 'Hn$(13,6)') + self.assertEqual(ts.company.sequence, 3) + self.assertEqual(ts.key_type.name, 'key_type') + self.assertEqual(ts.key_type.value, 'Cn$(19,3)') + self.assertEqual(ts.key_type.sequence, 4) + self.assertEqual(ts.available.name, 'available') + self.assertEqual(ts.available.value, 'Zn$(1,1)') + self.assertEqual(ts.available.sequence, 5) + self.assertEqual(ts.contract_item.name, 'contract_item') + self.assertEqual(ts.contract_item.value, 'Bn(2,1)') + self.assertEqual(ts.contract_item.sequence, 6) + self.assertEqual(ts.sales_category.name, 'sales_category') + self.assertEqual(ts.sales_category.value, 'Fn') + self.assertEqual(ts.sales_category.sequence, 7) + self.assertEqual(ts.gl_category.name, 'gl_category') + self.assertEqual(ts.gl_category.value, 'Rn$(5,1)') + self.assertEqual(ts.gl_category.sequence, 8) + self.assertEqual(ts.warehouse_category.name, 'warehouse_category') + self.assertEqual(ts.warehouse_category.value, 'Sn$(6,1)') + self.assertEqual(ts.warehouse_category.sequence, 9) + self.assertEqual(ts.inv_units.name, 'inv_units') + self.assertEqual(ts.inv_units.value, 'Qn$(7,2)') + self.assertEqual(ts.inv_units.sequence, 10) + # and then without + class TestSequence(Enum): + _order_ = lambda member: member.value[1] + item_id = 'An$(1,6)', 0 # Item Code + company_id = 'An$(7,2)', 1 # Company Code + warehouse_no = 'An$(9,4)', 2 # Warehouse Number + company = 'Hn$(13,6)', 3 # 4 SPACES + COMPANY + key_type = 'Cn$(19,3)', 4 # Key Type = '1**' + available = 'Zn$(1,1)', 5 # Available? + contract_item = 'Bn(2,1)', 6 # Contract Item? + sales_category = 'Fn', 7 # Sales Category + gl_category = 'Rn$(5,1)', 8 # G/L Category + warehouse_category = 'Sn$(6,1)', 9 # Warehouse Category + inv_units = 'Qn$(7,2)', 10 # Inv Units + for i, member in enumerate(TestSequence): + self.assertEqual(i, member.value[1]) + ts = TestSequence + self.assertEqual(ts.item_id.name, 'item_id') + self.assertEqual(ts.item_id.value, ('An$(1,6)', 0)) + self.assertEqual(ts.company_id.name, 'company_id') + self.assertEqual(ts.company_id.value, ('An$(7,2)', 1)) + self.assertEqual(ts.warehouse_no.name, 'warehouse_no') + self.assertEqual(ts.warehouse_no.value, ('An$(9,4)', 2)) + self.assertEqual(ts.company.name, 'company') + self.assertEqual(ts.company.value, ('Hn$(13,6)', 3)) + self.assertEqual(ts.key_type.name, 'key_type') + self.assertEqual(ts.key_type.value, ('Cn$(19,3)', 4)) + self.assertEqual(ts.available.name, 'available') + self.assertEqual(ts.available.value, ('Zn$(1,1)', 5)) + self.assertEqual(ts.contract_item.name, 'contract_item') + self.assertEqual(ts.contract_item.value, ('Bn(2,1)', 6)) + self.assertEqual(ts.sales_category.name, 'sales_category') + self.assertEqual(ts.sales_category.value, ('Fn', 7)) + self.assertEqual(ts.gl_category.name, 'gl_category') + self.assertEqual(ts.gl_category.value, ('Rn$(5,1)', 8)) + self.assertEqual(ts.warehouse_category.name, 'warehouse_category') + self.assertEqual(ts.warehouse_category.value, ('Sn$(6,1)', 9)) + self.assertEqual(ts.inv_units.name, 'inv_units') + self.assertEqual(ts.inv_units.value, ('Qn$(7,2)', 10)) + # then with _init_ but without value + with self.assertRaises(TypeError): + class TestSequence(Enum): + _init_ = 'sequence' + _order_ = lambda member: member.sequence + item_id = 'An$(1,6)', 0 # Item Code + company_id = 'An$(7,2)', 1 # Company Code + warehouse_no = 'An$(9,4)', 2 # Warehouse Number + company = 'Hn$(13,6)', 3 # 4 SPACES + COMPANY + key_type = 'Cn$(19,3)', 4 # Key Type = '1**' + available = 'Zn$(1,1)', 5 # Available? + contract_item = 'Bn(2,1)', 6 # Contract Item? + sales_category = 'Fn', 7 # Sales Category + gl_category = 'Rn$(5,1)', 8 # G/L Category + warehouse_category = 'Sn$(6,1)', 9 # Warehouse Category + inv_units = 'Qn$(7,2)', 10 # Inv Units + # finally, out of order so Python 3 barfs + with self.assertRaises(TypeError): + class TestSequence(Enum): + _init_ = 'sequence' + _order_ = lambda member: member.sequence + item_id = 'An$(1,6)', 0 # Item Code + warehouse_no = 'An$(9,4)', 2 # Warehouse Number + company = 'Hn$(13,6)', 3 # 4 SPACES + COMPANY + company_id = 'An$(7,2)', 1 # Company Code + inv_units = 'Qn$(7,2)', 10 # Inv Units + available = 'Zn$(1,1)', 5 # Available? + contract_item = 'Bn(2,1)', 6 # Contract Item? + sales_category = 'Fn', 7 # Sales Category + key_type = 'Cn$(19,3)', 4 # Key Type = '1**' + gl_category = 'Rn$(5,1)', 8 # G/L Category + warehouse_category = 'Sn$(6,1)', 9 # Warehouse Category + + def test_order_as_function_in_subclass(self): + # + class Parent(Enum): + _init_ = 'value sequence' + _order_ = lambda m: m.sequence + # + class Child(Parent): + item_id = 'An$(1,6)', 0 # Item Code + company_id = 'An$(7,2)', 1 # Company Code + warehouse_no = 'An$(9,4)', 2 # Warehouse Number + company = 'Hn$(13,6)', 3 # 4 SPACES + COMPANY + key_type = 'Cn$(19,3)', 4 # Key Type = '1**' + available = 'Zn$(1,1)', 5 # Available? + contract_item = 'Bn(2,1)', 6 # Contract Item? + sales_category = 'Fn', 7 # Sales Category + gl_category = 'Rn$(5,1)', 8 # G/L Category + warehouse_category = 'Sn$(6,1)', 9 # Warehouse Category + inv_units = 'Qn$(7,2)', 10 # Inv Units + # + for i, member in enumerate(Child): + self.assertEqual(i, member.sequence) + # + ts = Child + self.assertEqual(ts.item_id.name, 'item_id') + self.assertEqual(ts.item_id.value, 'An$(1,6)') + self.assertEqual(ts.item_id.sequence, 0) + self.assertEqual(ts.company_id.name, 'company_id') + self.assertEqual(ts.company_id.value, 'An$(7,2)') + self.assertEqual(ts.company_id.sequence, 1) + self.assertEqual(ts.warehouse_no.name, 'warehouse_no') + self.assertEqual(ts.warehouse_no.value, 'An$(9,4)') + self.assertEqual(ts.warehouse_no.sequence, 2) + self.assertEqual(ts.company.name, 'company') + self.assertEqual(ts.company.value, 'Hn$(13,6)') + self.assertEqual(ts.company.sequence, 3) + self.assertEqual(ts.key_type.name, 'key_type') + self.assertEqual(ts.key_type.value, 'Cn$(19,3)') + self.assertEqual(ts.key_type.sequence, 4) + self.assertEqual(ts.available.name, 'available') + self.assertEqual(ts.available.value, 'Zn$(1,1)') + self.assertEqual(ts.available.sequence, 5) + self.assertEqual(ts.contract_item.name, 'contract_item') + self.assertEqual(ts.contract_item.value, 'Bn(2,1)') + self.assertEqual(ts.contract_item.sequence, 6) + self.assertEqual(ts.sales_category.name, 'sales_category') + self.assertEqual(ts.sales_category.value, 'Fn') + self.assertEqual(ts.sales_category.sequence, 7) + self.assertEqual(ts.gl_category.name, 'gl_category') + self.assertEqual(ts.gl_category.value, 'Rn$(5,1)') + self.assertEqual(ts.gl_category.sequence, 8) + self.assertEqual(ts.warehouse_category.name, 'warehouse_category') + self.assertEqual(ts.warehouse_category.value, 'Sn$(6,1)') + self.assertEqual(ts.warehouse_category.sequence, 9) + self.assertEqual(ts.inv_units.name, 'inv_units') + self.assertEqual(ts.inv_units.value, 'Qn$(7,2)') + self.assertEqual(ts.inv_units.sequence, 10) + + pass + + def test_multiple_mixin(self): + class MaxMixin(object): + @classproperty + def MAX(cls): + max = len(cls) + cls.MAX = max + return max + class StrMixin(object): + def __str__(self): + return self._name_.lower() + class SomeEnum(Enum): + def behavior(self): + return 'booyah' + class AnotherEnum(Enum): + def behavior(self): + return 'nuhuh!' + def social(self): + return "what's up?" + class Color(MaxMixin, Enum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 3) + self.assertEqual(Color.MAX, 3) + self.assertEqual(str(Color.BLUE), 'Color.BLUE') + class Color(MaxMixin, StrMixin, Enum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 3) + self.assertEqual(Color.MAX, 3) + self.assertEqual(str(Color.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + class Color(StrMixin, MaxMixin, Enum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 3) + self.assertEqual(Color.MAX, 3) + self.assertEqual(str(Color.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + class CoolColor(StrMixin, SomeEnum, Enum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(CoolColor.RED.value, 1) + self.assertEqual(CoolColor.GREEN.value, 2) + self.assertEqual(CoolColor.BLUE.value, 3) + self.assertEqual(str(CoolColor.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + self.assertEqual(CoolColor.RED.behavior(), 'booyah') + class CoolerColor(StrMixin, AnotherEnum, Enum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(CoolerColor.RED.value, 1) + self.assertEqual(CoolerColor.GREEN.value, 2) + self.assertEqual(CoolerColor.BLUE.value, 3) + self.assertEqual(str(CoolerColor.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!') + self.assertEqual(CoolerColor.RED.social(), "what's up?") + class CoolestColor(StrMixin, SomeEnum, AnotherEnum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(CoolestColor.RED.value, 1) + self.assertEqual(CoolestColor.GREEN.value, 2) + self.assertEqual(CoolestColor.BLUE.value, 3) + self.assertEqual(str(CoolestColor.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + self.assertEqual(CoolestColor.RED.behavior(), 'booyah') + self.assertEqual(CoolestColor.RED.social(), "what's up?") + class ConfusedColor(StrMixin, AnotherEnum, SomeEnum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(ConfusedColor.RED.value, 1) + self.assertEqual(ConfusedColor.GREEN.value, 2) + self.assertEqual(ConfusedColor.BLUE.value, 3) + self.assertEqual(str(ConfusedColor.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!') + self.assertEqual(ConfusedColor.RED.social(), "what's up?") + class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(ReformedColor.RED.value, 1) + self.assertEqual(ReformedColor.GREEN.value, 2) + self.assertEqual(ReformedColor.BLUE.value, 3) + self.assertEqual(str(ReformedColor.BLUE), 'blue', '%r is not %r' % (str(Color.BLUE), 'blue')) + self.assertEqual(ReformedColor.RED.behavior(), 'booyah') + self.assertEqual(ConfusedColor.RED.social(), "what's up?") + self.assertTrue(issubclass(ReformedColor, int)) + + def test_multiple_inherited_mixin(self): + @unique + class Decision1(StrEnum): + REVERT = "REVERT" + REVERT_ALL = "REVERT_ALL" + RETRY = "RETRY" + class MyEnum(StrEnum): + pass + @unique + class Decision2(MyEnum): + REVERT = "REVERT" + REVERT_ALL = "REVERT_ALL" + RETRY = "RETRY" + + def test_value_auto_assign(self): + class Some(Enum): + def __new__(cls, val): + return object.__new__(cls) + x = 1 + y = 2 + self.assertEqual(Some.x.value, 1) + self.assertEqual(Some.y.value, 2) + + def test_enum_of_types(self): + """Support using Enum to refer to types deliberately.""" + class MyTypes(Enum): + i = int + f = float + s = str + self.assertEqual(MyTypes.i.value, int) + self.assertEqual(MyTypes.f.value, float) + self.assertEqual(MyTypes.s.value, str) + class Foo: + pass + class Bar: + pass + class MyTypes2(Enum): + a = Foo + b = Bar + self.assertEqual(MyTypes2.a.value, Foo) + self.assertEqual(MyTypes2.b.value, Bar) + class SpamEnumNotInner: + pass + class SpamEnum(Enum): + spam = SpamEnumNotInner + self.assertEqual(SpamEnum.spam.value, SpamEnumNotInner) + + if PY2: + def test_nested_classes_in_enum_do_become_members(self): + # manually set __qualname__ to remove testing framework noise + class Outer(Enum): + _order_ = 'a b Inner' + __qualname__ = "Outer" + a = 1 + b = 2 + class Inner(Enum): + __qualname__ = "Outer.Inner" + foo = 10 + bar = 11 + self.assertTrue(isinstance(Outer.Inner, Outer)) + self.assertEqual(Outer.a.value, 1) + self.assertEqual(Outer.Inner.value.foo.value, 10) + self.assertEqual( + list(Outer.Inner.value), + [Outer.Inner.value.foo, Outer.Inner.value.bar], + ) + self.assertEqual( + list(Outer), + [Outer.a, Outer.b, Outer.Inner], + ) + + def test_really_nested_classes_in_enum_do_become_members(self): + class Outer(Enum): + _order_ = 'a b Inner' + a = 1 + b = 2 + class Inner(Enum): + foo = 10 + bar = 11 + self.assertTrue(isinstance(Outer.Inner, Outer)) + self.assertEqual(Outer.a.value, 1) + self.assertEqual(Outer.Inner.value.foo.value, 10) + self.assertEqual( + list(Outer.Inner.value), + [Outer.Inner.value.foo, Outer.Inner.value.bar], + ) + self.assertEqual( + list(Outer), + [Outer.a, Outer.b, Outer.Inner], + ) + + def test_nested_classes_in_enum_are_skipped_with_skip(self): + """Support locally-defined nested classes using @skip""" + # manually set __qualname__ to remove testing framework noise + class Outer(Enum): + __qualname__ = "Outer" + a = 1 + b = 2 + @skip + class Inner(Enum): + __qualname__ = "Outer.Inner" + foo = 10 + bar = 11 + self.assertTrue(isinstance(Outer.Inner, type)) + self.assertEqual(Outer.a.value, 1) + self.assertEqual(Outer.Inner.foo.value, 10) + self.assertEqual( + list(Outer.Inner), + [Outer.Inner.foo, Outer.Inner.bar], + ) + self.assertEqual( + list(Outer), + [Outer.a, Outer.b], + ) + + def test_really_nested_classes_in_enum_are_skipped_with_skip(self): + """Support locally-defined nested classes using @skip""" + class Outer(Enum): + a = 1 + b = 2 + @skip + class Inner(Enum): + foo = 10 + bar = 11 + self.assertTrue(isinstance(Outer.Inner, type)) + self.assertEqual(Outer.a.value, 1) + self.assertEqual(Outer.Inner.foo.value, 10) + self.assertEqual( + list(Outer.Inner), + [Outer.Inner.foo, Outer.Inner.bar], + ) + self.assertEqual( + list(Outer), + [Outer.a, Outer.b], + ) + + def test_enum_call_without_arg(self): + class Color(Enum): + black = 0 + red = 1 + green = 2 + blue = 3 + # + @classmethod + def _missing_value_(cls, value): + if value is no_arg: + return cls.black + self.assertTrue(Color.red is Color(1)) + self.assertTrue(Color.black is Color()) + + def test_init_subclass(self): + class MyEnum(Enum): + def __init_subclass__(cls, **kwds): + super(MyEnum, cls).__init_subclass__(**kwds) + self.assertFalse(cls.__dict__.get('_test', False)) + cls._test1 = 'MyEnum' + # + class TheirEnum(MyEnum): + def __init_subclass__(cls, **kwds): + super(TheirEnum, cls).__init_subclass__(**kwds) + cls._test2 = 'TheirEnum' + class WhoseEnum(TheirEnum): + def __init_subclass__(cls, **kwds): + pass + class NoEnum(WhoseEnum): + ONE = 1 + self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') + self.assertFalse(NoEnum.__dict__.get('_test1', False)) + self.assertFalse(NoEnum.__dict__.get('_test2', False)) + # + class OurEnum(MyEnum): + def __init_subclass__(cls, **kwds): + cls._test2 = 'OurEnum' + class WhereEnum(OurEnum): + def __init_subclass__(cls, **kwds): + pass + class NeverEnum(WhereEnum): + ONE = 'one' + self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') + self.assertFalse(WhereEnum.__dict__.get('_test1', False)) + self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') + self.assertFalse(NeverEnum.__dict__.get('_test1', False)) + self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + + +class TestStrEnum(TestCase): + + def test_set_name(self): + class Descriptor(object): + name = None + def __get__(self, instance, owner_class=None): + if instance is None: + return self + else: + return instance.__dict__[self.name] + def __set__(self, instance, value): + instance.__dict__[self.name] = value + def __set_name__(self, owner, name): + self.name = name + # + class AnEnum(Enum): + ONE = 'one' + two = Descriptor() + # + self.assertEqual(list(AnEnum), [AnEnum.ONE]) + self.assertEqual(AnEnum.two.name, 'two') + AnEnum.ONE.two = 'three' + self.assertEqual(AnEnum.ONE.two, 'three') + self.assertEqual(AnEnum.ONE.__dict__['two'], 'three') + + def test_private_names(self): + class Private(Enum): + __corporal = 'Radar' + __major_ = 'Hoolihan' + self.assertEqual(len(Private), 0) + self.assertEqual(Private._Private__corporal, 'Radar') + self.assertFalse(isinstance(Private._Private__corporal, Enum)) + self.assertEqual(Private._Private__major_, 'Hoolihan') + self.assertFalse(isinstance(Private._Private__major_, Enum)) + + def test_strenum_inherited_methods(self): + class phy(StrEnum): + pi = 'Pi' + tau = 'Tau' + self.assertTrue(phy.pi < phy.tau) + self.assertEqual(phy.pi.upper(), 'PI') + self.assertEqual(phy.tau.count('a'), 1) + + def test_strict_strenum(self): + for uhoh in (object, object(), [], Enum, 9): + with self.assertRaisesRegex(TypeError, r'values must be str'): + class Huh(StrEnum): + huh = uhoh + class Either(StrEnum): + _order_ = 'this that Those lower upper' + this = auto() + that = 'That' + Those = auto() + lower = 'lower' + upper = 'UPPER' + self.assertEqual([m.value for m in Either], ['this', 'That', 'those', 'lower', 'UPPER']) + # + with self.assertRaisesRegex(ValueError, r' is not lower-case'): + class Huh(LowerStrEnum): + huh = 'What' + # + class Lower(LowerStrEnum): + _order_ = 'this that Those lower upper' + this = auto() + that = 'that' + Those = auto() + lower = 'lower' + upper = 'upper' + self.assertEqual([m.value for m in Lower], ['this', 'that', 'those', 'lower', 'upper']) + # + with self.assertRaisesRegex(ValueError, r' is not upper-case'): + class Huh(UpperStrEnum): + huh = 'What' + # + class Upper(UpperStrEnum): + _order_ = 'this that Those lower upper' + this = auto() + that = 'THAT' + Those = auto() + lower = 'LOWER' + upper = 'UPPER' + self.assertEqual([m.value for m in Upper], ['THIS', 'THAT', 'THOSE', 'LOWER', 'UPPER']) + + def test_init_subclass(self): + class MyEnum(StrEnum): + def __init_subclass__(cls, **kwds): + super(MyEnum, cls).__init_subclass__(**kwds) + self.assertFalse(cls.__dict__.get('_test', False)) + cls._test1 = 'MyEnum' + # + class TheirEnum(MyEnum): + def __init_subclass__(cls, **kwds): + super(TheirEnum, cls).__init_subclass__(**kwds) + cls._test2 = 'TheirEnum' + class WhoseEnum(TheirEnum): + def __init_subclass__(cls, **kwds): + pass + class NoEnum(WhoseEnum): + ONE = 'one' + self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') + self.assertFalse(NoEnum.__dict__.get('_test1', False)) + self.assertFalse(NoEnum.__dict__.get('_test2', False)) + # + class OurEnum(MyEnum): + def __init_subclass__(cls, **kwds): + cls._test2 = 'OurEnum' + class WhereEnum(OurEnum): + def __init_subclass__(cls, **kwds): + pass + class NeverEnum(WhereEnum): + ONE = 'one' + self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') + self.assertFalse(WhereEnum.__dict__.get('_test1', False)) + self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') + self.assertFalse(NeverEnum.__dict__.get('_test1', False)) + self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + + +class TestFlag(TestCase): + """Tests of the Flags.""" + + def setUp(self): + class Perm(Flag): + _order_ = 'R W X' + R, W, X = 4, 2, 1 + self.Perm = Perm + # + class Color(Flag): + BLACK = 0 + RED = 1 + ROJO = 1 + GREEN = 2 + BLUE = 4 + PURPLE = RED|BLUE + WHITE = RED|GREEN|BLUE + BLANCO = RED|GREEN|BLUE + self.Color = Color + # + class Fun(Flag): + _order_ = 'ONE TWO FOUR EIGHT' + ONE = auto() + TWO = auto() + THREE = ONE | TWO + FOUR = auto() + FIVE = FOUR | ONE + SIX = FOUR | TWO + SEVEN = FOUR | TWO | ONE + EIGHT = auto() + self.Fun = Fun + # + class TermColor(str, Flag): + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + # + @classmethod + def _create_pseudo_member_values_(cls, members, *values): + code = ';'.join(m.code for m in members) + return values + (code, ) + # + AllReset = '0' # ESC [ 0 m # reset all (colors and brightness) + Bright = '1' # ESC [ 1 m # bright + Dim = '2' # ESC [ 2 m # dim (looks same as normal brightness) + Underline = '4' + Normal = '22' # ESC [ 22 m # normal brightness + # + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Yellow = '33' # ESC [ 33 m # yellow + FG_Blue = '34' # ESC [ 34 m # blue + FG_Magenta = '35' # ESC [ 35 m # magenta + FG_Cyan = '36' # ESC [ 36 m # cyan + FG_White = '37' # ESC [ 37 m # white + FG_Reset = '39' # ESC [ 39 m # reset + # + BG_Black = '40' # ESC [ 30 m # black + BG_Red = '41' # ESC [ 31 m # red + BG_Green = '42' # ESC [ 32 m # green + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Blue = '44' # ESC [ 34 m # blue + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + BG_Reset = '49' # ESC [ 39 m # reset + # + __str__ = str.__str__ + # + def __repr__(self): + if self._name_ is not None: + return '<%s.%s>' % (self.__class__.__name__, self._name_) + else: + return '<%s: %s>' % (self.__class__.__name__, '|'.join([m.name for m in Flag.__iter__(self)])) + # + def __enter__(self): + print(self.AllReset, end='', verbose=0) + return self + # + def __exit__(self, *args): + print(self.AllReset, end='', verbose=0) + self.TermColor = TermColor + # + class Open(Flag): + RO = 0 + WO = 1 + RW = 2 + AC = 3 + CE = 1<<19 + self.Open = Open + + def test_set_name(self): + class Descriptor(object): + name = None + def __get__(self, instance, owner_class=None): + if instance is None: + return self + else: + return instance.__dict__[self.name] + def __set__(self, instance, value): + instance.__dict__[self.name] = value + def __set_name__(self, owner, name): + self.name = name + # + class AnEnum(Enum): + ONE = 1 + two = Descriptor() + # + self.assertEqual(list(AnEnum), [AnEnum.ONE]) + self.assertEqual(AnEnum.two.name, 'two') + AnEnum.ONE.two = 'three' + self.assertEqual(AnEnum.ONE.two, 'three') + self.assertEqual(AnEnum.ONE.__dict__['two'], 'three') + + def test_new_with_keywords(self): + class Huh(IntFlag): + __order__ = 'PLAIN BOLD_ITALIC HIGHLIGHT' + def __new__(cls, docstring, open=None, close=None): + if cls.__members__: + value = 2 ** (len(cls.__members__)-1) + else: + value = 0 + member = int.__new__(cls, value) + if open and close is None: + close = open + member.open = open + member.close = close + member.__doc__ = docstring + member._value_ = value + return member + PLAIN = 'normal' + BOLD_ITALIC = '***really super important***', '***' + HIGHLIGHT = 'please ==take notice==', '==', '==' + p = Huh.PLAIN + self.assertTrue(type(p) is Huh, type(p)) + self.assertEqual( + (p.value, p.__doc__, p.open, p.close), + (0, 'normal', None, None), + ) + bi = Huh.BOLD_ITALIC + self.assertEqual( + (bi.value, bi.__doc__, bi.open, bi.close), + (1, '***really super important***', '***', '***'), + ) + h = Huh.HIGHLIGHT + self.assertEqual( + (h.value, h.__doc__, h.open, h.close), + (2, 'please ==take notice==', '==', '=='), + ) + + def test_private_names(self): + class Private(Enum): + __corporal = 'Radar' + __major_ = 'Hoolihan' + self.assertEqual(len(Private), 0) + self.assertEqual(Private._Private__corporal, 'Radar') + self.assertFalse(isinstance(Private._Private__corporal, Enum)) + self.assertEqual(Private._Private__major_, 'Hoolihan') + self.assertFalse(isinstance(Private._Private__major_, Enum)) + + def test_auto_alias(self): + Fun = self.Fun + self.assertEqual( + list(Fun), + [Fun.ONE, Fun.TWO, Fun.FOUR, Fun.EIGHT], + ) + self.assertEqual(Fun.THREE._value_, 3) + self.assertEqual(repr(Fun.SEVEN), '<Fun.SEVEN: 7>') + self.assertEqual(list(Fun.SEVEN), [Fun.ONE, Fun.TWO, Fun.FOUR]) + + def test_str_is_str_str(self): + red, white = self.TermColor.FG_Red, self.TermColor.BG_White + barber = red | white + self.assertEqual(barber, '\x1b[31;47m') + self.assertEqual(barber.value, red.value | white.value) + self.assertEqual(barber.code, ';'.join([red.code, white.code])) + self.assertEqual(repr(barber), '<TermColor.FG_Red|BG_White>') + self.assertEqual(str(barber), '\x1b[31;47m') + + def test_membership(self): + Color = self.Color + Open = self.Open + self.assertRaises(TypeError, lambda: 'BLACK' in Color) + self.assertRaises(TypeError, lambda: 'RO' in Open) + self.assertTrue(Color.BLACK in Color) + self.assertTrue(Open.RO in Open) + self.assertFalse(Color.BLACK in Open) + self.assertFalse(Open.RO in Color) + self.assertRaises(TypeError, lambda: 0 in Color) + self.assertRaises(TypeError, lambda: 0 in Open) + + def test_member_contains(self): + Color = self.Color + self.assertRaises(TypeError, lambda: 'test' in Color.BLUE) + self.assertRaises(TypeError, lambda: 2 in Color.BLUE) + self.assertTrue(Color.BLUE in Color.BLUE) + self.assertTrue(Color.BLUE in Color['RED|GREEN|BLUE']) + + def test_member_length(self): + self.assertEqual(self.Color.__len__(self.Color.BLACK), 0) + self.assertEqual(self.Color.__len__(self.Color.GREEN), 1) + self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2) + self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3) + + def test_number_reset_and_order_cleanup(self): + class Confused(Flag): + _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN' + ONE = auto() + TWO = auto() + FOUR = auto() + DOS = 2 + EIGHT = auto() + SIXTEEN = auto() + self.assertEqual( + list(Confused), + [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN]) + self.assertIs(Confused.TWO, Confused.DOS) + self.assertEqual(Confused.DOS._value_, 2) + self.assertEqual(Confused.EIGHT._value_, 8) + self.assertEqual(Confused.SIXTEEN._value_, 16) + + 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(-1)), 'Perm.R|W|X') + 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.WO|CE') + self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE') + self.assertEqual(str(~Open.WO), 'Open.RW|CE') + 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.WO|CE: 524289>') + self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>') + self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 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_name_lookup(self): + Color = self.Color + self.assertTrue(Color.RED is Color['RED']) + self.assertTrue(Color.RED|Color.GREEN is Color['RED|GREEN']) + self.assertTrue(Color.PURPLE is Color['RED|BLUE']) + + 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_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_doc_flag(self): + class DocFlag(Flag): + _init_ = 'value __doc__' + _start_ = 0 + # def __new__(cls, value, doc=None): + # # if doc is None and isinstance(value, basestring): + # # value, doc = doc, value + # # if value is None: + # # if not len(cls): + # # value = 0 + # # else: + # # value = 2 ** (len(cls) -1) + # # if not isinstance(value, baseinteger): + # # raise TypeError("%r is not a valid %s value" % (value, cls.__name__)) + # obj = object.__new__(cls) + # # if doc is None, don't mess with the value + # if doc: + # value = value >> 1 + # obj._value_ = value + # obj.__doc__ = doc + # return obj + # + class AddressSegment(DocFlag): + _order_ = 'UNKNOWN PO PO_TYPE NUMBER PREORD NAME STREET POSTORD SECONDARY_TYPE SECONDARY_NUMBER AND' + UNKNOWN = "unable to determine address element type" + PO = "post office delivery" + PO_TYPE = "box or drawer" + NUMBER = "main unit designator" + PREORD = "N S E W etc" + NAME = "street name" + STREET = "st ave blvd etc" + POSTORD = "N S E W etc" + SECONDARY_TYPE = "apt bldg floor etc" + SECONDARY_NUMBER = "secondary unit designator" + AND = "& indicates a corner address" + AS = AddressSegment + self.assertEqual(AS.NAME._value_, 16) + self.assertEqual(AS.STREET._value_, 32) + self.assertEqual(AS.SECONDARY_TYPE._value_, 128) + self.assertEqual((AS.NAME | AS.STREET)._value_, 48, "%r is not 48" % (AS.NAME | AS.STREET)) + + def test_iteration(self): + C = self.Color + self.assertEqual(list(C), [C.RED, C.GREEN, C.BLUE]) + self.assertEqual(list(C.PURPLE), [C.RED, C.BLUE]) + + def test_member_iteration(self): + C = self.Color + self.assertEqual(list(C.BLACK), []) + self.assertEqual(list(C.RED), [C.RED]) + self.assertEqual(list(C.PURPLE), [C.RED, C.BLUE]) + + def test_programatic_function_string(self): + Perm = Flag('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 = Flag('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 = Flag('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 = Flag('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 = Flag('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) + + def test_programatic_function_empty_list(self): + Perm = IntFlag('Perm', []) + self.assertEqual(len(list(Perm)), len(Perm)) + self.assertEqual(len(Perm), 0) + Thing = Enum('Thing', []) + self.assertEqual(len(list(Thing)), len(Thing)) + self.assertEqual(len(Thing), 0) + + def test_programatic_function_empty_tuple(self): + Perm = IntFlag('Perm', ()) + self.assertEqual(len(list(Perm)), len(Perm)) + self.assertEqual(len(Perm), 0) + Thing = Enum('Thing', ()) + self.assertEqual(len(list(Thing)), len(Thing)) + self.assertEqual(len(Thing), 0) + + def test_pickle(self): + if isinstance(FlagStooges, Exception): + raise FlagStooges + test_pickle_dump_load(self.assertIs, FlagStooges.CURLY|FlagStooges.MOE) + test_pickle_dump_load(self.assertIs, FlagStooges) + + def test_containment(self): + Perm = self.Perm + R, W, X = Perm + RW = R | W + RX = R | X + WX = W | X + RWX = R | W | X + self.assertTrue(R in RW) + self.assertTrue(R in RX) + self.assertTrue(R in RWX) + self.assertTrue(W in RW) + self.assertTrue(W in WX) + self.assertTrue(W in RWX) + self.assertTrue(X in RX) + self.assertTrue(X in WX) + self.assertTrue(X in RWX) + self.assertFalse(R in WX) + self.assertFalse(W in RX) + self.assertFalse(X in RW) + + def test_auto_number(self): + class Color(Flag): + _order_ = 'red blue green' + red = auto() + blue = auto() + green = auto() + + self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(Color.red.value, 1) + self.assertEqual(Color.blue.value, 2) + self.assertEqual(Color.green.value, 4) + + def test_auto_number_garbage(self): + with self.assertRaisesRegex(TypeError, r'invalid Flag value: .not an int.'): + class Color(Flag): + _order_ = 'red blue' + red = 'not an int' + blue = auto() + + def test_auto_w_pending(self): + class Required(Flag): + _order_ = 'TO_S FROM_S' + NONE = 0 + TO_S = auto() + FROM_S = auto() + BOTH = TO_S | FROM_S + self.assertEqual(Required.TO_S.value, 1) + self.assertEqual(Required.FROM_S.value, 2) + self.assertEqual(Required.BOTH.value, 3) + + def test_duplicate_auto(self): + class Dupes(Enum): + _order_ = 'first second third' + first = primero = auto() + second = auto() + third = auto() + self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) + + def test_bizarre(self): + with self.assertRaisesRegex(TypeError, r"invalid Flag 'Bizarre' -- missing values: 1, 2"): + class Bizarre(Flag): + b = 3 + c = 4 + d = 6 + + def test_multiple_mixin(self): + class AllMixin(object): + @classproperty + def ALL(cls): + members = list(cls) + all_value = None + if members: + all_value = members[0] + for member in members[1:]: + all_value |= member + cls.ALL = all_value + return all_value + class StrMixin(object): + def __str__(self): + return self._name_.lower() + class Color(AllMixin, Flag): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 4) + self.assertEqual(Color.ALL.value, 7) + self.assertEqual(str(Color.BLUE), 'Color.BLUE') + class Color(AllMixin, StrMixin, Flag): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 4) + self.assertEqual(Color.ALL.value, 7) + self.assertEqual(str(Color.BLUE), 'blue') + class Color(StrMixin, AllMixin, Flag): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 4) + self.assertEqual(Color.ALL.value, 7) + self.assertEqual(str(Color.BLUE), 'blue') + + @unittest.skipUnless(threading, 'Threading required for this test.') + def test_unique_composite(self): + # override __eq__ to be identity only + class TestFlag(Flag): + _order_ = 'one two three four five six seven eight' + one = auto() + two = auto() + three = auto() + four = auto() + five = auto() + six = auto() + seven = auto() + eight = auto() + def __eq__(self, other): + return self is other + def __hash__(self): + return hash(self._value_) + # have multiple threads competing to complete the composite members + seen = set() + failed = [False] + def cycle_enum(): + # nonlocal failed + try: + for i in range(256): + seen.add(TestFlag(i)) + except Exception: + failed[0] = True + threads = [ + threading.Thread(target=cycle_enum) + for _ in range(8) + ] + for t in threads: + t.start() + for t in threads: + t.join() + # check that only 248 members were created (8 were created originally) + self.assertFalse( + failed[0], + 'at least one thread failed while creating composite members') + self.assertEqual(256, len(seen), 'too many composite members created') + + def test_init_with_autovalue_and_generate_next_value(self): + class Color(Flag): + _init_ = 'value code' + def _generate_next_value_(name, start, count, last_values, *args, **kwds): + if not count: + return ((1, start)[start is not None], ) + args + error = False + for last_value in reversed(last_values): + try: + high_bit = aenum._high_bit(last_value) + break + except Exception: + error = True + break + if error: + raise TypeError('Invalid Flag value: %r' % (last_value, )) + return (2 ** (high_bit+1), ) + args + # TODO: actually test _create_pseudo_member + @classmethod + def _create_pseudo_member_(cls, value): + members = list(cls._iter_member_(value)) + pseudo_member = super(Color, cls)._create_pseudo_member_(value) + pseudo_member.code = ';'.join(m.code for m in members) + return pseudo_member + AllReset = '0' # ESC [ 0 m # reset all (colors and brightness) + Bright = '1' # ESC [ 1 m # bright + Dim = '2' # ESC [ 2 m # dim (looks same as normal brightness) + Underline = '4' + Normal = '22' # ESC [ 22 m # normal brightness + # if we got here, we're good + + def test_autovalue_and_generate_next_value(self): + class Color(str, Flag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (2 ** count, ) + args + # TODO: actually test _create_pseudo_member + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(Color, cls)._create_pseudo_member_(value, code) + return pseudo_member + # + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + # if we got here, we're good + + def test_subclass(self): + class Color(str, Flag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (2 ** count, ) + args + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(Color, cls)._create_pseudo_member_(value, code) + return pseudo_member + # + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + self.assertTrue(isinstance(Color.FG_Black, Color)) + self.assertTrue(isinstance(Color.FG_Black, str)) + self.assertEqual(Color.FG_Black, '\x1b[30m') + self.assertEqual(Color.FG_Black.code, '30') + + def test_sub_subclass_1(self): + class StrFlag(str, Flag): + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(Color, cls)._create_pseudo_member_(value, code) + return pseudo_member + class Color(StrFlag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + self.assertTrue(isinstance(Color.FG_Black, Color)) + self.assertTrue(isinstance(Color.FG_Black, str)) + self.assertEqual(Color.FG_Black, '\x1b[30m') + self.assertEqual(Color.FG_Black.code, '30') + + def test_sub_subclass_2(self): + class StrFlag(str, Flag): + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (2 ** count, ) + args + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(Color, cls)._create_pseudo_member_(value, code) + return pseudo_member + # + class Color(StrFlag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + self.assertTrue(isinstance(Color.FG_Black, Color)) + self.assertTrue(isinstance(Color.FG_Black, str)) + self.assertEqual(Color.FG_Black, '\x1b[30m') + self.assertEqual(Color.FG_Black.code, '30') + + def test_sub_subclass_3(self): + class StrFlag(str, Flag): + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(Color, cls)._create_pseudo_member_(value, code) + return pseudo_member + # + class Color(StrFlag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + self.assertTrue(isinstance(Color.FG_Black, Color)) + self.assertTrue(isinstance(Color.FG_Black, str)) + self.assertEqual(Color.FG_Black, '\x1b[30m') + self.assertEqual(Color.FG_Black.code, '30') + + def test_sub_subclass_4(self): + class StrFlag(str, Flag): + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @classmethod + def _create_pseudo_member_values_(cls, members, *values): + code = ';'.join(m.code for m in members) + return values + (code, ) + # + class Color(StrFlag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + # + def __repr__(self): + return '<%s.%s>' % (self.__class__.__name__, self._name_) + self.assertTrue(isinstance(Color.FG_Black, Color)) + self.assertTrue(isinstance(Color.FG_Black, str)) + self.assertEqual(Color.FG_Black, '\x1b[30m') + self.assertEqual(Color.FG_Black.code, '30') + colors = Color.BG_Magenta | Color.FG_Black + self.assertTrue(isinstance(colors, Color)) + self.assertTrue(isinstance(colors, str)) + self.assertEqual(colors, '\x1b[30;45m') + self.assertEqual(colors.code, '30;45') + self.assertEqual(repr(colors), '<Color.FG_Black|BG_Magenta>') + + def test_sub_subclass_with_new_new(self): + class StrFlag(str, Flag): + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(StrFlag, cls)._create_pseudo_member_(value, code) + return pseudo_member + # + class Color(StrFlag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + def __new__(cls, value, string, abbr): + str_value = (abbr or '').title() + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = string + obj.abbr = abbr + return obj + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30', 'blk' # ESC [ 30 m # black + FG_Red = '31', 'red' # ESC [ 31 m # red + FG_Green = '32', 'grn' # ESC [ 32 m # green + FG_Blue = '34', 'blu' # ESC [ 34 m # blue + # + BG_Yellow = '43', 'ylw' # ESC [ 33 m # yellow + BG_Magenta = '45', 'mag' # ESC [ 35 m # magenta + BG_Cyan = '46', 'cyn' # ESC [ 36 m # cyan + BG_White = '47', 'wht' # ESC [ 37 m # white + # + def __repr__(self): + if self._name_ is not None: + return '<%s.%s>' % (self.__class__.__name__, self._name_) + else: + return '<%s: %s>' % (self.__class__.__name__, '|'.join([m.name for m in self])) + self.assertTrue(isinstance(Color.FG_Black, Color)) + self.assertTrue(isinstance(Color.FG_Black, str)) + self.assertEqual(Color.FG_Black, 'Blk', str.__repr__(Color.FG_Black)) + self.assertEqual(Color.FG_Black.abbr, 'blk') + + def test_subclass_with_default_new(self): + class MyFlag(str, Flag): + _order_ = 'this these theother' + this = 'that' + these = 'those' + theother = 'thingimibobs' + self.assertEqual(MyFlag.this, 'that') + self.assertEqual(MyFlag.this.value, 1) + self.assertEqual(MyFlag.these, 'those') + self.assertEqual(MyFlag.these.value, 2) + self.assertEqual(MyFlag.theother, 'thingimibobs') + self.assertEqual(MyFlag.theother.value, 4) + + def test_subclass_a_bunch(self): + class Color(str, Flag): + _order_ = 'FG_Black FG_Red FG_Green FG_Blue BG_Yellow BG_Magenta BG_Cyan BG_White' + def __new__(cls, value, code): + str_value = '\x1b[%sm' % code + obj = str.__new__(cls, str_value) + obj._value_ = value + obj.code = code + return obj + @staticmethod + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (2 ** count, ) + args + @classmethod + def _create_pseudo_member_(cls, value): + # calculate the code + members = list(cls._iter_member_(value)) + code = ';'.join(m.code for m in members) + pseudo_member = super(Color, cls)._create_pseudo_member_(value, code) + return pseudo_member + # + # # FOREGROUND - 30s BACKGROUND - 40s: + FG_Black = '30' # ESC [ 30 m # black + FG_Red = '31' # ESC [ 31 m # red + FG_Green = '32' # ESC [ 32 m # green + FG_Blue = '34' # ESC [ 34 m # blue + # + BG_Yellow = '43' # ESC [ 33 m # yellow + BG_Magenta = '45' # ESC [ 35 m # magenta + BG_Cyan = '46' # ESC [ 36 m # cyan + BG_White = '47' # ESC [ 37 m # white + # + def __repr__(self): + if self._name_ is not None: + return '<%s.%s>' % (self.__class__.__name__, self._name_) + else: + return '<%s: %s>' % (self.__class__.__name__, '|'.join([m.name for m in self])) + # + Purple = Color.BG_Magenta | Color.FG_Blue + self.assertTrue(isinstance(Purple, Color)) + self.assertTrue(isinstance(Purple, str)) + self.assertIs(Purple, Color.BG_Magenta | Color.FG_Blue) + self.assertEqual(Purple, '\x1b[34;45m') + self.assertEqual(Purple.code, '34;45') + self.assertEqual(Purple.name, 'FG_Blue|BG_Magenta') + + def test_init_subclass(self): + class MyEnum(Flag): + def __init_subclass__(cls, **kwds): + super(MyEnum, cls).__init_subclass__(**kwds) + self.assertFalse(cls.__dict__.get('_test', False)) + cls._test1 = 'MyEnum' + # + class TheirEnum(MyEnum): + def __init_subclass__(cls, **kwds): + super(TheirEnum, cls).__init_subclass__(**kwds) + cls._test2 = 'TheirEnum' + class WhoseEnum(TheirEnum): + def __init_subclass__(cls, **kwds): + pass + class NoEnum(WhoseEnum): + ONE = 1 + self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') + self.assertFalse(NoEnum.__dict__.get('_test1', False)) + self.assertFalse(NoEnum.__dict__.get('_test2', False)) + # + class OurEnum(MyEnum): + def __init_subclass__(cls, **kwds): + cls._test2 = 'OurEnum' + class WhereEnum(OurEnum): + def __init_subclass__(cls, **kwds): + pass + class NeverEnum(WhereEnum): + ONE = 1 + self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') + self.assertFalse(WhereEnum.__dict__.get('_test1', False)) + self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') + self.assertFalse(NeverEnum.__dict__.get('_test1', False)) + self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + + def test_int_long_conversion(self): + class Perm(Flag): + EXEC = 1 << 0 + WRITE = 1 << 1 + READ = 1 << 2 + MSB32 = 1 << 31 + MSB64 = 1 << 63 + + # 32-bit system test + self.assertEqual(Perm.MSB32, Perm(0x80000000)) + self.assertEqual(Perm.WRITE|Perm.MSB32, Perm(0x80000002)) + + # 64-bit system test + self.assertEqual(Perm.MSB64, Perm(0x8000000000000000)) + self.assertEqual(Perm.MSB64|Perm.WRITE, Perm(0x8000000000000002)) + + +class TestIntFlag(TestCase): + """Tests of the IntFlags.""" + + def setUp(self): + # + class Perm(IntFlag): + _order_ = 'R W X' + R = 1 << 2 + W = 1 << 1 + X = 1 << 0 + # + class Color(IntFlag): + BLACK = 0 + RED = 1 + GREEN = 2 + BLUE = 4 + PURPLE = RED|BLUE + # + class Open(IntFlag): + "not a good flag candidate" + RO = 0 + WO = 1 + RW = 2 + AC = 3 + CE = 1<<19 + # + self.Perm = Perm + self.Color = Color + self.Open = Open + + def test_set_name(self): + class Descriptor(object): + name = None + def __get__(self, instance, owner_class=None): + if instance is None: + return self + else: + return instance.__dict__[self.name] + def __set__(self, instance, value): + instance.__dict__[self.name] = value + def __set_name__(self, owner, name): + self.name = name + # + class AnEnum(Enum): + ONE = 1 + two = Descriptor() + # + self.assertEqual(list(AnEnum), [AnEnum.ONE]) + self.assertEqual(AnEnum.two.name, 'two') + AnEnum.ONE.two = 'three' + self.assertEqual(AnEnum.ONE.two, 'three') + self.assertEqual(AnEnum.ONE.__dict__['two'], 'three') + + def test_private_names(self): + class Private(Enum): + __corporal = 'Radar' + __major_ = 'Hoolihan' + self.assertEqual(len(Private), 0) + self.assertEqual(Private._Private__corporal, 'Radar') + self.assertFalse(isinstance(Private._Private__corporal, Enum)) + self.assertEqual(Private._Private__major_, 'Hoolihan') + self.assertFalse(isinstance(Private._Private__major_, Enum)) + + def test_membership(self): + Color = self.Color + Open = self.Open + self.assertRaises(TypeError, lambda: 'GREEN' in Color) + self.assertRaises(TypeError, lambda: 'RW' in Open) + self.assertTrue(Color.GREEN in Color) + self.assertTrue(Open.RW in Open) + self.assertFalse(Color.GREEN in Open) + self.assertFalse(Open.RW in Color) + self.assertRaises(TypeError, lambda: 2 in Color) + self.assertRaises(TypeError, lambda: 2 in Open) + + def test_member_contains(self): + Color = self.Color + self.assertRaises(TypeError, lambda: 'test' in Color.RED) + self.assertRaises(TypeError, lambda: 1 in Color.RED) + self.assertTrue(Color.RED in Color.RED) + self.assertTrue(Color.RED in Color.PURPLE) + + def test_name_lookup(self): + Color = self.Color + self.assertTrue(Color.RED is Color['RED']) + self.assertTrue(Color.RED|Color.GREEN is Color['RED|GREEN']) + self.assertTrue(Color.PURPLE is Color['RED|BLUE']) + + def test_type(self): + Perm = self.Perm + Open = self.Open + for f in Perm: + self.assertTrue(isinstance(f, Perm)) + self.assertEqual(f, f.value) + self.assertTrue(isinstance(Perm.W | Perm.X, Perm)) + self.assertEqual(Perm.W | Perm.X, 3) + for f in Open: + self.assertTrue(isinstance(f, Open)) + self.assertEqual(f, f.value) + self.assertTrue(isinstance(Open.WO | Open.RW, Open)) + self.assertEqual(Open.WO | Open.RW, 3) + + + def test_str(self): + Perm = self.Perm + self.assertEqual(str(Perm.R), '4') + self.assertEqual(str(Perm.W), '2') + self.assertEqual(str(Perm.X), '1') + self.assertEqual(str(Perm.R | Perm.W), '6') + self.assertEqual(str(Perm.R | Perm.W | Perm.X), '7') + self.assertEqual(str(Perm(0)), '0') + self.assertEqual(str(~Perm.R), '3') + self.assertEqual(str(~Perm.W), '5') + self.assertEqual(str(~Perm.X), '6') + self.assertEqual(str(~(Perm.R | Perm.W)), '1') + self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), '0') + self.assertEqual(str(Perm(~0)), '7') + + Open = self.Open + self.assertEqual(str(Open.RO), '0') + self.assertEqual(str(Open.WO), '1') + self.assertEqual(str(Open.AC), '3') + self.assertEqual(str(Open.RO | Open.CE), '524288') + self.assertEqual(str(Open.WO | Open.CE), '524289') + self.assertEqual(str(~Open.RO), '524291') + self.assertEqual(str(~Open.WO), '524290') + self.assertEqual(str(~Open.AC), '524288') + self.assertEqual(str(~(Open.RO | Open.CE)), '3') + self.assertEqual(str(~(Open.WO | Open.CE)), '2') + + def test_repr_strict(self): + class Perm(IntFlag): + _order_ = 'R W X' + R = 1 << 2 + W = 1 << 1 + X = 1 << 0 + Perm._boundary_ = aenum.STRICT + 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>') + # + with self.assertRaisesRegex(ValueError, r'invalid value: 12'): + repr(Perm.R | 8) + with self.assertRaisesRegex(ValueError, r'invalid value: 12'): + repr(~(Perm.R | 8)) + with self.assertRaisesRegex(ValueError, r'invalid value: -9'): + repr(Perm(~8)) + + def test_repr_conform(self): + class Perm(IntFlag): + _order_ = 'R W X' + R = 1 << 2 + W = 1 << 1 + X = 1 << 0 + Perm._boundary_ = aenum.CONFORM + 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.R | 8), '<Perm.R: 4>') + self.assertEqual(repr(Perm(8)), '<Perm: 0>') + self.assertEqual(repr(~(Perm.R | 8)), '<Perm.W|X: 3>') + self.assertEqual(repr(Perm(~8)), '<Perm.R|W|X: 7>') + + def test_repr_eject(self): + class Perm(IntFlag): + _order_ = 'R W X' + _boundary_ = EJECT + R = 1 << 2 + W = 1 << 1 + X = 1 << 0 + 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.R | 8), '12') + self.assertEqual(repr(Perm(8)), '8') + self.assertEqual(repr(~(Perm.R | 8)), '-13') + self.assertEqual(repr(Perm(~8)), '-9') + + def test_repr_open(self): + class Open(IntFlag): + "not a good flag candidate" + RO = 0 + WO = 1 + RW = 2 + AC = 3 + CE = 1<<19 + Open._boundary_ = aenum.STRICT + 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.WO|CE: 524289>') + self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>') + self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 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>') + with self.assertRaisesRegex(ValueError, r'invalid value: -5'): + repr(Open(~4)) + with self.assertRaisesRegex(ValueError, r'invalid value: 4'): + repr(Open(4)) + # + class Open(IntFlag): + "not a good flag candidate" + RO = 0 + WO = 1 + RW = 2 + AC = 3 + CE = 1<<19 + Open._boundary_ = aenum.CONFORM + 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.WO|CE: 524289>') + self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>') + self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 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>') + self.assertEqual(repr(Open(~4)), '<Open.WO|RW|CE: 524291>') + self.assertEqual(repr(Open(4)), '<Open.RO: 0>') + # + class Open(IntFlag): + "not a good flag candidate" + RO = 0 + WO = 1 + RW = 2 + AC = 3 + CE = 1<<19 + Open._boundary_ = aenum.EJECT + 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.WO|CE: 524289>') + self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>') + self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 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>') + self.assertEqual(repr(Open(~4)), '-5') + self.assertEqual(repr(Open(4)), '4') + + 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.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_iter(self): + Perm = self.Perm + NoPerm = Perm.R ^ Perm.R + RWX = Perm.R | Perm.W | Perm.X + self.assertEqual(list(NoPerm), []) + self.assertEqual(list(Perm.R), [Perm.R]) + self.assertEqual(list(RWX), [Perm.R, Perm.W, Perm.X]) + + def test_programatic_function_string(self): + Perm = IntFlag('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 = IntFlag('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 = IntFlag('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 = IntFlag('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 = IntFlag('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) + + def test_containment(self): + Perm = self.Perm + R, W, X = Perm + RW = R | W + RX = R | X + WX = W | X + RWX = R | W | X + self.assertTrue(R in RW) + self.assertTrue(R in RX) + self.assertTrue(R in RWX) + self.assertTrue(W in RW) + self.assertTrue(W in WX) + self.assertTrue(W in RWX) + self.assertTrue(X in RX) + self.assertTrue(X in WX) + self.assertTrue(X in RWX) + self.assertFalse(R in WX) + 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)) + + def test_multiple_mixin(self): + class AllMixin(object): + @classproperty + def ALL(cls): + members = list(cls) + all_value = None + if members: + all_value = members[0] + for member in members[1:]: + all_value |= member + cls.ALL = all_value + return all_value + class StrMixin(object): + def __str__(self): + return self._name_.lower() + class Color(AllMixin, IntFlag): + _order_ = 'RED GREEN BLUE' + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 4) + self.assertEqual(Color.ALL.value, 7) + self.assertEqual(str(Color.BLUE), '4') + class Color(AllMixin, StrMixin, IntFlag): + _order_ = 'RED GREEN BLUE' + __str__ = StrMixin.__str__ + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 4) + self.assertEqual(Color.ALL.value, 7) + self.assertEqual(str(Color.BLUE), 'blue') + class Color(StrMixin, AllMixin, IntFlag): + _order_ = 'RED GREEN BLUE' + __str__ = StrMixin.__str__ + RED = auto() + GREEN = auto() + BLUE = auto() + self.assertEqual(Color.RED.value, 1) + self.assertEqual(Color.GREEN.value, 2) + self.assertEqual(Color.BLUE.value, 4) + self.assertEqual(Color.ALL.value, 7) + self.assertEqual(str(Color.BLUE), 'blue') + + @unittest.skipUnless(threading, 'Threading required for this test.') + def test_unique_composite(self): + # override __eq__ to be identity only + class TestFlag(IntFlag): + _order_ = 'one two three four five six seven eight' + one = auto() + two = auto() + three = auto() + four = auto() + five = auto() + six = auto() + seven = auto() + eight = auto() + def __eq__(self, other): + return self is other + def __hash__(self): + return hash(self._value_) + # have multiple threads competing to complete the composite members + seen = set() + failed = [False] + def cycle_enum(): + # nonlocal failed + try: + for i in range(256): + seen.add(TestFlag(i)) + except Exception: + failed[0] = True + threads = [ + threading.Thread(target=cycle_enum) + for _ in range(8) + ] + for t in threads: + t.start() + for t in threads: + t.join() + # check that only 248 members were created (8 were created originally) + self.assertFalse( + failed[0], + 'at least one thread failed while creating composite members') + self.assertEqual(256, len(seen), 'too many composite members created') + + def test_init_subclass(self): + class MyEnum(IntEnum): + def __init_subclass__(cls, **kwds): + super(MyEnum, cls).__init_subclass__(**kwds) + self.assertFalse(cls.__dict__.get('_test', False)) + cls._test1 = 'MyEnum' + # + class TheirEnum(MyEnum): + def __init_subclass__(cls, **kwds): + super(TheirEnum, cls).__init_subclass__(**kwds) + cls._test2 = 'TheirEnum' + class WhoseEnum(TheirEnum): + def __init_subclass__(cls, **kwds): + pass + class NoEnum(WhoseEnum): + ONE = 1 + self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum') + self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum') + self.assertFalse(NoEnum.__dict__.get('_test1', False)) + self.assertFalse(NoEnum.__dict__.get('_test2', False)) + # + class OurEnum(MyEnum): + def __init_subclass__(cls, **kwds): + cls._test2 = 'OurEnum' + class WhereEnum(OurEnum): + def __init_subclass__(cls, **kwds): + pass + class NeverEnum(WhereEnum): + ONE = 1 + self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum') + self.assertFalse(WhereEnum.__dict__.get('_test1', False)) + self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum') + self.assertFalse(NeverEnum.__dict__.get('_test1', False)) + self.assertFalse(NeverEnum.__dict__.get('_test2', False)) + + + +class TestEmptyAndNonLatinStrings(unittest.TestCase): + + def test_empty_string(self): + with self.assertRaises(ValueError): + empty_abc = Enum('empty_abc', ('', 'B', 'C')) + + def test_non_latin_character_string(self): + greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C')) + item = getattr(greek_abc, '\u03B1') + self.assertEqual(item.value, 1) + + def test_non_latin_number_string(self): + hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3')) + item = getattr(hebrew_123, '\u05D0') + self.assertEqual(item.value, 1) + + +class TestUnique(TestCase): + """2.4 doesn't allow class decorators, use function syntax.""" + + def test_unique_clean(self): + class Clean(Enum): + one = 1 + two = 'dos' + tres = 4.0 + unique(Clean) + class Cleaner(IntEnum): + single = 1 + double = 2 + triple = 3 + unique(Cleaner) + + def test_unique_dirty(self): + try: + class Dirty(Enum): + __order__ = 'one two' + one = 1 + two = 'dos' + tres = 1 + unique(Dirty) + except ValueError: + exc = sys.exc_info()[1] + message = exc.args[0] + self.assertTrue('tres -> one' in message) + + try: + class Dirtier(IntEnum): + __order__ = 'single triple' + single = 1 + double = 1 + triple = 3 + turkey = 3 + unique(Dirtier) + except ValueError: + exc = sys.exc_info()[1] + message = exc.args[0] + self.assertTrue('double -> single' in message) + self.assertTrue('turkey -> triple' in message) + + def test_unique_with_name(self): + @unique + class Silly(Enum): + one = 1 + two = 'dos' + name = 3 + @unique + class Sillier(IntEnum): + single = 1 + name = 2 + triple = 3 + value = 4 + + +class TestNamedTuple(TestCase): + + def test_explicit_indexing(self): + class Person(NamedTuple): + age = 0 + first = 1 + last = 2 + p1 = Person(17, 'John', 'Doe') + p2 = Person(21, 'Jane', 'Doe') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p2[0], 21) + self.assertEqual(p2[1], 'Jane') + self.assertEqual(p2[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + self.assertEqual(p2.age, 21) + self.assertEqual(p2.first, 'Jane') + self.assertEqual(p2.last, 'Doe') + + def test_implicit_indexing(self): + class Person(NamedTuple): + __order__ = "age first last" + age = "person's age" + first = "person's first name" + last = "person's last name" + p1 = Person(17, 'John', 'Doe') + p2 = Person(21, 'Jane', 'Doe') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p2[0], 21) + self.assertEqual(p2[1], 'Jane') + self.assertEqual(p2[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + self.assertEqual(p2.age, 21) + self.assertEqual(p2.first, 'Jane') + self.assertEqual(p2.last, 'Doe') + + def test_mixed_indexing(self): + class Person(NamedTuple): + __order__ = "age last cars" + age = "person's age" + last = 2, "person's last name" + cars = "person's cars" + p1 = Person(17, 'John', 'Doe', 3) + p2 = Person(21, 'Jane', 'Doe', 9) + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p1[3], 3) + self.assertEqual(p2[0], 21) + self.assertEqual(p2[1], 'Jane') + self.assertEqual(p2[2], 'Doe') + self.assertEqual(p2[3], 9) + self.assertEqual(p1.age, 17) + self.assertEqual(p1.last, 'Doe') + self.assertEqual(p1.cars, 3) + self.assertEqual(p2.age, 21) + self.assertEqual(p2.last, 'Doe') + self.assertEqual(p2.cars, 9) + + def test_issubclass(self): + class Person(NamedTuple): + age = 0 + first = 1 + last = 2 + self.assertTrue(issubclass(Person, NamedTuple)) + self.assertTrue(issubclass(Person, tuple)) + + def test_isinstance(self): + class Person(NamedTuple): + age = 0 + first = 1 + last = 2 + p1 = Person(17, 'John', 'Doe') + self.assertTrue(isinstance(p1, Person)) + self.assertTrue(isinstance(p1, NamedTuple)) + self.assertTrue(isinstance(p1, tuple)) + + def test_explicit_indexing_after_functional_api(self): + Person = NamedTuple('Person', (('age', 0), ('first', 1), ('last', 2))) + p1 = Person(17, 'John', 'Doe') + p2 = Person(21, 'Jane', 'Doe') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p2[0], 21) + self.assertEqual(p2[1], 'Jane') + self.assertEqual(p2[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + self.assertEqual(p2.age, 21) + self.assertEqual(p2.first, 'Jane') + self.assertEqual(p2.last, 'Doe') + + def test_implicit_indexing_after_functional_api(self): + Person = NamedTuple('Person', 'age first last') + p1 = Person(17, 'John', 'Doe') + p2 = Person(21, 'Jane', 'Doe') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p2[0], 21) + self.assertEqual(p2[1], 'Jane') + self.assertEqual(p2[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + self.assertEqual(p2.age, 21) + self.assertEqual(p2.first, 'Jane') + self.assertEqual(p2.last, 'Doe') + + def test_mixed_indexing_after_functional_api(self): + Person = NamedTuple('Person', (('age', 0), ('last', 2), ('cars', 3))) + p1 = Person(17, 'John', 'Doe', 3) + p2 = Person(21, 'Jane', 'Doe', 9) + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p1[3], 3) + self.assertEqual(p2[0], 21) + self.assertEqual(p2[1], 'Jane') + self.assertEqual(p2[2], 'Doe') + self.assertEqual(p2[3], 9) + self.assertEqual(p1.age, 17) + self.assertEqual(p1.last, 'Doe') + self.assertEqual(p1.cars, 3) + self.assertEqual(p2.age, 21) + self.assertEqual(p2.last, 'Doe') + self.assertEqual(p2.cars, 9) + + def test_issubclass_after_functional_api(self): + Person = NamedTuple('Person', 'age first last') + self.assertTrue(issubclass(Person, NamedTuple)) + self.assertTrue(issubclass(Person, tuple)) + + def test_isinstance_after_functional_api(self): + Person = NamedTuple('Person', 'age first last') + p1 = Person(17, 'John', 'Doe') + self.assertTrue(isinstance(p1, Person)) + self.assertTrue(isinstance(p1, NamedTuple)) + self.assertTrue(isinstance(p1, tuple)) + + def test_creation_with_all_keywords(self): + Person = NamedTuple('Person', 'age first last') + p1 = Person(age=17, first='John', last='Doe') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + + def test_creation_with_some_keywords(self): + Person = NamedTuple('Person', 'age first last') + p1 = Person(17, first='John', last='Doe') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + p1 = Person(17, last='Doe', first='John') + self.assertEqual(p1[0], 17) + self.assertEqual(p1[1], 'John') + self.assertEqual(p1[2], 'Doe') + self.assertEqual(p1.age, 17) + self.assertEqual(p1.first, 'John') + self.assertEqual(p1.last, 'Doe') + + def test_custom_new(self): + class Book(NamedTuple): + title = 0 + author = 1 + genre = 2 + def __new__(cls, string): + args = [s.strip() for s in string.split(';')] + return super(Book, cls).__new__(cls, *tuple(args)) + b1 = Book('The Last Mohican; John Doe; Historical') + self.assertEqual(b1.title, 'The Last Mohican') + self.assertEqual(b1.author, 'John Doe') + self.assertEqual(b1.genre, 'Historical') + + def test_defaults_in_class(self): + class Character(NamedTuple): + name = 0 + gender = 1, None, 'male' + klass = 2, None, 'fighter' + for char in ( + {'name':'John Doe'}, + {'name':'William Pickney', 'klass':'scholar'}, + {'name':'Sarah Doughtery', 'gender':'female'}, + {'name':'Sissy Moonbeam', 'gender':'female', 'klass':'sorceress'}, + ): + c = Character(**char) + for name, value in (('name', None), ('gender','male'), ('klass','fighter')): + if name in char: + value = char[name] + self.assertEqual(getattr(c, name), value) + + def test_defaults_in_class_that_are_falsey(self): + class Point(NamedTuple): + x = 0, 'horizondal coordinate', 0 + y = 1, 'vertical coordinate', 0 + p = Point() + self.assertEqual(p.x, 0) + self.assertEqual(p.y, 0) + + def test_pickle_namedtuple_with_module(self): + if isinstance(LifeForm, Exception): + raise LifeForm + lf = LifeForm('this', 'that', 'theother') + test_pickle_dump_load(self.assertEqual, lf) + + def test_pickle_namedtuple_without_module(self): + if isinstance(DeathForm, Exception): + raise DeathForm + df = DeathForm('sickly green', '2x4', 'foul') + test_pickle_dump_load(self.assertEqual, df) + + def test_subclassing(self): + if isinstance(ThatsIt, Exception): + raise ThatsIt + ti = ThatsIt('Henry', 'Weinhardt') + self.assertEqual(ti.blah, 'Henry') + self.assertTrue(ti.what(), 'Henry') + test_pickle_dump_load(self.assertEqual, ti) + + def test_contains(self): + Book = NamedTuple('Book', 'title author genre') + b = Book('Teckla', 'Steven Brust', 'fantasy') + self.assertTrue('Teckla' in b) + self.assertTrue('Steven Brust' in b) + self.assertTrue('fantasy' in b) + + def test_fixed_size(self): + class Book(NamedTuple): + _size_ = TupleSize.fixed + title = 0 + author = 1 + genre = 2 + b = Book('Teckla', 'Steven Brust', 'fantasy') + self.assertTrue('Teckla' in b) + self.assertTrue('Steven Brust' in b) + self.assertTrue('fantasy' in b) + self.assertEqual(b.title, 'Teckla') + self.assertEqual(b.author, 'Steven Brust') + self.assertRaises(TypeError, Book, 'Teckla', 'Steven Brust') + self.assertRaises(TypeError, Book, 'Teckla') + + def test_minimum_size(self): + class Book(NamedTuple): + _size_ = TupleSize.minimum + title = 0 + author = 1 + b = Book('Teckla', 'Steven Brust', 'fantasy') + self.assertTrue('Teckla' in b) + self.assertTrue('Steven Brust' in b) + self.assertTrue('fantasy' in b) + self.assertEqual(b.title, 'Teckla') + self.assertEqual(b.author, 'Steven Brust') + b = Book('Teckla', 'Steven Brust') + self.assertTrue('Teckla' in b) + self.assertTrue('Steven Brust' in b) + self.assertEqual(b.title, 'Teckla') + self.assertEqual(b.author, 'Steven Brust') + self.assertRaises(TypeError, Book, 'Teckla') + + def test_variable_size(self): + class Book(NamedTuple): + _size_ = TupleSize.variable + title = 0 + author = 1 + genre = 2 + b = Book('Teckla', 'Steven Brust', 'fantasy') + self.assertTrue('Teckla' in b) + self.assertTrue('Steven Brust' in b) + self.assertTrue('fantasy' in b) + self.assertEqual(b.title, 'Teckla') + self.assertEqual(b.author, 'Steven Brust') + self.assertEqual(b.genre, 'fantasy') + b = Book('Teckla', 'Steven Brust') + self.assertTrue('Teckla' in b) + self.assertTrue('Steven Brust' in b) + self.assertEqual(b.title, 'Teckla') + self.assertEqual(b.author, 'Steven Brust') + self.assertRaises(AttributeError, getattr, b, 'genre') + self.assertRaises(TypeError, Book, title='Teckla', genre='fantasy') + self.assertRaises(TypeError, Book, author='Steven Brust') + + def test_combining_namedtuples(self): + class Point(NamedTuple): + x = 0, 'horizontal coordinate', 1 + y = 1, 'vertical coordinate', -1 + class Color(NamedTuple): + r = 0, 'red component', 11 + g = 1, 'green component', 29 + b = 2, 'blue component', 37 + Pixel1 = NamedTuple('Pixel', Point+Color, module=__name__) + class Pixel2(Point, Color): + "a colored dot" + class Pixel3(Point): + r = 2, 'red component', 11 + g = 3, 'green component', 29 + b = 4, 'blue component', 37 + self.assertEqual(Pixel1._fields_, 'x y r g b'.split()) + self.assertEqual(Pixel1.x.__doc__, 'horizontal coordinate') + self.assertEqual(Pixel1.x.default, 1) + self.assertEqual(Pixel1.y.__doc__, 'vertical coordinate') + self.assertEqual(Pixel1.y.default, -1) + self.assertEqual(Pixel1.r.__doc__, 'red component') + self.assertEqual(Pixel1.r.default, 11) + self.assertEqual(Pixel1.g.__doc__, 'green component') + self.assertEqual(Pixel1.g.default, 29) + self.assertEqual(Pixel1.b.__doc__, 'blue component') + self.assertEqual(Pixel1.b.default, 37) + self.assertEqual(Pixel2._fields_, 'x y r g b'.split()) + self.assertEqual(Pixel2.x.__doc__, 'horizontal coordinate') + self.assertEqual(Pixel2.x.default, 1) + self.assertEqual(Pixel2.y.__doc__, 'vertical coordinate') + self.assertEqual(Pixel2.y.default, -1) + self.assertEqual(Pixel2.r.__doc__, 'red component') + self.assertEqual(Pixel2.r.default, 11) + self.assertEqual(Pixel2.g.__doc__, 'green component') + self.assertEqual(Pixel2.g.default, 29) + self.assertEqual(Pixel2.b.__doc__, 'blue component') + self.assertEqual(Pixel2.b.default, 37) + self.assertEqual(Pixel3._fields_, 'x y r g b'.split()) + self.assertEqual(Pixel3.x.__doc__, 'horizontal coordinate') + self.assertEqual(Pixel3.x.default, 1) + self.assertEqual(Pixel3.y.__doc__, 'vertical coordinate') + self.assertEqual(Pixel3.y.default, -1) + self.assertEqual(Pixel3.r.__doc__, 'red component') + self.assertEqual(Pixel3.r.default, 11) + self.assertEqual(Pixel3.g.__doc__, 'green component') + self.assertEqual(Pixel3.g.default, 29) + self.assertEqual(Pixel3.b.__doc__, 'blue component') + self.assertEqual(Pixel3.b.default, 37) + + def test_function_api_type(self): + class Tester(NamedTuple): + def howdy(self): + return 'backwards', list(reversed(self)) + Testee = NamedTuple('Testee', 'a c e', type=Tester) + t = Testee(1, 2, 3) + self.assertEqual(t.howdy(), ('backwards', [3, 2, 1])) + + def test_asdict(self): + class Point(NamedTuple): + x = 0, 'horizontal coordinate', 1 + y = 1, 'vertical coordinate', -1 + class Color(NamedTuple): + r = 0, 'red component', 11 + g = 1, 'green component', 29 + b = 2, 'blue component', 37 + Pixel = NamedTuple('Pixel', Point+Color, module=__name__) + pixel = Pixel(99, -101, 255, 128, 0) + self.assertEqual(pixel._asdict(), {'x':99, 'y':-101, 'r':255, 'g':128, 'b':0}) + + def test_make(self): + class Point(NamedTuple): + x = 0, 'horizontal coordinate', 1 + y = 1, 'vertical coordinate', -1 + self.assertEqual(Point(4, 5), (4, 5)) + self.assertEqual(Point._make((4, 5)), (4, 5)) + + def test_replace(self): + class Color(NamedTuple): + r = 0, 'red component', 11 + g = 1, 'green component', 29 + b = 2, 'blue component', 37 + purple = Color(127, 0, 127) + mid_gray = purple._replace(g=127) + self.assertEqual(mid_gray, (127, 127, 127)) + + +class TestNamedConstant(TestCase): + + def test_constantness(self): + class K(NamedConstant): + PI = 3.141596 + TAU = 2 * PI + self.assertEqual(K.PI, 3.141596) + self.assertEqual(K.TAU, 2 * K.PI) + with self.assertRaisesRegex(AttributeError, r'cannot rebind constant'): + K.PI = 9 + with self.assertRaisesRegex(AttributeError, r'cannot delete constant'): + del K.PI + with self.assertRaisesRegex(AttributeError, r'cannot rebind constant'): + K('PI', 3) + self.assertTrue(K.PI in K) + self.assertTrue(K.TAU in K) + + def test_duplicates(self): + class CardNumber(NamedConstant): + ACE = 11 + TWO = 2 + THREE = 3 + FOUR = 4 + FIVE = 5 + SIX = 6 + SEVEN = 7 + EIGHT = 8 + NINE = 9 + TEN = 10 + JACK = 10 + QUEEN = 10 + KING = 10 + self.assertFalse(CardNumber.TEN is CardNumber.JACK) + self.assertEqual(CardNumber.TEN, CardNumber.JACK) + self.assertEqual(CardNumber.TEN, 10) + + def test_extend_constants(self): + class CardSuit(NamedConstant): + HEARTS = 1 + SPADES = 2 + DIAMONTS = 3 + CLUBS = 4 + self.assertEqual(CardSuit.HEARTS, 1) + stars = CardSuit('STARS', 5) + self.assertIs(stars, CardSuit.STARS) + self.assertEqual(CardSuit.STARS, 5) + self.assertTrue(CardSuit.STARS in CardSuit) + + def test_constant_with_docstring(self): + class Stuff(NamedConstant): + Artifact = constant(7, "lucky number!") + Bowling = 11 + HillWomp = constant(29, 'blah blah') + self.assertEqual(Stuff.Artifact, 7) + self.assertEqual(Stuff.Artifact.__doc__, 'lucky number!') + self.assertEqual(Stuff.Bowling, 11) + self.assertEqual(Stuff.Bowling.__doc__, None) + self.assertEqual(Stuff.HillWomp, 29) + self.assertEqual(Stuff.HillWomp.__doc__, 'blah blah') + + def test_deep_copy(self): + import copy + class APITypes(aenum.Constant): + STRING = "string" + INT = "int" + APITypes('string') + d = {"first": APITypes.STRING} + copy.deepcopy(d) + self.assertTrue(d['first'] is APITypes.STRING) + + def test_subclass_w_same_value(self): + class Foo(aenum.Constant): + BLA = 'bla1' + ABA = 'aba1' + class Bar(aenum.Constant): + BLA = Foo.BLA + ABA = 'aba2' + self.assertEqual(Foo.BLA, Bar.BLA) + self.assertFalse(Foo.BLA is Bar.BLA) + + +class TestStarImport(TestCase): + + def test_all_exports_names(self): + scope = {} + exec('from aenum import *', scope, scope) + self.assertIn('Enum', scope) + +class TestStackoverflowAnswers(TestCase): + + def test_self_referential_directions(self): + # https://stackoverflow.com/a/64000706/208880 + class Directions(Enum): + _order_ = 'NORTH WEST SOUTH EAST' + # + NORTH = 1, 0 + WEST = 0, 1 + SOUTH = -1, 0 + EAST = 0, -1 + # + def __init__(self, x, y): + self.x = x + self.y = y + if len(self.__class__): + # make links + all = list(self.__class__) + left, right = all[0], all[-1] + self.left = left + self.right = right + left.right = self + right.left = self + # + D = Directions + self.assertEqual(D.NORTH.value, (1, 0)) + self.assertTrue(D.NORTH.left is D.WEST) + self.assertTrue(D.SOUTH.right is D.WEST) + + def test_self_referential_rock_paper_scissors(self): + # https://stackoverflow.com/a/57085357/208880 + class RPS(Enum): + _order_ = 'Rock, Paper, Scissors' + # + Rock = "rock" + Paper = "paper" + Scissors = "scissors" + # + def __init__(self, value): + if len(self.__class__): + # make links + all = list(self.__class__) + first, previous = all[0], all[-1] + first.beats = self + self.beats = previous + # + self.assertTrue(RPS.Rock.beats is RPS.Scissors) + self.assertTrue(RPS.Scissors.beats is RPS.Paper) + self.assertTrue(RPS.Paper.beats is RPS.Rock) + + def test_arduino_headers(self): + # https://stackoverflow.com/q/65048495/208880 + class CHeader(Enum): + def __init_subclass__(cls, **kwds): + # write Enums to C header file + cls_name = cls.__name__ + header_path = getattr(cls, '_%s__header' % cls_name) + with open(header_path, 'w') as fh: + fh.write('initial header stuff here\n') + for enum in cls: + fh.write('#define %s %r\n' % (enum.name, enum.value)) + class Arduino(CHeader): + _order_ = 'ONE TWO' + __header = os.path.join(tempdir, 'arduino.h') + ONE = 1 + TWO = 2 + with open(os.path.join(tempdir, 'arduino.h')) as fh: + data = fh.read() + self.assertEqual(textwrap.dedent("""\ + initial header stuff here + #define ONE 1 + #define TWO 2 + """), + data, + ) + + def test_lowercase_compare(self): + # https://stackoverflow.com/q/65139026/208880 + class CompareLowerCase(Enum): + def __init_subclass__(cls, **kwds): + super(CompareLowerCase, cls).__init_subclass__(**kwds) + cls.lowered_names = set([m.name.lower() for m in cls]) + @classmethod + def has_name(cls, name): + return name.lower() in cls.lowered_names + # + class LabelEnum(CompareLowerCase, StrEnum): + ENUM_ONE = "Enum One" + ENUM_TWO = "Enum Two" + ENUM_THREE = "Enum Three" + FOUR = "FOUR" + FIVE = "FIVE" + SIX = "SIX" + # + self.assertTrue(LabelEnum.has_name('Enum_Three')) + + +class TestExtendEnum(TestCase): + + def test_extend_enum_plain(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + self.assertRaisesRegex(TypeError, 'already in use as', extend_enum, Color, 'blue', 5) + # + extend_enum(Color, 'brown', 4) + self.assertEqual(Color.brown.name, 'brown') + self.assertEqual(Color.brown.value, 4) + self.assertTrue(Color.brown in Color) + self.assertEqual(Color(4), Color.brown) + self.assertEqual(Color['brown'], Color.brown) + self.assertEqual(len(Color), 4) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, 5) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(5), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + self.assertEqual(len(Color), 5) + + def test_extend_enum_alias(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + extend_enum(Color, 'rojo', 1) + self.assertEqual(Color.rojo.name, 'red') + self.assertEqual(Color.rojo.value, 1) + self.assertTrue(Color.rojo in Color) + self.assertEqual(Color(1), Color.rojo) + self.assertEqual(Color['rojo'], Color.red) + self.assertEqual(len(Color), 3) + + def test_extend_enum_unique(self): + class Color(UniqueEnum): + red = 1 + green = 2 + blue = 3 + self.assertRaisesRegex(ValueError, r'<Color.rojo: 1> is a duplicate of <Color.red: 1>', extend_enum, Color, 'rojo', 1) + # + self.assertEqual(Color.red.name, 'red') + self.assertEqual(Color.red.value, 1) + self.assertTrue(Color.red in Color) + self.assertEqual(Color(1), Color.red) + self.assertEqual(Color['red'], Color.red) + self.assertEqual(Color.green.name, 'green') + self.assertEqual(Color.green.value, 2) + self.assertTrue(Color.green in Color) + self.assertEqual(Color(2), Color.green) + self.assertEqual(Color['blue'], Color.blue) + self.assertEqual(Color.blue.name, 'blue') + self.assertEqual(Color.blue.value, 3) + self.assertTrue(Color.blue in Color) + self.assertEqual(Color(3), Color.blue) + self.assertEqual(len(Color), 3) + # + extend_enum(Color, 'brown', 4) + self.assertEqual(Color.brown.name, 'brown') + self.assertEqual(Color.brown.value, 4) + self.assertTrue(Color.brown in Color) + self.assertEqual(Color(4), Color.brown) + self.assertEqual(Color['brown'], Color.brown) + self.assertEqual(len(Color), 4) + # + self.assertRaisesRegex(ValueError, '', extend_enum, Color, 'verde', 2) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, 5) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(5), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + self.assertEqual(len(Color), 5) + + + def test_extend_enum_shadow_property(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + extend_enum(Color, 'value', 4) + self.assertEqual(Color.value.name, 'value') + self.assertEqual(Color.value.value, 4) + self.assertTrue(Color.value in Color) + self.assertEqual(Color(4), Color.value) + self.assertEqual(Color['value'], Color.value) + self.assertEqual(len(Color), 4) + self.assertEqual(Color.red.value, 1) + + def test_extend_enum_shadow_base(self): + class hohum(object): + def cyan(self): + "cyanize a color" + return self.value + class Color(hohum, Enum): + red = 1 + green = 2 + blue = 3 + self.assertRaisesRegex(TypeError, r'already in use in superclass', extend_enum, Color, 'cyan', 4) + self.assertEqual(len(Color), 3) + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + + def test_extend_enum_multivalue(self): + class Color(MultiValueEnum): + red = 1, 4, 7 + green = 2, 5, 8 + blue = 3, 6, 9 + extend_enum(Color, 'brown', 10, 20) + self.assertEqual(Color.brown.name, 'brown') + self.assertEqual(Color.brown.value, 10) + self.assertTrue(Color.brown in Color) + self.assertEqual(Color(10), Color.brown) + self.assertEqual(Color(20), Color.brown) + self.assertEqual(Color['brown'], Color.brown) + self.assertEqual(len(Color), 4) + # + self.assertRaisesRegex(ValueError, 'no values specified for MultiValue enum', extend_enum, Color, 'mauve') + + def test_extend_enum_multivalue_alias(self): + class Color(MultiValueEnum): + red = 1, 4, 7 + green = 2, 5, 8 + blue = 3, 6, 9 + self.assertRaisesRegex(ValueError, r'<Color.rojo: 7> is a duplicate of <Color.red: 1>', extend_enum, Color, 'rojo', 7) + self.assertEqual(Color.red.name, 'red') + self.assertEqual(Color.red.value, 1) + self.assertTrue(Color.red in Color) + self.assertEqual(Color(1), Color.red) + self.assertEqual(Color(4), Color.red) + self.assertEqual(Color(7), Color.red) + self.assertEqual(Color['red'], Color.red) + self.assertEqual(Color.green.name, 'green') + self.assertEqual(Color.green.value, 2) + self.assertTrue(Color.green in Color) + self.assertEqual(Color(2), Color.green) + self.assertEqual(Color(5), Color.green) + self.assertEqual(Color(8), Color.green) + self.assertEqual(Color['blue'], Color.blue) + self.assertEqual(Color.blue.name, 'blue') + self.assertEqual(Color.blue.value, 3) + self.assertTrue(Color.blue in Color) + self.assertEqual(Color(3), Color.blue) + self.assertEqual(Color(6), Color.blue) + self.assertEqual(Color(9), Color.blue) + self.assertEqual(len(Color), 3) + + def test_extend_enum_multivalue_str(self): + class M(str, MultiValueEnum): + VALUE_1 = 'value_1', 'VALUE_1' + VALUE_2 = 'value_2', 'VALUE_2' + VALUE_3 = 'value_3', 'VALUE_3' + self.assertTrue(M._member_type_ is str) + extend_enum(M, 'VALUE_4', 'value_4', 'VALUE_4') + self.assertEqual(list(M), [M.VALUE_1, M.VALUE_2, M.VALUE_3, M.VALUE_4]) + self.assertTrue(M('value_4') is M.VALUE_4) + self.assertTrue(M('VALUE_4') is M.VALUE_4) + self.assertTrue(M.VALUE_4.name == 'VALUE_4') + self.assertTrue(M.VALUE_4.value == 'value_4') + + def test_extend_intenum(self): + class Index(IntEnum): + DeviceType = 0x1000 + ErrorRegister = 0x1001 + + for name, value in ( + ('ControlWord', 0x6040), + ('StatusWord', 0x6041), + ('OperationMode', 0x6060), + ): + extend_enum(Index, name, value) + + self.assertEqual(len(Index), 5) + self.assertEqual(list(Index), [Index.DeviceType, Index.ErrorRegister, Index.ControlWord, Index.StatusWord, Index.OperationMode]) + self.assertEqual(Index.DeviceType.value, 0x1000) + self.assertEqual(Index.StatusWord.value, 0x6041) + + def test_extend_multi_init(self): + try: + from http import HTTPStatus + length = len(HTTPStatus) + except ImportError: + class HTTPStatus(IntEnum): + def __new__(cls, value, phrase, description): + obj = int.__new__(cls, value) + obj._value_ = value + + obj.phrase = phrase + obj.description = description + return obj + CONTINUE = 100, 'Continue', 'Request received, please continue' + SWITCHING_PROTOCOLS = 101, 'Switching Protocols', 'Switching to new protocol; obey Upgrade header' + PROCESSING = 102, 'Processing', '' + length = 3 + extend_enum(HTTPStatus, 'BAD_SPAM', 513, 'Too greasy', 'for a train') + extend_enum(HTTPStatus, 'BAD_EGGS', 514, 'Too green', '') + self.assertEqual(len(HTTPStatus), length+2) + self.assertEqual( + list(HTTPStatus)[-2:], + [HTTPStatus.BAD_SPAM, HTTPStatus.BAD_EGGS], + ) + self.assertEqual(HTTPStatus.BAD_SPAM.value, 513) + self.assertEqual(HTTPStatus.BAD_SPAM.name, 'BAD_SPAM') + self.assertEqual(HTTPStatus.BAD_SPAM.phrase, 'Too greasy') + self.assertEqual(HTTPStatus.BAD_SPAM.description, 'for a train') + self.assertEqual(HTTPStatus.BAD_EGGS.value, 514) + self.assertEqual(HTTPStatus.BAD_EGGS.name, 'BAD_EGGS') + self.assertEqual(HTTPStatus.BAD_EGGS.phrase, 'Too green') + self.assertEqual(HTTPStatus.BAD_EGGS.description, '') + + def test_extend_flag(self): + class Color(Flag): + BLACK = 0 + RED = 1 + GREEN = 2 + BLUE = 4 + extend_enum(Color, 'MAGENTA') + self.assertTrue(Color(8) is Color.MAGENTA) + self.assertTrue(isinstance(Color.MAGENTA, Color)) + self.assertEqual(Color.MAGENTA.value, 8) + extend_enum(Color, 'PURPLE', 11) + self.assertTrue(Color(11) is Color.PURPLE) + self.assertTrue(isinstance(Color.PURPLE, Color)) + self.assertEqual(Color.PURPLE.value, 11) + self.assertTrue(issubclass(Color, Flag)) + + def test_extend_flag_backwards(self): + class Color(Flag): + BLACK = 0 + RED = 1 + GREEN = 2 + BLUE = 4 + extend_enum(Color, 'PURPLE', 11) + self.assertTrue(Color(11) is Color.PURPLE) + self.assertTrue(isinstance(Color.PURPLE, Color)) + self.assertEqual(Color.PURPLE.value, 11) + self.assertTrue(issubclass(Color, Flag)) + # + extend_enum(Color, 'MAGENTA') + self.assertTrue(Color(8) is Color.MAGENTA) + self.assertTrue(isinstance(Color.MAGENTA, Color)) + self.assertEqual(Color.MAGENTA.value, 8) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, 16) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(16), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + self.assertEqual(len(Color), 5) + + def test_extend_intflag(self): + class Color(IntFlag): + BLACK = 0 + RED = 1 + GREEN = 2 + BLUE = 4 + extend_enum(Color, 'MAGENTA') + self.assertTrue(Color(8) is Color.MAGENTA) + self.assertTrue(isinstance(Color.MAGENTA, Color)) + self.assertEqual(Color.MAGENTA.value, 8) + extend_enum(Color, 'PURPLE', 11) + self.assertTrue(Color(11) is Color.PURPLE) + self.assertTrue(isinstance(Color.PURPLE, Color)) + self.assertEqual(Color.PURPLE.value, 11) + self.assertTrue(issubclass(Color, Flag)) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, 16) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(16), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + self.assertEqual(len(Color), 5) + + def test_extend_intflag_backwards(self): + class Color(IntFlag): + BLACK = 0 + RED = 1 + GREEN = 2 + BLUE = 4 + extend_enum(Color, 'PURPLE', 11) + self.assertTrue(Color(11) is Color.PURPLE) + self.assertTrue(isinstance(Color.PURPLE, Color)) + self.assertEqual(Color.PURPLE.value, 11) + self.assertTrue(issubclass(Color, Flag)) + # + extend_enum(Color, 'MAGENTA') + self.assertTrue(Color(8) is Color.MAGENTA) + self.assertTrue(isinstance(Color.MAGENTA, Color)) + self.assertEqual(Color.MAGENTA.value, 8) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, 16) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(16), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + self.assertEqual(len(Color), 5) + + def test_extend_strenum(self): + class Color(StrEnum): + RED = auto() + GREEN = auto() + BLUE = auto() + extend_enum(Color, 'BLACK') + self.assertEqual(Color.BLACK.name, 'BLACK') + self.assertEqual(Color.BLACK.value, 'black') + self.assertEqual(len(Color), 4) + + +class TestIssues(TestCase): + + def test_auto_multi_int(self): + class Measurement(int, MultiValueEnum, AddValueEnum): + _order_ = 'one two three' + _start_ = 0 + one = "20110721" + two = "20120911" + three = "20110518" + self.assertEqual([m.value for m in Measurement], [0, 1, 2]) + self.assertEqual([m.name for m in Measurement], ['one', 'two', 'three']) + self.assertIs(Measurement('20110721'), Measurement.one) + self.assertIs(Measurement(0), Measurement.one) + self.assertIs(Measurement('20120911'), Measurement.two) + self.assertIs(Measurement(1), Measurement.two) + self.assertIs(Measurement('20110518'), Measurement.three) + self.assertIs(Measurement(2), Measurement.three) + + def test_auto_kwds(self): + class Item(Enum): + _order_ = 'A B' + A = auto(size=100, requirements={}) + B = auto(size=200, requirements={A: 1}) + # + def __new__(cls, value, size, requirements): + obj = object.__new__(cls) + obj._value_ = value + obj.size = size + # fix requirements + new_requirements = {} + for k, v in requirements.items(): + if isinstance(k, auto): + k = k.enum_member + new_requirements[k] = v + obj.requirements = new_requirements + return obj + self.assertEqual((Item.A.value, Item.A.size, Item.A.requirements), (1, 100, {})) + self.assertEqual((Item.B.value, Item.B.size, Item.B.requirements), (2, 200, {Item.A: 1})) + + def test_extend_flag(self): + class FlagTest(Flag): # Or IntFlag + NONE = 0 + LOW = 1 + MID = 2 + extend_enum(FlagTest, 'HIGH', 4) + self.assertEqual(FlagTest.LOW | FlagTest.HIGH, FlagTest(5)) + self.assertEqual((FlagTest.LOW | FlagTest.HIGH).value, 5) + + def test_extend_unhashable(self): + class TestEnum(Enum): + ABC = { + 'id': 0, + 'value': 'abc' + } + DEF = { + 'id': 1, + 'value': 'def' + } + rand = uuid.uuid4().hex + new_value = { + 'id': 99, + 'value': 'new', + } + extend_enum(TestEnum, rand, new_value) + + + +# Test conversion of global constants +# These are unordered here on purpose to ensure that declaration order +# makes no difference. +CONVERT_TEST_NAME_D = 5 +CONVERT_TEST_NAME_C = 5 +CONVERT_TEST_NAME_B = 5 +CONVERT_TEST_NAME_A = 5 # This one should sort first. +CONVERT_TEST_NAME_E = 5 +CONVERT_TEST_NAME_F = 5 +CONVERT_TEST_SIGABRT = 4 # and this one +CONVERT_TEST_SIGIOT = 4 +CONVERT_TEST_EIO = 7 +CONVERT_TEST_EBUS = 7 # and this one + +CONVERT_STRING_TEST_NAME_D = 5 +CONVERT_STRING_TEST_NAME_C = 5 +CONVERT_STRING_TEST_NAME_B = 5 +CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first. +CONVERT_STRING_TEST_NAME_E = 5 +CONVERT_STRING_TEST_NAME_F = 5 + +# global names for StrEnum._convert_ test +CONVERT_STR_TEST_2 = 'goodbye' +CONVERT_STR_TEST_1 = 'hello' + +# We also need values that cannot be compared: +UNCOMPARABLE_A = 5 +UNCOMPARABLE_C = (9, 1) # naming order is broken on purpose +UNCOMPARABLE_B = 'value' + +COMPLEX_C = 1j +COMPLEX_A = 2j +COMPLEX_B = 3j + + +class TestConvert(TestCase): + + def tearDown(self): + # Reset the module-level test variables to their original integer + # values, otherwise the already created enum values get converted + # instead. + g = globals() + for suffix in ['A', 'B', 'C', 'D', 'E', 'F']: + g['CONVERT_TEST_NAME_%s' % suffix] = 5 + g['CONVERT_STRING_TEST_NAME_%s' % suffix] = 5 + for suffix, value in (('A', 5), ('B', (9, 1)), ('C', 'value')): + g['UNCOMPARABLE_%s' % suffix] = value + for suffix, value in (('A', 2j), ('B', 3j), ('C', 1j)): + g['COMPLEX_%s' % suffix] = value + for suffix, value in (('1', 'hello'), ('2', 'goodbye')): + g['CONVERT_STR_TEST_%s' % suffix] = value + g['CONVERT_TEST_SIGABRT'] = 4 + g['CONVERT_TEST_SIGIOT'] = 4 + g['CONVERT_TEST_EIO'] = 7 + g['CONVERT_TEST_EBUS'] = 7 + + def test_convert_value_lookup_priority(self): + test_type = IntEnum._convert_( + 'UnittestConvert', + MODULE, + filter=lambda x: x.startswith('CONVERT_TEST_')) + # We don't want the reverse lookup value to vary when there are + # multiple possible names for a given value. It should always + # report the first lexigraphical name in that case. + self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A') + self.assertEqual(test_type(4).name, 'CONVERT_TEST_SIGABRT') + self.assertEqual(test_type(7).name, 'CONVERT_TEST_EBUS') + self.assertEqual( + list(test_type), + [ + test_type.CONVERT_TEST_SIGABRT, + test_type.CONVERT_TEST_NAME_A, + test_type.CONVERT_TEST_EBUS, + ], + ) + + def test_convert_int(self): + test_type = IntEnum._convert_( + 'UnittestConvert', + MODULE, + filter=lambda x: x.startswith('CONVERT_TEST_')) + # Ensure that test_type has all of the desired names and values. + self.assertEqual(test_type.CONVERT_TEST_NAME_F, + test_type.CONVERT_TEST_NAME_A) + self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5) + self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5) + self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5) + self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5) + # Ensure that test_type only picked up names matching the filter. + int_dir = dir(int) + [ + 'CONVERT_TEST_NAME_A', 'CONVERT_TEST_NAME_B', 'CONVERT_TEST_NAME_C', + 'CONVERT_TEST_NAME_D', 'CONVERT_TEST_NAME_E', 'CONVERT_TEST_NAME_F', + 'CONVERT_TEST_SIGABRT', 'CONVERT_TEST_SIGIOT', + 'CONVERT_TEST_EIO', 'CONVERT_TEST_EBUS', + ] + extra = [name for name in dir(test_type) if name not in enum_dir(test_type)] + missing = [name for name in enum_dir(test_type) if name not in dir(test_type)] + self.assertEqual( + extra + missing, + [], + msg='extra names: %r; missing names: %r' % (extra, missing), + ) + + @unittest.skipUnless(PY3, 'everything is comparable on Python 2') + def test_convert_uncomparable(self): + uncomp = Enum._convert_( + 'Uncomparable', + MODULE, + filter=lambda x: x.startswith('UNCOMPARABLE_')) + # Should be ordered by `name` only: + self.assertEqual( + list(uncomp), + [uncomp.UNCOMPARABLE_A, uncomp.UNCOMPARABLE_B, uncomp.UNCOMPARABLE_C], + list(uncomp), + ) + + @unittest.skipUnless(PY3, 'everything is comparable on Python 2') + def test_convert_complex(self): + uncomp = Enum._convert_( + 'Uncomparable', + MODULE, + filter=lambda x: x.startswith('COMPLEX_')) + # Should be ordered by `name` only: + self.assertEqual( + list(uncomp), + [uncomp.COMPLEX_A, uncomp.COMPLEX_B, uncomp.COMPLEX_C], + ) + + def test_convert_str(self): + test_type = StrEnum._convert_( + 'UnittestConvert', + MODULE, + filter=lambda x: x.startswith('CONVERT_STR_'), + as_global=True) + # Ensure that test_type has all of the desired names and values. + self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello') + self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye') + # Ensure that test_type only picked up names matching the filter. + extra = [name for name in dir(test_type) if name not in enum_dir(test_type)] + missing = [name for name in enum_dir(test_type) if name not in dir(test_type)] + self.assertEqual( + extra + missing, + [], + msg='extra names: %r; missing names: %r' % (extra, missing), + ) + self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE) + self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye') + self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello') + + def test_convert_repr_and_str(self): + test_type = IntEnum._convert_( + 'UnittestConvert', + MODULE, + filter=lambda x: x.startswith('CONVERT_STRING_TEST_'), + as_global=True) + self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE) + self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), '5') + self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5') + +# helpers + +def enum_dir(cls): + interesting = set(cls._member_names_ + [ + '__class__', '__contains__', '__doc__', '__getitem__', + '__iter__', '__len__', '__members__', '__module__', + '__name__', + ]) + if cls._new_member_ is not object.__new__: + interesting.add('__new__') + if cls.__init_subclass__ is not Enum.__init_subclass__: + interesting.add('__init_subclass__') + if hasattr(object, '__qualname__'): + interesting.add('__qualname__') + for method in ('__init__', '__format__', '__repr__', '__str__'): + if getattr(cls, method) not in (getattr(Enum, method), getattr(Flag, method)): + interesting.add(method) + if cls._member_type_ is object: + return sorted(interesting) + else: + # return whatever mixed-in data type has + return sorted(set(dir(cls._member_type_)) | interesting) + +def member_dir(member): + if member.__class__._member_type_ is object: + allowed = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value']) + else: + allowed = set(dir(member)) + for cls in member.__class__.mro(): + for name, obj in cls.__dict__.items(): + if name[0] == '_': + continue + if isinstance(obj, enum.property): + if obj.fget is not None or name not in member._member_map_: + allowed.add(name) + else: + allowed.discard(name) + else: + allowed.add(name) + return sorted(allowed) + + + +if __name__ == '__main__': + tempdir = tempfile.mkdtemp() + test = None + try: + if PY3: + test_v3.tempdir = tempdir + test = unittest.main(exit=False) + sys.stdout.flush() + for name, reason in test.result.skipped: + print("%s: %s" % (name, reason)) + finally: + shutil.rmtree(tempdir, True) + if test: + sys.exit(len(test.result.errors or test.result.failures) and 1 or 0) + |