From 00ca6a6db4674713a10d1de312559cb924ed3c55 Mon Sep 17 00:00:00 2001 From: ThereforeGames <95403634+ThereforeGames@users.noreply.github.com> Date: Sun, 11 Dec 2022 17:59:59 -0500 Subject: [PATCH 1/4] Add files via upload --- venv/Lib/site-packages/aenum/CHANGES | 489 ++ venv/Lib/site-packages/aenum/LICENSE | 32 + venv/Lib/site-packages/aenum/__init__.py | 4111 ++++++++++ .../aenum/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 104964 bytes .../aenum/__pycache__/_py3.cpython-39.pyc | Bin 0 -> 686 bytes venv/Lib/site-packages/aenum/_py2.py | 7 + venv/Lib/site-packages/aenum/_py3.py | 12 + venv/Lib/site-packages/aenum/doc/aenum.rst | 1568 ++++ venv/Lib/site-packages/aenum/test.py | 6832 +++++++++++++++++ venv/Lib/site-packages/aenum/test_v3.py | 1982 +++++ venv/Lib/site-packages/blendmodes/__init__.py | 2 + .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 285 bytes .../__pycache__/blend.cpython-39.pyc | Bin 0 -> 13302 bytes .../__pycache__/blendtype.cpython-39.pyc | Bin 0 -> 2850 bytes venv/Lib/site-packages/blendmodes/blend.py | 511 ++ .../Lib/site-packages/blendmodes/blendtype.py | 72 + .../site-packages/blendmodes/imagetools.py | 48 + 17 files changed, 15666 insertions(+) create mode 100644 venv/Lib/site-packages/aenum/CHANGES create mode 100644 venv/Lib/site-packages/aenum/LICENSE create mode 100644 venv/Lib/site-packages/aenum/__init__.py create mode 100644 venv/Lib/site-packages/aenum/__pycache__/__init__.cpython-39.pyc create mode 100644 venv/Lib/site-packages/aenum/__pycache__/_py3.cpython-39.pyc create mode 100644 venv/Lib/site-packages/aenum/_py2.py create mode 100644 venv/Lib/site-packages/aenum/_py3.py create mode 100644 venv/Lib/site-packages/aenum/doc/aenum.rst create mode 100644 venv/Lib/site-packages/aenum/test.py create mode 100644 venv/Lib/site-packages/aenum/test_v3.py create mode 100644 venv/Lib/site-packages/blendmodes/__init__.py create mode 100644 venv/Lib/site-packages/blendmodes/__pycache__/__init__.cpython-39.pyc create mode 100644 venv/Lib/site-packages/blendmodes/__pycache__/blend.cpython-39.pyc create mode 100644 venv/Lib/site-packages/blendmodes/__pycache__/blendtype.cpython-39.pyc create mode 100644 venv/Lib/site-packages/blendmodes/blend.py create mode 100644 venv/Lib/site-packages/blendmodes/blendtype.py create mode 100644 venv/Lib/site-packages/blendmodes/imagetools.py diff --git a/venv/Lib/site-packages/aenum/CHANGES b/venv/Lib/site-packages/aenum/CHANGES new file mode 100644 index 00000000..e8799f6d --- /dev/null +++ b/venv/Lib/site-packages/aenum/CHANGES @@ -0,0 +1,489 @@ +3.1.8 +===== + +recalculate bits used after all flags created (sometimes needed when a custom +`__new__` is in place. + + +3.1.7 +===== + +update flag creation to (possibly) add bitwise operator methods to newly +created flags + +update extend_enum() to work with 3.11 flags + + +3.1.6 +===== + +Update `dir()` on mixed enums to include mixed data type methods and +attributes. + +Rename `enum_property` to `property` to match stdlib. Recommended usage is +`aenum.property` (prefix with module name). + +Remove quadritic creation behavior. + + +BREAKING CHANGE BUG FIX that won't affect most people + +Enums with a custom `__new__` that: + +- use the enum machinery to generate the values; AND +- have keyword arguments set to a default (like `None`) + +will fail to generate a missing value. To fix: remove the default value and +instead specify it on the member creation line. + +BREAKING CHANGE + +In Python 3.11 the `str()` of mixed enums will now match its `format()` which +will be the normal `str()` of the data type -- so for an IntEnum you'll see +`5` instead of `Perm.R|X`. This affects IntEnum, StrEnum, and IntFlag. + + +3.1.5 +===== + +fix support of `auto()` kwds + + +3.1.3 +===== + +rename `aenum.property` to `aenum.enum_property` + +fix `enum_property` to work with `_init_` attributes + + +3.1.2 +===== + +fix `extend_enum()` for unhashable values + + +3.1.1 +===== + +fix `extend_enum()` for most cases + + +3.1.0 +===== + +AddValue is similar to the old AutoNumber: it will always activate, but +uses _generate_next_value_ to get the next value (so the user has some +control over the return data type instead of always getting an int). + + +BREAKING CHANGES + +AutoValue is gone. It was superflous and its removal simplified the code. +Simply put the fields needed in an `_init_` and `_generate_next_value_` +will be called to supply the missing values (this is probably already what +is happening). + + + +3.0.0 +===== + +standard Enum usage is unchanged + +BREAKING CHANGES + +Enum +- the more esoteric method of creating Enums have been modified or removed + - AutoNumber setting is gone, inherit from AutoNumberEnum instead + - creating members without specifying anything is removed (if you don't + know what this means, you weren't doing it) + +Flag +- unique flags are canonical (i.e. flags with powers of two values such as + 1, 2, 4, 8, 16, etc.) +- non-unique flags are aliases (i.e. values such as 3 or 7) +- iteration of Flag and flag members only uses canonical flags + + +ENHANCEMENTS + +Member creation has been redone to match Python 3.10's methods. This also +allows all supported Pythons (2.7, 3.3+) to use the __set_name__ and +__init_subclass__ protocols (more robustly than in aenum 2.2.5) + + +CHANGES + +enum_property() has been renamed to property() (old name still available, but +deprecated). + +bin() replacement shows negative integers in twos-complement + + + + +2.2.5 +===== + +call __init_subclass__ after members have been added, and in Pythons < 3.6 +call __set_name__ in Pythons < 3.6 +do not convert/disallow private names +add iteration/len support to NamedConstant + + +2.2.4 +===== + +add support to Constant to retrieve members by value + + --> class K(Constant): + ... one = 1 + ... two = 2 + + --> K.one + + + --> K(1) + + +add pickle/deepcopy support to Constant + +add support for Constant to use other Constant values + (resulting members /are not/ the same) + + --> class C(Constant) + ... one = K.one + ... three = 3 + + --> C.one == K.one + True + + --> C.one is K.one + False + +AutoNumber and auto() now work together + +Enum members are now added to the class as enum_property, which supports +unshadowing of parent class attributes when called on an Enum member: + + --> class StrEnum(str, Enum): + ... lower = 'lower' + ... upper = 'upper' + ... mixed = 'mixed' + + --> StrEnum.lower + + + --> StrEnum.lower.upper() + 'LOWER' + + --> StrEnum.upper + + + --> StrEnum.upper.upper() + 'UPPER' + + +2.2.3 +===== + +use members' type's methods __str__, __repr__, __format__, and +__reduce_ex__ if directly assigned in Enum class body; i.e.: + + --> class Color(str, Enum): + ... red = 'red' + ... green = 'green' + ... blue = 'blue' + ... __str__ = str.__str__ + + --> print(repr(Color.green)) + + + --> print(Color.green) + green + + +2.2.2 +===== + +replace _RouteClassAttributeToGetattr with enum_property (it is still +available as an alias) + +support constant() and auto() being used together: + + --> class Fruit(Flag): + ... _order_ = 'apple banana lemon orange' + ... apple = auto() + ... banana = auto() + ... lemon = auto() + ... orange = auto() + ... CitrusTypes = constant(lemon | orange) + + --> list(Fruit) + [Fruit.apple, Fruit.banana, Fruit.lemon, Fruit.orange] + + --> list(Fruit.CitrusTypes) + [Fruit.orange, Fruit.lemon] + + --> Fruit.orange in Fruit.CitrusTypes + True + + +2.2.1 +===== + +allow Enums to be called without a value + + 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 + + >>> Color() + + +allow Enum name use while constructing Enum (Python 3.4+ only) + + --> class Color(Enum): + ... _order_ = 'BLACK WHITE' + ... BLACK = Color('black', '#000') + ... WHITE = Color('white', '#fff') + ... # + ... def __init__(self, label, hex): + ... self.label = label + ... self.hex = hex + + +2.2.0 +===== + +BREAKING CHANGE +--------------- +In Python 3+ classes defined inside an Enum no longer become members by +default; in Python 2 they still become members, but see below. + +For cross-compatibility and full control two decorators are provided: + +- @member --> forces item to become a member +- @nonmember --> excludes item from becoming a member + +So to have an Enum that behaves the same in Python 2 and 3, use the +decorators (and other compatibility shims): + + class Color(Enum): + + _order_ = 'red green blue' + + red = 1 + green = 2 + blue = 3 + + @nonmember + class Shades(Enum): + + _order_ = 'light medium dark' + + light = 1 + medium = 2 + dark = 3 + + +2.1.4 +===== + +EnumMeta: +- change __member_new__ to __new_member__ (as the stdlib enum does) +- assign member name to enum() instances (an Enum helper for defining members) +- handle empty iterables when using functional API +- make auto() work with previous enum members +- keep searching mixins until base class is found + +Enum: +- fix bug in Flag checks (ensure it is a Flag before checking the name) +- add multiple mixin support +- do not allow blank names (functional API) +- raise TypeError if _missing_* returns wrong type +- fix __format__ to honor custom __str__ + +extend_enum: +- support stdlib Enums +- use _generate_next_value_ if value not provided + +general: +- standardize exception formatting +- use getfullargspec() in Python 3 (avoids deprecation warnings) + + +2.1.2 +===== + +when order is callable, save it for subclass use + + +2.1.1 +===== + +correctly raise TypeError for non-Enum containment checks +support combining names with | for Flag key access +support _order_ being a callable + + +2.1.0 +===== + +support Flags being combined with other data types: +- add _create_pseudo_member_values_ +- add default __new__ and temporary _init_ + + +2.0.10 +====== + +ensure _ignore_ is set when _settings_ specified in body which includes +AutoValue + +make Flag members iterable + + +2.0.9 +===== + +fix missing comma in __all__ +fix extend_enum with custom __new__ methods +fix MultiValue with AutoNumber without _init_ + + +2.0.8 +===== + +extend_enum now handles aliases and multivalues correctly + + +2.0.7 +===== + +support mixin types with extend_enum +init and AutoNumber can now work together +add test for new Enum using EnumMeta +add tests for variations of multivalue and init +prevent deletion of NamedConstant.constant + + +2.0.6 +===== + +constants cannot be deleted (they already couldn't be changed) +constants can be used to define other constants + + +2.0.5 +===== + +_init_ and MultiValue can now work together + + +2.0.4 +===== + +_init_ and AutoValue (and _generate_next_value_) can now work together to +supply missing values even when some of the required values per member are +absent + + +2.0.3 +===== + +add _missing_value_ and _missing_name_ methods, deprecate _missing_ +make enum instances comparable + + +2.0.2 +===== + +both EnumMeta.__getattr__ and Enum.__new__ fall back to _missing_ + + +2.0.1 +===== + +auto() now works with other data types +AutoNumber supports legacy Enums (fixed regression) + + +2.0.0 +===== + +Flag and IntFlag added. + + +1.4.7 +===== + +fix %-interpolation bug +defined SqlLiteEnum only if sqlite exists +support pyflakes + + +1.4.6 +===== + +version numbering error + + +1.4.5 +===== + +revert AutoNumberEnum to custom __new__ instead of AutoNumber +use _ignore_ to shield against AutoNumber magic +inherit start and init settings from base Enums + + +1.4.4 +===== + +enabled export as a decorator +enabled _order_ to replace __order__ +enabled python2 support for settings, init, and start + + +1.4.3 +===== + +support _ignore_ for dynamically creating class bodies + + +1.4.2 +===== + +MultiValue, NoAlias, Unique, and init now work with Python 2 + + +1.4.1 +===== + +Py3: added Enum creation flags: Auto, MultiValue, NoAlias, Unique + +fixed extend_enum to honor Enum flags + + +1.4.0 +===== + +When possible aenum inherits from Python's own enum. + +Breaking change: enum members now default to evaluating as True to maintain +compatibility with the stdlib. + +Add your own __bool__ (__nonzero__ in Python 2) if need this behavior: + + def __bool__(self): + return bool(self.value) + __nonzero__ = __bool__ + diff --git a/venv/Lib/site-packages/aenum/LICENSE b/venv/Lib/site-packages/aenum/LICENSE new file mode 100644 index 00000000..b20361ce --- /dev/null +++ b/venv/Lib/site-packages/aenum/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) 2015, 2016, 2017, 2018 Ethan Furman. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + Neither the name Ethan Furman nor the names of any + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/aenum/__init__.py b/venv/Lib/site-packages/aenum/__init__.py new file mode 100644 index 00000000..26c504cc --- /dev/null +++ b/venv/Lib/site-packages/aenum/__init__.py @@ -0,0 +1,4111 @@ +"""Python Advanced Enumerations & NameTuples""" +from __future__ import print_function + +# imports +import sys as _sys +pyver = _sys.version_info[:2] +PY2 = pyver < (3, ) +PY3 = pyver >= (3, ) +PY2_6 = (2, 6) +PY3_3 = (3, 3) +PY3_4 = (3, 4) +PY3_5 = (3, 5) +PY3_6 = (3, 6) +PY3_11 = (3, 11) + +import re + +_bltin_property = property +_bltin_bin = bin + +try: + from collections import OrderedDict +except ImportError: + OrderedDict = dict +from collections import defaultdict +try: + import sqlite3 +except ImportError: + sqlite3 = None + +try: + RecursionError +except NameError: + # python3.4 + RecursionError = RuntimeError + +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 ._py2 import * +if PY3: + from ._py3 import * + +obj_type = type + +__all__ = [ + 'NamedConstant', 'constant', 'skip', 'nonmember', 'member', 'no_arg', + 'Enum', 'IntEnum', 'AutoNumberEnum', 'OrderedEnum', 'UniqueEnum', + 'StrEnum', 'UpperStrEnum', 'LowerStrEnum', + 'Flag', 'IntFlag', + 'AddValue', 'MagicValue', 'MultiValue', 'NoAlias', 'Unique', + 'AddValueEnum', 'MultiValueEnum', 'NoAliasEnum', + 'enum', 'extend_enum', 'unique', 'property', + 'NamedTuple', 'SqliteEnum', + 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP', + 'add_stdlib_integration', 'remove_stdlib_integration' + ] + +if sqlite3 is None: + __all__.remove('SqliteEnum') + +version = 3, 1, 12, 1 + +# shims +try: + any +except NameError: + def any(iterable): + for element in iterable: + if element: + return True + return False + +try: + unicode + unicode = unicode +except NameError: + # In Python 3 unicode no longer exists (it's just str) + unicode = str + +try: + basestring + basestring = bytes, unicode +except NameError: + # In Python 2 basestring is the ancestor of both str and unicode + # in Python 3 it's just str, but was missing in 3.1 + basestring = str, + +try: + long + baseinteger = int, long +except NameError: + baseinteger = int, + long = int +# deprecated +baseint = baseinteger + +try: + NoneType +except NameError: + NoneType = type(None) + +try: + # derive from stdlib enum if possible + import enum + if hasattr(enum, 'version'): + raise ImportError('wrong version') + else: + from enum import EnumMeta as StdlibEnumMeta, Enum as StdlibEnum, IntEnum as StdlibIntEnum + StdlibFlag = StdlibIntFlag = StdlibStrEnum = StdlibReprEnum = None +except ImportError: + StdlibEnumMeta = StdlibEnum = StdlibIntEnum = StdlibIntFlag = StdlibFlag = StdlibStrEnum = None + +if StdlibEnum: + try: + from enum import IntFlag as StdlibIntFlag, Flag as StdlibFlag + except ImportError: + pass + try: + from enum import StrEnum as StdlibStrEnum + except ImportError: + pass + try: + from enum import ReprEnum as StdlibReprEnum + except ImportError: + pass + + + + +# helpers +# will be exported later +MagicValue = AddValue = MultiValue = NoAlias = Unique = None + +def _bit_count(num): + """ + return number of set bits + + Counting bits set, Brian Kernighan's way* + + unsigned int v; // count the number of bits set in v + unsigned int c; // c accumulates the total bits set in v + for (c = 0; v; c++) + { v &= v - 1; } //clear the least significant bit set + + This method goes through as many iterations as there are set bits. So if we + have a 32-bit word with only the high bit set, then it will only go once + through the loop. + + * The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988. + + This works because each subtraction "borrows" from the lowest 1-bit. For + example: + + loop pass 1 loop pass 2 + ----------- ----------- + 101000 100000 + - 1 - 1 + = 100111 = 011111 + & 101000 & 100000 + = 100000 = 0 + + It is an excellent technique for Python, since the size of the integer need + not be determined beforehand. + + (from https://wiki.python.org/moin/BitManipulation) + """ + count = 0 + while num: + num &= num - 1 + count += 1 + return count + +def _is_single_bit(value): + """ + True if only one bit set in value (should be an int) + """ + if value == 0: + return False + value &= value - 1 + return value == 0 + +def _iter_bits_lsb(value): + """ + Return each bit value one at a time. + + >>> list(_iter_bits_lsb(6)) + [2, 4] + """ + + while value: + bit = value & (~value + 1) + yield bit + value ^= bit + +def bin(value, max_bits=None): + """ + Like built-in bin(), except negative values are represented in + twos-compliment, and the leading bit always indicates sign + (0=positive, 1=negative). + + >>> bin(10) + '0b0 1010' + >>> bin(~10) # ~10 is -11 + '0b1 0101' + """ + + ceiling = 2 ** (value).bit_length() + if value >= 0: + s = _bltin_bin(value + ceiling).replace('1', '0', 1) + else: + s = _bltin_bin(~value ^ (ceiling - 1) + ceiling) + sign = s[:3] + digits = s[3:] + if max_bits is not None: + if len(digits) < max_bits: + digits = (sign[-1] * max_bits + digits)[-max_bits:] + return "%s %s" % (sign, digits) + + +try: + from types import DynamicClassAttribute + base = DynamicClassAttribute +except ImportError: + base = object + DynamicClassAttribute = None + +class property(base): + """ + This is a descriptor, used to define attributes that act differently + when accessed through an enum member and through an enum class. + Instance access is the same as property(), but access to an attribute + through the enum class will look in the class' _member_map_. + """ + + # inherit from DynamicClassAttribute if we can in order to get `inspect` + # support + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + self.fget = fget + self.fset = fset + self.fdel = fdel + # next two lines make property act the same as _bltin_property + self.__doc__ = doc or fget.__doc__ + self.overwrite_doc = doc is None + # support for abstract methods + self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False)) + # names, if possible + + def getter(self, fget): + fdoc = fget.__doc__ if self.overwrite_doc else None + result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__) + result.overwrite_doc = self.__doc__ is None + return result + + def setter(self, fset): + fdoc = fget.__doc__ if self.overwrite_doc else None + result = type(self)(self.fget, fset, self.fdel, self.__doc__) + result.overwrite_doc = self.__doc__ is None + return result + + def deleter(self, fdel): + fdoc = fget.__doc__ if self.overwrite_doc else None + result = type(self)(self.fget, self.fset, fdel, self.__doc__) + result.overwrite_doc = self.__doc__ is None + return result + + def __repr__(self): + member = self.ownerclass._member_map_.get(self.name) + func = self.fget or self.fset or self.fdel + strings = [] + if member: + strings.append('%r' % member) + if func: + strings.append('function=%s' % func.__name__) + return 'property(%s)' % ', '.join(strings) + + def __get__(self, instance, ownerclass=None): + if instance is None: + try: + return ownerclass._member_map_[self.name] + except KeyError: + raise AttributeError( + '%r has no attribute %r' % (ownerclass, self.name) + ) + else: + if self.fget is not None: + return self.fget(instance) + else: + if self.fset is not None: + raise AttributeError( + 'cannot read attribute %r on %r' % (self.name, ownerclass) + ) + else: + try: + return instance.__dict__[self.name] + except KeyError: + raise AttributeError( + '%r member has no attribute %r' % (ownerclass, self.name) + ) + + def __set__(self, instance, value): + if self.fset is None: + if self.fget is not None: + raise AttributeError( + "cannot set attribute %r on " % (self.name, self.clsname) + ) + else: + instance.__dict__[self.name] = value + else: + return self.fset(instance, value) + + def __delete__(self, instance): + if self.fdel is None: + if self.fget or self.fset: + raise AttributeError( + "cannot delete attribute %r on " % (self.name, self.clsname) + ) + elif self.name in instance.__dict__: + del instance.__dict__[self.name] + else: + raise AttributeError( + "no attribute %r on member" % (self.name, self.clsname) + ) + else: + return self.fdel(instance) + + def __set_name__(self, ownerclass, name): + self.name = name + self.clsname = ownerclass.__name__ + self.ownerclass = ownerclass + +_RouteClassAttributeToGetattr = property +if DynamicClassAttribute is None: + DynamicClassAttribute = property +# deprecated +enum_property = property + +class NonMember(object): + """ + Protects item from becaming an Enum member during class creation. + """ + def __init__(self, value): + self.value = value + + def __get__(self, instance, ownerclass=None): + return self.value +skip = nonmember = NonMember + +class Member(object): + """ + Forces item to became an Enum member during class creation. + """ + def __init__(self, value): + self.value = value +member = Member + +class SentinelType(type): + def __repr__(cls): + return '<%s>' % cls.__name__ +Sentinel = SentinelType('Sentinel', (object, ), {}) + +def _is_descriptor(obj): + """Returns True if obj is a descriptor, False otherwise.""" + return ( + hasattr(obj, '__get__') or + hasattr(obj, '__set__') or + hasattr(obj, '__delete__')) + + +def _is_dunder(name): + """Returns True if a __dunder__ name, False otherwise.""" + return (len(name) > 4 and + name[:2] == name[-2:] == '__' and + name[2] != '_' and + name[-3] != '_') + + +def _is_sunder(name): + """Returns True if a _sunder_ name, False otherwise.""" + return (len(name) > 2 and + name[0] == name[-1] == '_' and + name[1] != '_' and + name[-2] != '_') + +def _is_internal_class(cls_name, obj): + # only 3.3 and up, always return False in 3.2 and below + if pyver < PY3_3: + return False + else: + qualname = getattr(obj, '__qualname__', False) + return not _is_descriptor(obj) and qualname and re.search(r"\.?%s\.\w+$" % cls_name, qualname) + +def _is_private_name(cls_name, name): + pattern = r'^_%s__\w+[^_]_?$' % (cls_name, ) + return re.search(pattern, name) + +def _power_of_two(value): + if value < 1: + return False + return value == 2 ** _high_bit(value) + +def bits(num): + if num in (0, 1): + return str(num) + negative = False + if num < 0: + negative = True + num = ~num + result = bits(num>>1) + str(num&1) + if negative: + result = '1' + ''.join(['10'[d=='1'] for d in result]) + return result + + +def bit_count(num): + """ + return number of set bits + + Counting bits set, Brian Kernighan's way* + + unsigned int v; // count the number of bits set in v + unsigned int c; // c accumulates the total bits set in v + for (c = 0; v; c++) + { v &= v - 1; } //clear the least significant bit set + + This method goes through as many iterations as there are set bits. So if we + have a 32-bit word with only the high bit set, then it will only go once + through the loop. + + * The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988. + + This works because each subtraction "borrows" from the lowest 1-bit. For example: + + loop pass 1 loop pass 2 + ----------- ----------- + 101000 100000 + - 1 - 1 + = 100111 = 011111 + & 101000 & 100000 + = 100000 = 0 + + It is an excellent technique for Python, since the size of the integer need not + be determined beforehand. + """ + count = 0 + while(num): + num &= num - 1 + count += 1 + return(count) + +def bit_len(num): + length = 0 + while num: + length += 1 + num >>= 1 + return length + +def is_single_bit(num): + """ + True if only one bit set in num (should be an int) + """ + num &= num - 1 + return num == 0 + +def _make_class_unpicklable(obj): + """ + Make the given obj un-picklable. + + obj should be either a dictionary, on an Enum + """ + def _break_on_call_reduce(self, proto): + raise TypeError('%r cannot be pickled' % self) + if isinstance(obj, dict): + obj['__reduce_ex__'] = _break_on_call_reduce + obj['__module__'] = '' + else: + setattr(obj, '__reduce_ex__', _break_on_call_reduce) + setattr(obj, '__module__', '') + +def _check_auto_args(method): + """check if new generate method supports *args and **kwds""" + if isinstance(method, staticmethod): + method = method.__get__(type) + method = getattr(method, 'im_func', method) + args, varargs, keywords, defaults = getargspec(method) + return varargs is not None and keywords is not None + +def _get_attr_from_chain(cls, attr): + sentinel = object() + for basecls in cls.mro(): + obj = basecls.__dict__.get(attr, sentinel) + if obj is not sentinel: + return obj + +def _value(obj): + if isinstance(obj, (auto, constant)): + return obj.value + else: + return obj + +def enumsort(things): + """ + sorts things by value if all same type; otherwise by name + """ + if not things: + return things + sort_type = type(things[0]) + if not issubclass(sort_type, tuple): + # direct sort or type error + if not all((type(v) is sort_type) for v in things[1:]): + raise TypeError('cannot sort items of different types') + return sorted(things) + else: + # expecting list of (name, value) tuples + sort_type = type(things[0][1]) + try: + if all((type(v[1]) is sort_type) for v in things[1:]): + return sorted(things, key=lambda i: i[1]) + else: + raise TypeError('try name sort instead') + except TypeError: + return sorted(things, key=lambda i: i[0]) + +def export(collection, namespace=None): + """ + export([collection,] namespace) -> Export members to target namespace. + + If collection is not given, act as a decorator. + """ + if namespace is None: + namespace = collection + def export_decorator(collection): + return export(collection, namespace) + return export_decorator + elif issubclass(collection, NamedConstant): + for n, c in collection.__dict__.items(): + if isinstance(c, NamedConstant): + namespace[n] = c + elif issubclass(collection, Enum): + data = collection.__members__.items() + for n, m in data: + namespace[n] = m + else: + raise TypeError('%r is not a supported collection' % (collection,) ) + return collection + +class _Addendum(object): + def __init__(self, dict, doc, ns): + # dict is the dict to update with functions + # doc is the docstring to put in the dict + # ns is the namespace to remove the function names from + self.dict = dict + self.ns = ns + self.added = set() + def __call__(self, func): + if isinstance(func, (staticmethod, classmethod)): + name = func.__func__.__name__ + elif isinstance(func, (property, _bltin_property)): + name = (func.fget or func.fset or func.fdel).__name__ + else: + name = func.__name__ + self.dict[name] = func + self.added.add(name) + def resolve(self): + ns = self.ns + for name in self.added: + del ns[name] + return self.dict + +# Constant / NamedConstant + +class constant(object): + ''' + Simple constant descriptor for NamedConstant and Enum use. + ''' + def __init__(self, value, doc=None): + self.value = value + self.__doc__ = doc + + def __get__(self, *args): + return self.value + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, self.value) + + def __and__(self, other): + return _and_(self.value, _value(other)) + + def __rand__(self, other): + return _and_(_value(other), self.value) + + def __invert__(self): + return _inv_(self.value) + + def __or__(self, other): + return _or_(self.value, _value(other)) + + def __ror__(self, other): + return _or_(_value(other), self.value) + + def __xor__(self, other): + return _xor_(self.value, _value(other)) + + def __rxor__(self, other): + return _xor_(_value(other), self.value) + + def __abs__(self): + return _abs_(self.value) + + def __add__(self, other): + return _add_(self.value, _value(other)) + + def __radd__(self, other): + return _add_(_value(other), self.value) + + def __neg__(self): + return _neg_(self.value) + + def __pos__(self): + return _pos_(self.value) + + if PY2: + def __div__(self, other): + return _div_(self.value, _value(other)) + + def __rdiv__(self, other): + return _div_(_value(other), (self.value)) + + def __floordiv__(self, other): + return _floordiv_(self.value, _value(other)) + + def __rfloordiv__(self, other): + return _floordiv_(_value(other), self.value) + + def __truediv__(self, other): + return _truediv_(self.value, _value(other)) + + def __rtruediv__(self, other): + return _truediv_(_value(other), self.value) + + def __lshift__(self, other): + return _lshift_(self.value, _value(other)) + + def __rlshift__(self, other): + return _lshift_(_value(other), self.value) + + def __rshift__(self, other): + return _rshift_(self.value, _value(other)) + + def __rrshift__(self, other): + return _rshift_(_value(other), self.value) + + def __mod__(self, other): + return _mod_(self.value, _value(other)) + + def __rmod__(self, other): + return _mod_(_value(other), self.value) + + def __mul__(self, other): + return _mul_(self.value, _value(other)) + + def __rmul__(self, other): + return _mul_(_value(other), self.value) + + def __pow__(self, other): + return _pow_(self.value, _value(other)) + + def __rpow__(self, other): + return _pow_(_value(other), self.value) + + def __sub__(self, other): + return _sub_(self.value, _value(other)) + + def __rsub__(self, other): + return _sub_(_value(other), self.value) + + def __set_name__(self, ownerclass, name): + self.name = name + self.clsname = ownerclass.__name__ + + +NamedConstant = None + +class _NamedConstantDict(dict): + """Track constant order and ensure names are not reused. + + NamedConstantMeta will use the names found in self._names as the + Constant names. + """ + def __init__(self): + super(_NamedConstantDict, self).__init__() + self._names = [] + + def __setitem__(self, key, value): + """Changes anything not dundered or not a constant descriptor. + + If an constant name is used twice, an error is raised; duplicate + values are not checked for. + + Single underscore (sunder) names are reserved. + """ + if _is_sunder(key): + raise ValueError( + '_sunder_ names, such as %r, are reserved for future NamedConstant use' + % (key, ) + ) + elif _is_dunder(key): + pass + elif key in self._names: + # overwriting an existing constant? + raise TypeError('attempt to reuse name: %r' % (key, )) + elif isinstance(value, constant) or not _is_descriptor(value): + if key in self: + # overwriting a descriptor? + raise TypeError('%s already defined as: %r' % (key, self[key])) + self._names.append(key) + super(_NamedConstantDict, self).__setitem__(key, value) + + +class NamedConstantMeta(type): + """ + Block attempts to reassign NamedConstant attributes. + """ + + @classmethod + def __prepare__(metacls, cls, bases, **kwds): + return _NamedConstantDict() + + def __new__(metacls, cls, bases, clsdict): + if type(clsdict) is dict: + original_dict = clsdict + clsdict = _NamedConstantDict() + for k, v in original_dict.items(): + clsdict[k] = v + newdict = {} + constants = {} + for name, obj in clsdict.items(): + if name in clsdict._names: + constants[name] = obj + continue + elif isinstance(obj, nonmember): + obj = obj.value + newdict[name] = obj + newcls = super(NamedConstantMeta, metacls).__new__(metacls, cls, bases, newdict) + newcls._named_constant_cache_ = {} + newcls._members_ = {} + for name, obj in constants.items(): + new_k = newcls.__new__(newcls, name, obj) + newcls._members_[name] = new_k + return newcls + + def __bool__(cls): + return True + + def __delattr__(cls, attr): + cur_obj = cls.__dict__.get(attr) + if NamedConstant is not None and isinstance(cur_obj, NamedConstant): + raise AttributeError('cannot delete constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_)) + super(NamedConstantMeta, cls).__delattr__(attr) + + def __iter__(cls): + return (k for k in cls._members_.values()) + + def __reversed__(cls): + return (k for k in reversed(cls._members_.values())) + + def __len__(cls): + return len(cls._members_) + + __nonzero__ = __bool__ + + def __setattr__(cls, name, value): + """Block attempts to reassign NamedConstants. + """ + cur_obj = cls.__dict__.get(name) + if NamedConstant is not None and isinstance(cur_obj, NamedConstant): + raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_)) + super(NamedConstantMeta, cls).__setattr__(name, value) + +constant_dict = _Addendum( + dict=NamedConstantMeta.__prepare__('NamedConstant', (object, )), + doc="NamedConstants protection.\n\n Derive from this class to lock NamedConstants.\n\n", + ns=globals(), + ) + +@constant_dict +def __new__(cls, name, value=None, doc=None): + if value is None: + # lookup, name is value + value = name + for name, obj in cls.__dict__.items(): + if isinstance(obj, cls) and obj._value_ == value: + return obj + else: + raise ValueError('%r does not exist in %r' % (value, cls.__name__)) + cur_obj = cls.__dict__.get(name) + if isinstance(cur_obj, NamedConstant): + raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_)) + elif isinstance(value, constant): + doc = doc or value.__doc__ + value = value.value + metacls = cls.__class__ + if isinstance(value, NamedConstant): + # constants from other classes are reduced to their actual value + value = value._value_ + actual_type = type(value) + value_type = cls._named_constant_cache_.get(actual_type) + if value_type is None: + value_type = type(cls.__name__, (cls, type(value)), {}) + cls._named_constant_cache_[type(value)] = value_type + obj = actual_type.__new__(value_type, value) + obj._name_ = name + obj._value_ = value + obj.__doc__ = doc + cls._members_[name] = obj + metacls.__setattr__(cls, name, obj) + return obj + +@constant_dict +def __repr__(self): + return "<%s.%s: %r>" % ( + self.__class__.__name__, self._name_, self._value_) + +@constant_dict +def __reduce_ex__(self, proto): + return getattr, (self.__class__, self._name_) + +NamedConstant = NamedConstantMeta('NamedConstant', (object, ), constant_dict.resolve()) +Constant = NamedConstant +del constant_dict + +# NamedTuple + +class _NamedTupleDict(OrderedDict): + """Track field order and ensure field names are not reused. + + NamedTupleMeta will use the names found in self._field_names to translate + to indices. + """ + def __init__(self, *args, **kwds): + self._field_names = [] + super(_NamedTupleDict, self).__init__(*args, **kwds) + + def __setitem__(self, key, value): + """Records anything not dundered or not a descriptor. + + If a field name is used twice, an error is raised. + + Single underscore (sunder) names are reserved. + """ + if _is_sunder(key): + if key not in ('_size_', '_order_', '_fields_'): + raise ValueError( + '_sunder_ names, such as %r, are reserved for future NamedTuple use' + % (key, ) + ) + elif _is_dunder(key): + if key == '__order__': + key = '_order_' + elif key in self._field_names: + # overwriting a field? + raise TypeError('attempt to reuse field name: %r' % (key, )) + elif not _is_descriptor(value): + if key in self: + # field overwriting a descriptor? + raise TypeError('%s already defined as: %r' % (key, self[key])) + self._field_names.append(key) + super(_NamedTupleDict, self).__setitem__(key, value) + + +class _TupleAttributeAtIndex(object): + + def __init__(self, name, index, doc, default): + self.name = name + self.index = index + if doc is undefined: + doc = None + self.__doc__ = doc + self.default = default + + def __get__(self, instance, owner): + if instance is None: + return self + if len(instance) <= self.index: + raise AttributeError('%s instance has no value for %s' % (instance.__class__.__name__, self.name)) + return instance[self.index] + + def __repr__(self): + return '%s(%d)' % (self.__class__.__name__, self.index) + + +class undefined(object): + def __repr__(self): + return 'undefined' + def __bool__(self): + return False + __nonzero__ = __bool__ +undefined = undefined() + + +class TupleSize(NamedConstant): + fixed = constant('fixed', 'tuple length is static') + minimum = constant('minimum', 'tuple must be at least x long (x is calculated during creation') + variable = constant('variable', 'tuple length can be anything') + +class NamedTupleMeta(type): + """Metaclass for NamedTuple""" + + @classmethod + def __prepare__(metacls, cls, bases, size=undefined, **kwds): + return _NamedTupleDict() + + def __init__(cls, *args , **kwds): + super(NamedTupleMeta, cls).__init__(*args) + + def __new__(metacls, cls, bases, clsdict, size=undefined, **kwds): + if bases == (object, ): + bases = (tuple, object) + elif tuple not in bases: + if object in bases: + index = bases.index(object) + bases = bases[:index] + (tuple, ) + bases[index:] + else: + bases = bases + (tuple, ) + # include any fields from base classes + base_dict = _NamedTupleDict() + namedtuple_bases = [] + for base in bases: + if isinstance(base, NamedTupleMeta): + namedtuple_bases.append(base) + i = 0 + if namedtuple_bases: + for name, index, doc, default in metacls._convert_fields(*namedtuple_bases): + base_dict[name] = index, doc, default + i = max(i, index) + # construct properly ordered dict with normalized indexes + for k, v in clsdict.items(): + base_dict[k] = v + original_dict = base_dict + if size is not undefined and '_size_' in original_dict: + raise TypeError('_size_ cannot be set if "size" is passed in header') + add_order = isinstance(clsdict, _NamedTupleDict) + clsdict = _NamedTupleDict() + clsdict.setdefault('_size_', size or TupleSize.fixed) + unnumbered = OrderedDict() + numbered = OrderedDict() + _order_ = original_dict.pop('_order_', []) + if _order_ : + _order_ = _order_.replace(',',' ').split() + add_order = False + # and process this class + for k, v in original_dict.items(): + if k not in original_dict._field_names: + clsdict[k] = v + else: + # TODO:normalize v here + if isinstance(v, baseinteger): + # assume an offset + v = v, undefined, undefined + i = v[0] + 1 + target = numbered + elif isinstance(v, basestring): + # assume a docstring + if add_order: + v = i, v, undefined + i += 1 + target = numbered + else: + v = undefined, v, undefined + target = unnumbered + elif isinstance(v, tuple) and len(v) in (2, 3) and isinstance(v[0], baseinteger) and isinstance(v[1], (basestring, NoneType)): + # assume an offset, a docstring, and (maybe) a default + if len(v) == 2: + v = v + (undefined, ) + v = v + i = v[0] + 1 + target = numbered + elif isinstance(v, tuple) and len(v) in (1, 2) and isinstance(v[0], (basestring, NoneType)): + # assume a docstring, and (maybe) a default + if len(v) == 1: + v = v + (undefined, ) + if add_order: + v = (i, ) + v + i += 1 + target = numbered + else: + v = (undefined, ) + v + target = unnumbered + else: + # refuse to guess further + raise ValueError('not sure what to do with %s=%r (should be OFFSET [, DOC [, DEFAULT]])' % (k, v)) + target[k] = v + # all index values have been normalized + # deal with _order_ (or lack thereof) + fields = [] + aliases = [] + seen = set() + max_len = 0 + if not _order_: + if unnumbered: + raise ValueError("_order_ not specified and OFFSETs not declared for %r" % (unnumbered.keys(), )) + for name, (index, doc, default) in sorted(numbered.items(), key=lambda nv: (nv[1][0], nv[0])): + if index in seen: + aliases.append(name) + else: + fields.append(name) + seen.add(index) + max_len = max(max_len, index + 1) + offsets = numbered + else: + # check if any unnumbered not in _order_ + missing = set(unnumbered) - set(_order_) + if missing: + raise ValueError("unable to order fields: %s (use _order_ or specify OFFSET" % missing) + offsets = OrderedDict() + # if any unnumbered, number them from their position in _order_ + i = 0 + for k in _order_: + try: + index, doc, default = unnumbered.pop(k, None) or numbered.pop(k) + except IndexError: + raise ValueError('%s (from _order_) not found in %s' % (k, cls)) + if index is not undefined: + i = index + if i in seen: + aliases.append(k) + else: + fields.append(k) + seen.add(i) + offsets[k] = i, doc, default + i += 1 + max_len = max(max_len, i) + # now handle anything in numbered + for k, (index, doc, default) in sorted(numbered.items(), key=lambda nv: (nv[1][0], nv[0])): + if index in seen: + aliases.append(k) + else: + fields.append(k) + seen.add(index) + offsets[k] = index, doc, default + max_len = max(max_len, index+1) + + # at this point fields and aliases should be ordered lists, offsets should be an + # OrdededDict with each value an int, str or None or undefined, default or None or undefined + assert len(fields) + len(aliases) == len(offsets), "number of fields + aliases != number of offsets" + assert set(fields) & set(offsets) == set(fields), "some fields are not in offsets: %s" % set(fields) & set(offsets) + assert set(aliases) & set(offsets) == set(aliases), "some aliases are not in offsets: %s" % set(aliases) & set(offsets) + for name, (index, doc, default) in offsets.items(): + assert isinstance(index, baseinteger), "index for %s is not an int (%s:%r)" % (name, type(index), index) + assert isinstance(doc, (basestring, NoneType)) or doc is undefined, "doc is not a str, None, nor undefined (%s:%r)" % (name, type(doc), doc) + + # create descriptors for fields + for name, (index, doc, default) in offsets.items(): + clsdict[name] = _TupleAttributeAtIndex(name, index, doc, default) + clsdict['__slots__'] = () + + # create our new NamedTuple type + namedtuple_class = super(NamedTupleMeta, metacls).__new__(metacls, cls, bases, clsdict) + namedtuple_class._fields_ = fields + namedtuple_class._aliases_ = aliases + namedtuple_class._defined_len_ = max_len + return namedtuple_class + + @staticmethod + def _convert_fields(*namedtuples): + "create list of index, doc, default triplets for cls in namedtuples" + all_fields = [] + for cls in namedtuples: + base = len(all_fields) + for field in cls._fields_: + desc = getattr(cls, field) + all_fields.append((field, base+desc.index, desc.__doc__, desc.default)) + return all_fields + + def __add__(cls, other): + "A new NamedTuple is created by concatenating the _fields_ and adjusting the descriptors" + if not isinstance(other, NamedTupleMeta): + return NotImplemented + return NamedTupleMeta('%s%s' % (cls.__name__, other.__name__), (cls, other), {}) + + def __call__(cls, *args, **kwds): + """Creates a new NamedTuple class or an instance of a NamedTuple subclass. + + NamedTuple should have args of (class_name, names, module) + + `names` can be: + + * A string containing member names, separated either with spaces or + commas. Values are auto-numbered from 1. + * An iterable of member names. Values are auto-numbered from 1. + * An iterable of (member name, value) pairs. + * A mapping of member name -> value. + + `module`, if set, will be stored in the new class' __module__ attribute; + + Note: if `module` is not set this routine will attempt to discover the + calling module by walking the frame stack; if this is unsuccessful + the resulting class will not be pickleable. + + subclass should have whatever arguments and/or keywords will be used to create an + instance of the subclass + """ + if cls is NamedTuple: + original_args = args + original_kwds = kwds.copy() + # create a new subclass + try: + if 'class_name' in kwds: + class_name = kwds.pop('class_name') + else: + class_name, args = args[0], args[1:] + if 'names' in kwds: + names = kwds.pop('names') + else: + names, args = args[0], args[1:] + if 'module' in kwds: + module = kwds.pop('module') + elif args: + module, args = args[0], args[1:] + else: + module = None + if 'type' in kwds: + type = kwds.pop('type') + elif args: + type, args = args[0], args[1:] + else: + type = None + + except IndexError: + raise TypeError('too few arguments to NamedTuple: %s, %s' % (original_args, original_kwds)) + if args or kwds: + raise TypeError('too many arguments to NamedTuple: %s, %s' % (original_args, original_kwds)) + if PY2: + # if class_name is unicode, attempt a conversion to ASCII + if isinstance(class_name, unicode): + try: + class_name = class_name.encode('ascii') + except UnicodeEncodeError: + raise TypeError('%r is not representable in ASCII' % (class_name, )) + # quick exit if names is a NamedTuple + if isinstance(names, NamedTupleMeta): + names.__name__ = class_name + if type is not None and type not in names.__bases__: + names.__bases__ = (type, ) + names.__bases__ + return names + + metacls = cls.__class__ + bases = (cls, ) + clsdict = metacls.__prepare__(class_name, bases) + + # special processing needed for names? + if isinstance(names, basestring): + names = names.replace(',', ' ').split() + if isinstance(names, (tuple, list)) and isinstance(names[0], basestring): + names = [(e, i) for (i, e) in enumerate(names)] + # Here, names is either an iterable of (name, index) or (name, index, doc, default) or a mapping. + item = None # in case names is empty + for item in names: + if isinstance(item, basestring): + # mapping + field_name, field_index = item, names[item] + else: + # non-mapping + if len(item) == 2: + field_name, field_index = item + else: + field_name, field_index = item[0], item[1:] + clsdict[field_name] = field_index + if type is not None: + if not isinstance(type, tuple): + type = (type, ) + bases = type + bases + namedtuple_class = metacls.__new__(metacls, class_name, bases, clsdict) + + # TODO: replace the frame hack if a blessed way to know the calling + # module is ever developed + if module is None: + try: + module = _sys._getframe(1).f_globals['__name__'] + except (AttributeError, ValueError, KeyError): + pass + if module is None: + _make_class_unpicklable(namedtuple_class) + else: + namedtuple_class.__module__ = module + + return namedtuple_class + else: + # instantiate a subclass + namedtuple_instance = cls.__new__(cls, *args, **kwds) + if isinstance(namedtuple_instance, cls): + namedtuple_instance.__init__(*args, **kwds) + return namedtuple_instance + + @_bltin_property + def __fields__(cls): + return list(cls._fields_) + # collections.namedtuple compatibility + _fields = __fields__ + + @_bltin_property + def __aliases__(cls): + return list(cls._aliases_) + + def __repr__(cls): + return "" % (cls.__name__, ) + +namedtuple_dict = _Addendum( + dict=NamedTupleMeta.__prepare__('NamedTuple', (object, )), + doc="NamedTuple base class.\n\n Derive from this class to define new NamedTuples.\n\n", + ns=globals(), + ) + +@namedtuple_dict +def __new__(cls, *args, **kwds): + if cls._size_ is TupleSize.fixed and len(args) > cls._defined_len_: + raise TypeError('%d fields expected, %d received' % (cls._defined_len_, len(args))) + unknown = set(kwds) - set(cls._fields_) - set(cls._aliases_) + if unknown: + raise TypeError('unknown fields: %r' % (unknown, )) + final_args = list(args) + [undefined] * (len(cls.__fields__) - len(args)) + for field, value in kwds.items(): + index = getattr(cls, field).index + if final_args[index] != undefined: + raise TypeError('field %s specified more than once' % field) + final_args[index] = value + missing = [] + for index, value in enumerate(final_args): + if value is undefined: + # look for default values + name = cls.__fields__[index] + default = getattr(cls, name).default + if default is undefined: + missing.append(name) + else: + final_args[index] = default + if missing: + if cls._size_ in (TupleSize.fixed, TupleSize.minimum): + raise TypeError('values not provided for field(s): %s' % ', '.join(missing)) + while final_args and final_args[-1] is undefined: + final_args.pop() + missing.pop() + if cls._size_ is not TupleSize.variable or undefined in final_args: + raise TypeError('values not provided for field(s): %s' % ', '.join(missing)) + return tuple.__new__(cls, tuple(final_args)) + +@namedtuple_dict +def __reduce_ex__(self, proto): + return self.__class__, tuple(getattr(self, f) for f in self._fields_) + +@namedtuple_dict +def __repr__(self): + if len(self) == len(self._fields_): + return "%s(%s)" % ( + self.__class__.__name__, ', '.join(['%s=%r' % (f, o) for f, o in zip(self._fields_, self)]) + ) + else: + return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(o) for o in self])) + +@namedtuple_dict +def __str__(self): + return "%s(%s)" % ( + self.__class__.__name__, ', '.join(['%r' % (getattr(self, f), ) for f in self._fields_]) + ) + +@namedtuple_dict +@_bltin_property +def _fields_(self): + return list(self.__class__._fields_) + + # compatibility methods with stdlib namedtuple +@namedtuple_dict +@_bltin_property +def __aliases__(self): + return list(self.__class__._aliases_) + +@namedtuple_dict +@_bltin_property +def _fields(self): + return list(self.__class__._fields_) + +@namedtuple_dict +@classmethod +def _make(cls, iterable, new=None, len=None): + return cls.__new__(cls, *iterable) + +@namedtuple_dict +def _asdict(self): + return OrderedDict(zip(self._fields_, self)) + +@namedtuple_dict +def _replace(self, **kwds): + current = self._asdict() + current.update(kwds) + return self.__class__(**current) + +NamedTuple = NamedTupleMeta('NamedTuple', (object, ), namedtuple_dict.resolve()) +del namedtuple_dict + + +# Enum + + # _init_ and value and AddValue + # ----------------------------- + # by default, when defining a member everything after the = is "the value", everything is + # passed to __new__, everything is passed to __init__ + # + # if _init_ is present then + # if `value` is not in _init_, everything is "the value", defaults apply + # if `value` is in _init_, only the first thing after the = is the value, and the rest will + # be passed to __init__ + # if fewer values are present for member assignment than _init_ calls for, _generate_next_value_ + # will be called in an attempt to generate them + # + # if AddValue is present then + # _generate_next_value_ is always called, and any generated values are prepended to provided + # values (custom _gnv_s can change that) + # default _init_ rules apply + + + # Constants used in Enum + +@export(globals()) +class EnumConstants(NamedConstant): + AddValue = constant('addvalue', 'prepends value(s) from _generate_next_value_ to each member') + MagicValue = constant('magicvalue', 'calls _generate_next_value_ when no arguments are given') + MultiValue = constant('multivalue', 'each member can have several values') + NoAlias = constant('noalias', 'duplicate valued members are distinct, not aliased') + Unique = constant('unique', 'duplicate valued members are not allowed') + def __repr__(self): + return self._name_ + + + # Dummy value for Enum as EnumType explicity checks for it, but of course until + # EnumType finishes running the first time the Enum class doesn't exist. This + # is also why there are checks in EnumType like `if Enum is not None`. + # + # Ditto for Flag. + +Enum = ReprEnum = IntEnum = StrEnum = Flag = IntFlag = EJECT = KEEP = None + +class enum(object): + """ + Helper class to track args, kwds. + """ + def __init__(self, *args, **kwds): + self._args = args + self._kwds = dict(kwds.items()) + self._hash = hash(args) + self.name = None + + @_bltin_property + def args(self): + return self._args + + @_bltin_property + def kwds(self): + return self._kwds.copy() + + def __hash__(self): + return self._hash + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return self.args == other.args and self.kwds == other.kwds + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return self.args != other.args or self.kwds != other.kwds + + def __repr__(self): + final = [] + args = ', '.join(['%r' % (a, ) for a in self.args]) + if args: + final.append(args) + kwds = ', '.join([('%s=%r') % (k, v) for k, v in enumsort(list(self.kwds.items()))]) + if kwds: + final.append(kwds) + return '%s(%s)' % (self.__class__.__name__, ', '.join(final)) + +_auto_null = SentinelType('no_value', (object, ), {}) +class auto(enum): + """ + Instances are replaced with an appropriate value in Enum class suites. + """ + enum_member = _auto_null + _value = _auto_null + _operations = [] + + def __and__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_and_, (self, other))) + return new_auto + + def __rand__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_and_, (other, self))) + return new_auto + + def __invert__(self): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_inv_, (self,))) + return new_auto + + def __or__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_or_, (self, other))) + return new_auto + + def __ror__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_or_, (other, self))) + return new_auto + + def __xor__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_xor_, (self, other))) + return new_auto + + def __rxor__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_xor_, (other, self))) + return new_auto + + def __abs__(self): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_abs_, (self, ))) + return new_auto + + def __add__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_add_, (self, other))) + return new_auto + + def __radd__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_add_, (other, self))) + return new_auto + + def __neg__(self): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_neg_, (self, ))) + return new_auto + + def __pos__(self): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_pos_, (self, ))) + return new_auto + + if PY2: + def __div__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_div_, (self, other))) + return new_auto + + def __rdiv__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_div_, (other, self))) + return new_auto + + def __floordiv__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_floordiv_, (self, other))) + return new_auto + + def __rfloordiv__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_floordiv_, (other, self))) + return new_auto + + def __truediv__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_truediv_, (self, other))) + return new_auto + + def __rtruediv__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_truediv_, (other, self))) + return new_auto + + def __lshift__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_lshift_, (self, other))) + return new_auto + + def __rlshift__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_lshift_, (other, self))) + return new_auto + + def __rshift__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_rshift_, (self, other))) + return new_auto + + def __rrshift__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_rshift_, (other, self))) + return new_auto + + def __mod__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_mod_, (self, other))) + return new_auto + + def __rmod__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_mod_, (other, self))) + return new_auto + + def __mul__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_mul_, (self, other))) + return new_auto + + def __rmul__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_mul_, (other, self))) + return new_auto + + def __pow__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_pow_, (self, other))) + return new_auto + + def __rpow__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_pow_, (other, self))) + return new_auto + + def __sub__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_sub_, (self, other))) + return new_auto + + def __rsub__(self, other): + new_auto = self.__class__() + new_auto._operations = self._operations[:] + new_auto._operations.append((_sub_, (other, self))) + return new_auto + + def __repr__(self): + if self._operations: + return 'auto(...)' + else: + return 'auto(%r, *%r, **%r)' % (self._value, self._args, self._kwds) + + @_bltin_property + def value(self): + if self._value is not _auto_null and self._operations: + raise TypeError('auto() object out of sync') + elif self._value is _auto_null and not self._operations: + return self._value + elif self._value is not _auto_null: + return self._value + else: + return self._resolve() + + @value.setter + def value(self, value): + if self._operations: + value = self._resolve(value) + self._value = value + + def _resolve(self, base_value=None): + cls = self.__class__ + for op, params in self._operations: + values = [] + for param in params: + if isinstance(param, cls): + if param.value is _auto_null: + if base_value is None: + return _auto_null + else: + values.append(base_value) + else: + values.append(param.value) + else: + values.append(param) + value = op(*values) + self._operations[:] = [] + self._value = value + return value + + +class _EnumArgSpec(NamedTuple): + args = 0, 'all args except *args and **kwds' + varargs = 1, 'the name of the *args variable' + keywords = 2, 'the name of the **kwds variable' + defaults = 3, 'any default values' + required = 4, 'number of required values (no default available)' + + def __new__(cls, _new_func): + argspec = getargspec(_new_func) + args, varargs, keywords, defaults = argspec + if defaults: + reqs = args[1:-len(defaults)] + else: + reqs = args[1:] + return tuple.__new__(_EnumArgSpec, (args, varargs, keywords, defaults, reqs)) + + +class _proto_member: + """ + intermediate step for enum members between class execution and final creation + """ + + def __init__(self, value): + self.value = value + + def __set_name__(self, enum_class, member_name): + """ + convert each quasi-member into an instance of the new enum class + """ + # first step: remove ourself from enum_class + delattr(enum_class, member_name) + # second step: create member based on enum_class + value = self.value + kwds = {} + args = () + init_args = () + extra_mv_args = () + multivalue = None + if isinstance(value, tuple) and value and isinstance(value[0], auto): + multivalue = value + value = value[0] + if isinstance(value, auto) and value.value is _auto_null: + args = value.args + kwds = value.kwds + elif isinstance(value, auto): + kwds = value.kwds + args = (value.value, ) + value.args + value = value.value + elif isinstance(value, enum): + args = value.args + kwds = value.kwds + elif isinstance(value, Member): + value = value.value + args = (value, ) + elif not isinstance(value, tuple): + args = (value, ) + else: + args = value + if multivalue is not None: + value = (value, ) + multivalue[1:] + kwds = {} + args = value + del multivalue + # possibilities + # + # - no init, multivalue -> __new__[0], __init__(*[:]), extra=[1:] + # - init w/o value, multivalue -> __new__[0], __init__(*[:]), extra=[1:] + # + # - init w/value, multivalue -> __new__[0], __init__(*[1:]), extra=[1:] + # + # - init w/value, no multivalue -> __new__[0], __init__(*[1:]), extra=[] + # + # - init w/o value, no multivalue -> __new__[:], __init__(*[:]), extra=[] + # - no init, no multivalue -> __new__[:], __init__(*[:]), extra=[] + if enum_class._multivalue_ or 'value' in enum_class._creating_init_: + if enum_class._multivalue_: + # when multivalue is True, creating_init can be anything + mv_arg = args[0] + extra_mv_args = args[1:] + if 'value' in enum_class._creating_init_: + init_args = args[1:] + else: + init_args = args + args = args[0:1] + value = args[0] + else: + # 'value' is definitely in creating_init + if enum_class._auto_init_ and enum_class._new_args_: + # we have a custom __new__ and an auto __init__ + # divvy up according to number of params in each + init_args = args[-len(enum_class._creating_init_)+1:] + if not enum_class._auto_args_: + args = args[:len(enum_class._new_args_.args)] + value = args[0] + elif enum_class._auto_init_: + # don't pass in value + init_args = args[1:] + args = args[0:1] + value = args[0] + elif enum_class._new_args_: + # do not modify args + value = args[0] + else: + # keep all args for user-defined __init__ + # keep value as-is + init_args = args + else: + # either no creating_init, or it doesn't have 'value' + init_args = args + if enum_class._member_type_ is tuple: # special case for tuple enums + args = (args, ) # wrap it one more time + if not enum_class._use_args_: + enum_member = enum_class._new_member_(enum_class) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = value + else: + enum_member = enum_class._new_member_(enum_class, *args, **kwds) + if not hasattr(enum_member, '_value_'): + if enum_class._member_type_ is object: + enum_member._value_ = value + else: + try: + enum_member._value_ = enum_class._member_type_(*args, **kwds) + except Exception: + te = TypeError('_value_ not set in __new__, unable to create it') + te.__cause__ = None + raise te + value = enum_member._value_ + enum_member._name_ = member_name + enum_member.__objclass__ = enum_class + enum_member.__init__(*init_args, **kwds) + enum_member._sort_order_ = len(enum_class._member_names_) + # If another member with the same value was already defined, the + # new member becomes an alias to the existing one. + if enum_class._noalias_: + # unless NoAlias was specified + enum_class._member_names_.append(member_name) + else: + nonunique = defaultdict(list) + try: + try: + # try to do a fast lookup to avoid the quadratic loop + enum_member = enum_class._value2member_map_[value] + if enum_class._unique_: + nonunique[enum_member.name].append(member_name) + except TypeError: + # unhashable members are stored elsewhere + for unhashable_value, canonical_member in enum_class._value2member_seq_: + name = canonical_member.name + if unhashable_value == enum_member._value_: + if enum_class._unique_: + nonunique[name].append(member_name) + enum_member = canonical_member + break + else: + raise KeyError + except KeyError: + # this could still be an alias if the value is multi-bit and the + # class is a flag class + if ( + Flag is None + or not issubclass(enum_class, Flag) + ): + # no other instances found, record this member in _member_names_ + enum_class._member_names_.append(member_name) + elif ( + Flag is not None + and issubclass(enum_class, Flag) + and _is_single_bit(value) + ): + # no other instances found, record this member in _member_names_ + enum_class._member_names_.append(member_name) + if nonunique: + # duplicates not allowed if Unique specified + message = [] + for name, aliases in nonunique.items(): + bad_aliases = ','.join(aliases) + message.append('%s --> %s [%r]' % (name, bad_aliases, enum_class[name].value)) + raise ValueError( + '%s: duplicate names found: %s' % + (enum_class.__name__, '; '.join(message)) + ) + # if self.value is an `auto()`, replace the value attribute with the new enum member + if isinstance(self.value, auto): + self.value.enum_member = enum_member + # get redirect in place before adding to _member_map_ + # but check for other instances in parent classes first + need_override = False + descriptor = None + descriptor_property = None + for base in enum_class.__mro__[1:]: + descriptor = base.__dict__.get(member_name) + if descriptor is not None: + if isinstance(descriptor, (property, DynamicClassAttribute)): + break + else: + need_override = True + if isinstance(descriptor, _bltin_property) and descriptor_property is None: + descriptor_property = descriptor + # keep looking for an enum.property + descriptor = descriptor or descriptor_property + if descriptor and not need_override: + # previous enum.property found, no further action needed + pass + else: + redirect = property() + redirect.__set_name__(enum_class, member_name) + if descriptor and need_override: + # previous enum.property found, but some other inherited + # attribute is in the way; copy fget, fset, fdel to this one + redirect.fget = descriptor.fget + redirect.fset = descriptor.fset + redirect.fdel = descriptor.fdel + setattr(enum_class, member_name, redirect) + # now add to _member_map_ (even aliases) + enum_class._member_map_[member_name] = enum_member + # + # process (possible) MultiValues + values = (value, ) + extra_mv_args + if enum_class._multivalue_ and mv_arg not in values: + values += (mv_arg, ) + enum_member._values_ = values + for value in values: + # first check if value has already been used + if enum_class._multivalue_ and ( + value in enum_class._value2member_map_ + or any(v == value for (v, m) in enum_class._value2member_seq_) + ): + raise ValueError('%r has already been used' % (value, )) + try: + # This may fail if value is not hashable. We can't add the value + # to the map, and by-value lookups for this value will be + # linear. + if enum_class._noalias_: + raise TypeError('cannot use dict to store value') + enum_class._value2member_map_[value] = enum_member + except TypeError: + enum_class._value2member_seq_ += ((value, enum_member), ) + + +class _EnumDict(dict): + """Track enum member order and ensure member names are not reused. + + EnumType will use the names found in self._member_names as the + enumeration member names. + """ + def __init__(self, cls_name, settings, start, constructor_init, constructor_start, constructor_boundary): + super(_EnumDict, self).__init__() + self._cls_name = cls_name + self._constructor_init = constructor_init + self._constructor_start = constructor_start + self._constructor_boundary = constructor_boundary + self._generate_next_value = None + self._member_names = [] + self._member_names_set = set() + self._settings = settings + self._addvalue = addvalue = AddValue in settings + self._magicvalue = MagicValue in settings + self._multivalue = MultiValue in settings + if self._addvalue and self._magicvalue: + raise TypeError('%r: AddValue and MagicValue are mutually exclusive' % cls_name) + if self._multivalue and self._magicvalue: + raise TypeError('%r: MultiValue and MagicValue are mutually exclusive' % cls_name) + self._start = start + self._addvalue_value = start + self._new_args = () + self._auto_args = False + # when the magic turns off + self._locked = MagicValue not in settings + # if init fields are specified + self._init = [] + # list of temporary names + self._ignore = [] + if self._magicvalue: + self._ignore = ['property', 'staticmethod', 'classmethod'] + self._ignore_init_done = False + # if _sunder_ values can be changed via the class body + self._allow_init = True + self._last_values = [] + + def __getitem__(self, key): + if key == self._cls_name and self._cls_name not in self: + return enum + elif ( + self._locked + or key in self + or key in self._ignore + or _is_sunder(key) + or _is_dunder(key) + ): + return super(_EnumDict, self).__getitem__(key) + elif self._magicvalue: + value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:]) + self.__setitem__(key, value) + return value + else: + raise Exception('Magic is not set -- why am I here?') + + def __setitem__(self, key, value): + """Changes anything not sundured, dundered, nor a descriptor. + + If an enum member name is used twice, an error is raised; duplicate + values are not checked for. + + Single underscore (sunder) names are reserved. + """ + # Flag classes that have MagicValue and __new__ will get a generated _gnv_ + if _is_internal_class(self._cls_name, value): + pass + elif _is_private_name(self._cls_name, key): + pass + elif _is_sunder(key): + if key not in ( + '_init_', '_settings_', '_order_', '_ignore_', '_start_', + '_create_pseudo_member_', '_create_pseudo_member_values_', + '_generate_next_value_', '_boundary_', '_numeric_repr_', + '_missing_', '_missing_value_', '_missing_name_', + '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_', + ): + raise ValueError('%r: _sunder_ names, such as %r, are reserved for future Enum use' + % (self._cls_name, key) + ) + elif not self._allow_init and key not in ( + 'create_pseudo_member_', '_missing_', '_missing_value_', '_missing_name_', + ): + # sunder is used during creation, must be specified first + raise ValueError('%r: cannot set %r after init phase' % (self._cls_name, key)) + elif key == '_ignore_': + if self._ignore_init_done: + raise TypeError('%r: ignore can only be specified once' % self._cls_name) + if isinstance(value, basestring): + value = value.split() + else: + value = list(value) + self._ignore = value + already = set(value) & self._member_names_set + if already: + raise ValueError('%r: _ignore_ cannot specify already set names %s' % ( + self._cls_name, + ', '.join(repr(a) for a in already) + )) + self._ignore_init_done = True + elif key == '_boundary_': + if self._constructor_boundary: + raise TypeError('%r: boundary specified in constructor and class body' % self._cls_name) + elif key == '_start_': + if self._constructor_start: + raise TypeError('%r: start specified in constructor and class body' % self._cls_name) + self._start = value + elif key == '_settings_': + if not isinstance(value, (set, tuple)): + value = (value, ) + if not isinstance(value, set): + value = set(value) + self._settings |= value + if NoAlias in value and Unique in value: + raise TypeError('%r: NoAlias and Unique are mutually exclusive' % self._cls_name) + elif MultiValue in value and NoAlias in value: + raise TypeError('cannot specify both MultiValue and NoAlias' % self._cls_name) + allowed_settings = dict.fromkeys(['addvalue', 'magicvalue', 'noalias', 'unique', 'multivalue']) + for arg in self._settings: + if arg not in allowed_settings: + raise TypeError('%r: unknown qualifier %r (from %r)' % (self._cls_name, arg, value)) + allowed_settings[arg] = True + self._multivalue = allowed_settings['multivalue'] + self._addvalue = allowed_settings['addvalue'] + self._magicvalue = allowed_settings['magicvalue'] + self._locked = not self._magicvalue + if self._magicvalue and not self._ignore_init_done: + self._ignore = ['property', 'classmethod', 'staticmethod'] + if self._addvalue and self._init and 'value' not in self._init: + self._init.insert(0, 'value') + value = tuple(self._settings) + elif key == '_init_': + if self._constructor_init: + raise TypeError('%r: init specified in constructor and in class body' % self._cls_name) + _init_ = value + if isinstance(_init_, basestring): + _init_ = _init_.replace(',',' ').split() + if self._addvalue and 'value' not in self._init: + self._init.insert(0, 'value') + if self._magicvalue: + raise TypeError("%r: _init_ and MagicValue are mutually exclusive" % self._cls_name) + self._init = _init_ + value = _init_ + elif key == '_generate_next_value_': + gnv = value + if value is not None: + if isinstance(value, staticmethod): + gnv = value.__func__ + elif isinstance(value, classmethod): + raise TypeError('%r: _generate_next_value must be a staticmethod, not a classmethod' % self._cls_name) + else: + gnv = value + value = staticmethod(value) + self._auto_args = _check_auto_args(value) + setattr(self, '_generate_next_value', gnv) + elif _is_dunder(key): + if key == '__order__': + key = '_order_' + if not self._allow_init: + # _order_ is used during creation, must be specified first + raise ValueError('%r: cannot set %r after init phase' % (self._cls_name, key)) + elif key == '__new__': # and self._new_to_init: + if isinstance(value, staticmethod): + value = value.__func__ + self._new_args = _EnumArgSpec(value) + elif key == '__init_subclass__': + if not isinstance(value, classmethod): + value = classmethod(value) + if _is_descriptor(value): + self._locked = True + elif key in self._member_names_set: + # descriptor overwriting an enum? + raise TypeError('%r: attempt to reuse name: %r' % (self._cls_name, key)) + elif key in self._ignore: + pass + elif not _is_descriptor(value): + self._allow_init = False + if key in self: + # enum overwriting a descriptor? + raise TypeError('%r: %s already defined as %r' % (self._cls_name, key, self[key])) + if type(value) is enum: + value.name = key + if self._addvalue: + raise TypeError('%r: enum() and AddValue are incompatible' % self._cls_name) + elif self._addvalue and not self._multivalue: + # generate a value + value = self._gnv(key, value) + elif self._multivalue: + # make sure it's a tuple + if not isinstance(value, tuple): + value = (value, ) + if isinstance(value[0], auto): + value = (self._convert_auto(key, value[0]), ) + value[1:] + if self._addvalue: + value = self._gnv(key, value) + elif isinstance(value, auto): + value = self._convert_auto(key, value) + elif isinstance(value, tuple) and value and isinstance(value[0], auto): + value = (self._convert_auto(key, value[0]), ) + value[1:] + elif not isinstance(value, auto): + # call generate maybe if + # - init is specified; or + # - __new__ is specified; + # and either of them call for more values than are present + new_args = () or self._new_args and self._new_args.required + target_len = len(self._init or new_args) + if isinstance(value, tuple): + source_len = len(value) + else: + source_len = 1 + multi_args = len(self._init) > 1 or new_args + if source_len < target_len : + value = self._gnv(key, value) + else: + pass + if self._init: + if isinstance(value, auto): + test_value = value.args + elif not isinstance(value, tuple): + test_value = (value, ) + else: + test_value = value + if len(self._init) != len(test_value): + raise TypeError( + '%s.%s: number of fields provided do not match init [%r != %r]' + % (self._cls_name, key, self._init, test_value) + ) + self._member_names.append(key) + self._member_names_set.add(key) + else: + # not a new member, turn off the autoassign magic + self._locked = True + self._allow_init = False + if not (_is_sunder(key) or _is_dunder(key) or _is_private_name(self._cls_name, key) or _is_descriptor(value)): + if isinstance(value, auto): + self._last_values.append(value.value) + elif isinstance(value, tuple) and value and isinstance(value[0], auto): + self._last_values.append(value[0].value) + elif isinstance(value, tuple): + if value: + self._last_values.append(value[0]) + else: + self._last_values.append(value) + super(_EnumDict, self).__setitem__(key, value) + + def _convert_auto(self, key, value): + # if auto.args or auto.kwds, compare to _init_ and __new__ -- if lacking, call gnv + # if not auto.args|kwds but auto.value is _auto_null -- call gnv + if value.args or value.kwds or value.value is _auto_null: + if value.args or value.kwds: + values = value.args + else: + values = () + new_args = () or self._new_args and self._new_args.required + target_len = len(self._init or new_args) or 1 + if isinstance(values, tuple): + source_len = len(values) + else: + source_len = 1 + multi_args = len(self._init) > 1 or new_args + if source_len < target_len : + values = self._gnv(key, values) + if value.args: + value._args = values + else: + value.value = values + return value + + def _gnv(self, key, value): + # generate a value + if self._auto_args: + if not isinstance(value, tuple): + value = (value, ) + value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:], *value) + else: + value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:]) + if isinstance(value, tuple) and len(value) == 1: + value = value[0] + return value + + +no_arg = SentinelType('no_arg', (object, ), {}) +class EnumType(type): + """Metaclass for Enum""" + + @classmethod + def __prepare__(metacls, cls, bases, init=None, start=None, settings=(), boundary=None, **kwds): + metacls._check_for_existing_members_(cls, bases) + if Flag is None and cls == 'Flag': + initial_flag = True + else: + initial_flag = False + # settings are a combination of current and all past settings + constructor_init = init is not None + constructor_start = start is not None + constructor_boundary = boundary is not None + if not isinstance(settings, tuple): + settings = settings, + settings = set(settings) + generate = None + order = None + # inherit previous flags + member_type, first_enum = metacls._get_mixins_(cls, bases) + if first_enum is not None: + generate = getattr(first_enum, '_generate_next_value_', None) + generate = getattr(generate, 'im_func', generate) + settings |= metacls._get_settings_(bases) + init = init or first_enum._auto_init_[:] + order = first_enum._order_function_ + if start is None: + start = first_enum._start_ + else: + # first time through -- creating Enum itself + start = 1 + # check for custom settings + if AddValue in settings and init and 'value' not in init: + if isinstance(init, list): + init.insert(0, 'value') + else: + init = 'value ' + init + if NoAlias in settings and Unique in settings: + raise TypeError('%r: NoAlias and Unique are mutually exclusive' % cls) + if MultiValue in settings and NoAlias in settings: + raise TypeError('%r: MultiValue and NoAlias are mutually exclusive' % cls) + allowed_settings = dict.fromkeys(['addvalue', 'magicvalue', 'noalias', 'unique', 'multivalue']) + for arg in settings: + if arg not in allowed_settings: + raise TypeError('%r: unknown qualifier %r' % (cls, arg)) + enum_dict = _EnumDict(cls_name=cls, settings=settings, start=start, constructor_init=constructor_init, constructor_start=constructor_start, constructor_boundary=constructor_boundary) + enum_dict._member_type = member_type + enum_dict._base_type = ('enum', 'flag')[ + Flag is None and cls == 'Flag' + or + Flag is not None and any(issubclass(b, Flag) for b in bases) + ] + if Flag is not None and any(b is Flag for b in bases) and member_type not in (baseinteger + (object, )): + if Flag in bases: + # when a non-int data type is mixed in with Flag, we end up + # needing two values for two `__new__`s: + # - the integer value for the Flag itself; and + # - the mix-in value for the mix-in + # + # we provide a default `_generate_next_value_` to supply the int + # argument, and a default `__new__` to keep the two straight + def _generate_next_value_(name, start, count, values, *args, **kwds): + return (2 ** count, ) + args + enum_dict['_generate_next_value_'] = staticmethod(_generate_next_value_) + def __new__(cls, flag_value, type_value): + obj = member_type.__new__(cls, type_value) + obj._value_ = flag_value + return obj + enum_dict['__new__'] = __new__ + else: + try: + enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__) + except TypeError: + pass + elif not initial_flag: + if hasattr(first_enum, '__new_member__'): + enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__) + if generate: + enum_dict['_generate_next_value_'] = generate + enum_dict._inherited_gnv = True + if init is not None: + if isinstance(init, basestring): + init = init.replace(',',' ').split() + enum_dict._init = init + elif hasattr(first_enum, '__new_member__'): + enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__) + if order is not None: + enum_dict['_order_'] = staticmethod(order) + return enum_dict + + def __init__(cls, *args , **kwds): + pass + + def __new__(metacls, cls, bases, clsdict, init=None, start=None, settings=(), boundary=None, **kwds): + # handle py2 case first + if type(clsdict) is not _EnumDict: + # py2 and/or functional API gyrations + init = clsdict.pop('_init_', None) + start = clsdict.pop('_start_', None) + settings = clsdict.pop('_settings_', ()) + _order_ = clsdict.pop('_order_', clsdict.pop('__order__', None)) + _ignore_ = clsdict.pop('_ignore_', None) + _create_pseudo_member_ = clsdict.pop('_create_pseudo_member_', None) + _create_pseudo_member_values_ = clsdict.pop('_create_pseudo_member_values_', None) + _generate_next_value_ = clsdict.pop('_generate_next_value_', None) + _missing_ = clsdict.pop('_missing_', None) + _missing_value_ = clsdict.pop('_missing_value_', None) + _missing_name_ = clsdict.pop('_missing_name_', None) + _boundary_ = clsdict.pop('_boundary_', None) + _iter_member_ = clsdict.pop('_iter_member_', None) + _iter_member_by_value_ = clsdict.pop('_iter_member_by_value_', None) + _iter_member_by_def_ = clsdict.pop('_iter_member_by_def_', None) + __new__ = clsdict.pop('__new__', None) + __new__ = getattr(__new__, 'im_func', __new__) + __new__ = getattr(__new__, '__func__', __new__) + enum_members = dict([ + (k, v) for (k, v) in clsdict.items() + if not (_is_sunder(k) or _is_dunder(k) or _is_private_name(cls, k) or _is_descriptor(v)) + ]) + original_dict = clsdict + clsdict = metacls.__prepare__(cls, bases, init=init, start=start) + if settings: + clsdict['_settings_'] = settings + init = init or clsdict._init + if _order_ is None: + _order_ = clsdict.get('_order_') + if _order_ is not None: + _order_ = _order_.__get__(cls) + if isinstance(original_dict, OrderedDict): + calced_order = original_dict + elif _order_ is None: + calced_order = [name for (name, value) in enumsort(list(enum_members.items()))] + elif isinstance(_order_, basestring): + calced_order = _order_ = _order_.replace(',', ' ').split() + elif callable(_order_): + if init: + if not isinstance(init, basestring): + init = ' '.join(init) + member = NamedTuple('member', init and 'name ' + init or ['name', 'value']) + calced_order = [] + for name, value in enum_members.items(): + if init: + if not isinstance(value, tuple): + value = (value, ) + name_value = (name, ) + value + else: + name_value = tuple((name, value)) + if member._defined_len_ != len(name_value): + raise TypeError('%d values expected (%s), %d received (%s)' % ( + member._defined_len_, + ', '.join(member._fields_), + len(name_value), + ', '.join([repr(v) for v in name_value]), + )) + calced_order.append(member(*name_value)) + calced_order = [m.name for m in sorted(calced_order, key=_order_)] + else: + calced_order = _order_ + for name in ( + '_missing_', '_missing_value_', '_missing_name_', + '_ignore_', '_create_pseudo_member_', '_create_pseudo_member_values_', + '_generate_next_value_', '_order_', '__new__', + '_missing_', '_missing_value_', '_missing_name_', + '_boundary_', + '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_', + ): + attr = locals()[name] + if attr is not None: + clsdict[name] = attr + # now add members + for k in calced_order: + try: + clsdict[k] = original_dict[k] + except KeyError: + # this error will be handled when _order_ is checked + pass + for k, v in original_dict.items(): + if k not in calced_order: + clsdict[k] = v + del _order_, _ignore_, _create_pseudo_member_, _create_pseudo_member_values_, + del _generate_next_value_, _missing_, _missing_value_, _missing_name_ + # + # resume normal path + clsdict._locked = True + # + # check for illegal enum names (any others?) + member_names = clsdict._member_names + invalid_names = set(member_names) & set(['mro', '']) + if invalid_names: + raise ValueError('invalid enum member name(s): %s' % ( + ', '.join(invalid_names), )) + _order_ = clsdict.pop('_order_', None) + if isinstance(_order_, basestring): + _order_ = _order_.replace(',',' ').split() + init = clsdict._init + start = clsdict._start + settings = clsdict._settings + creating_init = [] + new_args = clsdict._new_args + auto_args = clsdict._auto_args + auto_init = False + if init is not None: + auto_init = True + creating_init = init[:] + if 'value' in creating_init and creating_init[0] != 'value': + raise TypeError("'value', if specified, must be the first item in 'init'") + magicvalue = MagicValue in settings + multivalue = MultiValue in settings + noalias = NoAlias in settings + unique = Unique in settings + # an Enum class cannot be mixed with other types (int, float, etc.) if + # it has an inherited __new__ unless a new __new__ is defined (or + # the resulting class will fail). + # an Enum class is final once enumeration items have been defined; + # + # remove any keys listed in _ignore_ + clsdict.setdefault('_ignore_', []).append('_ignore_') + ignore = clsdict['_ignore_'] + for key in ignore: + clsdict.pop(key, None) + # + boundary = boundary or clsdict.pop('_boundary_', None) + # convert to regular dict + clsdict = dict(clsdict.items()) + member_type, first_enum = metacls._get_mixins_(cls, bases) + # get the method to create enum members + __new__, save_new, new_uses_args = metacls._find_new_( + clsdict, + member_type, + first_enum, + ) + clsdict['_new_member_'] = staticmethod(__new__) + clsdict['_use_args_'] = new_uses_args + # + # convert future enum members into temporary _proto_members + # and record integer values in case this will be a Flag + flag_mask = 0 + for name in member_names: + value = test_value = clsdict[name] + if isinstance(value, auto) and value.value is not _auto_null: + test_value = value.value + if isinstance(test_value, baseinteger): + flag_mask |= test_value + if isinstance(test_value, tuple) and test_value and isinstance(test_value[0], baseinteger): + flag_mask |= test_value[0] + clsdict[name] = _proto_member(value) + # + # temp stuff + clsdict['_creating_init_'] = creating_init + clsdict['_multivalue_'] = multivalue + clsdict['_magicvalue_'] = magicvalue + clsdict['_noalias_'] = noalias + clsdict['_unique_'] = unique + # + # house-keeping structures + clsdict['_member_names_'] = [] + clsdict['_member_map_'] = OrderedDict() + clsdict['_member_type_'] = member_type + clsdict['_value2member_map_'] = {} + clsdict['_value2member_seq_'] = () + clsdict['_settings_'] = settings + clsdict['_start_'] = start + clsdict['_auto_init_'] = init + clsdict['_new_args_'] = new_args + clsdict['_auto_args_'] = auto_args + clsdict['_order_function_'] = None + # now set the __repr__ for the value + clsdict['_value_repr_'] = metacls._find_data_repr_(cls, bases) + # + # Flag structures (will be removed if final class is not a Flag + clsdict['_boundary_'] = ( + boundary + or getattr(first_enum, '_boundary_', None) + ) + clsdict['_flag_mask_'] = flag_mask + clsdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1 + clsdict['_inverted_'] = None + # + # move skipped values out of the descriptor + for name, obj in clsdict.items(): + if isinstance(obj, nonmember): + clsdict[name] = obj.value + # + # If a custom type is mixed into the Enum, and it does not know how + # to pickle itself, pickle.dumps will succeed but pickle.loads will + # fail. Rather than have the error show up later and possibly far + # from the source, sabotage the pickle protocol for this class so + # that pickle.dumps also fails. + # + # However, if the new class implements its own __reduce_ex__, do not + # sabotage -- it's on them to make sure it works correctly. We use + # __reduce_ex__ instead of any of the others as it is preferred by + # pickle over __reduce__, and it handles all pickle protocols. + unpicklable = False + if '__reduce_ex__' not in clsdict: + if member_type is not object: + methods = ('__getnewargs_ex__', '__getnewargs__', + '__reduce_ex__', '__reduce__') + if not any(m in member_type.__dict__ for m in methods): + _make_class_unpicklable(clsdict) + unpicklable = True + # + # create a default docstring if one has not been provided + if '__doc__' not in clsdict: + clsdict['__doc__'] = 'An enumeration.' + # + # create our new Enum type + try: + exc = None + enum_class = type.__new__(metacls, cls, bases, clsdict) + except RuntimeError as e: + # any exceptions raised by _proto_member (aka member.__new__) will get converted to + # a RuntimeError, so get that original exception back and raise + # it instead + exc = e.__cause__ or e + if exc is not None: + raise exc + # + # if Python 3.5 or ealier, implement the __set_name__ and + # __init_subclass__ protocols + if pyver < PY3_6: + for name in member_names: + enum_class.__dict__[name].__set_name__(enum_class, name) + for name, obj in enum_class.__dict__.items(): + if name in member_names: + continue + if hasattr(obj, '__set_name__'): + obj.__set_name__(enum_class, name) + if Enum is not None: + super(enum_class, enum_class).__init_subclass__() + # + # double check that repr and friends are not the mixin's or various + # things break (such as pickle) + # + # Also, special handling for ReprEnum + if ReprEnum is not None and ReprEnum in bases: + if member_type is object: + raise TypeError( + 'ReprEnum subclasses must be mixed with a data type (i.e.' + ' int, str, float, etc.)' + ) + if '__format__' not in clsdict: + enum_class.__format__ = member_type.__format__ + clsdict['__format__'] = enum_class.__format__ + if '__str__' not in clsdict: + method = member_type.__str__ + if method is object.__str__: + # if member_type does not define __str__, object.__str__ will use + # its __repr__ instead, so we'll also use its __repr__ + method = member_type.__repr__ + enum_class.__str__ = method + clsdict['__str__'] = enum_class.__str__ + + for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): + if name in clsdict: + # class has defined/imported/copied the method + continue + class_method = getattr(enum_class, name) + obj_method = getattr(member_type, name, None) + enum_method = getattr(first_enum, name, None) + if obj_method is not None and obj_method == class_method: + if name == '__reduce_ex__' and unpicklable: + continue + setattr(enum_class, name, enum_method) + clsdict[name] = enum_method + # + # for Flag, add __or__, __and__, __xor__, and __invert__ + if Flag is not None and issubclass(enum_class, Flag): + for name in ( + '__or__', '__and__', '__xor__', + '__ror__', '__rand__', '__rxor__', + '__invert__' + ): + if name not in clsdict: + setattr(enum_class, name, getattr(Flag, name)) + clsdict[name] = enum_method + # + # method resolution and int's are not playing nice + # Python's less than 2.6 use __cmp__ + if pyver < PY2_6: + # + if issubclass(enum_class, int): + setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) + # + elif PY2: + # + if issubclass(enum_class, int): + for method in ( + '__le__', + '__lt__', + '__gt__', + '__ge__', + '__eq__', + '__ne__', + '__hash__', + ): + setattr(enum_class, method, getattr(int, method)) + # + # replace any other __new__ with our own (as long as Enum is not None, + # anyway) -- again, this is to support pickle + if Enum is not None: + # if the user defined their own __new__, save it before it gets + # clobbered in case they subclass later + if save_new: + setattr(enum_class, '__new_member__', enum_class.__dict__['__new__']) + setattr(enum_class, '__new__', Enum.__dict__['__new__']) + # + # _order_ checking is spread out into three/four steps + # - ensure _order_ is a list, not a string nor a function + # - if enum_class is a Flag: + # - remove any non-single-bit flags from _order_ + # - remove any aliases from _order_ + # - check that _order_ and _member_names_ match + # + # _order_ step 1: ensure _order_ is a list + if _order_: + if isinstance(_order_, staticmethod): + _order_ = _order_.__func__ + if callable(_order_): + # save order for future subclasses + enum_class._order_function_ = staticmethod(_order_) + # create ordered list for comparison + _order_ = [m.name for m in sorted(enum_class, key=_order_)] + # + # remove Flag structures if final class is not a Flag + if ( + Flag is None and cls != 'Flag' + or Flag is not None and not issubclass(enum_class, Flag) + ): + delattr(enum_class, '_boundary_') + delattr(enum_class, '_flag_mask_') + delattr(enum_class, '_all_bits_') + delattr(enum_class, '_inverted_') + elif Flag is not None and issubclass(enum_class, Flag): + # ensure _all_bits_ is correct and there are no missing flags + single_bit_total = 0 + multi_bit_total = 0 + for flag in enum_class._member_map_.values(): + if _is_single_bit(flag._value_): + single_bit_total |= flag._value_ + else: + # multi-bit flags are considered aliases + multi_bit_total |= flag._value_ + if enum_class._boundary_ is not KEEP: + missed = list(_iter_bits_lsb(multi_bit_total & ~single_bit_total)) + if missed: + raise TypeError( + 'invalid Flag %r -- missing values: %s' + % (cls, ', '.join((str(i) for i in missed))) + ) + enum_class._flag_mask_ = single_bit_total + enum_class._all_bits_ = 2 ** ((single_bit_total).bit_length()) - 1 + # + # set correct __iter__ + if [m._value_ for m in enum_class] != sorted([m._value_ for m in enum_class]): + enum_class._iter_member_ = enum_class._iter_member_by_def_ + if _order_: + # _order_ step 2: remove any items from _order_ that are not single-bit + _order_ = [ + o + for o in _order_ + if o not in enum_class._member_map_ or _is_single_bit(enum_class[o]._value_) + ] + # + # check for constants with auto() values + for k, v in enum_class.__dict__.items(): + if isinstance(v, constant) and isinstance(v.value, auto): + v.value = enum_class(v.value.value) + # + if _order_: + # _order_ step 3: remove aliases from _order_ + _order_ = [ + o + for o in _order_ + if ( + o not in enum_class._member_map_ + or + (o in enum_class._member_map_ and o in enum_class._member_names_) + )] + # _order_ step 4: verify that _order_ and _member_names_ match + if _order_ != enum_class._member_names_: + raise TypeError( + 'member order does not match _order_:\n%r\n%r' + % (enum_class._member_names_, _order_) + ) + return enum_class + + def __bool__(cls): + """ + classes/types should always be True. + """ + return True + + def __call__(cls, value=no_arg, names=None, module=None, qualname=None, type=None, start=1, boundary=None): + """Either returns an existing member, or creates a new enum class. + + This method is used both when an enum class is given a value to match + to an enumeration member (i.e. Color(3)) and for the functional API + (i.e. Color = Enum('Color', names='red green blue')). + + When used for the functional API: `module`, if set, will be stored in + the new class' __module__ attribute; `type`, if set, will be mixed in + as the first base class. + + Note: if `module` is not set this routine will attempt to discover the + calling module by walking the frame stack; if this is unsuccessful + the resulting class will not be pickleable. + """ + if names is None: # simple value lookup + return cls.__new__(cls, value) + # otherwise, functional API: we're creating a new Enum type + return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start, boundary=boundary) + + def __contains__(cls, member): + if not isinstance(member, Enum): + raise TypeError("%r (%r) is not an " % (member, type(member))) + if not isinstance(member, cls): + return False + return True + + def __delattr__(cls, attr): + # nicer error message when someone tries to delete an attribute + # (see issue19025). + if attr in cls._member_map_: + raise AttributeError( + "%s: cannot delete Enum member %r." % (cls.__name__, attr), + ) + found_attr = _get_attr_from_chain(cls, attr) + if isinstance(found_attr, constant): + raise AttributeError( + "%s: cannot delete constant %r" % (cls.__name__, attr), + ) + elif isinstance(found_attr, property): + raise AttributeError( + "%s: cannot delete property %r" % (cls.__name__, attr), + ) + super(EnumType, cls).__delattr__(attr) + + def __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) + + @_bltin_property + def __members__(cls): + """Returns a mapping of member name->value. + + This mapping lists all enum members, including aliases. Note that this + is a copy of the internal mapping. + """ + return cls._member_map_.copy() + + def __getitem__(cls, name): + try: + return cls._member_map_[name] + except KeyError: + exc = _sys.exc_info()[1] + if Flag is not None and issubclass(cls, Flag) and '|' in name: + try: + # may be an __or__ed name + result = cls(0) + for n in name.split('|'): + result |= cls[n] + return result + except KeyError: + raise exc + result = cls._missing_name_(name) + if isinstance(result, cls): + return result + else: + raise exc + + def __iter__(cls): + return (cls._member_map_[name] for name in cls._member_names_) + + def __reversed__(cls): + return (cls._member_map_[name] for name in reversed(cls._member_names_)) + + def __len__(cls): + return len(cls._member_names_) + + __nonzero__ = __bool__ + + def __repr__(cls): + return "" % (cls.__name__, ) + + def __setattr__(cls, name, value): + """Block attempts to reassign Enum members/constants. + + A simple assignment to the class namespace only changes one of the + several possible ways to get an Enum member from the Enum class, + resulting in an inconsistent Enumeration. + """ + member_map = cls.__dict__.get('_member_map_', {}) + if name in member_map: + raise AttributeError( + '%s: cannot rebind member %r.' % (cls.__name__, name), + ) + found_attr = _get_attr_from_chain(cls, name) + if isinstance(found_attr, constant): + raise AttributeError( + "%s: cannot rebind constant %r" % (cls.__name__, name), + ) + elif isinstance(found_attr, property): + raise AttributeError( + "%s: cannot rebind property %r" % (cls.__name__, name), + ) + super(EnumType, cls).__setattr__(name, value) + + def _convert(cls, *args, **kwds): + import warnings + warnings.warn("_convert is deprecated and will be removed, use" + " _convert_ instead.", DeprecationWarning, stacklevel=2) + return cls._convert_(*args, **kwds) + + def _convert_(cls, name, module, filter, source=None, boundary=None, as_global=False): + """ + Create a new Enum subclass that replaces a collection of global constants + """ + # convert all constants from source (or module) that pass filter() to + # a new Enum called name, and export the enum and its members back to + # module; + # also, replace the __reduce_ex__ method so unpickling works in + # previous Python versions + module_globals = vars(_sys.modules[module]) + if source: + source = vars(source) + else: + source = module_globals + members = [(key, source[key]) for key in source.keys() if filter(key)] + try: + # sort by value, name + members.sort(key=lambda t: (t[1], t[0])) + except TypeError: + # unless some values aren't comparable, in which case sort by just name + members.sort(key=lambda t: t[0]) + cls = cls(name, members, module=module, boundary=boundary or KEEP) + cls.__reduce_ex__ = _reduce_ex_by_name + if as_global: + global_enum(cls) + else: + module_globals.update(cls.__members__) + module_globals[name] = cls + return cls + + def _create_(cls, class_name, names, module=None, qualname=None, type=None, start=1, boundary=None): + """Convenience method to create a new Enum class. + + `names` can be: + + * A string containing member names, separated either with spaces or + commas. Values are auto-numbered from 1. + * An iterable of member names. Values are auto-numbered from 1. + * An iterable of (member name, value) pairs. + * A mapping of member name -> value. + """ + if PY2: + # if class_name is unicode, attempt a conversion to ASCII + if isinstance(class_name, unicode): + try: + class_name = class_name.encode('ascii') + except UnicodeEncodeError: + raise TypeError('%r is not representable in ASCII' % (class_name, )) + metacls = cls.__class__ + if type is None: + bases = (cls, ) + else: + bases = (type, cls) + _, first_enum = cls._get_mixins_(class_name, bases) + generate = getattr(first_enum, '_generate_next_value_', None) + generate = getattr(generate, 'im_func', generate) + # special processing needed for names? + if isinstance(names, basestring): + names = names.replace(',', ' ').split() + if isinstance(names, (tuple, list)) and names and isinstance(names[0], basestring): + original_names, names = names, [] + last_values = [] + for count, name in enumerate(original_names): + value = generate(name, start, count, last_values[:]) + last_values.append(value) + names.append((name, value)) + # Here, names is either an iterable of (name, value) or a mapping. + item = None # in case names is empty + clsdict = None + for item in names: + if clsdict is None: + # first time initialization + if isinstance(item, basestring): + clsdict = {} + else: + # remember the order + clsdict = metacls.__prepare__(class_name, bases) + if isinstance(item, basestring): + member_name, member_value = item, names[item] + else: + member_name, member_value = item + clsdict[member_name] = member_value + if clsdict is None: + # in case names was empty + clsdict = metacls.__prepare__(class_name, bases) + enum_class = metacls.__new__(metacls, class_name, bases, clsdict, boundary=boundary) + # TODO: replace the frame hack if a blessed way to know the calling + # module is ever developed + if module is None: + try: + module = _sys._getframe(2).f_globals['__name__'] + except (AttributeError, KeyError): + pass + if module is None: + _make_class_unpicklable(enum_class) + else: + enum_class.__module__ = module + if qualname is not None: + enum_class.__qualname__ = qualname + return enum_class + + @classmethod + def _check_for_existing_members_(mcls, class_name, bases): + if Enum is None: + return + for chain in bases: + for base in chain.__mro__: + if issubclass(base, Enum) and base._member_names_: + raise TypeError( + " cannot extend %r" + % (class_name, base) + ) + @classmethod + def _get_mixins_(mcls, class_name, bases): + """Returns the type for creating enum members, and the first inherited + enum class. + + bases: the tuple of bases that was given to __new__ + """ + if not bases or Enum is None: + return object, Enum + + mcls._check_for_existing_members_(class_name, bases) + + # ensure final parent class is an Enum derivative, find any concrete + # data type, and check that Enum has no members + first_enum = bases[-1] + if not issubclass(first_enum, Enum): + raise TypeError("new enumerations should be created as " + "`EnumName([mixin_type, ...] [data_type,] enum_type)`") + member_type = mcls._find_data_type_(class_name, bases) or object + if first_enum._member_names_: + raise TypeError("cannot extend enumerations via subclassing") + # + return member_type, first_enum + + @classmethod + def _find_data_repr_(mcls, class_name, bases): + for chain in bases: + for base in chain.__mro__: + if base is object: + continue + elif issubclass(base, Enum): + # if we hit an Enum, use it's _value_repr_ + return base._value_repr_ + elif '__repr__' in base.__dict__: + # this is our data repr + return base.__dict__['__repr__'] + return None + + @classmethod + def _find_data_type_(mcls, class_name, bases): + data_types = set() + for chain in bases: + candidate = None + for base in chain.__mro__: + if base is object or base is StdlibEnum or base is StdlibFlag: + continue + elif issubclass(base, Enum): + if base._member_type_ is not object: + data_types.add(base._member_type_) + elif '__new__' in base.__dict__: + if issubclass(base, Enum): + continue + elif StdlibFlag is not None and issubclass(base, StdlibFlag): + continue + data_types.add(candidate or base) + break + else: + candidate = candidate or base + if len(data_types) > 1: + raise TypeError('%r: too many data types: %r' % (class_name, data_types)) + elif data_types: + return data_types.pop() + else: + return None + + @staticmethod + def _get_settings_(bases): + """Returns the combined _settings_ of all Enum base classes + + bases: the tuple of bases given to __new__ + """ + settings = set() + for chain in bases: + for base in chain.__mro__: + if issubclass(base, Enum): + for s in base._settings_: + settings.add(s) + return settings + + @classmethod + def _find_new_(mcls, clsdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + clsdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __new_member__ + __new__ = clsdict.get('__new__', None) + # + # should __new__ be saved as __new_member__ later? + save_new = first_enum is not None and __new__ is not None + # + if __new__ is None: + # check all possibles for __new_member__ before falling back to + # __new__ + for method in ('__new_member__', '__new__'): + for possible in (member_type, first_enum): + target = getattr(possible, method, None) + if target not in ( + None, + None.__new__, + object.__new__, + Enum.__new__, + StdlibEnum.__new__, + ): + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + new_uses_args = False + else: + new_uses_args = True + # + return __new__, save_new, new_uses_args + + + # In order to support Python 2 and 3 with a single + # codebase we have to create the Enum methods separately + # and then use the `type(name, bases, dict)` method to + # create the class. + +EnumMeta = EnumType + +enum_dict = _Addendum( + dict=EnumType.__prepare__('Enum', (object, )), + doc="Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n", + ns=globals(), + ) + +@enum_dict +def __init__(self, *args, **kwds): + # auto-init method + _auto_init_ = self._auto_init_ + if _auto_init_ is None: + return + if 'value' in _auto_init_: + # remove 'value' from _auto_init_ as it has already been handled + _auto_init_ = _auto_init_[1:] + if _auto_init_: + if len(_auto_init_) < len(args): + raise TypeError('%d arguments expected (%s), %d received (%s)' + % (len(_auto_init_), _auto_init_, len(args), args)) + for name, arg in zip(_auto_init_, args): + setattr(self, name, arg) + if len(args) < len(_auto_init_): + remaining_args = _auto_init_[len(args):] + for name in remaining_args: + value = kwds.pop(name, undefined) + if value is undefined: + raise TypeError('missing value for: %r' % (name, )) + setattr(self, name, value) + if kwds: + # too many keyword arguments + raise TypeError('invalid keyword(s): %s' % ', '.join(kwds.keys())) + +@enum_dict +def __new__(cls, value): + # all enum instances are actually created during class construction + # without calling this method; this method is called by the metaclass' + # __call__ (i.e. Color(3) ), and by pickle + if NoAlias in cls._settings_: + raise TypeError('NoAlias enumerations cannot be looked up by value') + if type(value) is cls: + # For lookups like Color(Color.red) + # value = value.value + return value + # by-value search for a matching enum member + # see if it's in the reverse mapping (for hashable values) + try: + if value in cls._value2member_map_: + return cls._value2member_map_[value] + except TypeError: + # not there, now do long search -- O(n) behavior + for name, member in cls._value2member_seq_: + if name == value: + return member + # still not found -- try _missing_ hook + try: + exc = None + result = cls._missing_value_(value) + except Exception as e: + exc = e + result = None + if isinstance(result, cls) or getattr(cls, '_boundary_', None) is EJECT: + return result + else: + if value is no_arg: + ve_exc = ValueError('%s() should be called with a value' % (cls.__name__, )) + else: + ve_exc = ValueError("%r is not a valid %s" % (value, cls.__name__)) + if result is None and exc is None: + raise ve_exc + elif exc is None: + exc = TypeError( + 'error in %s._missing_: returned %r instead of None or a valid member' + % (cls.__name__, result) + ) + if not isinstance(exc, ValueError): + exc.__cause__ = ve_exc + raise exc + +@enum_dict +@classmethod +def __init_subclass__(cls, **kwds): + if pyver < PY3_6: + # end of the line + if kwds: + raise TypeError('unconsumed keyword arguments: %r' % (kwds, )) + else: + super(Enum, cls).__init_subclass__(**kwds) + +@enum_dict +@staticmethod +def _generate_next_value_(name, start, count, last_values, *args, **kwds): + for last_value in reversed(last_values): + try: + new_value = last_value + 1 + break + except TypeError: + pass + else: + new_value = start + if args: + return (new_value, ) + args + else: + return new_value + +@enum_dict +@classmethod +def _missing_(cls, value): + "deprecated, use _missing_value_ instead" + return None + +@enum_dict +@classmethod +def _missing_value_(cls, value): + "used for failed value access" + return cls._missing_(value) + +@enum_dict +@classmethod +def _missing_name_(cls, name): + "used for failed item access" + return None + +@enum_dict +def __repr__(self): + v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__ + return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) + +@enum_dict +def __str__(self): + return "%s.%s" % (self.__class__.__name__, self._name_) + +if PY3: + @enum_dict + def __dir__(self): + """ + Returns all members and all public methods + """ + if self.__class__._member_type_ is object: + interesting = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value']) + else: + interesting = set(object.__dir__(self)) + for name in getattr(self, '__dict__', []): + if name[0] != '_': + interesting.add(name) + for cls in self.__class__.mro(): + for name, obj in cls.__dict__.items(): + if name[0] == '_': + continue + if isinstance(obj, property): + # that's an enum.property + if obj.fget is not None or name not in self._member_map_: + interesting.add(name) + else: + # in case it was added by `dir(self)` + interesting.discard(name) + else: + interesting.add(name) + return sorted(interesting) + +@enum_dict +def __format__(self, format_spec): + # mixed-in Enums should use the mixed-in type's __format__, otherwise + # we can get strange results with the Enum name showing up instead of + # the value + + # pure Enum branch / overridden __str__ branch + overridden_str = self.__class__.__str__ != Enum.__str__ + if self._member_type_ is object or overridden_str: + cls = str + val = str(self) + # mix-in branch + else: + cls = self._member_type_ + val = self.value + return cls.__format__(val, format_spec) + +@enum_dict +def __hash__(self): + return hash(self._name_) + +@enum_dict +def __reduce_ex__(self, proto): + return self.__class__, (self._value_, ) + + +#################################### +# Python's less than 2.6 use __cmp__ + +if pyver < PY2_6: + + @enum_dict + def __cmp__(self, other): + if type(other) is self.__class__: + if self is other: + return 0 + return -1 + return NotImplemented + raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) + +else: + + @enum_dict + def __le__(self, other): + raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) + + @enum_dict + def __lt__(self, other): + raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) + + @enum_dict + def __ge__(self, other): + raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) + + @enum_dict + def __gt__(self, other): + raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) + + +@enum_dict +def __eq__(self, other): + if type(other) is self.__class__: + return self is other + return NotImplemented + +@enum_dict +def __ne__(self, other): + if type(other) is self.__class__: + return self is not other + return NotImplemented + +@enum_dict +def __hash__(self): + return hash(self._name_) + +@enum_dict +def __reduce_ex__(self, proto): + return self.__class__, (self._value_, ) + + +# enum.property is used to provide access to the `name`, `value', etc., +# properties of enum members while keeping some measure of protection +# from modification, while still allowing for an enumeration to have +# members named `name`, `value`, etc.. This works because enumeration +# members are not set directly on the enum class -- enum.property will +# look them up in _member_map_. + +@enum_dict +@property +def name(self): + return self._name_ + +@enum_dict +@property +def value(self): + return self._value_ + +@enum_dict +@property +def values(self): + return self._values_ + +def _reduce_ex_by_name(self, proto): + return self.name + +Enum = EnumType('Enum', (object, ), enum_dict.resolve()) +del enum_dict + + # Enum has now been created + +class ReprEnum(Enum): + """ + Only changes the repr(), leaving str() and format() to the mixed-in type. + """ + + +class IntEnum(int, ReprEnum): + """ + Enum where members are also (and must be) ints + """ + + +class StrEnum(str, ReprEnum): + """ + Enum where members are also (and must already be) strings + + default value is member name, lower-cased + """ + + def __new__(cls, *values, **kwds): + if kwds: + raise TypeError('%r: keyword arguments not supported' % (cls.__name__)) + if values: + if not isinstance(values[0], str): + raise TypeError('%s: values must be str [%r is a %r]' % (cls.__name__, values[0], type(values[0]))) + value = str(*values) + member = str.__new__(cls, value) + member._value_ = value + return member + + __str__ = str.__str__ + + def _generate_next_value_(name, start, count, last_values): + """ + Return the lower-cased version of the member name. + """ + return name.lower() + + +class LowerStrEnum(StrEnum): + """ + Enum where members are also (and must already be) lower-case strings + + default value is member name, lower-cased + """ + + def __new__(cls, value, *args, **kwds): + obj = StrEnum.__new_member__(cls, value, *args, **kwds) + if value != value.lower(): + raise ValueError('%r is not lower-case' % value) + return obj + + +class UpperStrEnum(StrEnum): + """ + Enum where members are also (and must already be) upper-case strings + + default value is member name, upper-cased + """ + + def __new__(cls, value, *args, **kwds): + obj = StrEnum.__new_member__(cls, value, *args, **kwds) + if value != value.upper(): + raise ValueError('%r is not upper-case' % value) + return obj + + def _generate_next_value_(name, start, count, last_values, *args, **kwds): + return name.upper() + + +if PY3: + class AutoEnum(Enum): + """ + automatically use _generate_next_value_ when values are missing (Python 3 only) + """ + _settings_ = MagicValue + + +class AutoNumberEnum(Enum): + """ + Automatically assign increasing values to members. + + Py3: numbers match creation order + Py2: numbers are assigned alphabetically by member name + (unless `_order_` is specified) + """ + + def __new__(cls, *args, **kwds): + value = len(cls.__members__) + 1 + if cls._member_type_ is int: + obj = int.__new__(cls, value) + elif cls._member_type_ is long: + obj = long.__new__(cls, value) + else: + obj = object.__new__(cls) + obj._value_ = value + return obj + + +class AddValueEnum(Enum): + _settings_ = AddValue + + +class MultiValueEnum(Enum): + """ + Multiple values can map to each member. + """ + _settings_ = MultiValue + + +class NoAliasEnum(Enum): + """ + Duplicate value members are distinct, but cannot be looked up by value. + """ + _settings_ = NoAlias + + +class OrderedEnum(Enum): + """ + Add ordering based on values of Enum members. + """ + + def __ge__(self, other): + if self.__class__ is other.__class__: + return self._value_ >= other._value_ + return NotImplemented + + def __gt__(self, other): + if self.__class__ is other.__class__: + return self._value_ > other._value_ + return NotImplemented + + def __le__(self, other): + if self.__class__ is other.__class__: + return self._value_ <= other._value_ + return NotImplemented + + def __lt__(self, other): + if self.__class__ is other.__class__: + return self._value_ < other._value_ + return NotImplemented + + +if sqlite3: + class SqliteEnum(Enum): + def __conform__(self, protocol): + if protocol is sqlite3.PrepareProtocol: + return self.name + + +class UniqueEnum(Enum): + """ + Ensure no duplicate values exist. + """ + _settings_ = Unique + + +def convert(enum, name, module, filter, source=None): + """ + Create a new Enum subclass that replaces a collection of global constants + + enum: Enum, IntEnum, ... + name: name of new Enum + module: name of module (__name__ in global context) + filter: function that returns True if name should be converted to Enum member + source: namespace to check (defaults to 'module') + """ + # convert all constants from source (or module) that pass filter() to + # a new Enum called name, and export the enum and its members back to + # module; + # also, replace the __reduce_ex__ method so unpickling works in + # previous Python versions + module_globals = vars(_sys.modules[module]) + if source: + source = vars(source) + else: + source = module_globals + members = dict((name, value) for name, value in source.items() if filter(name)) + enum = enum(name, members, module=module) + enum.__reduce_ex__ = _reduce_ex_by_name + module_globals.update(enum.__members__) + module_globals[name] = enum + +def extend_enum(enumeration, name, *args, **kwds): + """ + Add a new member to an existing Enum. + """ + # there are four possibilities: + # - extending an aenum Enum or 3.11+ enum Enum + # - extending an aenum Flag or 3.11+ enum Flag + # - extending a pre-3.11 stdlib Enum Flag + # - extending a 3.11+ stdlib Flag + # + # fail early if name is already in the enumeration + if ( + name in enumeration.__dict__ + or name in enumeration._member_map_ + or name in [t[1] for t in getattr(enumeration, '_value2member_seq_', ())] + ): + raise TypeError('%r already in use as %r' % (name, enumeration.__dict__.get(name, enumeration[name]))) + # and check for other instances in parent classes + descriptor = None + for base in enumeration.__mro__[1:]: + descriptor = base.__dict__.get(name) + if descriptor is not None: + if isinstance(descriptor, (property, DynamicClassAttribute)): + break + else: + raise TypeError('%r already in use in superclass %r' % (name, base.__name__)) + try: + _member_map_ = enumeration._member_map_ + _member_names_ = enumeration._member_names_ + _member_type_ = enumeration._member_type_ + _value2member_map_ = enumeration._value2member_map_ + base_attributes = set([a for b in enumeration.mro() for a in b.__dict__]) + except AttributeError: + raise TypeError('%r is not a supported Enum' % (enumeration, )) + try: + _value2member_seq_ = enumeration._value2member_seq_ + _multi_value_ = MultiValue in enumeration._settings_ + _no_alias_ = NoAlias in enumeration._settings_ + _unique_ = Unique in enumeration._settings_ + _auto_init_ = enumeration._auto_init_ or [] + except AttributeError: + # standard Enum + _value2member_seq_ = [] + _multi_value_ = False + _no_alias_ = False + _unique_ = False + _auto_init_ = [] + if _multi_value_ and not args: + # must specify values for multivalue enums + raise ValueError('no values specified for MultiValue enum %r' % enumeration.__name__) + mt_new = _member_type_.__new__ + _new = getattr(enumeration, '__new_member__', mt_new) + if not args: + last_values = [m.value for m in enumeration] + count = len(enumeration) + start = getattr(enumeration, '_start_', None) + if start is None: + start = last_values and (last_values[-1] + 1) or 1 + _gnv = getattr(enumeration, '_generate_next_value_', None) + if _gnv is not None: + args = ( _gnv(name, start, count, last_values), ) + else: + # must be a 3.4 or 3.5 Enum + args = (start, ) + if _new is object.__new__: + new_uses_args = False + else: + new_uses_args = True + if len(args) == 1: + [value] = args + else: + value = args + more_values = () + kwds = {} + if isinstance(value, enum): + args = value.args + kwds = value.kwds + if not isinstance(value, tuple): + args = (value, ) + else: + args = value + # tease value out of auto-init if specified + if 'value' in _auto_init_: + if 'value' in kwds: + value = kwds.pop('value') + else: + value, args = args[0], args[1:] + elif _multi_value_: + value, more_values, args = args[0], args[1:], () + if new_uses_args: + args = (value, ) + if _member_type_ is tuple: + args = (args, ) + if not new_uses_args: + new_member = _new(enumeration) + if not hasattr(new_member, '_value_'): + new_member._value_ = value + else: + new_member = _new(enumeration, *args, **kwds) + if not hasattr(new_member, '_value_'): + new_member._value_ = _member_type_(*args) + value = new_member._value_ + if _multi_value_: + if 'value' in _auto_init_: + args = more_values + else: + # put all the values back into args for the init call + args = (value, ) + more_values + new_member._name_ = name + new_member.__objclass__ = enumeration.__class__ + new_member.__init__(*args) + new_member._values_ = (value, ) + more_values + # do final checks before modifying enum structures: + # - is new member a flag? + # - does the new member fit in the enum's declared _boundary_? + # - is new member an alias? + # + _all_bits_ = _flag_mask_ = None + if hasattr(enumeration, '_all_bits_'): + _all_bits_ = enumeration._all_bits_ | value + _flag_mask_ = enumeration._flag_mask_ | value + if enumeration._boundary_ != 'keep': + missed = list(_iter_bits_lsb(_flag_mask_ & ~_all_bits_)) + if missed: + raise TypeError( + 'invalid Flag %r -- missing values: %s' + % (cls, ', '.join((str(i) for i in missed))) + ) + # If another member with the same value was already defined, the + # new member becomes an alias to the existing one. + if _no_alias_: + # unless NoAlias was specified + return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_) + else: + # handle "normal" aliases + new_values = new_member._values_ + for canonical_member in _member_map_.values(): + canonical_values_ = getattr(canonical_member, '_values_', [canonical_member._value_]) + for canonical_value in canonical_values_: + for new_value in new_values: + if canonical_value == new_value: + # name is an alias + if _unique_ or _multi_value_: + # aliases not allowed in Unique and MultiValue enums + raise ValueError('%r is a duplicate of %r' % (new_member, canonical_member)) + else: + # aliased name can be added, remaining checks irrelevant + # aliases don't appear in member names (only in __members__ and _member_map_). + return _finalize_extend_enum(enumeration, canonical_member, name=name, bits=_all_bits_, mask=_flag_mask_, is_alias=True) + # not a standard alias, but maybe a flag alias + if pyver < PY3_6: + flag_bases = Flag, + else: + flag_bases = Flag, StdlibFlag + if issubclass(enumeration, flag_bases) and hasattr(enumeration, '_all_bits_'): + # handle the new flag type + if _is_single_bit(value): + # a new member! (an aliase would have been discovered in the previous loop) + return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_) + else: + # might be an 3.11 Flag alias + if value & enumeration._flag_mask_ == value and _value2member_map_.get(value) is not None: + # yup, it's an alias to existing members... and its an alias of an alias + canonical = _value2member_map_.get(value) + return _finalize_extend_enum(enumeration, canonical, name=name, bits=_all_bits_, mask=_flag_mask_, is_alias=True) + else: + return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_, is_alias=True) + else: + # if we get here, we have a brand new member + return _finalize_extend_enum(enumeration, new_member) + +def _finalize_extend_enum(enumeration, new_member, name=None, bits=None, mask=None, is_alias=False): + name = name or new_member.name + descriptor = None + for base in enumeration.__mro__[1:]: + descriptor = base.__dict__.get(name) + if descriptor is not None: + if isinstance(descriptor, (property, DynamicClassAttribute)): + break + else: + raise TypeError('%r already in use in superclass %r' % (name, base.__name__)) + if not descriptor: + # get redirect in place before adding to _member_map_ + redirect = property() + redirect.__set_name__(enumeration, name) + setattr(enumeration, name, redirect) + if not is_alias: + enumeration._member_names_.append(name) + enumeration._member_map_[name] = new_member + for v in getattr(new_member, '_values_', [new_member._value_]): + try: + enumeration._value2member_map_[v] = new_member + except TypeError: + enumeration._value2member_seq_ += ((v, new_member), ) + if bits: + enumeration._all_bits_ = bits + enumeration._flag_mask_ = mask + return new_member + +def unique(enumeration): + """ + Class decorator that ensures only unique members exist in an enumeration. + """ + duplicates = [] + for name, member in enumeration.__members__.items(): + if name != member.name: + duplicates.append((name, member.name)) + if duplicates: + duplicate_names = ', '.join( + ["%s -> %s" % (alias, name) for (alias, name) in duplicates] + ) + raise ValueError('duplicate names found in %r: %s' % + (enumeration, duplicate_names) + ) + return enumeration + +# Flag + +@export(globals()) +class FlagBoundary(StrEnum): + """ + control how out of range values are handled + "strict" -> error is raised [default] + "conform" -> extra bits are discarded + "eject" -> lose flag status (becomes a normal integer) + """ + STRICT = auto() + CONFORM = auto() + EJECT = auto() + KEEP = auto() +assert FlagBoundary.STRICT == 'strict', (FlagBoundary.STRICT, FlagBoundary.CONFORM) + +class Flag(Enum): + """ + Generic flag enumeration. + + Derive from this class to define new flag enumerations. + """ + + _boundary_ = STRICT + _numeric_repr_ = repr + + + def _generate_next_value_(name, start, count, last_values, *args, **kwds): + """ + Generate the next value when not given. + + name: the name of the member + start: the initital start value or None + count: the number of existing members + last_value: the last value assigned or None + """ + if not count: + if args: + return ((1, start)[start is not None], ) + args + else: + return (1, start)[start is not None] + else: + last_value = max(last_values) + try: + high_bit = _high_bit(last_value) + result = 2 ** (high_bit+1) + if args: + return (result,) + args + else: + return result + except Exception: + pass + raise TypeError('invalid Flag value: %r' % last_value) + + @classmethod + def _iter_member_by_value_(cls, value): + """ + Extract all members from the value in definition (i.e. increasing value) order. + """ + for val in _iter_bits_lsb(value & cls._flag_mask_): + yield cls._value2member_map_.get(val) + + _iter_member_ = _iter_member_by_value_ + + @classmethod + def _iter_member_by_def_(cls, value): + """ + Extract all members from the value in definition order. + """ + members = list(cls._iter_member_by_value_(value)) + members.sort(key=lambda m: m._sort_order_) + for member in members: + yield member + + @classmethod + def _missing_(cls, value): + """ + return a member matching the given value, or None + """ + return cls._create_pseudo_member_(value) + + @classmethod + def _create_pseudo_member_(cls, *values): + """ + Create a composite member. + """ + value = values[0] + if not isinstance(value, baseinteger): + raise ValueError( + "%r is not a valid %s" % (value, getattr(cls, '__qualname__', cls.__name__)) + ) + # check boundaries + # - value must be in range (e.g. -16 <-> +15, i.e. ~15 <-> 15) + # - value must not include any skipped flags (e.g. if bit 2 is not + # defined, then 0d10 is invalid) + neg_value = None + if ( + not ~cls._all_bits_ <= value <= cls._all_bits_ + or value & (cls._all_bits_ ^ cls._flag_mask_) + ): + if cls._boundary_ is STRICT: + max_bits = max(value.bit_length(), cls._flag_mask_.bit_length()) + raise ValueError( + "%s: invalid value: %r\n given %s\n allowed %s" + % (cls.__name__, value, bin(value, max_bits), bin(cls._flag_mask_, max_bits)) + ) + elif cls._boundary_ is CONFORM: + value = value & cls._flag_mask_ + elif cls._boundary_ is EJECT: + return value + elif cls._boundary_ is KEEP: + if value < 0: + value = ( + max(cls._all_bits_+1, 2**(value.bit_length())) + + value + ) + else: + raise ValueError( + 'unknown flag boundary: %r' % (cls._boundary_, ) + ) + if value < 0: + neg_value = value + value = cls._all_bits_ + 1 + value + # get members and unknown + unknown = value & ~cls._flag_mask_ + members = list(cls._iter_member_(value)) + if unknown and cls._boundary_ is not KEEP: + raise ValueError( + '%s(%r) --> unknown values %r [%s]' + % (cls.__name__, value, unknown, bin(unknown)) + ) + # let class adjust values + values = cls._create_pseudo_member_values_(members, *values) + __new__ = getattr(cls, '__new_member__', None) + if cls._member_type_ is object and not __new__: + # construct a singleton enum pseudo-member + pseudo_member = object.__new__(cls) + else: + pseudo_member = (__new__ or cls._member_type_.__new__)(cls, *values) + if not hasattr(pseudo_member, 'value'): + pseudo_member._value_ = value + if members: + pseudo_member._name_ = '|'.join([m._name_ for m in members]) + if unknown: + pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown) + else: + pseudo_member._name_ = None + # use setdefault in case another thread already created a composite + # with this value, but only if all members are known + # note: zero is a special case -- add it + if not unknown: + pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member) + if neg_value is not None: + cls._value2member_map_[neg_value] = pseudo_member + return pseudo_member + + + @classmethod + def _create_pseudo_member_values_(cls, members, *values): + """ + Return values to be fed to __new__ to create new member. + """ + if cls._member_type_ in (baseinteger + (object, )): + return values + elif len(values) < 2: + return values + (cls._member_type_(), ) + else: + return values + + def __contains__(self, other): + """ + Returns True if self has at least the same flags set as other. + """ + if not isinstance(other, self.__class__): + raise TypeError( + "unsupported operand type(s) for 'in': '%s' and '%s'" % ( + type(other).__name__, self.__class__.__name__)) + if other._value_ == 0 or self._value_ == 0: + return False + return other._value_ & self._value_ == other._value_ + + def __iter__(self): + """ + Returns flags in definition order. + """ + for member in self._iter_member_(self._value_): + yield member + + def __len__(self): + return _bit_count(self._value_) + + def __repr__(self): + cls = self.__class__ + if self._name_ is None: + # only zero is unnamed by default + return '<%s: %r>' % (cls.__name__, self._value_) + else: + return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_) + + def __str__(self): + cls = self.__class__ + if self._name_ is None: + return '%s(%s)' % (cls.__name__, self._value_) + else: + return '%s.%s' % (cls.__name__, self._name_) + + if PY2: + def __nonzero__(self): + return bool(self._value_) + else: + def __bool__(self): + return bool(self._value_) + + def __or__(self, other): + if isinstance(other, self.__class__): + other_value = other._value_ + elif self._member_type_ is not object and isinstance(other, self._member_type_): + other_value = other + else: + return NotImplemented + return self.__class__(self._value_ | other_value) + + def __and__(self, other): + if isinstance(other, self.__class__): + other_value = other._value_ + elif self._member_type_ is not object and isinstance(other, self._member_type_): + other_value = other + else: + return NotImplemented + return self.__class__(self._value_ & other_value) + + def __xor__(self, other): + if isinstance(other, self.__class__): + other_value = other._value_ + elif self._member_type_ is not object and isinstance(other, self._member_type_): + other_value = other + else: + return NotImplemented + return self.__class__(self._value_ ^ other_value) + + def __invert__(self): + if self._inverted_ is None: + if self._boundary_ is KEEP: + # use all bits + self._inverted_ = self.__class__(~self._value_) + else: + # calculate flags not in this member + self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_) + self._inverted_._inverted_ = self + return self._inverted_ + + __ror__ = __or__ + __rand__ = __and__ + __rxor__ = __xor__ + + + +class IntFlag(int, ReprEnum, Flag): + """Support for integer-based Flags""" + + _boundary_ = EJECT + + +def _high_bit(value): + """returns index of highest bit, or -1 if value is zero or negative""" + return value.bit_length() - 1 + +def global_enum_repr(self): + """ + use module.enum_name instead of class.enum_name + + the module is the last module in case of a multi-module name + """ + module = self.__class__.__module__.split('.')[-1] + return '%s.%s' % (module, self._name_) + +def global_flag_repr(self): + """ + use module.flag_name instead of class.flag_name + + the module is the last module in case of a multi-module name + """ + module = self.__class__.__module__.split('.')[-1] + cls_name = self.__class__.__name__ + if self._name_ is None: + return "%s.%s(%r)" % (module, cls_name, self._value_) + if _is_single_bit(self): + return '%s.%s' % (module, self._name_) + if self._boundary_ is not FlagBoundary.KEEP: + return '|'.join(['%s.%s' % (module, name) for name in self.name.split('|')]) + else: + name = [] + for n in self._name_.split('|'): + if n[0].isdigit(): + name.append(n) + else: + name.append('%s.%s' % (module, n)) + return '|'.join(name) + +def global_str(self): + """ + use enum_name instead of class.enum_name + """ + if self._name_ is None: + return "%s(%r)" % (cls_name, self._value_) + else: + return self._name_ + +def global_enum(cls, update_str=False): + """ + decorator that makes the repr() of an enum member reference its module + instead of its class; also exports all members to the enum's module's + global namespace + """ + if issubclass(cls, Flag): + cls.__repr__ = global_flag_repr + else: + cls.__repr__ = global_enum_repr + if not issubclass(cls, ReprEnum) or update_str: + cls.__str__ = global_str + _sys.modules[cls.__module__].__dict__.update(cls.__members__) + return cls + + +class module(object): + + def __init__(self, cls, *args): + self.__name__ = cls.__name__ + self._parent_module = cls.__module__ + self.__all__ = [] + all_objects = cls.__dict__ + if not args: + args = [k for k, v in all_objects.items() if isinstance(v, (NamedConstant, Enum))] + for name in args: + self.__dict__[name] = all_objects[name] + self.__all__.append(name) + + def register(self): + _sys.modules["%s.%s" % (self._parent_module, self.__name__)] = self + +if StdlibEnumMeta: + + from _weakrefset import WeakSet + + def __subclasscheck__(cls, subclass): + """ + Override for issubclass(subclass, cls). + """ + if not isinstance(subclass, type): + raise TypeError('issubclass() arg 1 must be a class (got %r)' % (subclass, )) + # Check cache + try: + cls.__dict__['_subclass_cache_'] + except KeyError: + cls._subclass_cache_ = WeakSet() + cls._subclass_negative_cache_ = WeakSet() + except RecursionError: + import sys + exc, cls, tb = sys.exc_info() + exc = RecursionError('possible causes for endless recursion:\n - __getattribute__ is not ignoring __dunder__ attibutes\n - __instancecheck__ and/or __subclasscheck_ are (mutually) recursive\n see `aenum.remove_stdlib_integration` for temporary work-around') + raise_from_none(exc) + if subclass in cls._subclass_cache_: + return True + # Check negative cache + elif subclass in cls._subclass_negative_cache_: + return False + if cls is subclass: + cls._subclass_cache_.add(subclass) + return True + # Check if it's a direct subclass + if cls in getattr(subclass, '__mro__', ()): + cls._subclass_cache_.add(subclass) + return True + # Check if it's an aenum.Enum|IntEnum|IntFlag|Flag subclass + if cls is StdlibIntFlag and issubclass(subclass, IntFlag): + cls._subclass_cache_.add(subclass) + return True + elif cls is StdlibFlag and issubclass(subclass, Flag): + cls._subclass_cache_.add(subclass) + return True + elif cls is StdlibIntEnum and issubclass(subclass, IntEnum): + cls._subclass_cache_.add(subclass) + return True + if cls is StdlibEnum and issubclass(subclass, Enum): + cls._subclass_cache_.add(subclass) + return True + # No dice; update negative cache + cls._subclass_negative_cache_.add(subclass) + return False + + def __instancecheck__(cls, instance): + subclass = instance.__class__ + try: + return cls.__subclasscheck__(subclass) + except RecursionError: + import sys + exc, cls, tb = sys.exc_info() + exc = RecursionError('possible causes for endless recursion:\n - __getattribute__ is not ignoring __dunder__ attibutes\n - __instancecheck__ and/or __subclasscheck_ are (mutually) recursive\n see `aenum.remove_stdlib_integration` for temporary work-around') + raise_from_none(exc) + + StdlibEnumMeta.__subclasscheck__ = __subclasscheck__ + StdlibEnumMeta.__instancecheck__ = __instancecheck__ + +def add_stdlib_integration(): + if StdlibEnum: + StdlibEnumMeta.__subclasscheck__ = __subclasscheck__ + StdlibEnumMeta.__instancecheck__ = __instancecheck__ + +def remove_stdlib_integration(): + """ + Remove the __instancecheck__ and __subclasscheck__ overrides from the stdlib Enum. + + Those overrides are in place so that code detecting stdlib enums will also detect + aenum enums. If a buggy __getattribute__, __instancecheck__, or __subclasscheck__ + is defined on a custom EnumMeta then RecursionErrors can result; using this + function after importing aenum will solve that problem, but the better solution is + to fix the buggy method. + """ + if StdlibEnum: + del StdlibEnumMeta.__instancecheck__ + del StdlibEnumMeta.__subclasscheck__ + diff --git a/venv/Lib/site-packages/aenum/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/aenum/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..176f78e250e4099e3c3b3bd6e90f89417d332065 GIT binary patch literal 104964 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 + +---------------- + +An ``Enum`` is a set of symbolic names (members) bound to unique, constant +values. Within an enumeration, the members can be compared by identity, and +the enumeration itself can be iterated over. + +A ``NamedTuple`` is a class-based, fixed-length tuple with a name for each +possible position accessible using attribute-access notation. + +A ``NamedConstant`` is a class whose members cannot be rebound; it lacks all +other ``Enum`` capabilities, however; consequently, it can have duplicate +values. There is also a ``module`` function that can insert the +``NamedConstant`` class into ``sys.modules`` where it will appear to be a +module whose top-level names cannot be rebound. + +.. note:: + ``constant`` refers to names not being rebound; mutable objects can be + mutated. + + +Module Contents +--------------- + +This module defines five enumeration classes that can be used to define unique +sets of names and values, one ``Enum`` class decorator, one ``NamedTuple`` +class, one ``NamedConstant`` class, and several helpers. + +``NamedConstant`` + +NamedConstant class for creating groups of constants. These names cannot be +rebound to other values. + +``Enum`` + +Base class for creating enumerated constants. See section `Enum Functional API`_ +for an alternate construction syntax. + +``AddValue`` + +Flag specifying that ``_generate_next_value_`` should always be called to +provide the initial value for an enum member. + +``MultiValue`` + +Flag specifying that each item of tuple value is a separate value for that +member; the first tuple item is the canonical one. + +``NoAlias`` + +Flag specifying that duplicate valued members are distinct and not aliases; +by-value lookups are disabled. + +``Unique`` + +Flag specifying that duplicate valued members are not allowed. + +.. note:: + The flags are inherited by the enumeration's subclasses. To use them in + Python 2 assign to ``_settings_`` in the class body. + +``IntEnum`` + +Base class for creating enumerated constants that are also subclasses of ``int``. + +``AutoNumberEnum`` + +Derived class that automatically assigns an ``int`` value to each member. + +``OrderedEnum`` + +Derived class that adds ``<``, ``<=``, ``>=``, and ``>`` methods to an ``Enum``. + +``UniqueEnum`` + +Derived class that ensures only one name is bound to any one value. + +``unique`` + +Enum class decorator that ensures only one name is bound to any one value. + +.. note:: + + the ``UniqueEnum`` class, the ``unique`` decorator, and the Unique + flag all do the same thing; you do not need to use more than one of + them at the same time. + +``NamedTuple`` + +Base class for `creating NamedTuples`_, either by subclassing or via it's +functional API. + +``constant`` + +Descriptor to add constant values to an ``Enum``, or advanced constants to +``NamedConstant``. + +``convert`` + +Helper to transform target global variables into an ``Enum``. + +``enum`` + +Helper for specifying keyword arguments when creating ``Enum`` members. + +``export`` + +Helper for inserting ``Enum`` members and ``NamedConstant`` constants into a +namespace (usually ``globals()``. + +``extend_enum`` + +Helper for adding new ``Enum`` members, both stdlib and aenum. + +``module`` + +Function to take a ``NamedConstant`` or ``Enum`` class and insert it into +``sys.modules`` with the affect of a module whose top-level constant and +member names cannot be rebound. + +``skip`` + +Descriptor to add a normal (non-``Enum`` member) attribute to an ``Enum`` +or ``NamedConstant``. + + +Creating an Enum +---------------- + +Enumerations are created using the ``class`` syntax, which makes them +easy to read and write. An alternative creation method is described in +`Enum Functional API`_. To define an enumeration, subclass ``Enum`` as +follows:: + + >>> from aenum import Enum + >>> class Color(Enum): + ... red = 1 + ... green = 2 + ... blue = 3 + +*Nomenclature* + + - The class ``Color`` is an *enumeration* (or *enum*) + - The attributes ``Color.red``, ``Color.green``, etc., are + *enumeration members* (or *enum members*). + - The enum members have *names* and *values* (the name of + ``Color.red`` is ``red``, the value of ``Color.blue`` is + ``3``, etc.) + +.. note:: + + Even though we use the ``class`` syntax to create Enums, Enums + are not normal Python classes. See `How are Enums different?`_ for + more details. + +Enumeration members have human readable string representations:: + + >>> print(Color.red) + Color.red + +...while their ``repr`` has more information:: + + >>> print(repr(Color.red)) + + +The *type* of an enumeration member is the enumeration it belongs to:: + + >>> type(Color.red) + + >>> isinstance(Color.green, Color) + True + +Enumerations support iteration. In Python 3.x definition order is used; in +Python 2.x the definition order is not available, but class attribute +``_order_`` is supported; otherwise, value order is used if posible, +otherwise alphabetical name order is used:: + + >>> class Shake(Enum): + ... _order_ = 'vanilla chocolate cookies mint' # only needed in 2.x + ... vanilla = 7 + ... chocolate = 4 + ... cookies = 9 + ... mint = 3 + ... + >>> for shake in Shake: + ... print(shake) + ... + Shake.vanilla + Shake.chocolate + Shake.cookies + Shake.mint + +The ``_order_`` attribute is always removed, but in 3.x it is also used to +verify that definition order is the same (useful for py2&3 code bases); +however, in the stdlib version it will be ignored and not removed. + +.. note:: + + To maintain compatibility with Python 3.4 and 3.5, use __order__ + instead (double leading and trailing underscores). + +Enumeration members are hashable, so they can be used in dictionaries and sets:: + + >>> apples = {} + >>> apples[Color.red] = 'red delicious' + >>> apples[Color.green] = 'granny smith' + >>> apples == {Color.red: 'red delicious', Color.green: 'granny smith'} + True + +In Python 3 the class syntax has a few extra advancements:: + + --> class Color( + ... Enum, + ... settings=(AddValue, MultiValue, NoAlias, Unique), + ... init='field_name1 field_name2 ...', + ... start=7, + ... ) + ... + +``start`` is used to specify the starting value for the first member:: + + --> class Count(Enum, start=11): + ... eleven + ... twelve + ... + --> Count.twelve.value == 12 + True + +``init`` specifies the attribute names to store creation values to:: + + --> class Planet(Enum, init='mass radius'): + ... MERCURY = (3.303e+23, 2.4397e6) + ... EARTH = (5.976e+24, 6.37814e6) + ... + --> Planet.EARTH.value + (5.976e+24, 6378140.0) + --> Planet.EARTH.radius + 2.4397e6 + +The various settings enable special behavior: + +- ``AddValue`` calls a user supplied ``_generate_next_value_`` to provide + the initial value +- ``MultiValue`` allows multiple values per member instead of the usual 1 +- ``NoAlias`` allows different members to have the same value +- ``Unique`` disallows different members to have the same value + +.. note:: + + To use these features in Python 2 use the _sundered_ versions of + the names in the class body: ``_start_``, ``_init_``, ``_settings_``. + + +Programmatic access to enumeration members and their attributes +--------------------------------------------------------------- + +Sometimes it's useful to access members in enumerations programmatically (i.e. +situations where ``Color.red`` won't do because the exact color is not known +at program-writing time). ``Enum`` allows such access:: + + >>> Color(1) + + >>> Color(3) + + +If you want to access enum members by *name*, use item access:: + + >>> Color['red'] + + >>> Color['green'] + + +If have an enum member and need its ``name`` or ``value``:: + + >>> member = Color.red + >>> member.name + 'red' + >>> member.value + 1 + + +Duplicating enum members and values +----------------------------------- + +Having two enum members (or any other attribute) with the same name is invalid; +in Python 3.x this would raise an error, but in Python 2.x the second member +simply overwrites the first:: + + # python 2.x + --> class Shape(Enum): + ... square = 2 + ... square = 3 + ... + --> Shape.square + + + # python 3.x + --> class Shape(Enum): + ... square = 2 + ... square = 3 + Traceback (most recent call last): + ... + TypeError: Attempted to reuse key: 'square' + +However, two enum members are allowed to have the same value. Given two members +A and B with the same value (and A defined first), B is an alias to A. By-value +lookup of the value of A and B will return A. By-name lookup of B will also +return A:: + + >>> class Shape(Enum): + ... _order_ = 'square diamond circle' # needed in 2.x + ... square = 2 + ... diamond = 1 + ... circle = 3 + ... alias_for_square = 2 + ... + >>> Shape.square + + >>> Shape.alias_for_square + + >>> Shape(2) + + + +Allowing aliases is not always desirable. ``unique`` can be used to ensure +that none exist in a particular enumeration:: + + >>> from aenum import unique + >>> @unique + ... class Mistake(Enum): + ... _order_ = 'one two three' # only needed in 2.x + ... one = 1 + ... two = 2 + ... three = 3 + ... four = 3 + Traceback (most recent call last): + ... + ValueError: duplicate names found in : four -> three + +Iterating over the members of an enum does not provide the aliases:: + + >>> list(Shape) + [, , ] + +The special attribute ``__members__`` is a dictionary mapping names to members. +It includes all names defined in the enumeration, including the aliases:: + + >>> for name, member in sorted(Shape.__members__.items()): + ... name, member + ... + ('alias_for_square', ) + ('circle', ) + ('diamond', ) + ('square', ) + +The ``__members__`` attribute can be used for detailed programmatic access to +the enumeration members. For example, finding all the aliases:: + + >>> [n for n, mbr in Shape.__members__.items() if mbr.name != n] + ['alias_for_square'] + +Comparisons +----------- + +Enumeration members are compared by identity:: + + >>> Color.red is Color.red + True + >>> Color.red is Color.blue + False + >>> Color.red is not Color.blue + True + +Ordered comparisons between enumeration values are *not* supported. Enum +members are not integers (but see `IntEnum`_ below):: + + >>> Color.red < Color.blue + Traceback (most recent call last): + File "", line 1, in + TypeError: unorderable types: Color() < Color() + +.. warning:: + + In Python 2 *everything* is ordered, even though the ordering may not + make sense. If you want your enumerations to have a sensible ordering + consider using an `OrderedEnum`_. + + +Equality comparisons are defined though:: + + >>> Color.blue == Color.red + False + >>> Color.blue != Color.red + True + >>> Color.blue == Color.blue + True + +Comparisons against non-enumeration values will always compare not equal +(again, ``IntEnum`` was explicitly designed to behave differently, see +below):: + + >>> Color.blue == 2 + False + + +Allowed members and attributes of enumerations +---------------------------------------------- + +The examples above use integers for enumeration values. Using integers is +short and handy (and provided by default by the `Enum Functional API`_), but not +strictly enforced. In the vast majority of use-cases, one doesn't care what +the actual value of an enumeration is. But if the value *is* important, +enumerations can have arbitrary values. + +Enumerations are Python classes, and can have methods and special methods as +usual. If we have this enumeration:: + + >>> class Mood(Enum): + ... funky = 1 + ... happy = 3 + ... + ... def describe(self): + ... # self is the member here + ... return self.name, self.value + ... + ... def __str__(self): + ... return 'my custom str! {0}'.format(self.value) + ... + ... @classmethod + ... def favorite_mood(cls): + ... # cls here is the enumeration + ... return cls.happy + +Then:: + + >>> Mood.favorite_mood() + + >>> Mood.happy.describe() + ('happy', 3) + >>> str(Mood.funky) + 'my custom str! 1' + +The rules for what is allowed are as follows: _sunder_ names (starting and +ending with a single underscore) are reserved by enum and cannot be used; +all other attributes defined within an enumeration will become members of this +enumeration, with the exception of *__dunder__* names and descriptors (methods +are also descriptors). + +.. note:: + + If your enumeration defines ``__new__`` and/or ``__init__`` then + whatever value(s) were given to the enum member will be passed into + those methods. See `Planet`_ for an example. + + +Restricted Enum subclassing +--------------------------- + +A new `Enum` class must have one base Enum class, up to one concrete +data type, and as many `object`-based mixin classes as needed. The +order of these base classes is:: + + def EnumName([mix-in, ...,] [data-type,] base-enum): + pass + +Also, subclassing an enumeration is allowed only if the enumeration does not define + +any members. So this is forbidden:: + + >>> class MoreColor(Color): + ... pink = 17 + Traceback (most recent call last): + ... + TypeError: cannot extend + +But this is allowed:: + + >>> class Foo(Enum): + ... def some_behavior(self): + ... pass + ... + >>> class Bar(Foo): + ... happy = 1 + ... sad = 2 + ... + +Allowing subclassing of enums that define members would lead to a violation of +some important invariants of types and instances. On the other hand, it makes +sense to allow sharing some common behavior between a group of enumerations. +(See `OrderedEnum`_ for an example.) + + +Pickling +-------- + +Enumerations can be pickled and unpickled:: + + >>> from aenum.test import Fruit + >>> from pickle import dumps, loads + >>> Fruit.tomato is loads(dumps(Fruit.tomato, 2)) + True + +The usual restrictions for pickling apply: picklable enums must be defined in +the top level of a module, since unpickling requires them to be importable +from that module. + +.. note:: + + With pickle protocol version 4 (introduced in Python 3.4) it is possible + to easily pickle enums nested in other classes. + + + +Enum Functional API +------------------- + +The ``Enum`` class is callable, providing the following functional API:: + + >>> Animal = Enum('Animal', 'ant bee cat dog') + >>> Animal + + >>> Animal.ant + + >>> Animal.ant.value + 1 + >>> list(Animal) + [, , , ] + +The semantics of this API resemble ``namedtuple``. The first argument +of the call to ``Enum`` is the name of the enumeration. + +The second argument is the *source* of enumeration member names. It can be a +whitespace-separated string of names, a sequence of names, a sequence of +2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to +values. The last two options enable assigning arbitrary values to +enumerations; the others auto-assign increasing integers starting with 1. A +new class derived from ``Enum`` is returned. In other words, the above +assignment to ``Animal`` is equivalent to:: + + >>> class Animals(Enum): + ... ant = 1 + ... bee = 2 + ... cat = 3 + ... dog = 4 + +Pickling enums created with the functional API can be tricky as frame stack +implementation details are used to try and figure out which module the +enumeration is being created in (e.g. it will fail if you use a utility +function in separate module, and also may not work on IronPython or Jython). +The solution is to specify the module name explicitly as follows:: + + >>> Animals = Enum('Animals', 'ant bee cat dog', module=__name__) + +Derived Enumerations +-------------------- + +IntEnum +^^^^^^^ + +A variation of ``Enum`` is provided which is also a subclass of +``int``. Members of an ``IntEnum`` can be compared to integers; +by extension, integer enumerations of different types can also be compared +to each other:: + + >>> from aenum import IntEnum + >>> class Shape(IntEnum): + ... circle = 1 + ... square = 2 + ... + >>> class Request(IntEnum): + ... post = 1 + ... get = 2 + ... + >>> Shape == 1 + False + >>> Shape.circle == 1 + True + >>> Shape.circle == Request.post + True + +However, they still can't be compared to standard ``Enum`` enumerations:: + + >>> class Shape(IntEnum): + ... circle = 1 + ... square = 2 + ... + >>> class Color(Enum): + ... red = 1 + ... green = 2 + ... + >>> Shape.circle == Color.red + False + +``IntEnum`` values behave like integers in other ways you'd expect:: + + >>> int(Shape.circle) + 1 + >>> ['a', 'b', 'c'][Shape.circle] + 'b' + >>> [i for i in range(Shape.square)] + [0, 1] + +For the vast majority of code, ``Enum`` is strongly recommended, +since ``IntEnum`` breaks some semantic promises of an enumeration (by +being comparable to integers, and thus by transitivity to other +unrelated enumerations). It should be used only in special cases where +there's no other choice; for example, when integer constants are +replaced with enumerations and backwards compatibility is required with code +that still expects integers. + + +IntFlag +^^^^^^^ + +The next variation of ``Enum`` provided, ``IntFlag``, is also based +on ``int``. The difference being ``IntFlag`` members can be combined +using the bitwise operators (&, \|, ^, ~) and the result is still an +``IntFlag`` member. However, as the name implies, ``IntFlag`` +members also subclass ``int`` and can be used wherever an ``int`` is +used. Any operation on an ``IntFlag`` member besides the bit-wise +operations will lose the ``IntFlag`` membership. + +Sample ``IntFlag`` class:: + + >>> from aenum import IntFlag + >>> class Perm(IntFlag): + ... _order_ = 'R W X' + ... R = 4 + ... W = 2 + ... X = 1 + ... + >>> Perm.R | Perm.W + + >>> Perm.R + Perm.W + 6 + >>> RW = Perm.R | Perm.W + >>> Perm.R in RW + True + +It is also possible to name the combinations:: + + >>> class Perm(IntFlag): + ... _order_ = 'R W X' + ... R = 4 + ... W = 2 + ... X = 1 + ... RWX = 7 + >>> Perm.RWX + + >>> ~Perm.RWX + + +Another important difference between ``IntFlag`` and ``Enum`` is that +if no flags are set (the value is 0), its boolean evaluation is ``False``:: + + >>> Perm.R & Perm.X + + >>> bool(Perm.R & Perm.X) + False + +Because ``IntFlag`` members are also subclasses of ``int`` they can +be combined with them:: + + >>> Perm.X | 4 + + +If the result is not a ``Flag`` then, depending on the ``_boundary_`` setting, +an exception is raised (``STRICT``), the extra bits are lost (``CONFORM``), or +it reverts to an int (``EJECT``): + + >>> from aenum import STRICT, CONFORM, EJECT + >>> Perm._boundary_ = STRICT + >>> Perm.X | 8 + Traceback (most recent call last): + ... + ValueError: Perm: invalid value: 9 + given 0b0 1001 + allowed 0b0 0111 + + >>> Perm._boundary_ = EJECT + >>> Perm.X | 8 + 9 + + >>> Perm._boundary_ = CONFORM + >>> Perm.X | 8 + + + +Flag +^^^^ + +The last variation is ``Flag``. Like ``IntFlag``, ``Flag`` +members can be combined using the bitwise operators (&, \|, ^, ~). Unlike +``IntFlag``, they cannot be combined with, nor compared against, any +other ``Flag`` enumeration, nor ``int``. While it is possible to +specify the values directly it is recommended to use ``auto`` as the +value and let ``Flag`` select an appropriate value. + +Like ``IntFlag``, if a combination of ``Flag`` members results in no +flags being set, the boolean evaluation is ``False``:: + + >>> from aenum import Flag, auto + >>> class Color(Flag): + ... RED = auto() + ... BLUE = auto() + ... GREEN = auto() + ... + >>> Color.RED & Color.GREEN + + >>> bool(Color.RED & Color.GREEN) + False + +Individual flags should have values that are powers of two (1, 2, 4, 8, ...), +while combinations of flags won't:: + + --> class Color(Flag): + ... RED = auto() + ... BLUE = auto() + ... GREEN = auto() + ... WHITE = RED | BLUE | GREEN + ... + --> Color.WHITE + + +Giving a name to the "no flags set" condition does not change its boolean +value:: + + >>> class Color(Flag): + ... BLACK = 0 + ... RED = auto() + ... BLUE = auto() + ... GREEN = auto() + ... + >>> Color.BLACK + + >>> bool(Color.BLACK) + False + +Flags can be iterated over to retrieve the individual truthy flags in the value:: + + >>> class Color(Flag): + ... _order_ = 'BLACK RED BLUE GREEN WHITE' + ... BLACK = 0 + ... RED = auto() + ... BLUE = auto() + ... GREEN = auto() + ... WHITE = RED | BLUE | GREEN + ... + >>> list(Color.GREEN) + [] + >>> list(Color.WHITE) + [, , ] + +.. note:: + + For the majority of new code, ``Enum`` and ``Flag`` are strongly + recommended, since ``IntEnum`` and ``IntFlag`` break some + semantic promises of an enumeration (by being comparable to integers, and + thus by transitivity to other unrelated enumerations). ``IntEnum`` + and ``IntFlag`` should be used only in cases where ``Enum`` and + ``Flag`` will not do; for example, when integer constants are replaced + with enumerations, or for interoperability with other systems. + + +Others +^^^^^^ + +While ``IntEnum`` is part of the ``aenum`` module, it would be very +simple to implement independently:: + + class MyIntEnum(int, Enum): + pass + +This demonstrates how similar derived enumerations can be defined; for example +a ``MyStrEnum`` that mixes in ``str`` instead of ``int``. + +Some rules: + +1. When subclassing ``Enum``, mix-in types must appear before + ``Enum`` itself in the sequence of bases, as in the ``MyIntEnum`` + example above. +2. While ``Enum`` can have members of any type, once you mix in an + additional type, all the members must have values of that type or be + convertible into that type. This restriction does not apply to mix-ins + which only add methods and don't specify another data type. +3. When another data type is mixed in, the ``value`` attribute is *not the + same* as the enum member itself, although it is equivalant and will compare + equal. +4. %-style formatting: ``%s`` and ``%r`` call ``Enum``'s ``__str__`` and + ``__repr__`` respectively; other codes (such as ``%i`` or ``%h`` for + MyIntEnum) treat the enum member as its mixed-in type. +5. ``str.__format__`` (or ``format``) will use the mixed-in + type's ``__format__``. If the ``Enum``'s ``str`` or ``repr`` is desired + use the ``!s`` or ``!r`` ``str`` format codes. + +.. note:: + + If you override the ``__str__`` method, then it will be used to provide the + string portion of the ``format()`` call. + +.. note:: + + Prior to Python 3.4 there is a bug in ``str``'s %-formatting: ``int`` + subclasses are printed as strings and not numbers when the ``%d``, ``%i``, + or ``%u`` codes are used. + + +Extra Goodies +------------- + +aenum supports a few extra techniques not found in the stdlib version. + +enum +^^^^ + +If you have several items to initialize your ``Enum`` members with and +would like to use keyword arguments, the ``enum`` helper is for you:: + + >>> from aenum import enum + >>> class Presidents(Enum): + ... Washington = enum('George Washington', circa=1776, death=1797) + ... Jackson = enum('Andrew Jackson', circa=1830, death=1837) + ... Lincoln = enum('Abraham Lincoln', circa=1860, death=1865) + ... + >>> Presidents.Lincoln + + +extend_enum +^^^^^^^^^^^ + +For those rare cases when you need to create your ``Enum`` in pieces, you +can use ``extend_enum`` to add new members after the initial creation +(the new member is returned):: + + >>> from aenum import extend_enum + >>> class Color(Enum): + ... red = 1 + ... green = 2 + ... blue = 3 + ... + >>> list(Color) + [, , ] + >>> extend_enum(Color, 'opacity', 4) + + >>> list(Color) + [, , , ] + >>> Color.opacity in Color + True + >>> Color.opacity.name == 'opacity' + True + >>> Color.opacity.value == 4 + True + >>> Color(4) + + >>> Color['opacity'] + + + --> Color.__members__ + OrderedDict([ + ('red', ), + ('green', ), + ('blue', ), + ('opacity', ) + ]) + +constant +^^^^^^^^ + +If you need to have some constant value in your ``Enum`` that isn't a member, +use ``constant``:: + + >>> from aenum import constant + >>> class Planet(Enum): + ... MERCURY = (3.303e+23, 2.4397e6) + ... EARTH = (5.976e+24, 6.37814e6) + ... JUPITER = (1.9e+27, 7.1492e7) + ... URANUS = (8.686e+25, 2.5559e7) + ... G = constant(6.67300E-11) + ... 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) + ... return self.G * self.mass / (self.radius * self.radius) + ... + >>> Planet.EARTH.value + (5.976e+24, 6378140.0) + >>> Planet.EARTH.surface_gravity + 9.802652743337129 + >>> Planet.G + 6.673e-11 + >>> Planet.G = 9 + Traceback (most recent call last): + ... + AttributeError: Planet: cannot rebind constant 'G' + +skip +^^^^ + +If you need a standard attribute that is not converted into an ``Enum`` +member, use ``skip``:: + + >>> from aenum import skip + >>> class Color(Enum): + ... red = 1 + ... green = 2 + ... blue = 3 + ... opacity = skip(0.45) + ... + >>> Color.opacity + 0.45 + >>> Color.opacity = 0.77 + >>> Color.opacity + 0.77 + +start +^^^^^ + +``start`` can be used to turn on auto-numbering (useful for when you don't +care which numbers are assigned as long as they are consistent and in order) +The Python 3 version can look like this:: + + >>> class Color(Enum, start=1): # doctest: +SKIP + ... red, green, blue + ... + >>> Color.blue + + +This can also be done in Python 2, albeit not as elegantly (this also works in +Python 3):: + + >>> class Color(Enum): # doctest: +SKIP + ... _start_ = 1 + ... red = auto() + ... green = auto() + ... blue = auto() + ... + >>> Color.blue + + +init +^^^^ + +If you need an ``__init__`` method that does nothing besides save its +arguments, ``init`` is for you:: + + >>> class Planet(Enum, init='mass radius'): # doctest: +SKIP + ... MERCURY = (3.303e+23, 2.4397e6) + ... EARTH = (5.976e+24, 6.37814e6) + ... JUPITER = (1.9e+27, 7.1492e7) + ... URANUS = (8.686e+25, 2.5559e7) + ... G = constant(6.67300E-11) + ... @property + ... def surface_gravity(self): + ... # universal gravitational constant (m3 kg-1 s-2) + ... return self.G * self.mass / (self.radius * self.radius) + ... + >>> Planet.JUPITER.value + (1.9e+27, 71492000.0) + >>> Planet.JUPITER.mass + 1.9e+27 + +.. note:: + + Just as with ``start`` above, in Python 2 you must put the keyword as a + _sunder_ in the class body -- ``_init_ = 'mass radius'``. + +init and missing values +^^^^^^^^^^^^^^^^^^^^^^^ + +If ``_init_`` calls for values that are not supplied, ``_generate_next_value_`` +will be called in an effort to generate them. Here is an example in Python 2:: + + >>> from aenum import Enum + >>> 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 NotificationType(SelectionEnum): + ... # usually, name is the same as db + ... # but not for blanks + ... blank = '', '' + ... C = 'Catalog' + ... S = 'Sheet' + ... B = 'Both' + ... + >>> NotificationType.blank + + >>> NotificationType.B + + >>> NotificationType.B.db + 'B' + >>> NotificationType.B.user + 'Both' + +combining Flag with other data types +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Flag does support being combined with other data types. To support this you +need to provide a ``_create_pseudo_member_values_`` method which will be called +with the members in a composite flag. You may also need to provide a custom +``__new__`` method:: + + >>> class AnsiFlag(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, ) + ... _order_ = 'FG_Red FG_Green BG_Magenta BG_White' + ... FG_Red = '31' # ESC [ 31 m # red + ... FG_Green = '32' # ESC [ 32 m # green + ... BG_Magenta = '45' # ESC [ 35 m # magenta + ... BG_White = '47' # ESC [ 37 m # white + ... + >>> color = AnsiFlag.BG_White | AnsiFlag.FG_Red + >>> repr(color) + '' + >>> str.__repr__(color) + "'\\x1b[31;47m'" + +.. note:: + + If you do not provide your own ``_create_pseudo_member_values_`` the flags + may still combine, but may be missing functionality. + + +Decorators +---------- + +unique +^^^^^^ + +A ``class`` decorator specifically for enumerations. It searches an +enumeration's ``__members__`` gathering any aliases it finds; if any are +found ``ValueError`` is raised with the details:: + + >>> @unique + ... class NoDupes(Enum): + ... first = 'one' + ... second = 'two' + ... third = 'two' + Traceback (most recent call last): + ... + ValueError: duplicate names found in : third -> second + + +Interesting examples +-------------------- + +While ``Enum`` and ``IntEnum`` are expected to cover the majority of +use-cases, they cannot cover them all. Here are recipes for some different +types of enumerations that can be used directly (the first three are included +in the module), or as examples for creating one's own. + + +AutoNumber +^^^^^^^^^^ + +Avoids having to specify the value for each enumeration member:: + + >>> class AutoNumber(Enum): + ... def __new__(cls): + ... value = len(cls.__members__) + 1 + ... obj = object.__new__(cls) + ... obj._value_ = value + ... return obj + ... + >>> class Color(AutoNumber): + ... _order_ = "red green blue" # only needed in 2.x + ... red = () + ... green = () + ... blue = () + ... + >>> Color.green.value == 2 + True + +.. note:: + + The `__new__` method, if defined, is used during creation of the Enum + members; it is then replaced by Enum's `__new__` which is used after + class creation for lookup of existing members. Due to the way Enums are + supposed to behave, there is no way to customize Enum's `__new__` without + modifying the class after it is created. + + +UniqueEnum +^^^^^^^^^^ + +Raises an error if a duplicate member name is found instead of creating an +alias:: + + >>> class UniqueEnum(Enum): + ... def __init__(self, *args): + ... cls = self.__class__ + ... if any(self.value == e.value for e in cls): + ... a = self.name + ... e = cls(self.value).name + ... raise ValueError( + ... "aliases not allowed in UniqueEnum: %r --> %r" + ... % (a, e)) + ... + >>> class Color(UniqueEnum): + ... _order_ = 'red green blue' + ... red = 1 + ... green = 2 + ... blue = 3 + ... grene = 2 + Traceback (most recent call last): + ... + ValueError: aliases not allowed in UniqueEnum: 'grene' --> 'green' + + +OrderedEnum +^^^^^^^^^^^ + +An ordered enumeration that is not based on ``IntEnum`` and so maintains +the normal ``Enum`` invariants (such as not being comparable to other +enumerations):: + + >>> class OrderedEnum(Enum): + ... def __ge__(self, other): + ... if self.__class__ is other.__class__: + ... return self._value_ >= other._value_ + ... return NotImplemented + ... def __gt__(self, other): + ... if self.__class__ is other.__class__: + ... return self._value_ > other._value_ + ... return NotImplemented + ... def __le__(self, other): + ... if self.__class__ is other.__class__: + ... return self._value_ <= other._value_ + ... return NotImplemented + ... def __lt__(self, other): + ... if self.__class__ is other.__class__: + ... return self._value_ < other._value_ + ... return NotImplemented + ... + >>> class Grade(OrderedEnum): + ... __ordered__ = 'A B C D F' + ... A = 5 + ... B = 4 + ... C = 3 + ... D = 2 + ... F = 1 + ... + >>> Grade.C < Grade.A + True + + +Planet +^^^^^^ + +If ``__new__`` or ``__init__`` is defined the value of the enum member +will be passed to those methods:: + + >>> 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) + ... + >>> Planet.EARTH.value + (5.976e+24, 6378140.0) + >>> Planet.EARTH.surface_gravity + 9.802652743337129 + + +How are Enums different? +------------------------ + +Enums have a custom metaclass that affects many aspects of both derived Enum +classes and their instances (members). + + +Enum Classes +^^^^^^^^^^^^ + +The ``EnumMeta`` metaclass is responsible for providing the +``__contains__``, ``__dir__``, ``__iter__`` and other methods that +allow one to do things with an ``Enum`` class that fail on a typical +class, such as ``list(Color)`` or ``some_var in Color``. ``EnumMeta`` is +responsible for ensuring that various other methods on the final ``Enum`` +class are correct (such as ``__new__``, ``__getnewargs__``, +``__str__`` and ``__repr__``). + +.. note:: + + ``__dir__`` is not changed in the Python 2 line as it messes up some + of the decorators included in the stdlib. + + +Enum Members (aka instances) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The most interesting thing about Enum members is that they are singletons. +``EnumMeta`` creates them all while it is creating the ``Enum`` +class itself, and then puts a custom ``__new__`` in place to ensure +that no new ones are ever instantiated by returning only the existing +member instances. + + +Finer Points +^^^^^^^^^^^^ + +``Enum`` members are instances of an ``Enum`` class, but are not +accessible as `EnumClass.member1.member2`. +(changed in version 1.1.1 to be accessible) +(changed in version 2.2.4 to be inaccessible):: + + >>> class FieldTypes(Enum): + ... name = 1 + ... value = 2 + ... size = 3 + ... + >>> FieldTypes.size.value + 3 + >>> FieldTypes.size + + >>> FieldTypes.value.size + Traceback (most recent call last): + ... + AttributeError: member has no attribute 'size' + +The ``__members__`` attribute is only available on the class. + + +``__members__`` is always an ``OrderedDict``, with the order being the +definition order in Python 3.x or the order in ``_order_`` in Python 2.7; +if no ``_order_`` was specified in Python 2.7 then the order of +``__members__`` is either increasing value or alphabetically by name. + +If you give your ``Enum`` subclass extra methods, like the `Planet`_ +class above, those methods will show up in a `dir` of the member, +but not of the class (in Python 3.x):: + + --> dir(Planet) + ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', + 'VENUS', '__class__', '__doc__', '__members__', '__module__'] + --> dir(Planet.EARTH) + ['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value'] + +A ``__new__`` method will only be used for the creation of the +``Enum`` members -- after that it is replaced. This means if you wish to +change how ``Enum`` members are looked up you either have to write a +helper function or a ``classmethod``. + +.. note:: + + If you create your own ``__new__`` you should set the ``_value_`` in it; + if you do not, aenum will try to, but will raise a ``TypeError`` if it + cannot. + +If the stdlib ``enum`` is available (Python 3.4+ and it hasn't been shadowed +by, for example, ``enum34``) then aenum will be a subclass of it. + +To use the ``AddValue``, ``MultiValue``, ``NoAlias``, and ``Unique`` flags +in Py2 or Py2/Py3 codebases, use ``_settings_ = ...`` in the class body. + +To use ``init`` in Py2 or Py2/Py3 codebases use ``_init_`` in the class body. + +To use ``start`` in Py2 or Py2/Py3 codebases use ``_start_`` in the class body. + +When creating class bodies dynamically, put any variables you need to use into +``_ignore_``:: + + >>> from datetime import timedelta + >>> from aenum import NoAlias + >>> 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' + ... + >>> hasattr(Period, '_ignore_') + False + >>> hasattr(Period, 'Period') + False + >>> hasattr(Period, 'i') + False + +The name listed in ``_ignore_``, as well as ``_ignore_`` itself, will not be +present in the final enumeration as neither attributes nor members. + +.. note:: + + except for __dunder__ attributes/methods, all _sunder_ attributes must + be before any thing else in the class body + +.. note:: + + all _sunder_ attributes that affect member creation are only looked up in + the last ``Enum`` class listed in the class header + + +Creating NamedTuples +-------------------- + +Simple +^^^^^^ + +The most common way to create a new NamedTuple will be via the functional API:: + + >>> from aenum import NamedTuple + >>> Book = NamedTuple('Book', 'title author genre', module=__name__) + +This creates a ``NamedTuple`` called ``Book`` that will always contain three +items, each of which is also addressable as ``title``, ``author``, or ``genre``. + +``Book`` instances can be created using positional or keyword argements or a +mixture of the two:: + + >>> b1 = Book('Lord of the Rings', 'J.R.R. Tolkien', 'fantasy') + >>> b2 = Book(title='Jhereg', author='Steven Brust', genre='fantasy') + >>> b3 = Book('Empire', 'Orson Scott Card', genre='scifi') + +If too few or too many arguments are used a ``TypeError`` will be raised:: + + >>> b4 = Book('Hidden Empire') + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): author, genre + >>> b5 = Book(genre='business') + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): title, author + +As a ``class`` the above ``Book`` ``NamedTuple`` would look like:: + + >>> class Book(NamedTuple): + ... title = 0 + ... author = 1 + ... genre = 2 + ... + +For compatibility with the stdlib ``namedtuple``, NamedTuple also has the +``_asdict``, ``_make``, and ``_replace`` methods, and the ``_fields`` +attribute, which all function similarly:: + + >>> 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) + + >>> pixel._asdict() + OrderedDict([('x', 99), ('y', -101), ('r', 255), ('g', 128), ('b', 0)]) + + >>> Point._make((4, 5)) + Point(x=4, y=5) + + >>> purple = Color(127, 0, 127) + >>> mid_gray = purple._replace(g=127) + >>> mid_gray + Color(r=127, g=127, b=127) + + >>> pixel._fields + ['x', 'y', 'r', 'g', 'b'] + + >>> Pixel._fields + ['x', 'y', 'r', 'g', 'b'] + + +Advanced +^^^^^^^^ + +The simple method of creating ``NamedTuples`` requires always specifying all +possible arguments when creating instances; failure to do so will raise +exceptions:: + + >>> class Point(NamedTuple): + ... x = 0 + ... y = 1 + ... + >>> Point() + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): x, y + >>> Point(1) + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): y + >>> Point(y=2) + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): x + +However, it is possible to specify both docstrings and default values when +creating a ``NamedTuple`` using the class method:: + + >>> class Point(NamedTuple): + ... x = 0, 'horizontal coordinate', 0 + ... y = 1, 'vertical coordinate', 0 + ... + >>> Point() + Point(x=0, y=0) + >>> Point(1) + Point(x=1, y=0) + >>> Point(y=2) + Point(x=0, y=2) + +It is also possible to create ``NamedTuples`` that only have named attributes +for certain fields; any fields without names can still be accessed by index:: + + >>> class Person(NamedTuple): + ... fullname = 2 + ... phone = 5 + ... + >>> p = Person('Ethan', 'Furman', 'Ethan Furman', + ... 'ethan at stoneleaf dot us', + ... 'ethan.furman', '999.555.1212') + >>> p + Person('Ethan', 'Furman', 'Ethan Furman', 'ethan at stoneleaf dot us', + 'ethan.furman', '999.555.1212') + >>> p.fullname + 'Ethan Furman' + >>> p.phone + '999.555.1212' + >>> p[0] + 'Ethan' + +In the above example the last named field was also the last field possible; in +those cases where you don't need to have the last possible field named, you can +provide a ``_size_`` of ``TupleSize.minimum`` to declare that more fields are +okay:: + + >>> from aenum import TupleSize + >>> class Person(NamedTuple): + ... _size_ = TupleSize.minimum + ... first = 0 + ... last = 1 + ... + +or, optionally if using Python 3:: + + >>> class Person(NamedTuple, size=TupleSize.minimum): # doctest: +SKIP + ... first = 0 + ... last = 1 + +and in use:: + + >>> Person('Ethan', 'Furman') + Person(first='Ethan', last='Furman') + + >>> Person('Ethan', 'Furman', 'ethan.furman') + Person('Ethan', 'Furman', 'ethan.furman') + + >>> Person('Ethan', 'Furman', 'ethan.furman', 'yay Python!') + Person('Ethan', 'Furman', 'ethan.furman', 'yay Python!') + + >>> Person('Ethan') + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): last + +Also, for those cases where even named fields may not be present, you can +specify ``TupleSize.variable``:: + + >>> class Person(NamedTuple): + ... _size_ = TupleSize.variable + ... first = 0 + ... last = 1 + ... + + >>> Person('Ethan') + Person('Ethan') + + >>> Person(last='Furman') + Traceback (most recent call last): + ... + TypeError: values not provided for field(s): first + +Creating new ``NamedTuples`` from existing ``NamedTuples`` is simple:: + + >>> Point = NamedTuple('Point', 'x y') + >>> Color = NamedTuple('Color', 'r g b') + >>> Pixel = NamedTuple('Pixel', Point+Color, module=__name__) + >>> Pixel + + +The existing fields in the bases classes are renumbered to fit the new class, +but keep their doc strings and default values. If you use standard +subclassing:: + + >>> Point = NamedTuple('Point', 'x y') + >>> class Pixel(Point): + ... r = 2, 'red component', 11 + ... g = 3, 'green component', 29 + ... b = 4, 'blue component', 37 + ... + >>> Pixel.__fields__ + ['x', 'y', 'r', 'g', 'b'] + +You must manage the numbering yourself. + + +Creating NamedConstants +----------------------- + +A ``NamedConstant`` class is created much like an ``Enum``:: + + >>> from aenum import NamedConstant + >>> class Konstant(NamedConstant): + ... PI = 3.14159 + ... TAU = 2 * PI + + >>> Konstant.PI + + + >> print(Konstant.PI) + 3.14159 + + >>> Konstant.PI = 'apple' + Traceback (most recent call last): + ... + AttributeError: cannot rebind constant + + >>> del Konstant.PI + Traceback (most recent call last): + ... + AttributeError: cannot delete constant 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, 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), '') + 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), '') + 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), '') + self.assertEqual(repr(Perm.W), '') + self.assertEqual(repr(Perm.X), '') + self.assertEqual(repr(Perm.R | Perm.W), '') + self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') + self.assertEqual(repr(Perm(0)), '') + self.assertEqual(repr(~Perm.R), '') + self.assertEqual(repr(~Perm.W), '') + self.assertEqual(repr(~Perm.X), '') + self.assertEqual(repr(~(Perm.R | Perm.W)), '') + self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') + self.assertEqual(repr(Perm(~0)), '') + + Open = self.Open + self.assertEqual(repr(Open.RO), '') + self.assertEqual(repr(Open.WO), '') + self.assertEqual(repr(Open.AC), '') + self.assertEqual(repr(Open.RO | Open.CE), '') + self.assertEqual(repr(Open.WO | Open.CE), '') + self.assertEqual(repr(~Open.RO), '') + self.assertEqual(repr(~Open.WO), '') + self.assertEqual(repr(~Open.AC), '') + self.assertEqual(repr(~(Open.RO | Open.CE)), '') + self.assertEqual(repr(~(Open.WO | Open.CE)), '') + + 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<' % (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), '') + + 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), '') + self.assertEqual(repr(Perm.W), '') + self.assertEqual(repr(Perm.X), '') + self.assertEqual(repr(Perm.R | Perm.W), '') + self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') + self.assertEqual(repr(Perm(0)), '') + self.assertEqual(repr(~Perm.R), '') + self.assertEqual(repr(~Perm.W), '') + self.assertEqual(repr(~Perm.X), '') + self.assertEqual(repr(~(Perm.R | Perm.W)), '') + self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') + # + 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), '') + self.assertEqual(repr(Perm.W), '') + self.assertEqual(repr(Perm.X), '') + self.assertEqual(repr(Perm.R | Perm.W), '') + self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') + self.assertEqual(repr(Perm(0)), '') + self.assertEqual(repr(~Perm.R), '') + self.assertEqual(repr(~Perm.W), '') + self.assertEqual(repr(~Perm.X), '') + self.assertEqual(repr(~(Perm.R | Perm.W)), '') + self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') + self.assertEqual(repr(Perm.R | 8), '') + self.assertEqual(repr(Perm(8)), '') + self.assertEqual(repr(~(Perm.R | 8)), '') + self.assertEqual(repr(Perm(~8)), '') + + 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), '') + self.assertEqual(repr(Perm.W), '') + self.assertEqual(repr(Perm.X), '') + self.assertEqual(repr(Perm.R | Perm.W), '') + self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') + self.assertEqual(repr(Perm(0)), '') + self.assertEqual(repr(~Perm.R), '') + self.assertEqual(repr(~Perm.W), '') + self.assertEqual(repr(~Perm.X), '') + self.assertEqual(repr(~(Perm.R | Perm.W)), '') + self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') + 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), '') + self.assertEqual(repr(Open.WO), '') + self.assertEqual(repr(Open.AC), '') + self.assertEqual(repr(Open.RO | Open.CE), '') + self.assertEqual(repr(Open.WO | Open.CE), '') + self.assertEqual(repr(~Open.RO), '') + self.assertEqual(repr(~Open.WO), '') + self.assertEqual(repr(~Open.AC), '') + self.assertEqual(repr(~(Open.RO | Open.CE)), '') + self.assertEqual(repr(~(Open.WO | Open.CE)), '') + 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), '') + self.assertEqual(repr(Open.WO), '') + self.assertEqual(repr(Open.AC), '') + self.assertEqual(repr(Open.RO | Open.CE), '') + self.assertEqual(repr(Open.WO | Open.CE), '') + self.assertEqual(repr(~Open.RO), '') + self.assertEqual(repr(~Open.WO), '') + self.assertEqual(repr(~Open.AC), '') + self.assertEqual(repr(~(Open.RO | Open.CE)), '') + self.assertEqual(repr(~(Open.WO | Open.CE)), '') + self.assertEqual(repr(Open(~4)), '') + self.assertEqual(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.EJECT + self.assertEqual(repr(Open.RO), '') + self.assertEqual(repr(Open.WO), '') + self.assertEqual(repr(Open.AC), '') + self.assertEqual(repr(Open.RO | Open.CE), '') + self.assertEqual(repr(Open.WO | Open.CE), '') + self.assertEqual(repr(~Open.RO), '') + self.assertEqual(repr(~Open.WO), '') + self.assertEqual(repr(~Open.AC), '') + self.assertEqual(repr(~(Open.RO | Open.CE)), '') + self.assertEqual(repr(~(Open.WO | Open.CE)), '') + 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< 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' is a duplicate of ', 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' is a duplicate of ', 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) + diff --git a/venv/Lib/site-packages/aenum/test_v3.py b/venv/Lib/site-packages/aenum/test_v3.py new file mode 100644 index 00000000..62453df1 --- /dev/null +++ b/venv/Lib/site-packages/aenum/test_v3.py @@ -0,0 +1,1982 @@ +from . import EnumMeta, Enum, IntEnum, Flag, IntFlag, StrEnum, UniqueEnum, AutoEnum, AddValueEnum +from . import NamedTuple, TupleSize, MagicValue, AddValue, NoAlias, Unique, MultiValue +from . import AutoNumberEnum,MultiValueEnum, OrderedEnum, unique, skip, extend_enum, auto +from . import StdlibEnumMeta, StdlibEnum, StdlibIntEnum, StdlibFlag, StdlibIntFlag, StdlibStrEnum +from . import pyver, PY3_3, PY3_4, PY3_5, PY3_6, PY3_11 +from . import add_stdlib_integration, remove_stdlib_integration + +from collections import OrderedDict +from datetime import timedelta +from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL +from unittest import TestCase, main + +import os +import sys +import tempfile +import textwrap +import unittest + +try: + import pyparsing +except (ImportError, SyntaxError): + pyparsing = None + +try: + RecursionError +except NameError: + # python3.4 + RecursionError = RuntimeError + +class TestEnumV3(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 + + @unittest.skipUnless(StdlibEnumMeta, 'Stdlib enum not available') + def test_stdlib_inheritence(self): + # 3.4 + self.assertTrue(issubclass(self.Season, StdlibEnum)) + self.assertTrue(isinstance(self.Season.SPRING, StdlibEnum)) + # + if pyver >= PY3_6: + class AFlag(Flag): + one = 1 + self.assertTrue(issubclass(AFlag, StdlibEnum)) + self.assertTrue(isinstance(AFlag.one, StdlibEnum)) + self.assertTrue(issubclass(AFlag, StdlibFlag)) + self.assertTrue(isinstance(AFlag.one, StdlibFlag)) + # + class AnIntFlag(IntFlag): + one = 1 + self.assertTrue(issubclass(AnIntFlag, StdlibEnum)) + self.assertTrue(isinstance(AnIntFlag.one, StdlibEnum)) + self.assertTrue(issubclass(AnIntFlag, StdlibFlag)) + self.assertTrue(isinstance(AnIntFlag.one, StdlibFlag)) + self.assertTrue(issubclass(AnIntFlag, StdlibIntFlag)) + self.assertTrue(isinstance(AnIntFlag.one, StdlibIntFlag)) + # + if pyver >= PY3_11: + class AStrEnum(StrFlag): + one = '1' + self.assertTrue(issubclass(AStrEnum, StdlibEnum)) + self.assertTrue(isinstance(AStrEnum.one, StdlibEnum)) + self.assertTrue(issubclass(AStrEnum, StdlibStrEnum)) + self.assertTrue(isinstance(AStrEnum.one, StdlibStrEnum)) + + @unittest.skipUnless(StdlibEnumMeta, 'Stdlib enum not available') + def test_stdlib_bad_getattribute(self): + class BadEnumType(StdlibEnumMeta): + def __getattribute__(cls, name): + obj = super().__getattribute__(name) + if isinstance(obj, cls): + obj.deprecate() + return obj + with self.assertRaisesRegex(RecursionError, 'endless recursion'): + class BaseEnum(StdlibEnum): + pass + class BadEnum(BaseEnum, metaclass=BadEnumType): + FOO = 'bar' + try: + remove_stdlib_integration() + class OkayEnum(StdlibEnum, metaclass=BadEnumType): + FOO = 'bar' + finally: + add_stdlib_integration() + + @unittest.skipUnless(pyver >= PY3_5, '__qualname__ requires python 3.5 or greater') + def test_pickle_enum_function_with_qualname(self): + Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition') + globals()['spanish_inquisition'] = Theory + test_pickle_dump_load(self.assertTrue, Theory.rule) + test_pickle_dump_load(self.assertTrue, Theory) + + 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_auto_turns_off(self): + with self.assertRaises(NameError): + class Color(Enum, settings=MagicValue): + red + green + blue + def hello(self): + print('Hello! My serial is %s.' % self.value) + rose + with self.assertRaises(NameError): + class Color(Enum, settings=MagicValue): + red + green + blue + def __init__(self, *args): + pass + rose + + def test_magic(self): + class Color(Enum, settings=MagicValue): + red, green, blue + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + self.assertEqual(Color.red.value, 1) + + def test_ignore_not_overridden(self): + with self.assertRaisesRegex(TypeError, 'object is not callable'): + class Color(Flag): + _ignore_ = 'irrelevent' + _settings_ = MagicValue + @property + def shade(self): + print('I am light', self.name.lower()) + + def test_magic_start(self): + class Color(Enum, settings=MagicValue, start=0): + red, green, blue + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + self.assertEqual(Color.red.value, 0) + + def test_dir_on_class(self): + Season = self.Season + self.assertEqual( + set(dir(Season)), + set(['__class__', '__doc__', '__members__', '__module__', + 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER', + '__init_subclass__', '__name__', '__getitem__', '__len__', + '__contains__', '__iter__', '__qualname__', + ])) + + def test_dir_on_item(self): + Season = self.Season + self.assertEqual( + set(dir(Season.WINTER)), + set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value', 'values']), + ) + + def test_dir_with_added_behavior(self): + class Test(Enum): + this = 'that' + these = 'those' + def wowser(self): + return ("Wowser! I'm %s!" % self.name) + self.assertEqual( + set(dir(Test)), + set([ + '__class__', '__doc__', '__members__', '__module__', 'this', 'these', + '__init_subclass__', '__name__', '__getitem__', '__len__', + '__contains__', '__iter__', '__qualname__', + ])) + self.assertEqual( + set(dir(Test.this)), + set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value', 'values', 'wowser']), + ) + + def test_dir_on_sub_with_behavior_on_super(self): + # see issue22506 + class SuperEnum(Enum): + def invisible(self): + return "did you see me?" + class SubEnum(SuperEnum): + sample = 5 + self.assertEqual( + set(dir(SubEnum.sample)), + set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value', 'values', 'invisible']), + ) + + def test_members_are_always_ordered(self): + class AlwaysOrdered(Enum): + first = 1 + second = 2 + third = 3 + self.assertTrue(type(AlwaysOrdered.__members__) is OrderedDict) + + def test_comparisons(self): + def bad_compare(): + Season.SPRING > 4 + Season = self.Season + self.assertNotEqual(Season.SPRING, 1) + self.assertRaises(TypeError, bad_compare) + + class Part(Enum): + SPRING = 1 + CLIP = 2 + BARREL = 3 + + self.assertNotEqual(Season.SPRING, Part.SPRING) + def bad_compare(): + Season.SPRING < Part.CLIP + self.assertRaises(TypeError, bad_compare) + + def test_duplicate_name(self): + with self.assertRaises(TypeError): + class Color1(Enum): + red = 1 + green = 2 + blue = 3 + red = 4 + + with self.assertRaises(TypeError): + class Color2(Enum): + red = 1 + green = 2 + blue = 3 + def red(self): + return 'red' + + with self.assertRaises(TypeError): + class Color3(Enum): + @property + def red(self): + return 'redder' + red = 1 + green = 2 + blue = 3 + + def test_duplicate_value_with_unique(self): + with self.assertRaises(ValueError): + class Color(Enum, settings=Unique): + red = 1 + green = 2 + blue = 3 + rojo = 1 + + def test_duplicate_value_with_noalias(self): + class Color(Enum, settings=NoAlias): + red = 1 + green = 2 + blue = 3 + rojo = 1 + self.assertFalse(Color.red is Color.rojo) + self.assertEqual(Color.red.value, 1) + self.assertEqual(Color.rojo.value, 1) + self.assertEqual(len(Color), 4) + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.rojo]) + + def test_noalias_value_lookup(self): + class Color(Enum, settings=NoAlias): + red = 1 + green = 2 + blue = 3 + rojo = 1 + self.assertRaises(TypeError, Color, 2) + + def test_multivalue(self): + class Color(Enum, settings=MultiValue): + red = 1, 'red' + green = 2, 'green' + blue = 3, 'blue' + self.assertEqual(Color.red.value, 1) + self.assertIs(Color('green'), Color.green) + self.assertEqual(Color.blue.values, (3, 'blue')) + + def test_multivalue_with_duplicate_values(self): + with self.assertRaises(ValueError): + class Color(Enum, settings=MultiValue): + red = 1, 'red' + green = 2, 'green' + blue = 3, 'blue', 'red' + + def test_multivalue_with_duplicate_values_and_noalias(self): + with self.assertRaises(TypeError): + class Color(Enum, settings=(MultiValue, NoAlias)): + red = 1, 'red' + green = 2, 'green' + blue = 3, 'blue', 'red' + + def test_multivalue_and_auto(self): + with self.assertRaisesRegex(TypeError, r'MultiValue and MagicValue are mutually exclusive'): + class Color(Enum, settings=(MultiValue, MagicValue)): + red + green = 3, 'green' + blue + + def test_autonumber_and_init(self): + class Field(IntEnum, settings=AddValue, init='__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') + self.assertFalse(hasattr(Field, '_order_')) + + def test_autovalue_and_init(self): + class Field(IntEnum, init='value __doc__'): + TYPE = "Char, Date, Logical, etc." + START = "Field offset in record" + self.assertEqual(Field.TYPE, 1) + self.assertEqual(Field.START.__doc__, 'Field offset in record') + + def test_autonumber_and_start(self): + class Field(IntEnum, init='__doc__', settings=AddValue, start=0): + 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_autonumber_and_init_and_some_values(self): + class Field(IntEnum, 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_autonumber_with_irregular_values(self): + class Point(AutoNumberEnum, init='x y'): + first = 7, 9 + second = 11, 13 + self.assertEqual(Point.first.value, 1) + self.assertEqual(Point.first.x, 7) + self.assertEqual(Point.first.y, 9) + self.assertEqual(Point.second.value, 2) + self.assertEqual(Point.second.x, 11) + self.assertEqual(Point.second.y, 13) + with self.assertRaisesRegex(TypeError, '.*number of fields provided do not match init ...x., .y.. != .3, 11, 13..'): + class Point(AutoNumberEnum, init='x y'): + first = 7, 9 + second = 3, 11, 13 + class Color(AutoNumberEnum, init='__doc__'): + # interactions between AutoNumberEnum and _generate_next_value_ may not be pretty + red = () + green = 'red' + blue = () + self.assertTrue(Color.red.__doc__, 1) + self.assertEqual(Color.green.__doc__, 'red') + self.assertTrue(Color.blue.__doc__, 2) + + def test_autonumber_and_property(self): + with self.assertRaises(TypeError): + class Color(AutoEnum): + _ignore_ = () + red = () + green = () + blue = () + @property + def cap_name(self) -> str: + return self.name.title() + + def test_autoenum(self): + class Color(AutoEnum): + red + green + blue + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + self.assertEqual([m.value for m in Color], [1, 2, 3]) + self.assertEqual([m.name for m in Color], ['red', 'green', 'blue']) + + def test_autoenum_with_str(self): + class Color(AutoEnum): + def _generate_next_value_(name, start, count, last_values): + return name + red + green + blue + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) + self.assertEqual([m.value for m in Color], ['red', 'green', 'blue']) + self.assertEqual([m.name for m in Color], ['red', 'green', 'blue']) + + def test_autoenum_and_default_ignore(self): + class Color(AutoEnum): + red + green + blue + @property + def cap_name(self): + return self.name.title() + self.assertEqual(Color.blue.cap_name, 'Blue') + + def test_autonumber_and_overridden_ignore(self): + with self.assertRaises(TypeError): + class Color(AutoEnum): + _ignore_ = 'staticmethod' + red + green + blue + @property + def cap_name(self) -> str: + return self.name.title() + + def test_autonumber_and_multiple_assignment(self): + class Color(AutoEnum): + _ignore_ = 'property' + red + green + blue = cyan + @property + def cap_name(self) -> str: + return self.name.title() + self.assertEqual(Color.blue.cap_name, 'Cyan') + + def test_multivalue_and_autonumber_inherited(self): + class Measurement(int, Enum, settings=(MultiValue, AddValue), start=0): + one = "20110721" + two = "20120911" + three = "20110518" + M = Measurement + self.assertEqual(M.one, 0) + self.assertTrue(M.one is M(0) is M('20110721')) + + def test_combine_new_settings_with_old_settings(self): + class Auto(Enum, settings=Unique): + pass + with self.assertRaises(ValueError): + class AutoUnique(Auto, settings=MagicValue): + BLAH + BLUH + 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_extend_enum_plain(self): + class Color(UniqueEnum): + red = 1 + green = 2 + blue = 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(len(Color), 4) + + def test_extend_enum_shadow(self): + class Color(UniqueEnum): + 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(len(Color), 4) + self.assertEqual(Color.red.value, 1) + + def test_extend_enum_generate(self): + class Foo(AutoEnum): + def _generate_next_value_(name, start, count, values, *args, **kwds): + return name + a + b + # + extend_enum(Foo, 'c') + self.assertEqual(Foo.a.value, 'a') + self.assertEqual(Foo.b.value, 'b') + self.assertEqual(Foo.c.value, 'c') + + def test_extend_enum_unique_with_duplicate(self): + with self.assertRaises(ValueError): + class Color(Enum, settings=Unique): + red = 1 + green = 2 + blue = 3 + extend_enum(Color, 'value', 1) + + def test_extend_enum_multivalue_with_duplicate(self): + with self.assertRaises(ValueError): + class Color(Enum, settings=MultiValue): + red = 1, 'rojo' + green = 2, 'verde' + blue = 3, 'azul' + extend_enum(Color, 'value', 2) + + def test_extend_enum_noalias_with_duplicate(self): + class Color(Enum, settings=NoAlias): + red = 1 + green = 2 + blue = 3 + extend_enum(Color, 'value', 3, ) + self.assertRaises(TypeError, Color, 3) + self.assertFalse(Color.value is Color.blue) + self.assertTrue(Color.value.value, 3) + + def test_no_duplicates(self): + def bad_duplicates(): + class Color(UniqueEnum): + red = 1 + green = 2 + blue = 3 + class Color(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_auto_number(self): + class Color(Enum, settings=MagicValue): + red + blue + green + + 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, settings=MagicValue): + def _generate_next_value_(name, start, count, last): + return name + red + blue + green + + 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, settings=MagicValue): + red + blue + green + + 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): + _settings_ = MagicValue + red = 'red' + blue + self.assertEqual(Color.blue.value, 1) + + def test_auto_garbage_corrected(self): + class Color(Enum, settings=MagicValue): + red = 'red' + blue = 2 + green + + 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 Dupes(Enum, settings=MagicValue): + first = primero + second + third + self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) + + 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 + + if pyver >= PY3_3: + def test_missing(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + @classmethod + def _missing_(cls, item): + if item == 'three': + return cls.blue + elif item == 'bad return': + # trigger internal error + return 5 + elif item == 'error out': + raise ZeroDivisionError + else: + # trigger not found + return None + self.assertIs(Color('three'), Color.blue) + self.assertRaises(ValueError, Color, 7) + try: + Color('bad return') + except TypeError as exc: + self.assertTrue(isinstance(exc.__cause__, ValueError)) + else: + raise Exception('Exception not raised.') + try: + Color('error out') + except ZeroDivisionError as exc: + self.assertTrue(isinstance(exc.__cause__, ValueError)) + else: + raise Exception('Exception not raised.') + + 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) + + def test_nested_classes_in_enum_do_not_create_members(self): + """Support locally-defined nested classes.""" + # manually set __qualname__ to remove testing framework noise + class Outer(Enum): + __qualname__ = "Outer" + a = 1 + b = 2 + 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], + ) + + if pyver == PY3_4: + def test_class_nested_enum_and_pickle_protocol_four(self): + # would normally just have this directly in the class namespace + class NestedEnum(Enum): + twigs = 'common' + shiny = 'rare' + + self.__class__.NestedEnum = NestedEnum + self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ + test_pickle_exception( + self.assertRaises, PicklingError, self.NestedEnum.twigs, + protocol=(0, 3)) + test_pickle_dump_load(self.assertTrue, self.NestedEnum.twigs, + protocol=(4, HIGHEST_PROTOCOL)) + + elif pyver >= PY3_5: + def test_class_nested_enum_and_pickle_protocol_four(self): + # would normally just have this directly in the class namespace + class NestedEnum(Enum): + twigs = 'common' + shiny = 'rare' + + self.__class__.NestedEnum = NestedEnum + self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ + test_pickle_dump_load(self.assertTrue, self.NestedEnum.twigs, + protocol=(0, HIGHEST_PROTOCOL)) + + if pyver >= PY3_4: + def test_enum_injection(self): + class Color(Enum): + _order_ = 'BLACK WHITE' + BLACK = Color('black', '#000') + WHITE = Color('white', '#fff') + + def __init__(self, label, hex): + self.label = label + self.hex = hex + + self.assertEqual([Color.BLACK, Color.WHITE], list(Color)) + self.assertEqual(Color.WHITE.hex, '#fff') + self.assertEqual(Color.BLACK.label, 'black') + + def test_subclasses_with_getnewargs_ex(self): + class NamedInt(int): + __qualname__ = 'NamedInt' # needed for pickle protocol 4 + def __new__(cls, *args): + _args = args + if len(args) < 2: + 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_ex__(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 "{}({!r}, {})".format(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( + '({0} + {1})'.format(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.assertIs(NEI.__new__, 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, protocol=(4, HIGHEST_PROTOCOL)) + self.assertEqual(NEI.y.value, 2) + test_pickle_dump_load(self.assertTrue, NEI.y, protocol=(4, HIGHEST_PROTOCOL)) + + +class TestOrderV3(TestCase): + """ + Test definition order versus _order_ order. + """ + + 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_same_members_wrong_order(self): + with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): + class Color(Enum): + _order_ = 'red green blue' + red = 1 + blue = 3 + green = 2 + + def test_order_has_extra_members(self): + with self.assertRaisesRegex(TypeError, '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, '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, '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, '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_same_members_wrong_order_falg(self): + with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): + class Color(Flag): + _order_ = 'red green blue' + red = 1 + blue = 4 + green = 2 + + def test_order_has_extra_members_flag(self): + with self.assertRaisesRegex(TypeError, '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, '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, '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, 'member order does not match _order_'): + class Color(Flag): + _order_ = 'red green blue' + red = 1 + green = 2 + blue = 4 + purple = 8 + verde = green + + +class TestNamedTupleV3(TestCase): + + 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') + self.assertEqual(b[2], '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(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') + + + +class TestStackoverflowAnswersV3(TestCase): + + def test_self_referential_directions(self): + # https://stackoverflow.com/a/64000706/208880 + class Directions(Enum): + # + 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): + # + 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): + __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_create_C_like_Enum(self): + # https://stackoverflow.com/a/35965438/208880 + class Id(Enum, settings=MagicValue, start=0): + # + NONE # 0x0 + HEARTBEAT # 0x1 + FLUID_TRANSFER_REQUEST + FLUID_TRANSFER_STATUS_MSG + FLUID_TRANSFER_ERROR_MSG + # ... + # + # Camera App Messages + START_SENDING_PICTURES = 0x010000 + STOP_SENDING_PICTURES + START_RECORDING_VIDEO_REQ + STOP_RECORDING_VIDEO_REQ + # ... + # + # Sensor Calibration + VOLUME_REQUEST = 0x020000 + START_CAL + CLI_COMMAND_REQUEST + CLI_COMMAND_RESPONSE + # + # File Mananger + NEW_DELIVERY_REQ = 0x30000 + GET_DELIVERY_FILE_REQ + GET_FILE_REQ + # + ACK_NACK + RESPONSE + # + LAST_ID + # + self.assertEqual(Id.NONE.value, 0) + self.assertEqual(Id.FLUID_TRANSFER_ERROR_MSG.value, 4) + self.assertEqual(Id.START_SENDING_PICTURES.value, 0x010000) + self.assertEqual(Id.STOP_RECORDING_VIDEO_REQ.value, 0x010003) + self.assertEqual(Id.START_CAL.value, 0x020001) + self.assertEqual(Id.LAST_ID.value, 0x30005) + + + @unittest.skipUnless(pyparsing, 'pyparsing not installed') + def test_c_header_scanner(self): + # https://stackoverflow.com/questions/58732872/208880 + with open(os.path.join(tempdir, 'c_plus_plus.h'), 'w') as fh: + fh.write(""" + stuff before + enum hello { + Zero, + One, + Two, + Three, + Five=5, + Six, + Ten=10 + }; + in the middle + enum blah + { + alpha, + beta, + gamma = 10 , + zeta = 50 + }; + at the end + """) + from pyparsing import Group, Optional, Suppress, Word, ZeroOrMore + from pyparsing import alphas, alphanums, nums + # + CPPEnum = None + class CPPEnumType(EnumMeta): + # + @classmethod + def __prepare__(metacls, clsname, bases, **kwds): + # return a standard dictionary for the initial processing + return {} + # + def __init__(clsname, *args , **kwds): + super(CPPEnumType, clsname).__init__(*args) + # + def __new__(metacls, clsname, bases, clsdict, **kwds): + if CPPEnum is None: + # first time through, ignore the rest + enum_dict = super(CPPEnumType, metacls).__prepare__(clsname, bases, **kwds) + enum_dict.update(clsdict) + return super(CPPEnumType, metacls).__new__(metacls, clsname, bases, enum_dict, **kwds) + members = [] + # + # remove _file and _name using `pop()` as they will cause problems in EnumMeta + try: + file = clsdict.pop('_file') + except KeyError: + raise TypeError('_file not specified') + cpp_enum_name = clsdict.pop('_name', clsname.lower()) + with open(file) as fh: + file_contents = fh.read() + # + # syntax we don't want to see in the final parse tree + LBRACE, RBRACE, EQ, COMMA = map(Suppress, "{}=,") + _enum = Suppress("enum") + identifier = Word(alphas, alphanums + "_") + integer = Word(nums) + enumValue = Group(identifier("name") + Optional(EQ + integer("value"))) + enumList = Group(enumValue + ZeroOrMore(COMMA + enumValue)) + enum = _enum + identifier("enum") + LBRACE + enumList("names") + RBRACE + # + # find the cpp_enum_name ignoring other syntax and other enums + for item, start, stop in enum.scanString(file_contents): + if item.enum != cpp_enum_name: + continue + id = 0 + for entry in item.names: + if entry.value != "": + id = int(entry.value) + members.append((entry.name.upper(), id)) + id += 1 + # + # get the real EnumDict + enum_dict = super(CPPEnumType, metacls).__prepare__(clsname, bases, **kwds) + # transfer the original dict content, names starting with '_' 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(CPPEnumType, metacls).__new__(metacls, clsname, bases, enum_dict, **kwds) + # + class CPPEnum(IntEnum, metaclass=CPPEnumType): + pass + # + class Hello(CPPEnum): + _file = os.path.join(tempdir, 'c_plus_plus.h') + # + class Blah(CPPEnum): + _file = os.path.join(tempdir, 'c_plus_plus.h') + _name = 'blah' + # + self.assertEqual( + list(Hello), + [Hello.ZERO, Hello.ONE, Hello.TWO, Hello.THREE, Hello.FIVE, Hello.SIX, Hello.TEN], + ) + self.assertEqual(Hello.ZERO.value, 0) + self.assertEqual(Hello.THREE.value, 3) + self.assertEqual(Hello.SIX.value, 6) + self.assertEqual(Hello.TEN.value, 10) + # + self.assertEqual( + list(Blah), + [Blah.ALPHA, Blah.BETA, Blah.GAMMA, Blah.ZETA], + ) + self.assertEqual(Blah.ALPHA.value, 0) + self.assertEqual(Blah.BETA.value, 1) + self.assertEqual(Blah.GAMMA.value, 10) + self.assertEqual(Blah.ZETA.value, 50) + +class TestIssuesV3(TestCase): + """ + Problems that were stated in issues. + """ + + def test_auto_multi_int_1(self): + class Measurement(int, AddValueEnum, MultiValueEnum, 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(0), Measurement.one) + self.assertIs(Measurement('20110721'), Measurement.one) + self.assertIs(Measurement(1), Measurement.two) + self.assertIs(Measurement('20120911'), Measurement.two) + self.assertIs(Measurement(2), Measurement.three) + self.assertIs(Measurement('20110518'), Measurement.three) + + def test_auto_multi_int_2(self): + class Measurement(int, Enum, settings=(MultiValue, AddValue), 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(0), Measurement.one) + self.assertIs(Measurement('20110721'), Measurement.one) + self.assertIs(Measurement(1), Measurement.two) + self.assertIs(Measurement('20120911'), Measurement.two) + self.assertIs(Measurement(2), Measurement.three) + self.assertIs(Measurement('20110518'), Measurement.three) + + def test_extend_enum_with_init(self): + class Color(Enum, settings=MultiValue, init='foo bar'): + red = '1', 'yes' + green = '2', 'no' + blue = '3', 'maybe' + self.assertEqual(Color.red.value, '1') + self.assertEqual(Color.red.foo, '1') + self.assertEqual(Color.red.bar, 'yes') + extend_enum(Color, 'opacity', '4', 'never') + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.opacity]) + self.assertEqual(Color.opacity.value, '4') + self.assertEqual(Color.opacity.name, 'opacity') + self.assertTrue(Color('4') is Color.opacity) + self.assertTrue(Color('never') is Color.opacity) + +class TestExtendEnumV3(TestCase): + + def test_extend_enum_plain(self): + class Color(Enum): + red = 1 + green = 2 + blue = 3 + self.assertRaisesRegex(TypeError, '.blue. already in use as property..Color.blue: 3.', 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' is a duplicate of ', 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, ' is a duplicate of ', 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' is a duplicate of ', 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): + 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) + + @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') + def test_extend_enum_stdlib(self): + class Color(StdlibEnum): + red = 1 + green = 2 + blue = 3 + self.assertEqual(getattr(Color.red, '_values_', None), None) + 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) + + @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') + def test_extend_enum_plain_stdlib(self): + class Color(StdlibEnum): + 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) + self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.brown]) + self.assertEqual([c.value for c in Color], [1, 2, 3, 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) + + @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') + def test_extend_enum_alias_stdlib(self): + class Color(StdlibEnum): + 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) + + @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') + def test_extend_enum_shadow_property_stdlib(self): + class Color(StdlibEnum): + 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) + + @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') + def test_extend_enum_shadow_base_stdlib(self): + class hohum(object): + def cyan(self): + "cyanize a color" + return self.value + class Color(hohum, StdlibEnum): + 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]) + + @unittest.skipUnless(StdlibIntEnum, 'Stdlib IntEnum not available') + def test_extend_intenum_stdlib(self): + class Index(StdlibIntEnum): + 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) + + @unittest.skipUnless(StdlibIntEnum, 'Stdlib IntEnum not available') + def test_extend_multi_init_stdlib(self): + class HTTPStatus(StdlibIntEnum): + 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, '') + + @unittest.skipUnless(StdlibFlag, 'Stdlib Flag not available') + def test_extend_flag_stdlib(self): + class Color(StdlibFlag): + 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, StdlibFlag)) + + @unittest.skipUnless(StdlibFlag, 'Stdlib Flag not available') + def test_extend_flag_backwards_stdlib(self): + class Color(StdlibFlag): + 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, StdlibFlag)) + # + extend_enum(Color, 'MAGENTA') + self.assertTrue(Color(16) is Color.MAGENTA) + self.assertTrue(isinstance(Color.MAGENTA, Color)) + self.assertEqual(Color.MAGENTA.value,16) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, 32) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(32), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + + @unittest.skipUnless(StdlibIntFlag, 'Stdlib IntFlag not available') + def test_extend_intflag_stdlib(self): + class Color(StdlibIntFlag): + 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, StdlibFlag)) + # + 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) + + @unittest.skipUnless(StdlibIntFlag, 'Stdlib IntFlag not available') + def test_extend_intflag_backwards_stdlib(self): + class Color(StdlibIntFlag): + BLACK = 0 + RED = 1 + GREEN = 2 + BLUE = 4 + if pyver >= PY3_11: + # flags make more sense in 3.11 + length = 5 + MAGENTA = 8 + mauve = 16 + else: + length = 7 + MAGENTA = 16 + mauve = 32 + 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, StdlibFlag)) + # + extend_enum(Color, 'MAGENTA') + self.assertTrue(Color(MAGENTA) is Color.MAGENTA) + self.assertTrue(isinstance(Color.MAGENTA, Color)) + self.assertEqual(Color.MAGENTA.value, MAGENTA) + # + extend_enum(Color, 'mauve') + self.assertEqual(Color.mauve.name, 'mauve') + self.assertEqual(Color.mauve.value, mauve) + self.assertTrue(Color.mauve in Color) + self.assertEqual(Color(mauve), Color.mauve) + self.assertEqual(Color['mauve'], Color.mauve) + self.assertEqual(len(Color), length, list(Color)) + + @unittest.skipUnless(StdlibStrEnum, 'Stdlib StrEnum not available') + def test_extend_strenum_stdlib(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) + + +if __name__ == '__main__': + raise RuntimeError("'test_v3.py' should not be run by itself; it's included in 'test.py'") diff --git a/venv/Lib/site-packages/blendmodes/__init__.py b/venv/Lib/site-packages/blendmodes/__init__.py new file mode 100644 index 00000000..2b6e91ad --- /dev/null +++ b/venv/Lib/site-packages/blendmodes/__init__.py @@ -0,0 +1,2 @@ +"""Use this module to apply a number of blending modes to a background and foreground image +""" diff --git a/venv/Lib/site-packages/blendmodes/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/blendmodes/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da1d6a38859540c7045ecb683d0533d09663f8a9 GIT binary patch literal 285 zcmYjMK~BUl3{3aJYNh>yuX`vDKnU@Iy#NPLP~0LCRtQI!8`a1FW4(jKwLQC z77kb%+ap*%tC#z`M34`hUav|*$_$^&+^+3%{;nK3Rj#=NOU|ekNO3AITqe&sHbSR7cU3|4A>V7DL(? U_MDA5kJD*=`J3cwj{GT5KLp5FlmGw# literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/blendmodes/__pycache__/blend.cpython-39.pyc b/venv/Lib/site-packages/blendmodes/__pycache__/blend.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..231846003cc72829e6134e11092b415beb764453 GIT binary patch literal 13302 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 literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/blendmodes/__pycache__/blendtype.cpython-39.pyc b/venv/Lib/site-packages/blendmodes/__pycache__/blendtype.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c599cfb826eeeee7b7784bf75fcdf6e55c3f9253 GIT binary patch literal 2850 zcmbVONpIUm6sA^^W7*mFG*NsgV4%*S$Dj?ONVFqVmI9h`(}7Td){Jc;6sdA?;#}K9 zZ~Yzp1^pBK1@GEZe?Tui_04dGWG_8bhB@C`W_fSkGXC~9G4S`-@4xuJ*@p3lAnLyk z60Z!Sk$#DQ8Ps46)(ji#CT%tZZiTINo315Odq5wthx9RfL_cGX z=@a%DeafEDK6^@^u|8V+4D8p!HV;knKeY|xzilVPp3dB(!KD9nfA@6#B8ro>AMSq9 z-&Kg%NArm{emnV2X{?1;HsO`fDKW7JqtVzKpEyd(XDrBqOD?oZOzh!oGMl@v=k8SL zt>Q4wlhZtjgl3J>x}(|XP%m1DS zVf;Y|gR zM*LhxmDsSv#GZ@~-*}Ez3WM{Dj7v9Yh?@@FZ%Pg3C+`adg@}DTbe&S3t`c6z6(aV# znX3%`7$;(TG2pb>fhTuY!Zbe10h&{4)+k~-?}n54aTQVg<0{NkEL7r*6@i{|j=ixCDaO+*kSYol^4VNx ziD1XM%n}XJYwmF1&ED$JNLGFpZ)9L7Sgcah5p%UtiHW_}{A8CU1-eB+LFN`Rb>#p{ zBPGzq0xXSCu#Gc{n-G-(NQF_jQwn8efUQC*2^13)s}caF0?0OzEs`JF;;Zyjwu7kv zvc=X_ZUd<>3WX&)p~2EfEhcZ0M_?*|Y~hX~ccEL1idiHqbc+$0UDU)}g%*C0>>*j^ zCD66WVQ~dgl~U*yCj?TJM6h(p15%YWsLB?uCJPgoV#ERjrYbXF z363ZxzZ%I9UsCe(_xIk5#VTfevAN1F;%MRLS-i%|z1qi8gO9g;k%zJZ?tkE?d9b+T z(d8lxP8V2_`ToXVz4y;~x{&WYyc-S0i|_g7D#3@5Vc~!JQh-K#x83-^e{!wqo|$}( zONmf8%dyK~C?ri}(2mdX^_aATu$5+sRIe;8&`3zFuZkdgDPERo7eDQ0ui0z;18nYT A{Qv*} literal 0 HcmV?d00001 diff --git a/venv/Lib/site-packages/blendmodes/blend.py b/venv/Lib/site-packages/blendmodes/blend.py new file mode 100644 index 00000000..4165bfa7 --- /dev/null +++ b/venv/Lib/site-packages/blendmodes/blend.py @@ -0,0 +1,511 @@ +"""Provide blending functions and types. + +Adapted from https://github.com/addisonElliott/pypdn/blob/master/pypdn/reader.py +and https://gitlab.com/inklabapp/pyora/-/blob/master/pyora/BlendNonSep.py +MIT License Copyright (c) 2020 FredHappyface + +Credits to: + +MIT License Copyright (c) 2019 Paul Jewell +For implementing blending from the Open Raster Image Spec + +MIT License Copyright (c) 2018 Addison Elliott +For implementing blending from Paint.NET + +MIT License Copyright (c) 2017 pashango +For implementing a number of blending functions used by other popular image +editors +""" + +from __future__ import annotations + +import warnings + +import numpy as np +from PIL import Image + +from .blendtype import BlendType + + +def normal(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.NORMAL.""" + del background # we don't care about this + return foreground + + +def multiply(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.MULTIPLY.""" + return np.clip(foreground * background, 0.0, 1.0) + + +def additive(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.ADDITIVE.""" + return np.minimum(background + foreground, 1.0) + + +def colourburn(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.COLOURBURN.""" + with np.errstate(divide="ignore"): + return np.where( + foreground != 0.0, np.maximum(1.0 - ((1.0 - background) / foreground), 0.0), 0.0 + ) + + +def colourdodge(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.COLOURDODGE.""" + with np.errstate(divide="ignore"): + return np.where(foreground != 1.0, np.minimum(background / (1.0 - foreground), 1.0), 1.0) + + +def reflect(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.REFLECT.""" + with np.errstate(divide="ignore"): + return np.where( + foreground != 1.0, np.minimum((background ** 2) / (1.0 - foreground), 1.0), 1.0 + ) + + +def glow(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.GLOW.""" + with np.errstate(divide="ignore"): + return np.where( + background != 1.0, np.minimum((foreground ** 2) / (1.0 - background), 1.0), 1.0 + ) + + +def overlay(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.OVERLAY.""" + return np.where( + background < 0.5, + 2 * background * foreground, + 1.0 - (2 * (1.0 - background) * (1.0 - foreground)), + ) + + +def difference(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.DIFFERENCE.""" + return np.abs(background - foreground) + + +def negation(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.NEGATION.""" + return np.maximum(background - foreground, 0.0) + + +def lighten(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.LIGHTEN.""" + return np.maximum(background, foreground) + + +def darken(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.DARKEN.""" + return np.minimum(background, foreground) + + +def screen(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.SCREEN.""" + return background + foreground - background * foreground + + +def xor(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.XOR.""" + # XOR requires int values so convert to uint8 + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + return imageIntToFloat(imageFloatToInt(background) ^ imageFloatToInt(foreground)) + + +def softlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.SOFTLIGHT.""" + return (1.0 - background) * background * foreground + background * ( + 1.0 - (1.0 - background) * (1.0 - foreground) + ) + + +def hardlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.HARDLIGHT.""" + return np.where( + foreground < 0.5, + np.minimum(background * 2 * foreground, 1.0), + np.minimum(1.0 - ((1.0 - background) * (1.0 - (foreground - 0.5) * 2.0)), 1.0), + ) + + +def grainextract(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.GRAINEXTRACT.""" + return np.clip(background - foreground + 0.5, 0.0, 1.0) + + +def grainmerge(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.GRAINMERGE.""" + return np.clip(background + foreground - 0.5, 0.0, 1.0) + + +def divide(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.DIVIDE.""" + return np.minimum((256.0 / 255.0 * background) / (1.0 / 255.0 + foreground), 1.0) + + +def pinlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.PINLIGHT.""" + return np.minimum(background, 2 * foreground) * (foreground < 0.5) + np.maximum( + background, 2 * (foreground - 0.5) + ) * (foreground >= 0.5) + + +def vividlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.VIVIDLIGHT.""" + return colourburn(background, foreground * 2) * (foreground < 0.5) + colourdodge( + background, 2 * (foreground - 0.5) + ) * (foreground >= 0.5) + + +def exclusion(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.EXCLUSION.""" + return background + foreground - (2.0 * background * foreground) + + +def _lum(colours: np.ndarray) -> np.ndarray: + """Luminosity. + + :param colours: x by x by 3 matrix of rgb color components of pixels + :return: x by x by 3 matrix of luminosity of pixels + """ + return (colours[:, :, 0] * 0.299) + (colours[:, :, 1] * 0.587) + (colours[:, :, 2] * 0.114) + + +def _setLum(originalColours: np.ndarray, newLuminosity: np.ndarray) -> np.ndarray: + """Set a new luminosity value for the matrix of color.""" + _colours = originalColours.copy() + _luminosity = _lum(_colours) + deltaLum = newLuminosity - _luminosity + _colours[:, :, 0] += deltaLum + _colours[:, :, 1] += deltaLum + _colours[:, :, 2] += deltaLum + _luminosity = _lum(_colours) + _minColours = np.min(_colours, axis=2) + _MaxColours = np.max(_colours, axis=2) + for i in range(_colours.shape[0]): + for j in range(_colours.shape[1]): + _colour = _colours[i][j] + newLuminosity = _luminosity[i, j] + minColour = _minColours[i, j] + maxColour = _MaxColours[i, j] + if minColour < 0: + _colours[i][j] = newLuminosity + ( + ((_colour - newLuminosity) * newLuminosity) / (newLuminosity - minColour) + ) + if maxColour > 1: + _colours[i][j] = newLuminosity + ( + ((_colour - newLuminosity) * (1 - newLuminosity)) / (maxColour - newLuminosity) + ) + return _colours + + +def _sat(colours: np.ndarray) -> np.ndarray: + """Saturation. + + :param colours: x by x by 3 matrix of rgb color components of pixels + :return: int of saturation of pixels + """ + return np.max(colours, axis=2) - np.min(colours, axis=2) + + +def _setSat(originalColours: np.ndarray, newSaturation: np.ndarray) -> np.ndarray: + """Set a new saturation value for the matrix of color. + + The current implementation cannot be vectorized in an efficient manner, + so it is very slow, + O(m*n) at least. This might be able to be improved with openCL if that is + the direction that the lib takes. + :param c: x by x by 3 matrix of rgb color components of pixels + :param s: int of the new saturation value for the matrix + :return: x by x by 3 matrix of luminosity of pixels + """ + _colours = originalColours.copy() + for i in range(_colours.shape[0]): + for j in range(_colours.shape[1]): + _colour = _colours[i][j] + minI = 0 + midI = 1 + maxI = 2 + if _colour[midI] < _colour[minI]: + minI, midI = midI, minI + if _colour[maxI] < _colour[midI]: + midI, maxI = maxI, midI + if _colour[midI] < _colour[minI]: + minI, midI = midI, minI + if _colour[maxI] - _colour[minI] > 0.0: + _colours[i][j][midI] = ((_colour[midI] - _colour[minI]) * newSaturation[i, j]) / ( + _colour[maxI] - _colour[minI] + ) + _colours[i][j][maxI] = newSaturation[i, j] + else: + _colours[i][j][midI] = 0 + _colours[i][j][maxI] = 0 + _colours[i][j][minI] = 0 + return _colours + + +def hue(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.HUE.""" + return _setLum(_setSat(foreground, _sat(background)), _lum(background)) + + +def saturation(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.SATURATION.""" + return _setLum(_setSat(background, _sat(foreground)), _lum(background)) + + +def colour(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.COLOUR.""" + return _setLum(foreground, _lum(background)) + + +def luminosity(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: + """BlendType.LUMINOSITY.""" + return _setLum(background, _lum(foreground)) + + +def destin( + backgroundAlpha: np.ndarray, + foregroundAlpha: np.ndarray, + backgroundColour: np.ndarray, + foregroundColour: np.ndarray, +): + """'clip' composite mode. + + All parts of 'layer above' which are alpha in 'layer below' will be made + also alpha in 'layer above' + (to whatever degree of alpha they were) + + Destination which overlaps the source, replaces the source. + + Fa = 0; Fb = αs + co = αb x Cb x αs + αo = αb x αs + """ + del foregroundColour # Not used by function + outAlpha = backgroundAlpha * foregroundAlpha + with np.errstate(divide="ignore", invalid="ignore"): + outRGB = np.divide( + np.multiply((backgroundAlpha * foregroundAlpha)[:, :, None], backgroundColour), + outAlpha[:, :, None], + ) + return outRGB, outAlpha + + +def destout( + backgroundAlpha: np.ndarray, + foregroundAlpha: np.ndarray, + backgroundColour: np.ndarray, + foregroundColour: np.ndarray, +): + """Reverse 'Clip' composite mode. + + All parts of 'layer below' which are alpha in 'layer above' will be made + also alpha in 'layer below' + (to whatever degree of alpha they were) + + """ + del foregroundColour # Not used by function + outAlpha = backgroundAlpha * (1 - foregroundAlpha) + with np.errstate(divide="ignore", invalid="ignore"): + outRGB = np.divide( + np.multiply((backgroundAlpha * (1 - foregroundAlpha))[:, :, None], backgroundColour), + outAlpha[:, :, None], + ) + return outRGB, outAlpha + + +def destatop( + backgroundAlpha: np.ndarray, + foregroundAlpha: np.ndarray, + backgroundColour: np.ndarray, + foregroundColour: np.ndarray, +): + """Place the layer below above the 'layer above' in places where the 'layer above' exists... + + where 'layer below' does not exist, but 'layer above' does, place 'layer-above' + + """ + outAlpha = (foregroundAlpha * (1 - backgroundAlpha)) + (backgroundAlpha * foregroundAlpha) + with np.errstate(divide="ignore", invalid="ignore"): + outRGB = np.divide( + np.multiply((foregroundAlpha * (1 - backgroundAlpha))[:, :, None], foregroundColour) + + np.multiply((backgroundAlpha * foregroundAlpha)[:, :, None], backgroundColour), + outAlpha[:, :, None], + ) + return outRGB, outAlpha + + +def srcatop( + backgroundAlpha: np.ndarray, + foregroundAlpha: np.ndarray, + backgroundColour: np.ndarray, + foregroundColour: np.ndarray, +): + """Place the layer below above the 'layer above' in places where the 'layer above' exists.""" + outAlpha = (foregroundAlpha * backgroundAlpha) + (backgroundAlpha * (1 - foregroundAlpha)) + with np.errstate(divide="ignore", invalid="ignore"): + outRGB = np.divide( + np.multiply((foregroundAlpha * backgroundAlpha)[:, :, None], foregroundColour) + + np.multiply((backgroundAlpha * (1 - foregroundAlpha))[:, :, None], backgroundColour), + outAlpha[:, :, None], + ) + + return outRGB, outAlpha + + +def imageIntToFloat(image: np.ndarray) -> np.ndarray: + """Convert a numpy array representing an image to an array of floats. + + Args: + image (np.ndarray): numpy array of ints + + Returns: + np.ndarray: numpy array of floats + """ + return image / 255 + + +def imageFloatToInt(image: np.ndarray) -> np.ndarray: + """Convert a numpy array representing an image to an array of ints. + + Args: + image (np.ndarray): numpy array of floats + + Returns: + np.ndarray: numpy array of ints + """ + return (image * 255).astype(np.uint8) + + +def blend(background: np.ndarray, foreground: np.ndarray, blendType: BlendType) -> np.ndarray: + """Blend pixels. + + Args: + background (np.ndarray): background + foreground (np.ndarray): foreground + blendType (BlendType): the blend type + + Returns: + np.ndarray: new array representing the image + + background: np.ndarray, + foreground: np.ndarray and the return are in the form + + [[[0. 0. 0.] + [0. 0. 0.] + [0. 0. 0.] + ... + [0. 0. 0.] + [0. 0. 0.] + [0. 0. 0.]] + + ... + + [[0. 0. 0.] + [0. 0. 0.] + [0. 0. 0.] + ... + [0. 0. 0.] + [0. 0. 0.] + [0. 0. 0.]]] + """ + blendLookup = { + BlendType.NORMAL: normal, + BlendType.MULTIPLY: multiply, + BlendType.COLOURBURN: colourburn, + BlendType.COLOURDODGE: colourdodge, + BlendType.REFLECT: reflect, + BlendType.OVERLAY: overlay, + BlendType.DIFFERENCE: difference, + BlendType.LIGHTEN: lighten, + BlendType.DARKEN: darken, + BlendType.SCREEN: screen, + BlendType.SOFTLIGHT: softlight, + BlendType.HARDLIGHT: hardlight, + BlendType.GRAINEXTRACT: grainextract, + BlendType.GRAINMERGE: grainmerge, + BlendType.DIVIDE: divide, + BlendType.HUE: hue, + BlendType.SATURATION: saturation, + BlendType.COLOUR: colour, + BlendType.LUMINOSITY: luminosity, + BlendType.XOR: xor, + BlendType.NEGATION: negation, + BlendType.PINLIGHT: pinlight, + BlendType.VIVIDLIGHT: vividlight, + BlendType.EXCLUSION: exclusion, + } + + if blendType not in blendLookup: + return normal(background, foreground) + return blendLookup[blendType](background, foreground) + + +def blendLayers( + background: Image.Image, + foreground: Image.Image, + blendType: BlendType | tuple[str, ...], + opacity: float = 1.0, +) -> Image.Image: + """Blend layers using numpy array. + + Args: + background (Image.Image): background layer + foreground (Image.Image): foreground layer (must be same size as background) + blendType (BlendType): The blendtype + opacity (float): The opacity of the foreground image + + Returns: + Image.Image: combined image + """ + # Convert the Image.Image to a numpy array + npForeground: np.ndarray = imageIntToFloat(np.array(foreground.convert("RGBA"))) + npBackground: np.ndarray = imageIntToFloat(np.array(background.convert("RGBA"))) + + # Get the alpha from the layers + backgroundAlpha = npBackground[:, :, 3] + foregroundAlpha = npForeground[:, :, 3] * opacity + combinedAlpha = backgroundAlpha * foregroundAlpha + + # Get the colour from the layers + backgroundColor = npBackground[:, :, 0:3] + foregroundColor = npForeground[:, :, 0:3] + + # Some effects require alpha + alphaFunc = { + BlendType.DESTIN: destin, + BlendType.DESTOUT: destout, + BlendType.SRCATOP: srcatop, + BlendType.DESTATOP: destatop, + } + + if blendType in alphaFunc: + return Image.fromarray( + imageFloatToInt( + np.clip( + np.dstack( + alphaFunc[blendType]( + backgroundAlpha, foregroundAlpha, backgroundColor, foregroundColor + ) + ), + a_min=0, + a_max=1, + ) + ) + ) + + # Get the colours and the alpha for the new image + colorComponents = ( + (backgroundAlpha - combinedAlpha)[:, :, None] * backgroundColor + + (foregroundAlpha - combinedAlpha)[:, :, None] * foregroundColor + + combinedAlpha[:, :, None] * blend(backgroundColor, foregroundColor, blendType) + ) + alphaComponent = backgroundAlpha + foregroundAlpha - combinedAlpha + + return Image.fromarray( + imageFloatToInt(np.clip(np.dstack((colorComponents, alphaComponent)), a_min=0, a_max=1)) + ) diff --git a/venv/Lib/site-packages/blendmodes/blendtype.py b/venv/Lib/site-packages/blendmodes/blendtype.py new file mode 100644 index 00000000..1bde12a6 --- /dev/null +++ b/venv/Lib/site-packages/blendmodes/blendtype.py @@ -0,0 +1,72 @@ +"""Specify supported blend types.""" + +from __future__ import annotations + +from aenum import MultiValueEnum + + +class BlendType(str, MultiValueEnum): + """Specify supported blend types. + + NORMAL = "bm:normal", "normal" + MULTIPLY = "bm:multiply", "multiply" + ADDITIVE = "bm:additive", "additive" + COLOURBURN = "bm:colourburn", "colourburn" + COLOURDODGE = "bm:colourdodge", "colourdodge" + REFLECT = "bm:reflect", "reflect" + GLOW = "bm:glow", "glow" + OVERLAY = "bm:overlay", "overlay" + DIFFERENCE = "bm:difference", "difference" + NEGATION = "bm:negation", "negation" + LIGHTEN = "bm:lighten", "lighten" + DARKEN = "bm:darken", "darken" + SCREEN = "bm:screen", "screen" + XOR = "bm:xor", "xor" + SOFTLIGHT = "bm:softlight", "softlight" + HARDLIGHT = "bm:hardlight", "hardlight" + GRAINEXTRACT = "bm:grainextract", "grainextract" + GRAINMERGE = "bm:grainmerge", "grainmerge" + DIVIDE = "bm:divide", "divide" + HUE = "bm:hue", "hue" + SATURATION = "bm:saturation", "saturation" + COLOUR = "bm:colour", "colour" + LUMINOSITY = "bm:luminosity", "luminosity" + PINLIGHT = "bm:pinlight", "pinlight" + VIVIDLIGHT = "bm:vividlight", "vividlight" + EXCLUSION = "bm:exclusion", "exclusion" + DESTIN = "bm:destin", "destin" + DESTOUT = "bm:destout", "destout" + SRCATOP = "bm:srcatop", "srcatop" + DESTATOP = "bm:destatop", "destatop" + """ + + NORMAL = "bm:normal", "normal" + MULTIPLY = "bm:multiply", "multiply" + ADDITIVE = "bm:additive", "additive" + COLOURBURN = "bm:colourburn", "colourburn" + COLOURDODGE = "bm:colourdodge", "colourdodge" + REFLECT = "bm:reflect", "reflect" + GLOW = "bm:glow", "glow" + OVERLAY = "bm:overlay", "overlay" + DIFFERENCE = "bm:difference", "difference" + NEGATION = "bm:negation", "negation" + LIGHTEN = "bm:lighten", "lighten" + DARKEN = "bm:darken", "darken" + SCREEN = "bm:screen", "screen" + XOR = "bm:xor", "xor" + SOFTLIGHT = "bm:softlight", "softlight" + HARDLIGHT = "bm:hardlight", "hardlight" + GRAINEXTRACT = "bm:grainextract", "grainextract" + GRAINMERGE = "bm:grainmerge", "grainmerge" + DIVIDE = "bm:divide", "divide" + HUE = "bm:hue", "hue" + SATURATION = "bm:saturation", "saturation" + COLOUR = "bm:colour", "colour" + LUMINOSITY = "bm:luminosity", "luminosity" + PINLIGHT = "bm:pinlight", "pinlight" + VIVIDLIGHT = "bm:vividlight", "vividlight" + EXCLUSION = "bm:exclusion", "exclusion" + DESTIN = "bm:destin", "destin" + DESTOUT = "bm:destout", "destout" + SRCATOP = "bm:srcatop", "srcatop" + DESTATOP = "bm:destatop", "destatop" diff --git a/venv/Lib/site-packages/blendmodes/imagetools.py b/venv/Lib/site-packages/blendmodes/imagetools.py new file mode 100644 index 00000000..834b7c86 --- /dev/null +++ b/venv/Lib/site-packages/blendmodes/imagetools.py @@ -0,0 +1,48 @@ +"""Do stuff to images to prepare them. +""" +from __future__ import annotations + +import warnings + +from deprecation import deprecated +from PIL import Image + + +@deprecated(deprecated_in="2021.1", removed_in="", details="use renderWAlphaOffset") +def rasterImageOA( # pylint:disable=missing-function-docstring + image: Image.Image, size: tuple[int, int], alpha: float = 1.0, offsets: tuple[int, int] = (0, 0) +) -> Image.Image: + warnings.warn( + "Call to deprecated function rasterImageOA.", category=DeprecationWarning, stacklevel=2 + ) + return renderWAlphaOffset(image, size, alpha, offsets) + + +@deprecated(deprecated_in="2021.1", removed_in="", details="use renderWAlphaOffset") +def rasterImageOffset( # pylint:disable=missing-function-docstring + image: Image.Image, size: tuple[int, int], offsets: tuple[int, int] = (0, 0) +) -> Image.Image: + warnings.warn( + "Call to deprecated function rasterImageOffset.", category=DeprecationWarning, stacklevel=2 + ) + return renderWAlphaOffset(image, size, 1, offsets) + + +def renderWAlphaOffset( + image: Image.Image, size: tuple[int, int], alpha: float = 1.0, offsets: tuple[int, int] = (0, 0) +) -> Image.Image: + """Render an image with offset and alpha to a given size. + + Args: + image (Image.Image): pil image to draw + size (tuple[int, int]): width, height as a tuple + alpha (float, optional): alpha transparency. Defaults to 1.0. + offsets (tuple[int, int], optional): x, y offsets as a tuple. + Defaults to (0, 0). + + Returns: + Image.Image: new image + """ + imageOffset = Image.new("RGBA", size) + imageOffset.paste(image.convert("RGBA"), offsets, image.convert("RGBA")) + return Image.blend(Image.new("RGBA", size), imageOffset, alpha) From 2e8b5418e3cd4e9212f2fcdb36305d7a40f97916 Mon Sep 17 00:00:00 2001 From: ThereforeGames <95403634+ThereforeGames@users.noreply.github.com> Date: Sun, 11 Dec 2022 18:03:36 -0500 Subject: [PATCH 2/4] Improve color correction with luminosity blend --- modules/processing.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 24c537d1..bc841837 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -27,6 +27,7 @@ from ldm.data.util import AddMiDaS from ldm.models.diffusion.ddpm import LatentDepth2ImageDiffusion from einops import repeat, rearrange +from blendmodes.blend import blendLayers, BlendType # some of those options should not be changed at all because they would break the model, so I removed them from options. opt_C = 4 @@ -39,17 +40,19 @@ def setup_color_correction(image): return correction_target -def apply_color_correction(correction, image): +def apply_color_correction(correction, original_image): logging.info("Applying color correction.") image = Image.fromarray(cv2.cvtColor(exposure.match_histograms( cv2.cvtColor( - np.asarray(image), + np.asarray(original_image), cv2.COLOR_RGB2LAB ), correction, channel_axis=2 ), cv2.COLOR_LAB2RGB).astype("uint8")) - + + image = blendLayers(image, original_image, BlendType.LUMINOSITY) + return image From 9170224d230fb22387e955d0b40ceda116f688b6 Mon Sep 17 00:00:00 2001 From: ThereforeGames <95403634+ThereforeGames@users.noreply.github.com> Date: Sun, 11 Dec 2022 18:06:22 -0500 Subject: [PATCH 3/4] Delete venv/Lib/site-packages directory --- venv/Lib/site-packages/aenum/CHANGES | 489 -- venv/Lib/site-packages/aenum/LICENSE | 32 - venv/Lib/site-packages/aenum/__init__.py | 4111 ---------- .../aenum/__pycache__/__init__.cpython-39.pyc | Bin 104964 -> 0 bytes .../aenum/__pycache__/_py3.cpython-39.pyc | Bin 686 -> 0 bytes venv/Lib/site-packages/aenum/_py2.py | 7 - venv/Lib/site-packages/aenum/_py3.py | 12 - venv/Lib/site-packages/aenum/doc/aenum.rst | 1568 ---- venv/Lib/site-packages/aenum/test.py | 6832 ----------------- venv/Lib/site-packages/aenum/test_v3.py | 1982 ----- venv/Lib/site-packages/blendmodes/__init__.py | 2 - .../__pycache__/__init__.cpython-39.pyc | Bin 285 -> 0 bytes .../__pycache__/blend.cpython-39.pyc | Bin 13302 -> 0 bytes .../__pycache__/blendtype.cpython-39.pyc | Bin 2850 -> 0 bytes venv/Lib/site-packages/blendmodes/blend.py | 511 -- .../Lib/site-packages/blendmodes/blendtype.py | 72 - .../site-packages/blendmodes/imagetools.py | 48 - 17 files changed, 15666 deletions(-) delete mode 100644 venv/Lib/site-packages/aenum/CHANGES delete mode 100644 venv/Lib/site-packages/aenum/LICENSE delete mode 100644 venv/Lib/site-packages/aenum/__init__.py delete mode 100644 venv/Lib/site-packages/aenum/__pycache__/__init__.cpython-39.pyc delete mode 100644 venv/Lib/site-packages/aenum/__pycache__/_py3.cpython-39.pyc delete mode 100644 venv/Lib/site-packages/aenum/_py2.py delete mode 100644 venv/Lib/site-packages/aenum/_py3.py delete mode 100644 venv/Lib/site-packages/aenum/doc/aenum.rst delete mode 100644 venv/Lib/site-packages/aenum/test.py delete mode 100644 venv/Lib/site-packages/aenum/test_v3.py delete mode 100644 venv/Lib/site-packages/blendmodes/__init__.py delete mode 100644 venv/Lib/site-packages/blendmodes/__pycache__/__init__.cpython-39.pyc delete mode 100644 venv/Lib/site-packages/blendmodes/__pycache__/blend.cpython-39.pyc delete mode 100644 venv/Lib/site-packages/blendmodes/__pycache__/blendtype.cpython-39.pyc delete mode 100644 venv/Lib/site-packages/blendmodes/blend.py delete mode 100644 venv/Lib/site-packages/blendmodes/blendtype.py delete mode 100644 venv/Lib/site-packages/blendmodes/imagetools.py diff --git a/venv/Lib/site-packages/aenum/CHANGES b/venv/Lib/site-packages/aenum/CHANGES deleted file mode 100644 index e8799f6d..00000000 --- a/venv/Lib/site-packages/aenum/CHANGES +++ /dev/null @@ -1,489 +0,0 @@ -3.1.8 -===== - -recalculate bits used after all flags created (sometimes needed when a custom -`__new__` is in place. - - -3.1.7 -===== - -update flag creation to (possibly) add bitwise operator methods to newly -created flags - -update extend_enum() to work with 3.11 flags - - -3.1.6 -===== - -Update `dir()` on mixed enums to include mixed data type methods and -attributes. - -Rename `enum_property` to `property` to match stdlib. Recommended usage is -`aenum.property` (prefix with module name). - -Remove quadritic creation behavior. - - -BREAKING CHANGE BUG FIX that won't affect most people - -Enums with a custom `__new__` that: - -- use the enum machinery to generate the values; AND -- have keyword arguments set to a default (like `None`) - -will fail to generate a missing value. To fix: remove the default value and -instead specify it on the member creation line. - -BREAKING CHANGE - -In Python 3.11 the `str()` of mixed enums will now match its `format()` which -will be the normal `str()` of the data type -- so for an IntEnum you'll see -`5` instead of `Perm.R|X`. This affects IntEnum, StrEnum, and IntFlag. - - -3.1.5 -===== - -fix support of `auto()` kwds - - -3.1.3 -===== - -rename `aenum.property` to `aenum.enum_property` - -fix `enum_property` to work with `_init_` attributes - - -3.1.2 -===== - -fix `extend_enum()` for unhashable values - - -3.1.1 -===== - -fix `extend_enum()` for most cases - - -3.1.0 -===== - -AddValue is similar to the old AutoNumber: it will always activate, but -uses _generate_next_value_ to get the next value (so the user has some -control over the return data type instead of always getting an int). - - -BREAKING CHANGES - -AutoValue is gone. It was superflous and its removal simplified the code. -Simply put the fields needed in an `_init_` and `_generate_next_value_` -will be called to supply the missing values (this is probably already what -is happening). - - - -3.0.0 -===== - -standard Enum usage is unchanged - -BREAKING CHANGES - -Enum -- the more esoteric method of creating Enums have been modified or removed - - AutoNumber setting is gone, inherit from AutoNumberEnum instead - - creating members without specifying anything is removed (if you don't - know what this means, you weren't doing it) - -Flag -- unique flags are canonical (i.e. flags with powers of two values such as - 1, 2, 4, 8, 16, etc.) -- non-unique flags are aliases (i.e. values such as 3 or 7) -- iteration of Flag and flag members only uses canonical flags - - -ENHANCEMENTS - -Member creation has been redone to match Python 3.10's methods. This also -allows all supported Pythons (2.7, 3.3+) to use the __set_name__ and -__init_subclass__ protocols (more robustly than in aenum 2.2.5) - - -CHANGES - -enum_property() has been renamed to property() (old name still available, but -deprecated). - -bin() replacement shows negative integers in twos-complement - - - - -2.2.5 -===== - -call __init_subclass__ after members have been added, and in Pythons < 3.6 -call __set_name__ in Pythons < 3.6 -do not convert/disallow private names -add iteration/len support to NamedConstant - - -2.2.4 -===== - -add support to Constant to retrieve members by value - - --> class K(Constant): - ... one = 1 - ... two = 2 - - --> K.one - - - --> K(1) - - -add pickle/deepcopy support to Constant - -add support for Constant to use other Constant values - (resulting members /are not/ the same) - - --> class C(Constant) - ... one = K.one - ... three = 3 - - --> C.one == K.one - True - - --> C.one is K.one - False - -AutoNumber and auto() now work together - -Enum members are now added to the class as enum_property, which supports -unshadowing of parent class attributes when called on an Enum member: - - --> class StrEnum(str, Enum): - ... lower = 'lower' - ... upper = 'upper' - ... mixed = 'mixed' - - --> StrEnum.lower - - - --> StrEnum.lower.upper() - 'LOWER' - - --> StrEnum.upper - - - --> StrEnum.upper.upper() - 'UPPER' - - -2.2.3 -===== - -use members' type's methods __str__, __repr__, __format__, and -__reduce_ex__ if directly assigned in Enum class body; i.e.: - - --> class Color(str, Enum): - ... red = 'red' - ... green = 'green' - ... blue = 'blue' - ... __str__ = str.__str__ - - --> print(repr(Color.green)) - - - --> print(Color.green) - green - - -2.2.2 -===== - -replace _RouteClassAttributeToGetattr with enum_property (it is still -available as an alias) - -support constant() and auto() being used together: - - --> class Fruit(Flag): - ... _order_ = 'apple banana lemon orange' - ... apple = auto() - ... banana = auto() - ... lemon = auto() - ... orange = auto() - ... CitrusTypes = constant(lemon | orange) - - --> list(Fruit) - [Fruit.apple, Fruit.banana, Fruit.lemon, Fruit.orange] - - --> list(Fruit.CitrusTypes) - [Fruit.orange, Fruit.lemon] - - --> Fruit.orange in Fruit.CitrusTypes - True - - -2.2.1 -===== - -allow Enums to be called without a value - - 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 - - >>> Color() - - -allow Enum name use while constructing Enum (Python 3.4+ only) - - --> class Color(Enum): - ... _order_ = 'BLACK WHITE' - ... BLACK = Color('black', '#000') - ... WHITE = Color('white', '#fff') - ... # - ... def __init__(self, label, hex): - ... self.label = label - ... self.hex = hex - - -2.2.0 -===== - -BREAKING CHANGE ---------------- -In Python 3+ classes defined inside an Enum no longer become members by -default; in Python 2 they still become members, but see below. - -For cross-compatibility and full control two decorators are provided: - -- @member --> forces item to become a member -- @nonmember --> excludes item from becoming a member - -So to have an Enum that behaves the same in Python 2 and 3, use the -decorators (and other compatibility shims): - - class Color(Enum): - - _order_ = 'red green blue' - - red = 1 - green = 2 - blue = 3 - - @nonmember - class Shades(Enum): - - _order_ = 'light medium dark' - - light = 1 - medium = 2 - dark = 3 - - -2.1.4 -===== - -EnumMeta: -- change __member_new__ to __new_member__ (as the stdlib enum does) -- assign member name to enum() instances (an Enum helper for defining members) -- handle empty iterables when using functional API -- make auto() work with previous enum members -- keep searching mixins until base class is found - -Enum: -- fix bug in Flag checks (ensure it is a Flag before checking the name) -- add multiple mixin support -- do not allow blank names (functional API) -- raise TypeError if _missing_* returns wrong type -- fix __format__ to honor custom __str__ - -extend_enum: -- support stdlib Enums -- use _generate_next_value_ if value not provided - -general: -- standardize exception formatting -- use getfullargspec() in Python 3 (avoids deprecation warnings) - - -2.1.2 -===== - -when order is callable, save it for subclass use - - -2.1.1 -===== - -correctly raise TypeError for non-Enum containment checks -support combining names with | for Flag key access -support _order_ being a callable - - -2.1.0 -===== - -support Flags being combined with other data types: -- add _create_pseudo_member_values_ -- add default __new__ and temporary _init_ - - -2.0.10 -====== - -ensure _ignore_ is set when _settings_ specified in body which includes -AutoValue - -make Flag members iterable - - -2.0.9 -===== - -fix missing comma in __all__ -fix extend_enum with custom __new__ methods -fix MultiValue with AutoNumber without _init_ - - -2.0.8 -===== - -extend_enum now handles aliases and multivalues correctly - - -2.0.7 -===== - -support mixin types with extend_enum -init and AutoNumber can now work together -add test for new Enum using EnumMeta -add tests for variations of multivalue and init -prevent deletion of NamedConstant.constant - - -2.0.6 -===== - -constants cannot be deleted (they already couldn't be changed) -constants can be used to define other constants - - -2.0.5 -===== - -_init_ and MultiValue can now work together - - -2.0.4 -===== - -_init_ and AutoValue (and _generate_next_value_) can now work together to -supply missing values even when some of the required values per member are -absent - - -2.0.3 -===== - -add _missing_value_ and _missing_name_ methods, deprecate _missing_ -make enum instances comparable - - -2.0.2 -===== - -both EnumMeta.__getattr__ and Enum.__new__ fall back to _missing_ - - -2.0.1 -===== - -auto() now works with other data types -AutoNumber supports legacy Enums (fixed regression) - - -2.0.0 -===== - -Flag and IntFlag added. - - -1.4.7 -===== - -fix %-interpolation bug -defined SqlLiteEnum only if sqlite exists -support pyflakes - - -1.4.6 -===== - -version numbering error - - -1.4.5 -===== - -revert AutoNumberEnum to custom __new__ instead of AutoNumber -use _ignore_ to shield against AutoNumber magic -inherit start and init settings from base Enums - - -1.4.4 -===== - -enabled export as a decorator -enabled _order_ to replace __order__ -enabled python2 support for settings, init, and start - - -1.4.3 -===== - -support _ignore_ for dynamically creating class bodies - - -1.4.2 -===== - -MultiValue, NoAlias, Unique, and init now work with Python 2 - - -1.4.1 -===== - -Py3: added Enum creation flags: Auto, MultiValue, NoAlias, Unique - -fixed extend_enum to honor Enum flags - - -1.4.0 -===== - -When possible aenum inherits from Python's own enum. - -Breaking change: enum members now default to evaluating as True to maintain -compatibility with the stdlib. - -Add your own __bool__ (__nonzero__ in Python 2) if need this behavior: - - def __bool__(self): - return bool(self.value) - __nonzero__ = __bool__ - diff --git a/venv/Lib/site-packages/aenum/LICENSE b/venv/Lib/site-packages/aenum/LICENSE deleted file mode 100644 index b20361ce..00000000 --- a/venv/Lib/site-packages/aenum/LICENSE +++ /dev/null @@ -1,32 +0,0 @@ -Copyright (c) 2015, 2016, 2017, 2018 Ethan Furman. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - Neither the name Ethan Furman nor the names of any - contributors may be used to endorse or promote products - derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/aenum/__init__.py b/venv/Lib/site-packages/aenum/__init__.py deleted file mode 100644 index 26c504cc..00000000 --- a/venv/Lib/site-packages/aenum/__init__.py +++ /dev/null @@ -1,4111 +0,0 @@ -"""Python Advanced Enumerations & NameTuples""" -from __future__ import print_function - -# imports -import sys as _sys -pyver = _sys.version_info[:2] -PY2 = pyver < (3, ) -PY3 = pyver >= (3, ) -PY2_6 = (2, 6) -PY3_3 = (3, 3) -PY3_4 = (3, 4) -PY3_5 = (3, 5) -PY3_6 = (3, 6) -PY3_11 = (3, 11) - -import re - -_bltin_property = property -_bltin_bin = bin - -try: - from collections import OrderedDict -except ImportError: - OrderedDict = dict -from collections import defaultdict -try: - import sqlite3 -except ImportError: - sqlite3 = None - -try: - RecursionError -except NameError: - # python3.4 - RecursionError = RuntimeError - -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 ._py2 import * -if PY3: - from ._py3 import * - -obj_type = type - -__all__ = [ - 'NamedConstant', 'constant', 'skip', 'nonmember', 'member', 'no_arg', - 'Enum', 'IntEnum', 'AutoNumberEnum', 'OrderedEnum', 'UniqueEnum', - 'StrEnum', 'UpperStrEnum', 'LowerStrEnum', - 'Flag', 'IntFlag', - 'AddValue', 'MagicValue', 'MultiValue', 'NoAlias', 'Unique', - 'AddValueEnum', 'MultiValueEnum', 'NoAliasEnum', - 'enum', 'extend_enum', 'unique', 'property', - 'NamedTuple', 'SqliteEnum', - 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP', - 'add_stdlib_integration', 'remove_stdlib_integration' - ] - -if sqlite3 is None: - __all__.remove('SqliteEnum') - -version = 3, 1, 12, 1 - -# shims -try: - any -except NameError: - def any(iterable): - for element in iterable: - if element: - return True - return False - -try: - unicode - unicode = unicode -except NameError: - # In Python 3 unicode no longer exists (it's just str) - unicode = str - -try: - basestring - basestring = bytes, unicode -except NameError: - # In Python 2 basestring is the ancestor of both str and unicode - # in Python 3 it's just str, but was missing in 3.1 - basestring = str, - -try: - long - baseinteger = int, long -except NameError: - baseinteger = int, - long = int -# deprecated -baseint = baseinteger - -try: - NoneType -except NameError: - NoneType = type(None) - -try: - # derive from stdlib enum if possible - import enum - if hasattr(enum, 'version'): - raise ImportError('wrong version') - else: - from enum import EnumMeta as StdlibEnumMeta, Enum as StdlibEnum, IntEnum as StdlibIntEnum - StdlibFlag = StdlibIntFlag = StdlibStrEnum = StdlibReprEnum = None -except ImportError: - StdlibEnumMeta = StdlibEnum = StdlibIntEnum = StdlibIntFlag = StdlibFlag = StdlibStrEnum = None - -if StdlibEnum: - try: - from enum import IntFlag as StdlibIntFlag, Flag as StdlibFlag - except ImportError: - pass - try: - from enum import StrEnum as StdlibStrEnum - except ImportError: - pass - try: - from enum import ReprEnum as StdlibReprEnum - except ImportError: - pass - - - - -# helpers -# will be exported later -MagicValue = AddValue = MultiValue = NoAlias = Unique = None - -def _bit_count(num): - """ - return number of set bits - - Counting bits set, Brian Kernighan's way* - - unsigned int v; // count the number of bits set in v - unsigned int c; // c accumulates the total bits set in v - for (c = 0; v; c++) - { v &= v - 1; } //clear the least significant bit set - - This method goes through as many iterations as there are set bits. So if we - have a 32-bit word with only the high bit set, then it will only go once - through the loop. - - * The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988. - - This works because each subtraction "borrows" from the lowest 1-bit. For - example: - - loop pass 1 loop pass 2 - ----------- ----------- - 101000 100000 - - 1 - 1 - = 100111 = 011111 - & 101000 & 100000 - = 100000 = 0 - - It is an excellent technique for Python, since the size of the integer need - not be determined beforehand. - - (from https://wiki.python.org/moin/BitManipulation) - """ - count = 0 - while num: - num &= num - 1 - count += 1 - return count - -def _is_single_bit(value): - """ - True if only one bit set in value (should be an int) - """ - if value == 0: - return False - value &= value - 1 - return value == 0 - -def _iter_bits_lsb(value): - """ - Return each bit value one at a time. - - >>> list(_iter_bits_lsb(6)) - [2, 4] - """ - - while value: - bit = value & (~value + 1) - yield bit - value ^= bit - -def bin(value, max_bits=None): - """ - Like built-in bin(), except negative values are represented in - twos-compliment, and the leading bit always indicates sign - (0=positive, 1=negative). - - >>> bin(10) - '0b0 1010' - >>> bin(~10) # ~10 is -11 - '0b1 0101' - """ - - ceiling = 2 ** (value).bit_length() - if value >= 0: - s = _bltin_bin(value + ceiling).replace('1', '0', 1) - else: - s = _bltin_bin(~value ^ (ceiling - 1) + ceiling) - sign = s[:3] - digits = s[3:] - if max_bits is not None: - if len(digits) < max_bits: - digits = (sign[-1] * max_bits + digits)[-max_bits:] - return "%s %s" % (sign, digits) - - -try: - from types import DynamicClassAttribute - base = DynamicClassAttribute -except ImportError: - base = object - DynamicClassAttribute = None - -class property(base): - """ - This is a descriptor, used to define attributes that act differently - when accessed through an enum member and through an enum class. - Instance access is the same as property(), but access to an attribute - through the enum class will look in the class' _member_map_. - """ - - # inherit from DynamicClassAttribute if we can in order to get `inspect` - # support - - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - self.fget = fget - self.fset = fset - self.fdel = fdel - # next two lines make property act the same as _bltin_property - self.__doc__ = doc or fget.__doc__ - self.overwrite_doc = doc is None - # support for abstract methods - self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False)) - # names, if possible - - def getter(self, fget): - fdoc = fget.__doc__ if self.overwrite_doc else None - result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__) - result.overwrite_doc = self.__doc__ is None - return result - - def setter(self, fset): - fdoc = fget.__doc__ if self.overwrite_doc else None - result = type(self)(self.fget, fset, self.fdel, self.__doc__) - result.overwrite_doc = self.__doc__ is None - return result - - def deleter(self, fdel): - fdoc = fget.__doc__ if self.overwrite_doc else None - result = type(self)(self.fget, self.fset, fdel, self.__doc__) - result.overwrite_doc = self.__doc__ is None - return result - - def __repr__(self): - member = self.ownerclass._member_map_.get(self.name) - func = self.fget or self.fset or self.fdel - strings = [] - if member: - strings.append('%r' % member) - if func: - strings.append('function=%s' % func.__name__) - return 'property(%s)' % ', '.join(strings) - - def __get__(self, instance, ownerclass=None): - if instance is None: - try: - return ownerclass._member_map_[self.name] - except KeyError: - raise AttributeError( - '%r has no attribute %r' % (ownerclass, self.name) - ) - else: - if self.fget is not None: - return self.fget(instance) - else: - if self.fset is not None: - raise AttributeError( - 'cannot read attribute %r on %r' % (self.name, ownerclass) - ) - else: - try: - return instance.__dict__[self.name] - except KeyError: - raise AttributeError( - '%r member has no attribute %r' % (ownerclass, self.name) - ) - - def __set__(self, instance, value): - if self.fset is None: - if self.fget is not None: - raise AttributeError( - "cannot set attribute %r on " % (self.name, self.clsname) - ) - else: - instance.__dict__[self.name] = value - else: - return self.fset(instance, value) - - def __delete__(self, instance): - if self.fdel is None: - if self.fget or self.fset: - raise AttributeError( - "cannot delete attribute %r on " % (self.name, self.clsname) - ) - elif self.name in instance.__dict__: - del instance.__dict__[self.name] - else: - raise AttributeError( - "no attribute %r on member" % (self.name, self.clsname) - ) - else: - return self.fdel(instance) - - def __set_name__(self, ownerclass, name): - self.name = name - self.clsname = ownerclass.__name__ - self.ownerclass = ownerclass - -_RouteClassAttributeToGetattr = property -if DynamicClassAttribute is None: - DynamicClassAttribute = property -# deprecated -enum_property = property - -class NonMember(object): - """ - Protects item from becaming an Enum member during class creation. - """ - def __init__(self, value): - self.value = value - - def __get__(self, instance, ownerclass=None): - return self.value -skip = nonmember = NonMember - -class Member(object): - """ - Forces item to became an Enum member during class creation. - """ - def __init__(self, value): - self.value = value -member = Member - -class SentinelType(type): - def __repr__(cls): - return '<%s>' % cls.__name__ -Sentinel = SentinelType('Sentinel', (object, ), {}) - -def _is_descriptor(obj): - """Returns True if obj is a descriptor, False otherwise.""" - return ( - hasattr(obj, '__get__') or - hasattr(obj, '__set__') or - hasattr(obj, '__delete__')) - - -def _is_dunder(name): - """Returns True if a __dunder__ name, False otherwise.""" - return (len(name) > 4 and - name[:2] == name[-2:] == '__' and - name[2] != '_' and - name[-3] != '_') - - -def _is_sunder(name): - """Returns True if a _sunder_ name, False otherwise.""" - return (len(name) > 2 and - name[0] == name[-1] == '_' and - name[1] != '_' and - name[-2] != '_') - -def _is_internal_class(cls_name, obj): - # only 3.3 and up, always return False in 3.2 and below - if pyver < PY3_3: - return False - else: - qualname = getattr(obj, '__qualname__', False) - return not _is_descriptor(obj) and qualname and re.search(r"\.?%s\.\w+$" % cls_name, qualname) - -def _is_private_name(cls_name, name): - pattern = r'^_%s__\w+[^_]_?$' % (cls_name, ) - return re.search(pattern, name) - -def _power_of_two(value): - if value < 1: - return False - return value == 2 ** _high_bit(value) - -def bits(num): - if num in (0, 1): - return str(num) - negative = False - if num < 0: - negative = True - num = ~num - result = bits(num>>1) + str(num&1) - if negative: - result = '1' + ''.join(['10'[d=='1'] for d in result]) - return result - - -def bit_count(num): - """ - return number of set bits - - Counting bits set, Brian Kernighan's way* - - unsigned int v; // count the number of bits set in v - unsigned int c; // c accumulates the total bits set in v - for (c = 0; v; c++) - { v &= v - 1; } //clear the least significant bit set - - This method goes through as many iterations as there are set bits. So if we - have a 32-bit word with only the high bit set, then it will only go once - through the loop. - - * The C Programming Language 2nd Ed., Kernighan & Ritchie, 1988. - - This works because each subtraction "borrows" from the lowest 1-bit. For example: - - loop pass 1 loop pass 2 - ----------- ----------- - 101000 100000 - - 1 - 1 - = 100111 = 011111 - & 101000 & 100000 - = 100000 = 0 - - It is an excellent technique for Python, since the size of the integer need not - be determined beforehand. - """ - count = 0 - while(num): - num &= num - 1 - count += 1 - return(count) - -def bit_len(num): - length = 0 - while num: - length += 1 - num >>= 1 - return length - -def is_single_bit(num): - """ - True if only one bit set in num (should be an int) - """ - num &= num - 1 - return num == 0 - -def _make_class_unpicklable(obj): - """ - Make the given obj un-picklable. - - obj should be either a dictionary, on an Enum - """ - def _break_on_call_reduce(self, proto): - raise TypeError('%r cannot be pickled' % self) - if isinstance(obj, dict): - obj['__reduce_ex__'] = _break_on_call_reduce - obj['__module__'] = '' - else: - setattr(obj, '__reduce_ex__', _break_on_call_reduce) - setattr(obj, '__module__', '') - -def _check_auto_args(method): - """check if new generate method supports *args and **kwds""" - if isinstance(method, staticmethod): - method = method.__get__(type) - method = getattr(method, 'im_func', method) - args, varargs, keywords, defaults = getargspec(method) - return varargs is not None and keywords is not None - -def _get_attr_from_chain(cls, attr): - sentinel = object() - for basecls in cls.mro(): - obj = basecls.__dict__.get(attr, sentinel) - if obj is not sentinel: - return obj - -def _value(obj): - if isinstance(obj, (auto, constant)): - return obj.value - else: - return obj - -def enumsort(things): - """ - sorts things by value if all same type; otherwise by name - """ - if not things: - return things - sort_type = type(things[0]) - if not issubclass(sort_type, tuple): - # direct sort or type error - if not all((type(v) is sort_type) for v in things[1:]): - raise TypeError('cannot sort items of different types') - return sorted(things) - else: - # expecting list of (name, value) tuples - sort_type = type(things[0][1]) - try: - if all((type(v[1]) is sort_type) for v in things[1:]): - return sorted(things, key=lambda i: i[1]) - else: - raise TypeError('try name sort instead') - except TypeError: - return sorted(things, key=lambda i: i[0]) - -def export(collection, namespace=None): - """ - export([collection,] namespace) -> Export members to target namespace. - - If collection is not given, act as a decorator. - """ - if namespace is None: - namespace = collection - def export_decorator(collection): - return export(collection, namespace) - return export_decorator - elif issubclass(collection, NamedConstant): - for n, c in collection.__dict__.items(): - if isinstance(c, NamedConstant): - namespace[n] = c - elif issubclass(collection, Enum): - data = collection.__members__.items() - for n, m in data: - namespace[n] = m - else: - raise TypeError('%r is not a supported collection' % (collection,) ) - return collection - -class _Addendum(object): - def __init__(self, dict, doc, ns): - # dict is the dict to update with functions - # doc is the docstring to put in the dict - # ns is the namespace to remove the function names from - self.dict = dict - self.ns = ns - self.added = set() - def __call__(self, func): - if isinstance(func, (staticmethod, classmethod)): - name = func.__func__.__name__ - elif isinstance(func, (property, _bltin_property)): - name = (func.fget or func.fset or func.fdel).__name__ - else: - name = func.__name__ - self.dict[name] = func - self.added.add(name) - def resolve(self): - ns = self.ns - for name in self.added: - del ns[name] - return self.dict - -# Constant / NamedConstant - -class constant(object): - ''' - Simple constant descriptor for NamedConstant and Enum use. - ''' - def __init__(self, value, doc=None): - self.value = value - self.__doc__ = doc - - def __get__(self, *args): - return self.value - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self.value) - - def __and__(self, other): - return _and_(self.value, _value(other)) - - def __rand__(self, other): - return _and_(_value(other), self.value) - - def __invert__(self): - return _inv_(self.value) - - def __or__(self, other): - return _or_(self.value, _value(other)) - - def __ror__(self, other): - return _or_(_value(other), self.value) - - def __xor__(self, other): - return _xor_(self.value, _value(other)) - - def __rxor__(self, other): - return _xor_(_value(other), self.value) - - def __abs__(self): - return _abs_(self.value) - - def __add__(self, other): - return _add_(self.value, _value(other)) - - def __radd__(self, other): - return _add_(_value(other), self.value) - - def __neg__(self): - return _neg_(self.value) - - def __pos__(self): - return _pos_(self.value) - - if PY2: - def __div__(self, other): - return _div_(self.value, _value(other)) - - def __rdiv__(self, other): - return _div_(_value(other), (self.value)) - - def __floordiv__(self, other): - return _floordiv_(self.value, _value(other)) - - def __rfloordiv__(self, other): - return _floordiv_(_value(other), self.value) - - def __truediv__(self, other): - return _truediv_(self.value, _value(other)) - - def __rtruediv__(self, other): - return _truediv_(_value(other), self.value) - - def __lshift__(self, other): - return _lshift_(self.value, _value(other)) - - def __rlshift__(self, other): - return _lshift_(_value(other), self.value) - - def __rshift__(self, other): - return _rshift_(self.value, _value(other)) - - def __rrshift__(self, other): - return _rshift_(_value(other), self.value) - - def __mod__(self, other): - return _mod_(self.value, _value(other)) - - def __rmod__(self, other): - return _mod_(_value(other), self.value) - - def __mul__(self, other): - return _mul_(self.value, _value(other)) - - def __rmul__(self, other): - return _mul_(_value(other), self.value) - - def __pow__(self, other): - return _pow_(self.value, _value(other)) - - def __rpow__(self, other): - return _pow_(_value(other), self.value) - - def __sub__(self, other): - return _sub_(self.value, _value(other)) - - def __rsub__(self, other): - return _sub_(_value(other), self.value) - - def __set_name__(self, ownerclass, name): - self.name = name - self.clsname = ownerclass.__name__ - - -NamedConstant = None - -class _NamedConstantDict(dict): - """Track constant order and ensure names are not reused. - - NamedConstantMeta will use the names found in self._names as the - Constant names. - """ - def __init__(self): - super(_NamedConstantDict, self).__init__() - self._names = [] - - def __setitem__(self, key, value): - """Changes anything not dundered or not a constant descriptor. - - If an constant name is used twice, an error is raised; duplicate - values are not checked for. - - Single underscore (sunder) names are reserved. - """ - if _is_sunder(key): - raise ValueError( - '_sunder_ names, such as %r, are reserved for future NamedConstant use' - % (key, ) - ) - elif _is_dunder(key): - pass - elif key in self._names: - # overwriting an existing constant? - raise TypeError('attempt to reuse name: %r' % (key, )) - elif isinstance(value, constant) or not _is_descriptor(value): - if key in self: - # overwriting a descriptor? - raise TypeError('%s already defined as: %r' % (key, self[key])) - self._names.append(key) - super(_NamedConstantDict, self).__setitem__(key, value) - - -class NamedConstantMeta(type): - """ - Block attempts to reassign NamedConstant attributes. - """ - - @classmethod - def __prepare__(metacls, cls, bases, **kwds): - return _NamedConstantDict() - - def __new__(metacls, cls, bases, clsdict): - if type(clsdict) is dict: - original_dict = clsdict - clsdict = _NamedConstantDict() - for k, v in original_dict.items(): - clsdict[k] = v - newdict = {} - constants = {} - for name, obj in clsdict.items(): - if name in clsdict._names: - constants[name] = obj - continue - elif isinstance(obj, nonmember): - obj = obj.value - newdict[name] = obj - newcls = super(NamedConstantMeta, metacls).__new__(metacls, cls, bases, newdict) - newcls._named_constant_cache_ = {} - newcls._members_ = {} - for name, obj in constants.items(): - new_k = newcls.__new__(newcls, name, obj) - newcls._members_[name] = new_k - return newcls - - def __bool__(cls): - return True - - def __delattr__(cls, attr): - cur_obj = cls.__dict__.get(attr) - if NamedConstant is not None and isinstance(cur_obj, NamedConstant): - raise AttributeError('cannot delete constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_)) - super(NamedConstantMeta, cls).__delattr__(attr) - - def __iter__(cls): - return (k for k in cls._members_.values()) - - def __reversed__(cls): - return (k for k in reversed(cls._members_.values())) - - def __len__(cls): - return len(cls._members_) - - __nonzero__ = __bool__ - - def __setattr__(cls, name, value): - """Block attempts to reassign NamedConstants. - """ - cur_obj = cls.__dict__.get(name) - if NamedConstant is not None and isinstance(cur_obj, NamedConstant): - raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_)) - super(NamedConstantMeta, cls).__setattr__(name, value) - -constant_dict = _Addendum( - dict=NamedConstantMeta.__prepare__('NamedConstant', (object, )), - doc="NamedConstants protection.\n\n Derive from this class to lock NamedConstants.\n\n", - ns=globals(), - ) - -@constant_dict -def __new__(cls, name, value=None, doc=None): - if value is None: - # lookup, name is value - value = name - for name, obj in cls.__dict__.items(): - if isinstance(obj, cls) and obj._value_ == value: - return obj - else: - raise ValueError('%r does not exist in %r' % (value, cls.__name__)) - cur_obj = cls.__dict__.get(name) - if isinstance(cur_obj, NamedConstant): - raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_)) - elif isinstance(value, constant): - doc = doc or value.__doc__ - value = value.value - metacls = cls.__class__ - if isinstance(value, NamedConstant): - # constants from other classes are reduced to their actual value - value = value._value_ - actual_type = type(value) - value_type = cls._named_constant_cache_.get(actual_type) - if value_type is None: - value_type = type(cls.__name__, (cls, type(value)), {}) - cls._named_constant_cache_[type(value)] = value_type - obj = actual_type.__new__(value_type, value) - obj._name_ = name - obj._value_ = value - obj.__doc__ = doc - cls._members_[name] = obj - metacls.__setattr__(cls, name, obj) - return obj - -@constant_dict -def __repr__(self): - return "<%s.%s: %r>" % ( - self.__class__.__name__, self._name_, self._value_) - -@constant_dict -def __reduce_ex__(self, proto): - return getattr, (self.__class__, self._name_) - -NamedConstant = NamedConstantMeta('NamedConstant', (object, ), constant_dict.resolve()) -Constant = NamedConstant -del constant_dict - -# NamedTuple - -class _NamedTupleDict(OrderedDict): - """Track field order and ensure field names are not reused. - - NamedTupleMeta will use the names found in self._field_names to translate - to indices. - """ - def __init__(self, *args, **kwds): - self._field_names = [] - super(_NamedTupleDict, self).__init__(*args, **kwds) - - def __setitem__(self, key, value): - """Records anything not dundered or not a descriptor. - - If a field name is used twice, an error is raised. - - Single underscore (sunder) names are reserved. - """ - if _is_sunder(key): - if key not in ('_size_', '_order_', '_fields_'): - raise ValueError( - '_sunder_ names, such as %r, are reserved for future NamedTuple use' - % (key, ) - ) - elif _is_dunder(key): - if key == '__order__': - key = '_order_' - elif key in self._field_names: - # overwriting a field? - raise TypeError('attempt to reuse field name: %r' % (key, )) - elif not _is_descriptor(value): - if key in self: - # field overwriting a descriptor? - raise TypeError('%s already defined as: %r' % (key, self[key])) - self._field_names.append(key) - super(_NamedTupleDict, self).__setitem__(key, value) - - -class _TupleAttributeAtIndex(object): - - def __init__(self, name, index, doc, default): - self.name = name - self.index = index - if doc is undefined: - doc = None - self.__doc__ = doc - self.default = default - - def __get__(self, instance, owner): - if instance is None: - return self - if len(instance) <= self.index: - raise AttributeError('%s instance has no value for %s' % (instance.__class__.__name__, self.name)) - return instance[self.index] - - def __repr__(self): - return '%s(%d)' % (self.__class__.__name__, self.index) - - -class undefined(object): - def __repr__(self): - return 'undefined' - def __bool__(self): - return False - __nonzero__ = __bool__ -undefined = undefined() - - -class TupleSize(NamedConstant): - fixed = constant('fixed', 'tuple length is static') - minimum = constant('minimum', 'tuple must be at least x long (x is calculated during creation') - variable = constant('variable', 'tuple length can be anything') - -class NamedTupleMeta(type): - """Metaclass for NamedTuple""" - - @classmethod - def __prepare__(metacls, cls, bases, size=undefined, **kwds): - return _NamedTupleDict() - - def __init__(cls, *args , **kwds): - super(NamedTupleMeta, cls).__init__(*args) - - def __new__(metacls, cls, bases, clsdict, size=undefined, **kwds): - if bases == (object, ): - bases = (tuple, object) - elif tuple not in bases: - if object in bases: - index = bases.index(object) - bases = bases[:index] + (tuple, ) + bases[index:] - else: - bases = bases + (tuple, ) - # include any fields from base classes - base_dict = _NamedTupleDict() - namedtuple_bases = [] - for base in bases: - if isinstance(base, NamedTupleMeta): - namedtuple_bases.append(base) - i = 0 - if namedtuple_bases: - for name, index, doc, default in metacls._convert_fields(*namedtuple_bases): - base_dict[name] = index, doc, default - i = max(i, index) - # construct properly ordered dict with normalized indexes - for k, v in clsdict.items(): - base_dict[k] = v - original_dict = base_dict - if size is not undefined and '_size_' in original_dict: - raise TypeError('_size_ cannot be set if "size" is passed in header') - add_order = isinstance(clsdict, _NamedTupleDict) - clsdict = _NamedTupleDict() - clsdict.setdefault('_size_', size or TupleSize.fixed) - unnumbered = OrderedDict() - numbered = OrderedDict() - _order_ = original_dict.pop('_order_', []) - if _order_ : - _order_ = _order_.replace(',',' ').split() - add_order = False - # and process this class - for k, v in original_dict.items(): - if k not in original_dict._field_names: - clsdict[k] = v - else: - # TODO:normalize v here - if isinstance(v, baseinteger): - # assume an offset - v = v, undefined, undefined - i = v[0] + 1 - target = numbered - elif isinstance(v, basestring): - # assume a docstring - if add_order: - v = i, v, undefined - i += 1 - target = numbered - else: - v = undefined, v, undefined - target = unnumbered - elif isinstance(v, tuple) and len(v) in (2, 3) and isinstance(v[0], baseinteger) and isinstance(v[1], (basestring, NoneType)): - # assume an offset, a docstring, and (maybe) a default - if len(v) == 2: - v = v + (undefined, ) - v = v - i = v[0] + 1 - target = numbered - elif isinstance(v, tuple) and len(v) in (1, 2) and isinstance(v[0], (basestring, NoneType)): - # assume a docstring, and (maybe) a default - if len(v) == 1: - v = v + (undefined, ) - if add_order: - v = (i, ) + v - i += 1 - target = numbered - else: - v = (undefined, ) + v - target = unnumbered - else: - # refuse to guess further - raise ValueError('not sure what to do with %s=%r (should be OFFSET [, DOC [, DEFAULT]])' % (k, v)) - target[k] = v - # all index values have been normalized - # deal with _order_ (or lack thereof) - fields = [] - aliases = [] - seen = set() - max_len = 0 - if not _order_: - if unnumbered: - raise ValueError("_order_ not specified and OFFSETs not declared for %r" % (unnumbered.keys(), )) - for name, (index, doc, default) in sorted(numbered.items(), key=lambda nv: (nv[1][0], nv[0])): - if index in seen: - aliases.append(name) - else: - fields.append(name) - seen.add(index) - max_len = max(max_len, index + 1) - offsets = numbered - else: - # check if any unnumbered not in _order_ - missing = set(unnumbered) - set(_order_) - if missing: - raise ValueError("unable to order fields: %s (use _order_ or specify OFFSET" % missing) - offsets = OrderedDict() - # if any unnumbered, number them from their position in _order_ - i = 0 - for k in _order_: - try: - index, doc, default = unnumbered.pop(k, None) or numbered.pop(k) - except IndexError: - raise ValueError('%s (from _order_) not found in %s' % (k, cls)) - if index is not undefined: - i = index - if i in seen: - aliases.append(k) - else: - fields.append(k) - seen.add(i) - offsets[k] = i, doc, default - i += 1 - max_len = max(max_len, i) - # now handle anything in numbered - for k, (index, doc, default) in sorted(numbered.items(), key=lambda nv: (nv[1][0], nv[0])): - if index in seen: - aliases.append(k) - else: - fields.append(k) - seen.add(index) - offsets[k] = index, doc, default - max_len = max(max_len, index+1) - - # at this point fields and aliases should be ordered lists, offsets should be an - # OrdededDict with each value an int, str or None or undefined, default or None or undefined - assert len(fields) + len(aliases) == len(offsets), "number of fields + aliases != number of offsets" - assert set(fields) & set(offsets) == set(fields), "some fields are not in offsets: %s" % set(fields) & set(offsets) - assert set(aliases) & set(offsets) == set(aliases), "some aliases are not in offsets: %s" % set(aliases) & set(offsets) - for name, (index, doc, default) in offsets.items(): - assert isinstance(index, baseinteger), "index for %s is not an int (%s:%r)" % (name, type(index), index) - assert isinstance(doc, (basestring, NoneType)) or doc is undefined, "doc is not a str, None, nor undefined (%s:%r)" % (name, type(doc), doc) - - # create descriptors for fields - for name, (index, doc, default) in offsets.items(): - clsdict[name] = _TupleAttributeAtIndex(name, index, doc, default) - clsdict['__slots__'] = () - - # create our new NamedTuple type - namedtuple_class = super(NamedTupleMeta, metacls).__new__(metacls, cls, bases, clsdict) - namedtuple_class._fields_ = fields - namedtuple_class._aliases_ = aliases - namedtuple_class._defined_len_ = max_len - return namedtuple_class - - @staticmethod - def _convert_fields(*namedtuples): - "create list of index, doc, default triplets for cls in namedtuples" - all_fields = [] - for cls in namedtuples: - base = len(all_fields) - for field in cls._fields_: - desc = getattr(cls, field) - all_fields.append((field, base+desc.index, desc.__doc__, desc.default)) - return all_fields - - def __add__(cls, other): - "A new NamedTuple is created by concatenating the _fields_ and adjusting the descriptors" - if not isinstance(other, NamedTupleMeta): - return NotImplemented - return NamedTupleMeta('%s%s' % (cls.__name__, other.__name__), (cls, other), {}) - - def __call__(cls, *args, **kwds): - """Creates a new NamedTuple class or an instance of a NamedTuple subclass. - - NamedTuple should have args of (class_name, names, module) - - `names` can be: - - * A string containing member names, separated either with spaces or - commas. Values are auto-numbered from 1. - * An iterable of member names. Values are auto-numbered from 1. - * An iterable of (member name, value) pairs. - * A mapping of member name -> value. - - `module`, if set, will be stored in the new class' __module__ attribute; - - Note: if `module` is not set this routine will attempt to discover the - calling module by walking the frame stack; if this is unsuccessful - the resulting class will not be pickleable. - - subclass should have whatever arguments and/or keywords will be used to create an - instance of the subclass - """ - if cls is NamedTuple: - original_args = args - original_kwds = kwds.copy() - # create a new subclass - try: - if 'class_name' in kwds: - class_name = kwds.pop('class_name') - else: - class_name, args = args[0], args[1:] - if 'names' in kwds: - names = kwds.pop('names') - else: - names, args = args[0], args[1:] - if 'module' in kwds: - module = kwds.pop('module') - elif args: - module, args = args[0], args[1:] - else: - module = None - if 'type' in kwds: - type = kwds.pop('type') - elif args: - type, args = args[0], args[1:] - else: - type = None - - except IndexError: - raise TypeError('too few arguments to NamedTuple: %s, %s' % (original_args, original_kwds)) - if args or kwds: - raise TypeError('too many arguments to NamedTuple: %s, %s' % (original_args, original_kwds)) - if PY2: - # if class_name is unicode, attempt a conversion to ASCII - if isinstance(class_name, unicode): - try: - class_name = class_name.encode('ascii') - except UnicodeEncodeError: - raise TypeError('%r is not representable in ASCII' % (class_name, )) - # quick exit if names is a NamedTuple - if isinstance(names, NamedTupleMeta): - names.__name__ = class_name - if type is not None and type not in names.__bases__: - names.__bases__ = (type, ) + names.__bases__ - return names - - metacls = cls.__class__ - bases = (cls, ) - clsdict = metacls.__prepare__(class_name, bases) - - # special processing needed for names? - if isinstance(names, basestring): - names = names.replace(',', ' ').split() - if isinstance(names, (tuple, list)) and isinstance(names[0], basestring): - names = [(e, i) for (i, e) in enumerate(names)] - # Here, names is either an iterable of (name, index) or (name, index, doc, default) or a mapping. - item = None # in case names is empty - for item in names: - if isinstance(item, basestring): - # mapping - field_name, field_index = item, names[item] - else: - # non-mapping - if len(item) == 2: - field_name, field_index = item - else: - field_name, field_index = item[0], item[1:] - clsdict[field_name] = field_index - if type is not None: - if not isinstance(type, tuple): - type = (type, ) - bases = type + bases - namedtuple_class = metacls.__new__(metacls, class_name, bases, clsdict) - - # TODO: replace the frame hack if a blessed way to know the calling - # module is ever developed - if module is None: - try: - module = _sys._getframe(1).f_globals['__name__'] - except (AttributeError, ValueError, KeyError): - pass - if module is None: - _make_class_unpicklable(namedtuple_class) - else: - namedtuple_class.__module__ = module - - return namedtuple_class - else: - # instantiate a subclass - namedtuple_instance = cls.__new__(cls, *args, **kwds) - if isinstance(namedtuple_instance, cls): - namedtuple_instance.__init__(*args, **kwds) - return namedtuple_instance - - @_bltin_property - def __fields__(cls): - return list(cls._fields_) - # collections.namedtuple compatibility - _fields = __fields__ - - @_bltin_property - def __aliases__(cls): - return list(cls._aliases_) - - def __repr__(cls): - return "" % (cls.__name__, ) - -namedtuple_dict = _Addendum( - dict=NamedTupleMeta.__prepare__('NamedTuple', (object, )), - doc="NamedTuple base class.\n\n Derive from this class to define new NamedTuples.\n\n", - ns=globals(), - ) - -@namedtuple_dict -def __new__(cls, *args, **kwds): - if cls._size_ is TupleSize.fixed and len(args) > cls._defined_len_: - raise TypeError('%d fields expected, %d received' % (cls._defined_len_, len(args))) - unknown = set(kwds) - set(cls._fields_) - set(cls._aliases_) - if unknown: - raise TypeError('unknown fields: %r' % (unknown, )) - final_args = list(args) + [undefined] * (len(cls.__fields__) - len(args)) - for field, value in kwds.items(): - index = getattr(cls, field).index - if final_args[index] != undefined: - raise TypeError('field %s specified more than once' % field) - final_args[index] = value - missing = [] - for index, value in enumerate(final_args): - if value is undefined: - # look for default values - name = cls.__fields__[index] - default = getattr(cls, name).default - if default is undefined: - missing.append(name) - else: - final_args[index] = default - if missing: - if cls._size_ in (TupleSize.fixed, TupleSize.minimum): - raise TypeError('values not provided for field(s): %s' % ', '.join(missing)) - while final_args and final_args[-1] is undefined: - final_args.pop() - missing.pop() - if cls._size_ is not TupleSize.variable or undefined in final_args: - raise TypeError('values not provided for field(s): %s' % ', '.join(missing)) - return tuple.__new__(cls, tuple(final_args)) - -@namedtuple_dict -def __reduce_ex__(self, proto): - return self.__class__, tuple(getattr(self, f) for f in self._fields_) - -@namedtuple_dict -def __repr__(self): - if len(self) == len(self._fields_): - return "%s(%s)" % ( - self.__class__.__name__, ', '.join(['%s=%r' % (f, o) for f, o in zip(self._fields_, self)]) - ) - else: - return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(o) for o in self])) - -@namedtuple_dict -def __str__(self): - return "%s(%s)" % ( - self.__class__.__name__, ', '.join(['%r' % (getattr(self, f), ) for f in self._fields_]) - ) - -@namedtuple_dict -@_bltin_property -def _fields_(self): - return list(self.__class__._fields_) - - # compatibility methods with stdlib namedtuple -@namedtuple_dict -@_bltin_property -def __aliases__(self): - return list(self.__class__._aliases_) - -@namedtuple_dict -@_bltin_property -def _fields(self): - return list(self.__class__._fields_) - -@namedtuple_dict -@classmethod -def _make(cls, iterable, new=None, len=None): - return cls.__new__(cls, *iterable) - -@namedtuple_dict -def _asdict(self): - return OrderedDict(zip(self._fields_, self)) - -@namedtuple_dict -def _replace(self, **kwds): - current = self._asdict() - current.update(kwds) - return self.__class__(**current) - -NamedTuple = NamedTupleMeta('NamedTuple', (object, ), namedtuple_dict.resolve()) -del namedtuple_dict - - -# Enum - - # _init_ and value and AddValue - # ----------------------------- - # by default, when defining a member everything after the = is "the value", everything is - # passed to __new__, everything is passed to __init__ - # - # if _init_ is present then - # if `value` is not in _init_, everything is "the value", defaults apply - # if `value` is in _init_, only the first thing after the = is the value, and the rest will - # be passed to __init__ - # if fewer values are present for member assignment than _init_ calls for, _generate_next_value_ - # will be called in an attempt to generate them - # - # if AddValue is present then - # _generate_next_value_ is always called, and any generated values are prepended to provided - # values (custom _gnv_s can change that) - # default _init_ rules apply - - - # Constants used in Enum - -@export(globals()) -class EnumConstants(NamedConstant): - AddValue = constant('addvalue', 'prepends value(s) from _generate_next_value_ to each member') - MagicValue = constant('magicvalue', 'calls _generate_next_value_ when no arguments are given') - MultiValue = constant('multivalue', 'each member can have several values') - NoAlias = constant('noalias', 'duplicate valued members are distinct, not aliased') - Unique = constant('unique', 'duplicate valued members are not allowed') - def __repr__(self): - return self._name_ - - - # Dummy value for Enum as EnumType explicity checks for it, but of course until - # EnumType finishes running the first time the Enum class doesn't exist. This - # is also why there are checks in EnumType like `if Enum is not None`. - # - # Ditto for Flag. - -Enum = ReprEnum = IntEnum = StrEnum = Flag = IntFlag = EJECT = KEEP = None - -class enum(object): - """ - Helper class to track args, kwds. - """ - def __init__(self, *args, **kwds): - self._args = args - self._kwds = dict(kwds.items()) - self._hash = hash(args) - self.name = None - - @_bltin_property - def args(self): - return self._args - - @_bltin_property - def kwds(self): - return self._kwds.copy() - - def __hash__(self): - return self._hash - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.args == other.args and self.kwds == other.kwds - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.args != other.args or self.kwds != other.kwds - - def __repr__(self): - final = [] - args = ', '.join(['%r' % (a, ) for a in self.args]) - if args: - final.append(args) - kwds = ', '.join([('%s=%r') % (k, v) for k, v in enumsort(list(self.kwds.items()))]) - if kwds: - final.append(kwds) - return '%s(%s)' % (self.__class__.__name__, ', '.join(final)) - -_auto_null = SentinelType('no_value', (object, ), {}) -class auto(enum): - """ - Instances are replaced with an appropriate value in Enum class suites. - """ - enum_member = _auto_null - _value = _auto_null - _operations = [] - - def __and__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_and_, (self, other))) - return new_auto - - def __rand__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_and_, (other, self))) - return new_auto - - def __invert__(self): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_inv_, (self,))) - return new_auto - - def __or__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_or_, (self, other))) - return new_auto - - def __ror__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_or_, (other, self))) - return new_auto - - def __xor__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_xor_, (self, other))) - return new_auto - - def __rxor__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_xor_, (other, self))) - return new_auto - - def __abs__(self): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_abs_, (self, ))) - return new_auto - - def __add__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_add_, (self, other))) - return new_auto - - def __radd__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_add_, (other, self))) - return new_auto - - def __neg__(self): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_neg_, (self, ))) - return new_auto - - def __pos__(self): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_pos_, (self, ))) - return new_auto - - if PY2: - def __div__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_div_, (self, other))) - return new_auto - - def __rdiv__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_div_, (other, self))) - return new_auto - - def __floordiv__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_floordiv_, (self, other))) - return new_auto - - def __rfloordiv__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_floordiv_, (other, self))) - return new_auto - - def __truediv__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_truediv_, (self, other))) - return new_auto - - def __rtruediv__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_truediv_, (other, self))) - return new_auto - - def __lshift__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_lshift_, (self, other))) - return new_auto - - def __rlshift__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_lshift_, (other, self))) - return new_auto - - def __rshift__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_rshift_, (self, other))) - return new_auto - - def __rrshift__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_rshift_, (other, self))) - return new_auto - - def __mod__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_mod_, (self, other))) - return new_auto - - def __rmod__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_mod_, (other, self))) - return new_auto - - def __mul__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_mul_, (self, other))) - return new_auto - - def __rmul__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_mul_, (other, self))) - return new_auto - - def __pow__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_pow_, (self, other))) - return new_auto - - def __rpow__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_pow_, (other, self))) - return new_auto - - def __sub__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_sub_, (self, other))) - return new_auto - - def __rsub__(self, other): - new_auto = self.__class__() - new_auto._operations = self._operations[:] - new_auto._operations.append((_sub_, (other, self))) - return new_auto - - def __repr__(self): - if self._operations: - return 'auto(...)' - else: - return 'auto(%r, *%r, **%r)' % (self._value, self._args, self._kwds) - - @_bltin_property - def value(self): - if self._value is not _auto_null and self._operations: - raise TypeError('auto() object out of sync') - elif self._value is _auto_null and not self._operations: - return self._value - elif self._value is not _auto_null: - return self._value - else: - return self._resolve() - - @value.setter - def value(self, value): - if self._operations: - value = self._resolve(value) - self._value = value - - def _resolve(self, base_value=None): - cls = self.__class__ - for op, params in self._operations: - values = [] - for param in params: - if isinstance(param, cls): - if param.value is _auto_null: - if base_value is None: - return _auto_null - else: - values.append(base_value) - else: - values.append(param.value) - else: - values.append(param) - value = op(*values) - self._operations[:] = [] - self._value = value - return value - - -class _EnumArgSpec(NamedTuple): - args = 0, 'all args except *args and **kwds' - varargs = 1, 'the name of the *args variable' - keywords = 2, 'the name of the **kwds variable' - defaults = 3, 'any default values' - required = 4, 'number of required values (no default available)' - - def __new__(cls, _new_func): - argspec = getargspec(_new_func) - args, varargs, keywords, defaults = argspec - if defaults: - reqs = args[1:-len(defaults)] - else: - reqs = args[1:] - return tuple.__new__(_EnumArgSpec, (args, varargs, keywords, defaults, reqs)) - - -class _proto_member: - """ - intermediate step for enum members between class execution and final creation - """ - - def __init__(self, value): - self.value = value - - def __set_name__(self, enum_class, member_name): - """ - convert each quasi-member into an instance of the new enum class - """ - # first step: remove ourself from enum_class - delattr(enum_class, member_name) - # second step: create member based on enum_class - value = self.value - kwds = {} - args = () - init_args = () - extra_mv_args = () - multivalue = None - if isinstance(value, tuple) and value and isinstance(value[0], auto): - multivalue = value - value = value[0] - if isinstance(value, auto) and value.value is _auto_null: - args = value.args - kwds = value.kwds - elif isinstance(value, auto): - kwds = value.kwds - args = (value.value, ) + value.args - value = value.value - elif isinstance(value, enum): - args = value.args - kwds = value.kwds - elif isinstance(value, Member): - value = value.value - args = (value, ) - elif not isinstance(value, tuple): - args = (value, ) - else: - args = value - if multivalue is not None: - value = (value, ) + multivalue[1:] - kwds = {} - args = value - del multivalue - # possibilities - # - # - no init, multivalue -> __new__[0], __init__(*[:]), extra=[1:] - # - init w/o value, multivalue -> __new__[0], __init__(*[:]), extra=[1:] - # - # - init w/value, multivalue -> __new__[0], __init__(*[1:]), extra=[1:] - # - # - init w/value, no multivalue -> __new__[0], __init__(*[1:]), extra=[] - # - # - init w/o value, no multivalue -> __new__[:], __init__(*[:]), extra=[] - # - no init, no multivalue -> __new__[:], __init__(*[:]), extra=[] - if enum_class._multivalue_ or 'value' in enum_class._creating_init_: - if enum_class._multivalue_: - # when multivalue is True, creating_init can be anything - mv_arg = args[0] - extra_mv_args = args[1:] - if 'value' in enum_class._creating_init_: - init_args = args[1:] - else: - init_args = args - args = args[0:1] - value = args[0] - else: - # 'value' is definitely in creating_init - if enum_class._auto_init_ and enum_class._new_args_: - # we have a custom __new__ and an auto __init__ - # divvy up according to number of params in each - init_args = args[-len(enum_class._creating_init_)+1:] - if not enum_class._auto_args_: - args = args[:len(enum_class._new_args_.args)] - value = args[0] - elif enum_class._auto_init_: - # don't pass in value - init_args = args[1:] - args = args[0:1] - value = args[0] - elif enum_class._new_args_: - # do not modify args - value = args[0] - else: - # keep all args for user-defined __init__ - # keep value as-is - init_args = args - else: - # either no creating_init, or it doesn't have 'value' - init_args = args - if enum_class._member_type_ is tuple: # special case for tuple enums - args = (args, ) # wrap it one more time - if not enum_class._use_args_: - enum_member = enum_class._new_member_(enum_class) - if not hasattr(enum_member, '_value_'): - enum_member._value_ = value - else: - enum_member = enum_class._new_member_(enum_class, *args, **kwds) - if not hasattr(enum_member, '_value_'): - if enum_class._member_type_ is object: - enum_member._value_ = value - else: - try: - enum_member._value_ = enum_class._member_type_(*args, **kwds) - except Exception: - te = TypeError('_value_ not set in __new__, unable to create it') - te.__cause__ = None - raise te - value = enum_member._value_ - enum_member._name_ = member_name - enum_member.__objclass__ = enum_class - enum_member.__init__(*init_args, **kwds) - enum_member._sort_order_ = len(enum_class._member_names_) - # If another member with the same value was already defined, the - # new member becomes an alias to the existing one. - if enum_class._noalias_: - # unless NoAlias was specified - enum_class._member_names_.append(member_name) - else: - nonunique = defaultdict(list) - try: - try: - # try to do a fast lookup to avoid the quadratic loop - enum_member = enum_class._value2member_map_[value] - if enum_class._unique_: - nonunique[enum_member.name].append(member_name) - except TypeError: - # unhashable members are stored elsewhere - for unhashable_value, canonical_member in enum_class._value2member_seq_: - name = canonical_member.name - if unhashable_value == enum_member._value_: - if enum_class._unique_: - nonunique[name].append(member_name) - enum_member = canonical_member - break - else: - raise KeyError - except KeyError: - # this could still be an alias if the value is multi-bit and the - # class is a flag class - if ( - Flag is None - or not issubclass(enum_class, Flag) - ): - # no other instances found, record this member in _member_names_ - enum_class._member_names_.append(member_name) - elif ( - Flag is not None - and issubclass(enum_class, Flag) - and _is_single_bit(value) - ): - # no other instances found, record this member in _member_names_ - enum_class._member_names_.append(member_name) - if nonunique: - # duplicates not allowed if Unique specified - message = [] - for name, aliases in nonunique.items(): - bad_aliases = ','.join(aliases) - message.append('%s --> %s [%r]' % (name, bad_aliases, enum_class[name].value)) - raise ValueError( - '%s: duplicate names found: %s' % - (enum_class.__name__, '; '.join(message)) - ) - # if self.value is an `auto()`, replace the value attribute with the new enum member - if isinstance(self.value, auto): - self.value.enum_member = enum_member - # get redirect in place before adding to _member_map_ - # but check for other instances in parent classes first - need_override = False - descriptor = None - descriptor_property = None - for base in enum_class.__mro__[1:]: - descriptor = base.__dict__.get(member_name) - if descriptor is not None: - if isinstance(descriptor, (property, DynamicClassAttribute)): - break - else: - need_override = True - if isinstance(descriptor, _bltin_property) and descriptor_property is None: - descriptor_property = descriptor - # keep looking for an enum.property - descriptor = descriptor or descriptor_property - if descriptor and not need_override: - # previous enum.property found, no further action needed - pass - else: - redirect = property() - redirect.__set_name__(enum_class, member_name) - if descriptor and need_override: - # previous enum.property found, but some other inherited - # attribute is in the way; copy fget, fset, fdel to this one - redirect.fget = descriptor.fget - redirect.fset = descriptor.fset - redirect.fdel = descriptor.fdel - setattr(enum_class, member_name, redirect) - # now add to _member_map_ (even aliases) - enum_class._member_map_[member_name] = enum_member - # - # process (possible) MultiValues - values = (value, ) + extra_mv_args - if enum_class._multivalue_ and mv_arg not in values: - values += (mv_arg, ) - enum_member._values_ = values - for value in values: - # first check if value has already been used - if enum_class._multivalue_ and ( - value in enum_class._value2member_map_ - or any(v == value for (v, m) in enum_class._value2member_seq_) - ): - raise ValueError('%r has already been used' % (value, )) - try: - # This may fail if value is not hashable. We can't add the value - # to the map, and by-value lookups for this value will be - # linear. - if enum_class._noalias_: - raise TypeError('cannot use dict to store value') - enum_class._value2member_map_[value] = enum_member - except TypeError: - enum_class._value2member_seq_ += ((value, enum_member), ) - - -class _EnumDict(dict): - """Track enum member order and ensure member names are not reused. - - EnumType will use the names found in self._member_names as the - enumeration member names. - """ - def __init__(self, cls_name, settings, start, constructor_init, constructor_start, constructor_boundary): - super(_EnumDict, self).__init__() - self._cls_name = cls_name - self._constructor_init = constructor_init - self._constructor_start = constructor_start - self._constructor_boundary = constructor_boundary - self._generate_next_value = None - self._member_names = [] - self._member_names_set = set() - self._settings = settings - self._addvalue = addvalue = AddValue in settings - self._magicvalue = MagicValue in settings - self._multivalue = MultiValue in settings - if self._addvalue and self._magicvalue: - raise TypeError('%r: AddValue and MagicValue are mutually exclusive' % cls_name) - if self._multivalue and self._magicvalue: - raise TypeError('%r: MultiValue and MagicValue are mutually exclusive' % cls_name) - self._start = start - self._addvalue_value = start - self._new_args = () - self._auto_args = False - # when the magic turns off - self._locked = MagicValue not in settings - # if init fields are specified - self._init = [] - # list of temporary names - self._ignore = [] - if self._magicvalue: - self._ignore = ['property', 'staticmethod', 'classmethod'] - self._ignore_init_done = False - # if _sunder_ values can be changed via the class body - self._allow_init = True - self._last_values = [] - - def __getitem__(self, key): - if key == self._cls_name and self._cls_name not in self: - return enum - elif ( - self._locked - or key in self - or key in self._ignore - or _is_sunder(key) - or _is_dunder(key) - ): - return super(_EnumDict, self).__getitem__(key) - elif self._magicvalue: - value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:]) - self.__setitem__(key, value) - return value - else: - raise Exception('Magic is not set -- why am I here?') - - def __setitem__(self, key, value): - """Changes anything not sundured, dundered, nor a descriptor. - - If an enum member name is used twice, an error is raised; duplicate - values are not checked for. - - Single underscore (sunder) names are reserved. - """ - # Flag classes that have MagicValue and __new__ will get a generated _gnv_ - if _is_internal_class(self._cls_name, value): - pass - elif _is_private_name(self._cls_name, key): - pass - elif _is_sunder(key): - if key not in ( - '_init_', '_settings_', '_order_', '_ignore_', '_start_', - '_create_pseudo_member_', '_create_pseudo_member_values_', - '_generate_next_value_', '_boundary_', '_numeric_repr_', - '_missing_', '_missing_value_', '_missing_name_', - '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_', - ): - raise ValueError('%r: _sunder_ names, such as %r, are reserved for future Enum use' - % (self._cls_name, key) - ) - elif not self._allow_init and key not in ( - 'create_pseudo_member_', '_missing_', '_missing_value_', '_missing_name_', - ): - # sunder is used during creation, must be specified first - raise ValueError('%r: cannot set %r after init phase' % (self._cls_name, key)) - elif key == '_ignore_': - if self._ignore_init_done: - raise TypeError('%r: ignore can only be specified once' % self._cls_name) - if isinstance(value, basestring): - value = value.split() - else: - value = list(value) - self._ignore = value - already = set(value) & self._member_names_set - if already: - raise ValueError('%r: _ignore_ cannot specify already set names %s' % ( - self._cls_name, - ', '.join(repr(a) for a in already) - )) - self._ignore_init_done = True - elif key == '_boundary_': - if self._constructor_boundary: - raise TypeError('%r: boundary specified in constructor and class body' % self._cls_name) - elif key == '_start_': - if self._constructor_start: - raise TypeError('%r: start specified in constructor and class body' % self._cls_name) - self._start = value - elif key == '_settings_': - if not isinstance(value, (set, tuple)): - value = (value, ) - if not isinstance(value, set): - value = set(value) - self._settings |= value - if NoAlias in value and Unique in value: - raise TypeError('%r: NoAlias and Unique are mutually exclusive' % self._cls_name) - elif MultiValue in value and NoAlias in value: - raise TypeError('cannot specify both MultiValue and NoAlias' % self._cls_name) - allowed_settings = dict.fromkeys(['addvalue', 'magicvalue', 'noalias', 'unique', 'multivalue']) - for arg in self._settings: - if arg not in allowed_settings: - raise TypeError('%r: unknown qualifier %r (from %r)' % (self._cls_name, arg, value)) - allowed_settings[arg] = True - self._multivalue = allowed_settings['multivalue'] - self._addvalue = allowed_settings['addvalue'] - self._magicvalue = allowed_settings['magicvalue'] - self._locked = not self._magicvalue - if self._magicvalue and not self._ignore_init_done: - self._ignore = ['property', 'classmethod', 'staticmethod'] - if self._addvalue and self._init and 'value' not in self._init: - self._init.insert(0, 'value') - value = tuple(self._settings) - elif key == '_init_': - if self._constructor_init: - raise TypeError('%r: init specified in constructor and in class body' % self._cls_name) - _init_ = value - if isinstance(_init_, basestring): - _init_ = _init_.replace(',',' ').split() - if self._addvalue and 'value' not in self._init: - self._init.insert(0, 'value') - if self._magicvalue: - raise TypeError("%r: _init_ and MagicValue are mutually exclusive" % self._cls_name) - self._init = _init_ - value = _init_ - elif key == '_generate_next_value_': - gnv = value - if value is not None: - if isinstance(value, staticmethod): - gnv = value.__func__ - elif isinstance(value, classmethod): - raise TypeError('%r: _generate_next_value must be a staticmethod, not a classmethod' % self._cls_name) - else: - gnv = value - value = staticmethod(value) - self._auto_args = _check_auto_args(value) - setattr(self, '_generate_next_value', gnv) - elif _is_dunder(key): - if key == '__order__': - key = '_order_' - if not self._allow_init: - # _order_ is used during creation, must be specified first - raise ValueError('%r: cannot set %r after init phase' % (self._cls_name, key)) - elif key == '__new__': # and self._new_to_init: - if isinstance(value, staticmethod): - value = value.__func__ - self._new_args = _EnumArgSpec(value) - elif key == '__init_subclass__': - if not isinstance(value, classmethod): - value = classmethod(value) - if _is_descriptor(value): - self._locked = True - elif key in self._member_names_set: - # descriptor overwriting an enum? - raise TypeError('%r: attempt to reuse name: %r' % (self._cls_name, key)) - elif key in self._ignore: - pass - elif not _is_descriptor(value): - self._allow_init = False - if key in self: - # enum overwriting a descriptor? - raise TypeError('%r: %s already defined as %r' % (self._cls_name, key, self[key])) - if type(value) is enum: - value.name = key - if self._addvalue: - raise TypeError('%r: enum() and AddValue are incompatible' % self._cls_name) - elif self._addvalue and not self._multivalue: - # generate a value - value = self._gnv(key, value) - elif self._multivalue: - # make sure it's a tuple - if not isinstance(value, tuple): - value = (value, ) - if isinstance(value[0], auto): - value = (self._convert_auto(key, value[0]), ) + value[1:] - if self._addvalue: - value = self._gnv(key, value) - elif isinstance(value, auto): - value = self._convert_auto(key, value) - elif isinstance(value, tuple) and value and isinstance(value[0], auto): - value = (self._convert_auto(key, value[0]), ) + value[1:] - elif not isinstance(value, auto): - # call generate maybe if - # - init is specified; or - # - __new__ is specified; - # and either of them call for more values than are present - new_args = () or self._new_args and self._new_args.required - target_len = len(self._init or new_args) - if isinstance(value, tuple): - source_len = len(value) - else: - source_len = 1 - multi_args = len(self._init) > 1 or new_args - if source_len < target_len : - value = self._gnv(key, value) - else: - pass - if self._init: - if isinstance(value, auto): - test_value = value.args - elif not isinstance(value, tuple): - test_value = (value, ) - else: - test_value = value - if len(self._init) != len(test_value): - raise TypeError( - '%s.%s: number of fields provided do not match init [%r != %r]' - % (self._cls_name, key, self._init, test_value) - ) - self._member_names.append(key) - self._member_names_set.add(key) - else: - # not a new member, turn off the autoassign magic - self._locked = True - self._allow_init = False - if not (_is_sunder(key) or _is_dunder(key) or _is_private_name(self._cls_name, key) or _is_descriptor(value)): - if isinstance(value, auto): - self._last_values.append(value.value) - elif isinstance(value, tuple) and value and isinstance(value[0], auto): - self._last_values.append(value[0].value) - elif isinstance(value, tuple): - if value: - self._last_values.append(value[0]) - else: - self._last_values.append(value) - super(_EnumDict, self).__setitem__(key, value) - - def _convert_auto(self, key, value): - # if auto.args or auto.kwds, compare to _init_ and __new__ -- if lacking, call gnv - # if not auto.args|kwds but auto.value is _auto_null -- call gnv - if value.args or value.kwds or value.value is _auto_null: - if value.args or value.kwds: - values = value.args - else: - values = () - new_args = () or self._new_args and self._new_args.required - target_len = len(self._init or new_args) or 1 - if isinstance(values, tuple): - source_len = len(values) - else: - source_len = 1 - multi_args = len(self._init) > 1 or new_args - if source_len < target_len : - values = self._gnv(key, values) - if value.args: - value._args = values - else: - value.value = values - return value - - def _gnv(self, key, value): - # generate a value - if self._auto_args: - if not isinstance(value, tuple): - value = (value, ) - value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:], *value) - else: - value = self._generate_next_value(key, self._start, len(self._member_names), self._last_values[:]) - if isinstance(value, tuple) and len(value) == 1: - value = value[0] - return value - - -no_arg = SentinelType('no_arg', (object, ), {}) -class EnumType(type): - """Metaclass for Enum""" - - @classmethod - def __prepare__(metacls, cls, bases, init=None, start=None, settings=(), boundary=None, **kwds): - metacls._check_for_existing_members_(cls, bases) - if Flag is None and cls == 'Flag': - initial_flag = True - else: - initial_flag = False - # settings are a combination of current and all past settings - constructor_init = init is not None - constructor_start = start is not None - constructor_boundary = boundary is not None - if not isinstance(settings, tuple): - settings = settings, - settings = set(settings) - generate = None - order = None - # inherit previous flags - member_type, first_enum = metacls._get_mixins_(cls, bases) - if first_enum is not None: - generate = getattr(first_enum, '_generate_next_value_', None) - generate = getattr(generate, 'im_func', generate) - settings |= metacls._get_settings_(bases) - init = init or first_enum._auto_init_[:] - order = first_enum._order_function_ - if start is None: - start = first_enum._start_ - else: - # first time through -- creating Enum itself - start = 1 - # check for custom settings - if AddValue in settings and init and 'value' not in init: - if isinstance(init, list): - init.insert(0, 'value') - else: - init = 'value ' + init - if NoAlias in settings and Unique in settings: - raise TypeError('%r: NoAlias and Unique are mutually exclusive' % cls) - if MultiValue in settings and NoAlias in settings: - raise TypeError('%r: MultiValue and NoAlias are mutually exclusive' % cls) - allowed_settings = dict.fromkeys(['addvalue', 'magicvalue', 'noalias', 'unique', 'multivalue']) - for arg in settings: - if arg not in allowed_settings: - raise TypeError('%r: unknown qualifier %r' % (cls, arg)) - enum_dict = _EnumDict(cls_name=cls, settings=settings, start=start, constructor_init=constructor_init, constructor_start=constructor_start, constructor_boundary=constructor_boundary) - enum_dict._member_type = member_type - enum_dict._base_type = ('enum', 'flag')[ - Flag is None and cls == 'Flag' - or - Flag is not None and any(issubclass(b, Flag) for b in bases) - ] - if Flag is not None and any(b is Flag for b in bases) and member_type not in (baseinteger + (object, )): - if Flag in bases: - # when a non-int data type is mixed in with Flag, we end up - # needing two values for two `__new__`s: - # - the integer value for the Flag itself; and - # - the mix-in value for the mix-in - # - # we provide a default `_generate_next_value_` to supply the int - # argument, and a default `__new__` to keep the two straight - def _generate_next_value_(name, start, count, values, *args, **kwds): - return (2 ** count, ) + args - enum_dict['_generate_next_value_'] = staticmethod(_generate_next_value_) - def __new__(cls, flag_value, type_value): - obj = member_type.__new__(cls, type_value) - obj._value_ = flag_value - return obj - enum_dict['__new__'] = __new__ - else: - try: - enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__) - except TypeError: - pass - elif not initial_flag: - if hasattr(first_enum, '__new_member__'): - enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__) - if generate: - enum_dict['_generate_next_value_'] = generate - enum_dict._inherited_gnv = True - if init is not None: - if isinstance(init, basestring): - init = init.replace(',',' ').split() - enum_dict._init = init - elif hasattr(first_enum, '__new_member__'): - enum_dict._new_args = _EnumArgSpec(first_enum.__new_member__) - if order is not None: - enum_dict['_order_'] = staticmethod(order) - return enum_dict - - def __init__(cls, *args , **kwds): - pass - - def __new__(metacls, cls, bases, clsdict, init=None, start=None, settings=(), boundary=None, **kwds): - # handle py2 case first - if type(clsdict) is not _EnumDict: - # py2 and/or functional API gyrations - init = clsdict.pop('_init_', None) - start = clsdict.pop('_start_', None) - settings = clsdict.pop('_settings_', ()) - _order_ = clsdict.pop('_order_', clsdict.pop('__order__', None)) - _ignore_ = clsdict.pop('_ignore_', None) - _create_pseudo_member_ = clsdict.pop('_create_pseudo_member_', None) - _create_pseudo_member_values_ = clsdict.pop('_create_pseudo_member_values_', None) - _generate_next_value_ = clsdict.pop('_generate_next_value_', None) - _missing_ = clsdict.pop('_missing_', None) - _missing_value_ = clsdict.pop('_missing_value_', None) - _missing_name_ = clsdict.pop('_missing_name_', None) - _boundary_ = clsdict.pop('_boundary_', None) - _iter_member_ = clsdict.pop('_iter_member_', None) - _iter_member_by_value_ = clsdict.pop('_iter_member_by_value_', None) - _iter_member_by_def_ = clsdict.pop('_iter_member_by_def_', None) - __new__ = clsdict.pop('__new__', None) - __new__ = getattr(__new__, 'im_func', __new__) - __new__ = getattr(__new__, '__func__', __new__) - enum_members = dict([ - (k, v) for (k, v) in clsdict.items() - if not (_is_sunder(k) or _is_dunder(k) or _is_private_name(cls, k) or _is_descriptor(v)) - ]) - original_dict = clsdict - clsdict = metacls.__prepare__(cls, bases, init=init, start=start) - if settings: - clsdict['_settings_'] = settings - init = init or clsdict._init - if _order_ is None: - _order_ = clsdict.get('_order_') - if _order_ is not None: - _order_ = _order_.__get__(cls) - if isinstance(original_dict, OrderedDict): - calced_order = original_dict - elif _order_ is None: - calced_order = [name for (name, value) in enumsort(list(enum_members.items()))] - elif isinstance(_order_, basestring): - calced_order = _order_ = _order_.replace(',', ' ').split() - elif callable(_order_): - if init: - if not isinstance(init, basestring): - init = ' '.join(init) - member = NamedTuple('member', init and 'name ' + init or ['name', 'value']) - calced_order = [] - for name, value in enum_members.items(): - if init: - if not isinstance(value, tuple): - value = (value, ) - name_value = (name, ) + value - else: - name_value = tuple((name, value)) - if member._defined_len_ != len(name_value): - raise TypeError('%d values expected (%s), %d received (%s)' % ( - member._defined_len_, - ', '.join(member._fields_), - len(name_value), - ', '.join([repr(v) for v in name_value]), - )) - calced_order.append(member(*name_value)) - calced_order = [m.name for m in sorted(calced_order, key=_order_)] - else: - calced_order = _order_ - for name in ( - '_missing_', '_missing_value_', '_missing_name_', - '_ignore_', '_create_pseudo_member_', '_create_pseudo_member_values_', - '_generate_next_value_', '_order_', '__new__', - '_missing_', '_missing_value_', '_missing_name_', - '_boundary_', - '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_', - ): - attr = locals()[name] - if attr is not None: - clsdict[name] = attr - # now add members - for k in calced_order: - try: - clsdict[k] = original_dict[k] - except KeyError: - # this error will be handled when _order_ is checked - pass - for k, v in original_dict.items(): - if k not in calced_order: - clsdict[k] = v - del _order_, _ignore_, _create_pseudo_member_, _create_pseudo_member_values_, - del _generate_next_value_, _missing_, _missing_value_, _missing_name_ - # - # resume normal path - clsdict._locked = True - # - # check for illegal enum names (any others?) - member_names = clsdict._member_names - invalid_names = set(member_names) & set(['mro', '']) - if invalid_names: - raise ValueError('invalid enum member name(s): %s' % ( - ', '.join(invalid_names), )) - _order_ = clsdict.pop('_order_', None) - if isinstance(_order_, basestring): - _order_ = _order_.replace(',',' ').split() - init = clsdict._init - start = clsdict._start - settings = clsdict._settings - creating_init = [] - new_args = clsdict._new_args - auto_args = clsdict._auto_args - auto_init = False - if init is not None: - auto_init = True - creating_init = init[:] - if 'value' in creating_init and creating_init[0] != 'value': - raise TypeError("'value', if specified, must be the first item in 'init'") - magicvalue = MagicValue in settings - multivalue = MultiValue in settings - noalias = NoAlias in settings - unique = Unique in settings - # an Enum class cannot be mixed with other types (int, float, etc.) if - # it has an inherited __new__ unless a new __new__ is defined (or - # the resulting class will fail). - # an Enum class is final once enumeration items have been defined; - # - # remove any keys listed in _ignore_ - clsdict.setdefault('_ignore_', []).append('_ignore_') - ignore = clsdict['_ignore_'] - for key in ignore: - clsdict.pop(key, None) - # - boundary = boundary or clsdict.pop('_boundary_', None) - # convert to regular dict - clsdict = dict(clsdict.items()) - member_type, first_enum = metacls._get_mixins_(cls, bases) - # get the method to create enum members - __new__, save_new, new_uses_args = metacls._find_new_( - clsdict, - member_type, - first_enum, - ) - clsdict['_new_member_'] = staticmethod(__new__) - clsdict['_use_args_'] = new_uses_args - # - # convert future enum members into temporary _proto_members - # and record integer values in case this will be a Flag - flag_mask = 0 - for name in member_names: - value = test_value = clsdict[name] - if isinstance(value, auto) and value.value is not _auto_null: - test_value = value.value - if isinstance(test_value, baseinteger): - flag_mask |= test_value - if isinstance(test_value, tuple) and test_value and isinstance(test_value[0], baseinteger): - flag_mask |= test_value[0] - clsdict[name] = _proto_member(value) - # - # temp stuff - clsdict['_creating_init_'] = creating_init - clsdict['_multivalue_'] = multivalue - clsdict['_magicvalue_'] = magicvalue - clsdict['_noalias_'] = noalias - clsdict['_unique_'] = unique - # - # house-keeping structures - clsdict['_member_names_'] = [] - clsdict['_member_map_'] = OrderedDict() - clsdict['_member_type_'] = member_type - clsdict['_value2member_map_'] = {} - clsdict['_value2member_seq_'] = () - clsdict['_settings_'] = settings - clsdict['_start_'] = start - clsdict['_auto_init_'] = init - clsdict['_new_args_'] = new_args - clsdict['_auto_args_'] = auto_args - clsdict['_order_function_'] = None - # now set the __repr__ for the value - clsdict['_value_repr_'] = metacls._find_data_repr_(cls, bases) - # - # Flag structures (will be removed if final class is not a Flag - clsdict['_boundary_'] = ( - boundary - or getattr(first_enum, '_boundary_', None) - ) - clsdict['_flag_mask_'] = flag_mask - clsdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1 - clsdict['_inverted_'] = None - # - # move skipped values out of the descriptor - for name, obj in clsdict.items(): - if isinstance(obj, nonmember): - clsdict[name] = obj.value - # - # If a custom type is mixed into the Enum, and it does not know how - # to pickle itself, pickle.dumps will succeed but pickle.loads will - # fail. Rather than have the error show up later and possibly far - # from the source, sabotage the pickle protocol for this class so - # that pickle.dumps also fails. - # - # However, if the new class implements its own __reduce_ex__, do not - # sabotage -- it's on them to make sure it works correctly. We use - # __reduce_ex__ instead of any of the others as it is preferred by - # pickle over __reduce__, and it handles all pickle protocols. - unpicklable = False - if '__reduce_ex__' not in clsdict: - if member_type is not object: - methods = ('__getnewargs_ex__', '__getnewargs__', - '__reduce_ex__', '__reduce__') - if not any(m in member_type.__dict__ for m in methods): - _make_class_unpicklable(clsdict) - unpicklable = True - # - # create a default docstring if one has not been provided - if '__doc__' not in clsdict: - clsdict['__doc__'] = 'An enumeration.' - # - # create our new Enum type - try: - exc = None - enum_class = type.__new__(metacls, cls, bases, clsdict) - except RuntimeError as e: - # any exceptions raised by _proto_member (aka member.__new__) will get converted to - # a RuntimeError, so get that original exception back and raise - # it instead - exc = e.__cause__ or e - if exc is not None: - raise exc - # - # if Python 3.5 or ealier, implement the __set_name__ and - # __init_subclass__ protocols - if pyver < PY3_6: - for name in member_names: - enum_class.__dict__[name].__set_name__(enum_class, name) - for name, obj in enum_class.__dict__.items(): - if name in member_names: - continue - if hasattr(obj, '__set_name__'): - obj.__set_name__(enum_class, name) - if Enum is not None: - super(enum_class, enum_class).__init_subclass__() - # - # double check that repr and friends are not the mixin's or various - # things break (such as pickle) - # - # Also, special handling for ReprEnum - if ReprEnum is not None and ReprEnum in bases: - if member_type is object: - raise TypeError( - 'ReprEnum subclasses must be mixed with a data type (i.e.' - ' int, str, float, etc.)' - ) - if '__format__' not in clsdict: - enum_class.__format__ = member_type.__format__ - clsdict['__format__'] = enum_class.__format__ - if '__str__' not in clsdict: - method = member_type.__str__ - if method is object.__str__: - # if member_type does not define __str__, object.__str__ will use - # its __repr__ instead, so we'll also use its __repr__ - method = member_type.__repr__ - enum_class.__str__ = method - clsdict['__str__'] = enum_class.__str__ - - for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): - if name in clsdict: - # class has defined/imported/copied the method - continue - class_method = getattr(enum_class, name) - obj_method = getattr(member_type, name, None) - enum_method = getattr(first_enum, name, None) - if obj_method is not None and obj_method == class_method: - if name == '__reduce_ex__' and unpicklable: - continue - setattr(enum_class, name, enum_method) - clsdict[name] = enum_method - # - # for Flag, add __or__, __and__, __xor__, and __invert__ - if Flag is not None and issubclass(enum_class, Flag): - for name in ( - '__or__', '__and__', '__xor__', - '__ror__', '__rand__', '__rxor__', - '__invert__' - ): - if name not in clsdict: - setattr(enum_class, name, getattr(Flag, name)) - clsdict[name] = enum_method - # - # method resolution and int's are not playing nice - # Python's less than 2.6 use __cmp__ - if pyver < PY2_6: - # - if issubclass(enum_class, int): - setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) - # - elif PY2: - # - if issubclass(enum_class, int): - for method in ( - '__le__', - '__lt__', - '__gt__', - '__ge__', - '__eq__', - '__ne__', - '__hash__', - ): - setattr(enum_class, method, getattr(int, method)) - # - # replace any other __new__ with our own (as long as Enum is not None, - # anyway) -- again, this is to support pickle - if Enum is not None: - # if the user defined their own __new__, save it before it gets - # clobbered in case they subclass later - if save_new: - setattr(enum_class, '__new_member__', enum_class.__dict__['__new__']) - setattr(enum_class, '__new__', Enum.__dict__['__new__']) - # - # _order_ checking is spread out into three/four steps - # - ensure _order_ is a list, not a string nor a function - # - if enum_class is a Flag: - # - remove any non-single-bit flags from _order_ - # - remove any aliases from _order_ - # - check that _order_ and _member_names_ match - # - # _order_ step 1: ensure _order_ is a list - if _order_: - if isinstance(_order_, staticmethod): - _order_ = _order_.__func__ - if callable(_order_): - # save order for future subclasses - enum_class._order_function_ = staticmethod(_order_) - # create ordered list for comparison - _order_ = [m.name for m in sorted(enum_class, key=_order_)] - # - # remove Flag structures if final class is not a Flag - if ( - Flag is None and cls != 'Flag' - or Flag is not None and not issubclass(enum_class, Flag) - ): - delattr(enum_class, '_boundary_') - delattr(enum_class, '_flag_mask_') - delattr(enum_class, '_all_bits_') - delattr(enum_class, '_inverted_') - elif Flag is not None and issubclass(enum_class, Flag): - # ensure _all_bits_ is correct and there are no missing flags - single_bit_total = 0 - multi_bit_total = 0 - for flag in enum_class._member_map_.values(): - if _is_single_bit(flag._value_): - single_bit_total |= flag._value_ - else: - # multi-bit flags are considered aliases - multi_bit_total |= flag._value_ - if enum_class._boundary_ is not KEEP: - missed = list(_iter_bits_lsb(multi_bit_total & ~single_bit_total)) - if missed: - raise TypeError( - 'invalid Flag %r -- missing values: %s' - % (cls, ', '.join((str(i) for i in missed))) - ) - enum_class._flag_mask_ = single_bit_total - enum_class._all_bits_ = 2 ** ((single_bit_total).bit_length()) - 1 - # - # set correct __iter__ - if [m._value_ for m in enum_class] != sorted([m._value_ for m in enum_class]): - enum_class._iter_member_ = enum_class._iter_member_by_def_ - if _order_: - # _order_ step 2: remove any items from _order_ that are not single-bit - _order_ = [ - o - for o in _order_ - if o not in enum_class._member_map_ or _is_single_bit(enum_class[o]._value_) - ] - # - # check for constants with auto() values - for k, v in enum_class.__dict__.items(): - if isinstance(v, constant) and isinstance(v.value, auto): - v.value = enum_class(v.value.value) - # - if _order_: - # _order_ step 3: remove aliases from _order_ - _order_ = [ - o - for o in _order_ - if ( - o not in enum_class._member_map_ - or - (o in enum_class._member_map_ and o in enum_class._member_names_) - )] - # _order_ step 4: verify that _order_ and _member_names_ match - if _order_ != enum_class._member_names_: - raise TypeError( - 'member order does not match _order_:\n%r\n%r' - % (enum_class._member_names_, _order_) - ) - return enum_class - - def __bool__(cls): - """ - classes/types should always be True. - """ - return True - - def __call__(cls, value=no_arg, names=None, module=None, qualname=None, type=None, start=1, boundary=None): - """Either returns an existing member, or creates a new enum class. - - This method is used both when an enum class is given a value to match - to an enumeration member (i.e. Color(3)) and for the functional API - (i.e. Color = Enum('Color', names='red green blue')). - - When used for the functional API: `module`, if set, will be stored in - the new class' __module__ attribute; `type`, if set, will be mixed in - as the first base class. - - Note: if `module` is not set this routine will attempt to discover the - calling module by walking the frame stack; if this is unsuccessful - the resulting class will not be pickleable. - """ - if names is None: # simple value lookup - return cls.__new__(cls, value) - # otherwise, functional API: we're creating a new Enum type - return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start, boundary=boundary) - - def __contains__(cls, member): - if not isinstance(member, Enum): - raise TypeError("%r (%r) is not an " % (member, type(member))) - if not isinstance(member, cls): - return False - return True - - def __delattr__(cls, attr): - # nicer error message when someone tries to delete an attribute - # (see issue19025). - if attr in cls._member_map_: - raise AttributeError( - "%s: cannot delete Enum member %r." % (cls.__name__, attr), - ) - found_attr = _get_attr_from_chain(cls, attr) - if isinstance(found_attr, constant): - raise AttributeError( - "%s: cannot delete constant %r" % (cls.__name__, attr), - ) - elif isinstance(found_attr, property): - raise AttributeError( - "%s: cannot delete property %r" % (cls.__name__, attr), - ) - super(EnumType, cls).__delattr__(attr) - - def __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) - - @_bltin_property - def __members__(cls): - """Returns a mapping of member name->value. - - This mapping lists all enum members, including aliases. Note that this - is a copy of the internal mapping. - """ - return cls._member_map_.copy() - - def __getitem__(cls, name): - try: - return cls._member_map_[name] - except KeyError: - exc = _sys.exc_info()[1] - if Flag is not None and issubclass(cls, Flag) and '|' in name: - try: - # may be an __or__ed name - result = cls(0) - for n in name.split('|'): - result |= cls[n] - return result - except KeyError: - raise exc - result = cls._missing_name_(name) - if isinstance(result, cls): - return result - else: - raise exc - - def __iter__(cls): - return (cls._member_map_[name] for name in cls._member_names_) - - def __reversed__(cls): - return (cls._member_map_[name] for name in reversed(cls._member_names_)) - - def __len__(cls): - return len(cls._member_names_) - - __nonzero__ = __bool__ - - def __repr__(cls): - return "" % (cls.__name__, ) - - def __setattr__(cls, name, value): - """Block attempts to reassign Enum members/constants. - - A simple assignment to the class namespace only changes one of the - several possible ways to get an Enum member from the Enum class, - resulting in an inconsistent Enumeration. - """ - member_map = cls.__dict__.get('_member_map_', {}) - if name in member_map: - raise AttributeError( - '%s: cannot rebind member %r.' % (cls.__name__, name), - ) - found_attr = _get_attr_from_chain(cls, name) - if isinstance(found_attr, constant): - raise AttributeError( - "%s: cannot rebind constant %r" % (cls.__name__, name), - ) - elif isinstance(found_attr, property): - raise AttributeError( - "%s: cannot rebind property %r" % (cls.__name__, name), - ) - super(EnumType, cls).__setattr__(name, value) - - def _convert(cls, *args, **kwds): - import warnings - warnings.warn("_convert is deprecated and will be removed, use" - " _convert_ instead.", DeprecationWarning, stacklevel=2) - return cls._convert_(*args, **kwds) - - def _convert_(cls, name, module, filter, source=None, boundary=None, as_global=False): - """ - Create a new Enum subclass that replaces a collection of global constants - """ - # convert all constants from source (or module) that pass filter() to - # a new Enum called name, and export the enum and its members back to - # module; - # also, replace the __reduce_ex__ method so unpickling works in - # previous Python versions - module_globals = vars(_sys.modules[module]) - if source: - source = vars(source) - else: - source = module_globals - members = [(key, source[key]) for key in source.keys() if filter(key)] - try: - # sort by value, name - members.sort(key=lambda t: (t[1], t[0])) - except TypeError: - # unless some values aren't comparable, in which case sort by just name - members.sort(key=lambda t: t[0]) - cls = cls(name, members, module=module, boundary=boundary or KEEP) - cls.__reduce_ex__ = _reduce_ex_by_name - if as_global: - global_enum(cls) - else: - module_globals.update(cls.__members__) - module_globals[name] = cls - return cls - - def _create_(cls, class_name, names, module=None, qualname=None, type=None, start=1, boundary=None): - """Convenience method to create a new Enum class. - - `names` can be: - - * A string containing member names, separated either with spaces or - commas. Values are auto-numbered from 1. - * An iterable of member names. Values are auto-numbered from 1. - * An iterable of (member name, value) pairs. - * A mapping of member name -> value. - """ - if PY2: - # if class_name is unicode, attempt a conversion to ASCII - if isinstance(class_name, unicode): - try: - class_name = class_name.encode('ascii') - except UnicodeEncodeError: - raise TypeError('%r is not representable in ASCII' % (class_name, )) - metacls = cls.__class__ - if type is None: - bases = (cls, ) - else: - bases = (type, cls) - _, first_enum = cls._get_mixins_(class_name, bases) - generate = getattr(first_enum, '_generate_next_value_', None) - generate = getattr(generate, 'im_func', generate) - # special processing needed for names? - if isinstance(names, basestring): - names = names.replace(',', ' ').split() - if isinstance(names, (tuple, list)) and names and isinstance(names[0], basestring): - original_names, names = names, [] - last_values = [] - for count, name in enumerate(original_names): - value = generate(name, start, count, last_values[:]) - last_values.append(value) - names.append((name, value)) - # Here, names is either an iterable of (name, value) or a mapping. - item = None # in case names is empty - clsdict = None - for item in names: - if clsdict is None: - # first time initialization - if isinstance(item, basestring): - clsdict = {} - else: - # remember the order - clsdict = metacls.__prepare__(class_name, bases) - if isinstance(item, basestring): - member_name, member_value = item, names[item] - else: - member_name, member_value = item - clsdict[member_name] = member_value - if clsdict is None: - # in case names was empty - clsdict = metacls.__prepare__(class_name, bases) - enum_class = metacls.__new__(metacls, class_name, bases, clsdict, boundary=boundary) - # TODO: replace the frame hack if a blessed way to know the calling - # module is ever developed - if module is None: - try: - module = _sys._getframe(2).f_globals['__name__'] - except (AttributeError, KeyError): - pass - if module is None: - _make_class_unpicklable(enum_class) - else: - enum_class.__module__ = module - if qualname is not None: - enum_class.__qualname__ = qualname - return enum_class - - @classmethod - def _check_for_existing_members_(mcls, class_name, bases): - if Enum is None: - return - for chain in bases: - for base in chain.__mro__: - if issubclass(base, Enum) and base._member_names_: - raise TypeError( - " cannot extend %r" - % (class_name, base) - ) - @classmethod - def _get_mixins_(mcls, class_name, bases): - """Returns the type for creating enum members, and the first inherited - enum class. - - bases: the tuple of bases that was given to __new__ - """ - if not bases or Enum is None: - return object, Enum - - mcls._check_for_existing_members_(class_name, bases) - - # ensure final parent class is an Enum derivative, find any concrete - # data type, and check that Enum has no members - first_enum = bases[-1] - if not issubclass(first_enum, Enum): - raise TypeError("new enumerations should be created as " - "`EnumName([mixin_type, ...] [data_type,] enum_type)`") - member_type = mcls._find_data_type_(class_name, bases) or object - if first_enum._member_names_: - raise TypeError("cannot extend enumerations via subclassing") - # - return member_type, first_enum - - @classmethod - def _find_data_repr_(mcls, class_name, bases): - for chain in bases: - for base in chain.__mro__: - if base is object: - continue - elif issubclass(base, Enum): - # if we hit an Enum, use it's _value_repr_ - return base._value_repr_ - elif '__repr__' in base.__dict__: - # this is our data repr - return base.__dict__['__repr__'] - return None - - @classmethod - def _find_data_type_(mcls, class_name, bases): - data_types = set() - for chain in bases: - candidate = None - for base in chain.__mro__: - if base is object or base is StdlibEnum or base is StdlibFlag: - continue - elif issubclass(base, Enum): - if base._member_type_ is not object: - data_types.add(base._member_type_) - elif '__new__' in base.__dict__: - if issubclass(base, Enum): - continue - elif StdlibFlag is not None and issubclass(base, StdlibFlag): - continue - data_types.add(candidate or base) - break - else: - candidate = candidate or base - if len(data_types) > 1: - raise TypeError('%r: too many data types: %r' % (class_name, data_types)) - elif data_types: - return data_types.pop() - else: - return None - - @staticmethod - def _get_settings_(bases): - """Returns the combined _settings_ of all Enum base classes - - bases: the tuple of bases given to __new__ - """ - settings = set() - for chain in bases: - for base in chain.__mro__: - if issubclass(base, Enum): - for s in base._settings_: - settings.add(s) - return settings - - @classmethod - def _find_new_(mcls, clsdict, member_type, first_enum): - """Returns the __new__ to be used for creating the enum members. - - clsdict: the class dictionary given to __new__ - member_type: the data type whose __new__ will be used by default - first_enum: enumeration to check for an overriding __new__ - """ - # now find the correct __new__, checking to see of one was defined - # by the user; also check earlier enum classes in case a __new__ was - # saved as __new_member__ - __new__ = clsdict.get('__new__', None) - # - # should __new__ be saved as __new_member__ later? - save_new = first_enum is not None and __new__ is not None - # - if __new__ is None: - # check all possibles for __new_member__ before falling back to - # __new__ - for method in ('__new_member__', '__new__'): - for possible in (member_type, first_enum): - target = getattr(possible, method, None) - if target not in ( - None, - None.__new__, - object.__new__, - Enum.__new__, - StdlibEnum.__new__, - ): - __new__ = target - break - if __new__ is not None: - break - else: - __new__ = object.__new__ - # if a non-object.__new__ is used then whatever value/tuple was - # assigned to the enum member name will be passed to __new__ and to the - # new enum member's __init__ - if __new__ is object.__new__: - new_uses_args = False - else: - new_uses_args = True - # - return __new__, save_new, new_uses_args - - - # In order to support Python 2 and 3 with a single - # codebase we have to create the Enum methods separately - # and then use the `type(name, bases, dict)` method to - # create the class. - -EnumMeta = EnumType - -enum_dict = _Addendum( - dict=EnumType.__prepare__('Enum', (object, )), - doc="Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n", - ns=globals(), - ) - -@enum_dict -def __init__(self, *args, **kwds): - # auto-init method - _auto_init_ = self._auto_init_ - if _auto_init_ is None: - return - if 'value' in _auto_init_: - # remove 'value' from _auto_init_ as it has already been handled - _auto_init_ = _auto_init_[1:] - if _auto_init_: - if len(_auto_init_) < len(args): - raise TypeError('%d arguments expected (%s), %d received (%s)' - % (len(_auto_init_), _auto_init_, len(args), args)) - for name, arg in zip(_auto_init_, args): - setattr(self, name, arg) - if len(args) < len(_auto_init_): - remaining_args = _auto_init_[len(args):] - for name in remaining_args: - value = kwds.pop(name, undefined) - if value is undefined: - raise TypeError('missing value for: %r' % (name, )) - setattr(self, name, value) - if kwds: - # too many keyword arguments - raise TypeError('invalid keyword(s): %s' % ', '.join(kwds.keys())) - -@enum_dict -def __new__(cls, value): - # all enum instances are actually created during class construction - # without calling this method; this method is called by the metaclass' - # __call__ (i.e. Color(3) ), and by pickle - if NoAlias in cls._settings_: - raise TypeError('NoAlias enumerations cannot be looked up by value') - if type(value) is cls: - # For lookups like Color(Color.red) - # value = value.value - return value - # by-value search for a matching enum member - # see if it's in the reverse mapping (for hashable values) - try: - if value in cls._value2member_map_: - return cls._value2member_map_[value] - except TypeError: - # not there, now do long search -- O(n) behavior - for name, member in cls._value2member_seq_: - if name == value: - return member - # still not found -- try _missing_ hook - try: - exc = None - result = cls._missing_value_(value) - except Exception as e: - exc = e - result = None - if isinstance(result, cls) or getattr(cls, '_boundary_', None) is EJECT: - return result - else: - if value is no_arg: - ve_exc = ValueError('%s() should be called with a value' % (cls.__name__, )) - else: - ve_exc = ValueError("%r is not a valid %s" % (value, cls.__name__)) - if result is None and exc is None: - raise ve_exc - elif exc is None: - exc = TypeError( - 'error in %s._missing_: returned %r instead of None or a valid member' - % (cls.__name__, result) - ) - if not isinstance(exc, ValueError): - exc.__cause__ = ve_exc - raise exc - -@enum_dict -@classmethod -def __init_subclass__(cls, **kwds): - if pyver < PY3_6: - # end of the line - if kwds: - raise TypeError('unconsumed keyword arguments: %r' % (kwds, )) - else: - super(Enum, cls).__init_subclass__(**kwds) - -@enum_dict -@staticmethod -def _generate_next_value_(name, start, count, last_values, *args, **kwds): - for last_value in reversed(last_values): - try: - new_value = last_value + 1 - break - except TypeError: - pass - else: - new_value = start - if args: - return (new_value, ) + args - else: - return new_value - -@enum_dict -@classmethod -def _missing_(cls, value): - "deprecated, use _missing_value_ instead" - return None - -@enum_dict -@classmethod -def _missing_value_(cls, value): - "used for failed value access" - return cls._missing_(value) - -@enum_dict -@classmethod -def _missing_name_(cls, name): - "used for failed item access" - return None - -@enum_dict -def __repr__(self): - v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__ - return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) - -@enum_dict -def __str__(self): - return "%s.%s" % (self.__class__.__name__, self._name_) - -if PY3: - @enum_dict - def __dir__(self): - """ - Returns all members and all public methods - """ - if self.__class__._member_type_ is object: - interesting = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value']) - else: - interesting = set(object.__dir__(self)) - for name in getattr(self, '__dict__', []): - if name[0] != '_': - interesting.add(name) - for cls in self.__class__.mro(): - for name, obj in cls.__dict__.items(): - if name[0] == '_': - continue - if isinstance(obj, property): - # that's an enum.property - if obj.fget is not None or name not in self._member_map_: - interesting.add(name) - else: - # in case it was added by `dir(self)` - interesting.discard(name) - else: - interesting.add(name) - return sorted(interesting) - -@enum_dict -def __format__(self, format_spec): - # mixed-in Enums should use the mixed-in type's __format__, otherwise - # we can get strange results with the Enum name showing up instead of - # the value - - # pure Enum branch / overridden __str__ branch - overridden_str = self.__class__.__str__ != Enum.__str__ - if self._member_type_ is object or overridden_str: - cls = str - val = str(self) - # mix-in branch - else: - cls = self._member_type_ - val = self.value - return cls.__format__(val, format_spec) - -@enum_dict -def __hash__(self): - return hash(self._name_) - -@enum_dict -def __reduce_ex__(self, proto): - return self.__class__, (self._value_, ) - - -#################################### -# Python's less than 2.6 use __cmp__ - -if pyver < PY2_6: - - @enum_dict - def __cmp__(self, other): - if type(other) is self.__class__: - if self is other: - return 0 - return -1 - return NotImplemented - raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) - -else: - - @enum_dict - def __le__(self, other): - raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) - - @enum_dict - def __lt__(self, other): - raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) - - @enum_dict - def __ge__(self, other): - raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) - - @enum_dict - def __gt__(self, other): - raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) - - -@enum_dict -def __eq__(self, other): - if type(other) is self.__class__: - return self is other - return NotImplemented - -@enum_dict -def __ne__(self, other): - if type(other) is self.__class__: - return self is not other - return NotImplemented - -@enum_dict -def __hash__(self): - return hash(self._name_) - -@enum_dict -def __reduce_ex__(self, proto): - return self.__class__, (self._value_, ) - - -# enum.property is used to provide access to the `name`, `value', etc., -# properties of enum members while keeping some measure of protection -# from modification, while still allowing for an enumeration to have -# members named `name`, `value`, etc.. This works because enumeration -# members are not set directly on the enum class -- enum.property will -# look them up in _member_map_. - -@enum_dict -@property -def name(self): - return self._name_ - -@enum_dict -@property -def value(self): - return self._value_ - -@enum_dict -@property -def values(self): - return self._values_ - -def _reduce_ex_by_name(self, proto): - return self.name - -Enum = EnumType('Enum', (object, ), enum_dict.resolve()) -del enum_dict - - # Enum has now been created - -class ReprEnum(Enum): - """ - Only changes the repr(), leaving str() and format() to the mixed-in type. - """ - - -class IntEnum(int, ReprEnum): - """ - Enum where members are also (and must be) ints - """ - - -class StrEnum(str, ReprEnum): - """ - Enum where members are also (and must already be) strings - - default value is member name, lower-cased - """ - - def __new__(cls, *values, **kwds): - if kwds: - raise TypeError('%r: keyword arguments not supported' % (cls.__name__)) - if values: - if not isinstance(values[0], str): - raise TypeError('%s: values must be str [%r is a %r]' % (cls.__name__, values[0], type(values[0]))) - value = str(*values) - member = str.__new__(cls, value) - member._value_ = value - return member - - __str__ = str.__str__ - - def _generate_next_value_(name, start, count, last_values): - """ - Return the lower-cased version of the member name. - """ - return name.lower() - - -class LowerStrEnum(StrEnum): - """ - Enum where members are also (and must already be) lower-case strings - - default value is member name, lower-cased - """ - - def __new__(cls, value, *args, **kwds): - obj = StrEnum.__new_member__(cls, value, *args, **kwds) - if value != value.lower(): - raise ValueError('%r is not lower-case' % value) - return obj - - -class UpperStrEnum(StrEnum): - """ - Enum where members are also (and must already be) upper-case strings - - default value is member name, upper-cased - """ - - def __new__(cls, value, *args, **kwds): - obj = StrEnum.__new_member__(cls, value, *args, **kwds) - if value != value.upper(): - raise ValueError('%r is not upper-case' % value) - return obj - - def _generate_next_value_(name, start, count, last_values, *args, **kwds): - return name.upper() - - -if PY3: - class AutoEnum(Enum): - """ - automatically use _generate_next_value_ when values are missing (Python 3 only) - """ - _settings_ = MagicValue - - -class AutoNumberEnum(Enum): - """ - Automatically assign increasing values to members. - - Py3: numbers match creation order - Py2: numbers are assigned alphabetically by member name - (unless `_order_` is specified) - """ - - def __new__(cls, *args, **kwds): - value = len(cls.__members__) + 1 - if cls._member_type_ is int: - obj = int.__new__(cls, value) - elif cls._member_type_ is long: - obj = long.__new__(cls, value) - else: - obj = object.__new__(cls) - obj._value_ = value - return obj - - -class AddValueEnum(Enum): - _settings_ = AddValue - - -class MultiValueEnum(Enum): - """ - Multiple values can map to each member. - """ - _settings_ = MultiValue - - -class NoAliasEnum(Enum): - """ - Duplicate value members are distinct, but cannot be looked up by value. - """ - _settings_ = NoAlias - - -class OrderedEnum(Enum): - """ - Add ordering based on values of Enum members. - """ - - def __ge__(self, other): - if self.__class__ is other.__class__: - return self._value_ >= other._value_ - return NotImplemented - - def __gt__(self, other): - if self.__class__ is other.__class__: - return self._value_ > other._value_ - return NotImplemented - - def __le__(self, other): - if self.__class__ is other.__class__: - return self._value_ <= other._value_ - return NotImplemented - - def __lt__(self, other): - if self.__class__ is other.__class__: - return self._value_ < other._value_ - return NotImplemented - - -if sqlite3: - class SqliteEnum(Enum): - def __conform__(self, protocol): - if protocol is sqlite3.PrepareProtocol: - return self.name - - -class UniqueEnum(Enum): - """ - Ensure no duplicate values exist. - """ - _settings_ = Unique - - -def convert(enum, name, module, filter, source=None): - """ - Create a new Enum subclass that replaces a collection of global constants - - enum: Enum, IntEnum, ... - name: name of new Enum - module: name of module (__name__ in global context) - filter: function that returns True if name should be converted to Enum member - source: namespace to check (defaults to 'module') - """ - # convert all constants from source (or module) that pass filter() to - # a new Enum called name, and export the enum and its members back to - # module; - # also, replace the __reduce_ex__ method so unpickling works in - # previous Python versions - module_globals = vars(_sys.modules[module]) - if source: - source = vars(source) - else: - source = module_globals - members = dict((name, value) for name, value in source.items() if filter(name)) - enum = enum(name, members, module=module) - enum.__reduce_ex__ = _reduce_ex_by_name - module_globals.update(enum.__members__) - module_globals[name] = enum - -def extend_enum(enumeration, name, *args, **kwds): - """ - Add a new member to an existing Enum. - """ - # there are four possibilities: - # - extending an aenum Enum or 3.11+ enum Enum - # - extending an aenum Flag or 3.11+ enum Flag - # - extending a pre-3.11 stdlib Enum Flag - # - extending a 3.11+ stdlib Flag - # - # fail early if name is already in the enumeration - if ( - name in enumeration.__dict__ - or name in enumeration._member_map_ - or name in [t[1] for t in getattr(enumeration, '_value2member_seq_', ())] - ): - raise TypeError('%r already in use as %r' % (name, enumeration.__dict__.get(name, enumeration[name]))) - # and check for other instances in parent classes - descriptor = None - for base in enumeration.__mro__[1:]: - descriptor = base.__dict__.get(name) - if descriptor is not None: - if isinstance(descriptor, (property, DynamicClassAttribute)): - break - else: - raise TypeError('%r already in use in superclass %r' % (name, base.__name__)) - try: - _member_map_ = enumeration._member_map_ - _member_names_ = enumeration._member_names_ - _member_type_ = enumeration._member_type_ - _value2member_map_ = enumeration._value2member_map_ - base_attributes = set([a for b in enumeration.mro() for a in b.__dict__]) - except AttributeError: - raise TypeError('%r is not a supported Enum' % (enumeration, )) - try: - _value2member_seq_ = enumeration._value2member_seq_ - _multi_value_ = MultiValue in enumeration._settings_ - _no_alias_ = NoAlias in enumeration._settings_ - _unique_ = Unique in enumeration._settings_ - _auto_init_ = enumeration._auto_init_ or [] - except AttributeError: - # standard Enum - _value2member_seq_ = [] - _multi_value_ = False - _no_alias_ = False - _unique_ = False - _auto_init_ = [] - if _multi_value_ and not args: - # must specify values for multivalue enums - raise ValueError('no values specified for MultiValue enum %r' % enumeration.__name__) - mt_new = _member_type_.__new__ - _new = getattr(enumeration, '__new_member__', mt_new) - if not args: - last_values = [m.value for m in enumeration] - count = len(enumeration) - start = getattr(enumeration, '_start_', None) - if start is None: - start = last_values and (last_values[-1] + 1) or 1 - _gnv = getattr(enumeration, '_generate_next_value_', None) - if _gnv is not None: - args = ( _gnv(name, start, count, last_values), ) - else: - # must be a 3.4 or 3.5 Enum - args = (start, ) - if _new is object.__new__: - new_uses_args = False - else: - new_uses_args = True - if len(args) == 1: - [value] = args - else: - value = args - more_values = () - kwds = {} - if isinstance(value, enum): - args = value.args - kwds = value.kwds - if not isinstance(value, tuple): - args = (value, ) - else: - args = value - # tease value out of auto-init if specified - if 'value' in _auto_init_: - if 'value' in kwds: - value = kwds.pop('value') - else: - value, args = args[0], args[1:] - elif _multi_value_: - value, more_values, args = args[0], args[1:], () - if new_uses_args: - args = (value, ) - if _member_type_ is tuple: - args = (args, ) - if not new_uses_args: - new_member = _new(enumeration) - if not hasattr(new_member, '_value_'): - new_member._value_ = value - else: - new_member = _new(enumeration, *args, **kwds) - if not hasattr(new_member, '_value_'): - new_member._value_ = _member_type_(*args) - value = new_member._value_ - if _multi_value_: - if 'value' in _auto_init_: - args = more_values - else: - # put all the values back into args for the init call - args = (value, ) + more_values - new_member._name_ = name - new_member.__objclass__ = enumeration.__class__ - new_member.__init__(*args) - new_member._values_ = (value, ) + more_values - # do final checks before modifying enum structures: - # - is new member a flag? - # - does the new member fit in the enum's declared _boundary_? - # - is new member an alias? - # - _all_bits_ = _flag_mask_ = None - if hasattr(enumeration, '_all_bits_'): - _all_bits_ = enumeration._all_bits_ | value - _flag_mask_ = enumeration._flag_mask_ | value - if enumeration._boundary_ != 'keep': - missed = list(_iter_bits_lsb(_flag_mask_ & ~_all_bits_)) - if missed: - raise TypeError( - 'invalid Flag %r -- missing values: %s' - % (cls, ', '.join((str(i) for i in missed))) - ) - # If another member with the same value was already defined, the - # new member becomes an alias to the existing one. - if _no_alias_: - # unless NoAlias was specified - return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_) - else: - # handle "normal" aliases - new_values = new_member._values_ - for canonical_member in _member_map_.values(): - canonical_values_ = getattr(canonical_member, '_values_', [canonical_member._value_]) - for canonical_value in canonical_values_: - for new_value in new_values: - if canonical_value == new_value: - # name is an alias - if _unique_ or _multi_value_: - # aliases not allowed in Unique and MultiValue enums - raise ValueError('%r is a duplicate of %r' % (new_member, canonical_member)) - else: - # aliased name can be added, remaining checks irrelevant - # aliases don't appear in member names (only in __members__ and _member_map_). - return _finalize_extend_enum(enumeration, canonical_member, name=name, bits=_all_bits_, mask=_flag_mask_, is_alias=True) - # not a standard alias, but maybe a flag alias - if pyver < PY3_6: - flag_bases = Flag, - else: - flag_bases = Flag, StdlibFlag - if issubclass(enumeration, flag_bases) and hasattr(enumeration, '_all_bits_'): - # handle the new flag type - if _is_single_bit(value): - # a new member! (an aliase would have been discovered in the previous loop) - return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_) - else: - # might be an 3.11 Flag alias - if value & enumeration._flag_mask_ == value and _value2member_map_.get(value) is not None: - # yup, it's an alias to existing members... and its an alias of an alias - canonical = _value2member_map_.get(value) - return _finalize_extend_enum(enumeration, canonical, name=name, bits=_all_bits_, mask=_flag_mask_, is_alias=True) - else: - return _finalize_extend_enum(enumeration, new_member, bits=_all_bits_, mask=_flag_mask_, is_alias=True) - else: - # if we get here, we have a brand new member - return _finalize_extend_enum(enumeration, new_member) - -def _finalize_extend_enum(enumeration, new_member, name=None, bits=None, mask=None, is_alias=False): - name = name or new_member.name - descriptor = None - for base in enumeration.__mro__[1:]: - descriptor = base.__dict__.get(name) - if descriptor is not None: - if isinstance(descriptor, (property, DynamicClassAttribute)): - break - else: - raise TypeError('%r already in use in superclass %r' % (name, base.__name__)) - if not descriptor: - # get redirect in place before adding to _member_map_ - redirect = property() - redirect.__set_name__(enumeration, name) - setattr(enumeration, name, redirect) - if not is_alias: - enumeration._member_names_.append(name) - enumeration._member_map_[name] = new_member - for v in getattr(new_member, '_values_', [new_member._value_]): - try: - enumeration._value2member_map_[v] = new_member - except TypeError: - enumeration._value2member_seq_ += ((v, new_member), ) - if bits: - enumeration._all_bits_ = bits - enumeration._flag_mask_ = mask - return new_member - -def unique(enumeration): - """ - Class decorator that ensures only unique members exist in an enumeration. - """ - duplicates = [] - for name, member in enumeration.__members__.items(): - if name != member.name: - duplicates.append((name, member.name)) - if duplicates: - duplicate_names = ', '.join( - ["%s -> %s" % (alias, name) for (alias, name) in duplicates] - ) - raise ValueError('duplicate names found in %r: %s' % - (enumeration, duplicate_names) - ) - return enumeration - -# Flag - -@export(globals()) -class FlagBoundary(StrEnum): - """ - control how out of range values are handled - "strict" -> error is raised [default] - "conform" -> extra bits are discarded - "eject" -> lose flag status (becomes a normal integer) - """ - STRICT = auto() - CONFORM = auto() - EJECT = auto() - KEEP = auto() -assert FlagBoundary.STRICT == 'strict', (FlagBoundary.STRICT, FlagBoundary.CONFORM) - -class Flag(Enum): - """ - Generic flag enumeration. - - Derive from this class to define new flag enumerations. - """ - - _boundary_ = STRICT - _numeric_repr_ = repr - - - def _generate_next_value_(name, start, count, last_values, *args, **kwds): - """ - Generate the next value when not given. - - name: the name of the member - start: the initital start value or None - count: the number of existing members - last_value: the last value assigned or None - """ - if not count: - if args: - return ((1, start)[start is not None], ) + args - else: - return (1, start)[start is not None] - else: - last_value = max(last_values) - try: - high_bit = _high_bit(last_value) - result = 2 ** (high_bit+1) - if args: - return (result,) + args - else: - return result - except Exception: - pass - raise TypeError('invalid Flag value: %r' % last_value) - - @classmethod - def _iter_member_by_value_(cls, value): - """ - Extract all members from the value in definition (i.e. increasing value) order. - """ - for val in _iter_bits_lsb(value & cls._flag_mask_): - yield cls._value2member_map_.get(val) - - _iter_member_ = _iter_member_by_value_ - - @classmethod - def _iter_member_by_def_(cls, value): - """ - Extract all members from the value in definition order. - """ - members = list(cls._iter_member_by_value_(value)) - members.sort(key=lambda m: m._sort_order_) - for member in members: - yield member - - @classmethod - def _missing_(cls, value): - """ - return a member matching the given value, or None - """ - return cls._create_pseudo_member_(value) - - @classmethod - def _create_pseudo_member_(cls, *values): - """ - Create a composite member. - """ - value = values[0] - if not isinstance(value, baseinteger): - raise ValueError( - "%r is not a valid %s" % (value, getattr(cls, '__qualname__', cls.__name__)) - ) - # check boundaries - # - value must be in range (e.g. -16 <-> +15, i.e. ~15 <-> 15) - # - value must not include any skipped flags (e.g. if bit 2 is not - # defined, then 0d10 is invalid) - neg_value = None - if ( - not ~cls._all_bits_ <= value <= cls._all_bits_ - or value & (cls._all_bits_ ^ cls._flag_mask_) - ): - if cls._boundary_ is STRICT: - max_bits = max(value.bit_length(), cls._flag_mask_.bit_length()) - raise ValueError( - "%s: invalid value: %r\n given %s\n allowed %s" - % (cls.__name__, value, bin(value, max_bits), bin(cls._flag_mask_, max_bits)) - ) - elif cls._boundary_ is CONFORM: - value = value & cls._flag_mask_ - elif cls._boundary_ is EJECT: - return value - elif cls._boundary_ is KEEP: - if value < 0: - value = ( - max(cls._all_bits_+1, 2**(value.bit_length())) - + value - ) - else: - raise ValueError( - 'unknown flag boundary: %r' % (cls._boundary_, ) - ) - if value < 0: - neg_value = value - value = cls._all_bits_ + 1 + value - # get members and unknown - unknown = value & ~cls._flag_mask_ - members = list(cls._iter_member_(value)) - if unknown and cls._boundary_ is not KEEP: - raise ValueError( - '%s(%r) --> unknown values %r [%s]' - % (cls.__name__, value, unknown, bin(unknown)) - ) - # let class adjust values - values = cls._create_pseudo_member_values_(members, *values) - __new__ = getattr(cls, '__new_member__', None) - if cls._member_type_ is object and not __new__: - # construct a singleton enum pseudo-member - pseudo_member = object.__new__(cls) - else: - pseudo_member = (__new__ or cls._member_type_.__new__)(cls, *values) - if not hasattr(pseudo_member, 'value'): - pseudo_member._value_ = value - if members: - pseudo_member._name_ = '|'.join([m._name_ for m in members]) - if unknown: - pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown) - else: - pseudo_member._name_ = None - # use setdefault in case another thread already created a composite - # with this value, but only if all members are known - # note: zero is a special case -- add it - if not unknown: - pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member) - if neg_value is not None: - cls._value2member_map_[neg_value] = pseudo_member - return pseudo_member - - - @classmethod - def _create_pseudo_member_values_(cls, members, *values): - """ - Return values to be fed to __new__ to create new member. - """ - if cls._member_type_ in (baseinteger + (object, )): - return values - elif len(values) < 2: - return values + (cls._member_type_(), ) - else: - return values - - def __contains__(self, other): - """ - Returns True if self has at least the same flags set as other. - """ - if not isinstance(other, self.__class__): - raise TypeError( - "unsupported operand type(s) for 'in': '%s' and '%s'" % ( - type(other).__name__, self.__class__.__name__)) - if other._value_ == 0 or self._value_ == 0: - return False - return other._value_ & self._value_ == other._value_ - - def __iter__(self): - """ - Returns flags in definition order. - """ - for member in self._iter_member_(self._value_): - yield member - - def __len__(self): - return _bit_count(self._value_) - - def __repr__(self): - cls = self.__class__ - if self._name_ is None: - # only zero is unnamed by default - return '<%s: %r>' % (cls.__name__, self._value_) - else: - return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_) - - def __str__(self): - cls = self.__class__ - if self._name_ is None: - return '%s(%s)' % (cls.__name__, self._value_) - else: - return '%s.%s' % (cls.__name__, self._name_) - - if PY2: - def __nonzero__(self): - return bool(self._value_) - else: - def __bool__(self): - return bool(self._value_) - - def __or__(self, other): - if isinstance(other, self.__class__): - other_value = other._value_ - elif self._member_type_ is not object and isinstance(other, self._member_type_): - other_value = other - else: - return NotImplemented - return self.__class__(self._value_ | other_value) - - def __and__(self, other): - if isinstance(other, self.__class__): - other_value = other._value_ - elif self._member_type_ is not object and isinstance(other, self._member_type_): - other_value = other - else: - return NotImplemented - return self.__class__(self._value_ & other_value) - - def __xor__(self, other): - if isinstance(other, self.__class__): - other_value = other._value_ - elif self._member_type_ is not object and isinstance(other, self._member_type_): - other_value = other - else: - return NotImplemented - return self.__class__(self._value_ ^ other_value) - - def __invert__(self): - if self._inverted_ is None: - if self._boundary_ is KEEP: - # use all bits - self._inverted_ = self.__class__(~self._value_) - else: - # calculate flags not in this member - self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_) - self._inverted_._inverted_ = self - return self._inverted_ - - __ror__ = __or__ - __rand__ = __and__ - __rxor__ = __xor__ - - - -class IntFlag(int, ReprEnum, Flag): - """Support for integer-based Flags""" - - _boundary_ = EJECT - - -def _high_bit(value): - """returns index of highest bit, or -1 if value is zero or negative""" - return value.bit_length() - 1 - -def global_enum_repr(self): - """ - use module.enum_name instead of class.enum_name - - the module is the last module in case of a multi-module name - """ - module = self.__class__.__module__.split('.')[-1] - return '%s.%s' % (module, self._name_) - -def global_flag_repr(self): - """ - use module.flag_name instead of class.flag_name - - the module is the last module in case of a multi-module name - """ - module = self.__class__.__module__.split('.')[-1] - cls_name = self.__class__.__name__ - if self._name_ is None: - return "%s.%s(%r)" % (module, cls_name, self._value_) - if _is_single_bit(self): - return '%s.%s' % (module, self._name_) - if self._boundary_ is not FlagBoundary.KEEP: - return '|'.join(['%s.%s' % (module, name) for name in self.name.split('|')]) - else: - name = [] - for n in self._name_.split('|'): - if n[0].isdigit(): - name.append(n) - else: - name.append('%s.%s' % (module, n)) - return '|'.join(name) - -def global_str(self): - """ - use enum_name instead of class.enum_name - """ - if self._name_ is None: - return "%s(%r)" % (cls_name, self._value_) - else: - return self._name_ - -def global_enum(cls, update_str=False): - """ - decorator that makes the repr() of an enum member reference its module - instead of its class; also exports all members to the enum's module's - global namespace - """ - if issubclass(cls, Flag): - cls.__repr__ = global_flag_repr - else: - cls.__repr__ = global_enum_repr - if not issubclass(cls, ReprEnum) or update_str: - cls.__str__ = global_str - _sys.modules[cls.__module__].__dict__.update(cls.__members__) - return cls - - -class module(object): - - def __init__(self, cls, *args): - self.__name__ = cls.__name__ - self._parent_module = cls.__module__ - self.__all__ = [] - all_objects = cls.__dict__ - if not args: - args = [k for k, v in all_objects.items() if isinstance(v, (NamedConstant, Enum))] - for name in args: - self.__dict__[name] = all_objects[name] - self.__all__.append(name) - - def register(self): - _sys.modules["%s.%s" % (self._parent_module, self.__name__)] = self - -if StdlibEnumMeta: - - from _weakrefset import WeakSet - - def __subclasscheck__(cls, subclass): - """ - Override for issubclass(subclass, cls). - """ - if not isinstance(subclass, type): - raise TypeError('issubclass() arg 1 must be a class (got %r)' % (subclass, )) - # Check cache - try: - cls.__dict__['_subclass_cache_'] - except KeyError: - cls._subclass_cache_ = WeakSet() - cls._subclass_negative_cache_ = WeakSet() - except RecursionError: - import sys - exc, cls, tb = sys.exc_info() - exc = RecursionError('possible causes for endless recursion:\n - __getattribute__ is not ignoring __dunder__ attibutes\n - __instancecheck__ and/or __subclasscheck_ are (mutually) recursive\n see `aenum.remove_stdlib_integration` for temporary work-around') - raise_from_none(exc) - if subclass in cls._subclass_cache_: - return True - # Check negative cache - elif subclass in cls._subclass_negative_cache_: - return False - if cls is subclass: - cls._subclass_cache_.add(subclass) - return True - # Check if it's a direct subclass - if cls in getattr(subclass, '__mro__', ()): - cls._subclass_cache_.add(subclass) - return True - # Check if it's an aenum.Enum|IntEnum|IntFlag|Flag subclass - if cls is StdlibIntFlag and issubclass(subclass, IntFlag): - cls._subclass_cache_.add(subclass) - return True - elif cls is StdlibFlag and issubclass(subclass, Flag): - cls._subclass_cache_.add(subclass) - return True - elif cls is StdlibIntEnum and issubclass(subclass, IntEnum): - cls._subclass_cache_.add(subclass) - return True - if cls is StdlibEnum and issubclass(subclass, Enum): - cls._subclass_cache_.add(subclass) - return True - # No dice; update negative cache - cls._subclass_negative_cache_.add(subclass) - return False - - def __instancecheck__(cls, instance): - subclass = instance.__class__ - try: - return cls.__subclasscheck__(subclass) - except RecursionError: - import sys - exc, cls, tb = sys.exc_info() - exc = RecursionError('possible causes for endless recursion:\n - __getattribute__ is not ignoring __dunder__ attibutes\n - __instancecheck__ and/or __subclasscheck_ are (mutually) recursive\n see `aenum.remove_stdlib_integration` for temporary work-around') - raise_from_none(exc) - - StdlibEnumMeta.__subclasscheck__ = __subclasscheck__ - StdlibEnumMeta.__instancecheck__ = __instancecheck__ - -def add_stdlib_integration(): - if StdlibEnum: - StdlibEnumMeta.__subclasscheck__ = __subclasscheck__ - StdlibEnumMeta.__instancecheck__ = __instancecheck__ - -def remove_stdlib_integration(): - """ - Remove the __instancecheck__ and __subclasscheck__ overrides from the stdlib Enum. - - Those overrides are in place so that code detecting stdlib enums will also detect - aenum enums. If a buggy __getattribute__, __instancecheck__, or __subclasscheck__ - is defined on a custom EnumMeta then RecursionErrors can result; using this - function after importing aenum will solve that problem, but the better solution is - to fix the buggy method. - """ - if StdlibEnum: - del StdlibEnumMeta.__instancecheck__ - del StdlibEnumMeta.__subclasscheck__ - diff --git a/venv/Lib/site-packages/aenum/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/aenum/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 176f78e250e4099e3c3b3bd6e90f89417d332065..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104964 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 - ----------------- - -An ``Enum`` is a set of symbolic names (members) bound to unique, constant -values. Within an enumeration, the members can be compared by identity, and -the enumeration itself can be iterated over. - -A ``NamedTuple`` is a class-based, fixed-length tuple with a name for each -possible position accessible using attribute-access notation. - -A ``NamedConstant`` is a class whose members cannot be rebound; it lacks all -other ``Enum`` capabilities, however; consequently, it can have duplicate -values. There is also a ``module`` function that can insert the -``NamedConstant`` class into ``sys.modules`` where it will appear to be a -module whose top-level names cannot be rebound. - -.. note:: - ``constant`` refers to names not being rebound; mutable objects can be - mutated. - - -Module Contents ---------------- - -This module defines five enumeration classes that can be used to define unique -sets of names and values, one ``Enum`` class decorator, one ``NamedTuple`` -class, one ``NamedConstant`` class, and several helpers. - -``NamedConstant`` - -NamedConstant class for creating groups of constants. These names cannot be -rebound to other values. - -``Enum`` - -Base class for creating enumerated constants. See section `Enum Functional API`_ -for an alternate construction syntax. - -``AddValue`` - -Flag specifying that ``_generate_next_value_`` should always be called to -provide the initial value for an enum member. - -``MultiValue`` - -Flag specifying that each item of tuple value is a separate value for that -member; the first tuple item is the canonical one. - -``NoAlias`` - -Flag specifying that duplicate valued members are distinct and not aliases; -by-value lookups are disabled. - -``Unique`` - -Flag specifying that duplicate valued members are not allowed. - -.. note:: - The flags are inherited by the enumeration's subclasses. To use them in - Python 2 assign to ``_settings_`` in the class body. - -``IntEnum`` - -Base class for creating enumerated constants that are also subclasses of ``int``. - -``AutoNumberEnum`` - -Derived class that automatically assigns an ``int`` value to each member. - -``OrderedEnum`` - -Derived class that adds ``<``, ``<=``, ``>=``, and ``>`` methods to an ``Enum``. - -``UniqueEnum`` - -Derived class that ensures only one name is bound to any one value. - -``unique`` - -Enum class decorator that ensures only one name is bound to any one value. - -.. note:: - - the ``UniqueEnum`` class, the ``unique`` decorator, and the Unique - flag all do the same thing; you do not need to use more than one of - them at the same time. - -``NamedTuple`` - -Base class for `creating NamedTuples`_, either by subclassing or via it's -functional API. - -``constant`` - -Descriptor to add constant values to an ``Enum``, or advanced constants to -``NamedConstant``. - -``convert`` - -Helper to transform target global variables into an ``Enum``. - -``enum`` - -Helper for specifying keyword arguments when creating ``Enum`` members. - -``export`` - -Helper for inserting ``Enum`` members and ``NamedConstant`` constants into a -namespace (usually ``globals()``. - -``extend_enum`` - -Helper for adding new ``Enum`` members, both stdlib and aenum. - -``module`` - -Function to take a ``NamedConstant`` or ``Enum`` class and insert it into -``sys.modules`` with the affect of a module whose top-level constant and -member names cannot be rebound. - -``skip`` - -Descriptor to add a normal (non-``Enum`` member) attribute to an ``Enum`` -or ``NamedConstant``. - - -Creating an Enum ----------------- - -Enumerations are created using the ``class`` syntax, which makes them -easy to read and write. An alternative creation method is described in -`Enum Functional API`_. To define an enumeration, subclass ``Enum`` as -follows:: - - >>> from aenum import Enum - >>> class Color(Enum): - ... red = 1 - ... green = 2 - ... blue = 3 - -*Nomenclature* - - - The class ``Color`` is an *enumeration* (or *enum*) - - The attributes ``Color.red``, ``Color.green``, etc., are - *enumeration members* (or *enum members*). - - The enum members have *names* and *values* (the name of - ``Color.red`` is ``red``, the value of ``Color.blue`` is - ``3``, etc.) - -.. note:: - - Even though we use the ``class`` syntax to create Enums, Enums - are not normal Python classes. See `How are Enums different?`_ for - more details. - -Enumeration members have human readable string representations:: - - >>> print(Color.red) - Color.red - -...while their ``repr`` has more information:: - - >>> print(repr(Color.red)) - - -The *type* of an enumeration member is the enumeration it belongs to:: - - >>> type(Color.red) - - >>> isinstance(Color.green, Color) - True - -Enumerations support iteration. In Python 3.x definition order is used; in -Python 2.x the definition order is not available, but class attribute -``_order_`` is supported; otherwise, value order is used if posible, -otherwise alphabetical name order is used:: - - >>> class Shake(Enum): - ... _order_ = 'vanilla chocolate cookies mint' # only needed in 2.x - ... vanilla = 7 - ... chocolate = 4 - ... cookies = 9 - ... mint = 3 - ... - >>> for shake in Shake: - ... print(shake) - ... - Shake.vanilla - Shake.chocolate - Shake.cookies - Shake.mint - -The ``_order_`` attribute is always removed, but in 3.x it is also used to -verify that definition order is the same (useful for py2&3 code bases); -however, in the stdlib version it will be ignored and not removed. - -.. note:: - - To maintain compatibility with Python 3.4 and 3.5, use __order__ - instead (double leading and trailing underscores). - -Enumeration members are hashable, so they can be used in dictionaries and sets:: - - >>> apples = {} - >>> apples[Color.red] = 'red delicious' - >>> apples[Color.green] = 'granny smith' - >>> apples == {Color.red: 'red delicious', Color.green: 'granny smith'} - True - -In Python 3 the class syntax has a few extra advancements:: - - --> class Color( - ... Enum, - ... settings=(AddValue, MultiValue, NoAlias, Unique), - ... init='field_name1 field_name2 ...', - ... start=7, - ... ) - ... - -``start`` is used to specify the starting value for the first member:: - - --> class Count(Enum, start=11): - ... eleven - ... twelve - ... - --> Count.twelve.value == 12 - True - -``init`` specifies the attribute names to store creation values to:: - - --> class Planet(Enum, init='mass radius'): - ... MERCURY = (3.303e+23, 2.4397e6) - ... EARTH = (5.976e+24, 6.37814e6) - ... - --> Planet.EARTH.value - (5.976e+24, 6378140.0) - --> Planet.EARTH.radius - 2.4397e6 - -The various settings enable special behavior: - -- ``AddValue`` calls a user supplied ``_generate_next_value_`` to provide - the initial value -- ``MultiValue`` allows multiple values per member instead of the usual 1 -- ``NoAlias`` allows different members to have the same value -- ``Unique`` disallows different members to have the same value - -.. note:: - - To use these features in Python 2 use the _sundered_ versions of - the names in the class body: ``_start_``, ``_init_``, ``_settings_``. - - -Programmatic access to enumeration members and their attributes ---------------------------------------------------------------- - -Sometimes it's useful to access members in enumerations programmatically (i.e. -situations where ``Color.red`` won't do because the exact color is not known -at program-writing time). ``Enum`` allows such access:: - - >>> Color(1) - - >>> Color(3) - - -If you want to access enum members by *name*, use item access:: - - >>> Color['red'] - - >>> Color['green'] - - -If have an enum member and need its ``name`` or ``value``:: - - >>> member = Color.red - >>> member.name - 'red' - >>> member.value - 1 - - -Duplicating enum members and values ------------------------------------ - -Having two enum members (or any other attribute) with the same name is invalid; -in Python 3.x this would raise an error, but in Python 2.x the second member -simply overwrites the first:: - - # python 2.x - --> class Shape(Enum): - ... square = 2 - ... square = 3 - ... - --> Shape.square - - - # python 3.x - --> class Shape(Enum): - ... square = 2 - ... square = 3 - Traceback (most recent call last): - ... - TypeError: Attempted to reuse key: 'square' - -However, two enum members are allowed to have the same value. Given two members -A and B with the same value (and A defined first), B is an alias to A. By-value -lookup of the value of A and B will return A. By-name lookup of B will also -return A:: - - >>> class Shape(Enum): - ... _order_ = 'square diamond circle' # needed in 2.x - ... square = 2 - ... diamond = 1 - ... circle = 3 - ... alias_for_square = 2 - ... - >>> Shape.square - - >>> Shape.alias_for_square - - >>> Shape(2) - - - -Allowing aliases is not always desirable. ``unique`` can be used to ensure -that none exist in a particular enumeration:: - - >>> from aenum import unique - >>> @unique - ... class Mistake(Enum): - ... _order_ = 'one two three' # only needed in 2.x - ... one = 1 - ... two = 2 - ... three = 3 - ... four = 3 - Traceback (most recent call last): - ... - ValueError: duplicate names found in : four -> three - -Iterating over the members of an enum does not provide the aliases:: - - >>> list(Shape) - [, , ] - -The special attribute ``__members__`` is a dictionary mapping names to members. -It includes all names defined in the enumeration, including the aliases:: - - >>> for name, member in sorted(Shape.__members__.items()): - ... name, member - ... - ('alias_for_square', ) - ('circle', ) - ('diamond', ) - ('square', ) - -The ``__members__`` attribute can be used for detailed programmatic access to -the enumeration members. For example, finding all the aliases:: - - >>> [n for n, mbr in Shape.__members__.items() if mbr.name != n] - ['alias_for_square'] - -Comparisons ------------ - -Enumeration members are compared by identity:: - - >>> Color.red is Color.red - True - >>> Color.red is Color.blue - False - >>> Color.red is not Color.blue - True - -Ordered comparisons between enumeration values are *not* supported. Enum -members are not integers (but see `IntEnum`_ below):: - - >>> Color.red < Color.blue - Traceback (most recent call last): - File "", line 1, in - TypeError: unorderable types: Color() < Color() - -.. warning:: - - In Python 2 *everything* is ordered, even though the ordering may not - make sense. If you want your enumerations to have a sensible ordering - consider using an `OrderedEnum`_. - - -Equality comparisons are defined though:: - - >>> Color.blue == Color.red - False - >>> Color.blue != Color.red - True - >>> Color.blue == Color.blue - True - -Comparisons against non-enumeration values will always compare not equal -(again, ``IntEnum`` was explicitly designed to behave differently, see -below):: - - >>> Color.blue == 2 - False - - -Allowed members and attributes of enumerations ----------------------------------------------- - -The examples above use integers for enumeration values. Using integers is -short and handy (and provided by default by the `Enum Functional API`_), but not -strictly enforced. In the vast majority of use-cases, one doesn't care what -the actual value of an enumeration is. But if the value *is* important, -enumerations can have arbitrary values. - -Enumerations are Python classes, and can have methods and special methods as -usual. If we have this enumeration:: - - >>> class Mood(Enum): - ... funky = 1 - ... happy = 3 - ... - ... def describe(self): - ... # self is the member here - ... return self.name, self.value - ... - ... def __str__(self): - ... return 'my custom str! {0}'.format(self.value) - ... - ... @classmethod - ... def favorite_mood(cls): - ... # cls here is the enumeration - ... return cls.happy - -Then:: - - >>> Mood.favorite_mood() - - >>> Mood.happy.describe() - ('happy', 3) - >>> str(Mood.funky) - 'my custom str! 1' - -The rules for what is allowed are as follows: _sunder_ names (starting and -ending with a single underscore) are reserved by enum and cannot be used; -all other attributes defined within an enumeration will become members of this -enumeration, with the exception of *__dunder__* names and descriptors (methods -are also descriptors). - -.. note:: - - If your enumeration defines ``__new__`` and/or ``__init__`` then - whatever value(s) were given to the enum member will be passed into - those methods. See `Planet`_ for an example. - - -Restricted Enum subclassing ---------------------------- - -A new `Enum` class must have one base Enum class, up to one concrete -data type, and as many `object`-based mixin classes as needed. The -order of these base classes is:: - - def EnumName([mix-in, ...,] [data-type,] base-enum): - pass - -Also, subclassing an enumeration is allowed only if the enumeration does not define - -any members. So this is forbidden:: - - >>> class MoreColor(Color): - ... pink = 17 - Traceback (most recent call last): - ... - TypeError: cannot extend - -But this is allowed:: - - >>> class Foo(Enum): - ... def some_behavior(self): - ... pass - ... - >>> class Bar(Foo): - ... happy = 1 - ... sad = 2 - ... - -Allowing subclassing of enums that define members would lead to a violation of -some important invariants of types and instances. On the other hand, it makes -sense to allow sharing some common behavior between a group of enumerations. -(See `OrderedEnum`_ for an example.) - - -Pickling --------- - -Enumerations can be pickled and unpickled:: - - >>> from aenum.test import Fruit - >>> from pickle import dumps, loads - >>> Fruit.tomato is loads(dumps(Fruit.tomato, 2)) - True - -The usual restrictions for pickling apply: picklable enums must be defined in -the top level of a module, since unpickling requires them to be importable -from that module. - -.. note:: - - With pickle protocol version 4 (introduced in Python 3.4) it is possible - to easily pickle enums nested in other classes. - - - -Enum Functional API -------------------- - -The ``Enum`` class is callable, providing the following functional API:: - - >>> Animal = Enum('Animal', 'ant bee cat dog') - >>> Animal - - >>> Animal.ant - - >>> Animal.ant.value - 1 - >>> list(Animal) - [, , , ] - -The semantics of this API resemble ``namedtuple``. The first argument -of the call to ``Enum`` is the name of the enumeration. - -The second argument is the *source* of enumeration member names. It can be a -whitespace-separated string of names, a sequence of names, a sequence of -2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to -values. The last two options enable assigning arbitrary values to -enumerations; the others auto-assign increasing integers starting with 1. A -new class derived from ``Enum`` is returned. In other words, the above -assignment to ``Animal`` is equivalent to:: - - >>> class Animals(Enum): - ... ant = 1 - ... bee = 2 - ... cat = 3 - ... dog = 4 - -Pickling enums created with the functional API can be tricky as frame stack -implementation details are used to try and figure out which module the -enumeration is being created in (e.g. it will fail if you use a utility -function in separate module, and also may not work on IronPython or Jython). -The solution is to specify the module name explicitly as follows:: - - >>> Animals = Enum('Animals', 'ant bee cat dog', module=__name__) - -Derived Enumerations --------------------- - -IntEnum -^^^^^^^ - -A variation of ``Enum`` is provided which is also a subclass of -``int``. Members of an ``IntEnum`` can be compared to integers; -by extension, integer enumerations of different types can also be compared -to each other:: - - >>> from aenum import IntEnum - >>> class Shape(IntEnum): - ... circle = 1 - ... square = 2 - ... - >>> class Request(IntEnum): - ... post = 1 - ... get = 2 - ... - >>> Shape == 1 - False - >>> Shape.circle == 1 - True - >>> Shape.circle == Request.post - True - -However, they still can't be compared to standard ``Enum`` enumerations:: - - >>> class Shape(IntEnum): - ... circle = 1 - ... square = 2 - ... - >>> class Color(Enum): - ... red = 1 - ... green = 2 - ... - >>> Shape.circle == Color.red - False - -``IntEnum`` values behave like integers in other ways you'd expect:: - - >>> int(Shape.circle) - 1 - >>> ['a', 'b', 'c'][Shape.circle] - 'b' - >>> [i for i in range(Shape.square)] - [0, 1] - -For the vast majority of code, ``Enum`` is strongly recommended, -since ``IntEnum`` breaks some semantic promises of an enumeration (by -being comparable to integers, and thus by transitivity to other -unrelated enumerations). It should be used only in special cases where -there's no other choice; for example, when integer constants are -replaced with enumerations and backwards compatibility is required with code -that still expects integers. - - -IntFlag -^^^^^^^ - -The next variation of ``Enum`` provided, ``IntFlag``, is also based -on ``int``. The difference being ``IntFlag`` members can be combined -using the bitwise operators (&, \|, ^, ~) and the result is still an -``IntFlag`` member. However, as the name implies, ``IntFlag`` -members also subclass ``int`` and can be used wherever an ``int`` is -used. Any operation on an ``IntFlag`` member besides the bit-wise -operations will lose the ``IntFlag`` membership. - -Sample ``IntFlag`` class:: - - >>> from aenum import IntFlag - >>> class Perm(IntFlag): - ... _order_ = 'R W X' - ... R = 4 - ... W = 2 - ... X = 1 - ... - >>> Perm.R | Perm.W - - >>> Perm.R + Perm.W - 6 - >>> RW = Perm.R | Perm.W - >>> Perm.R in RW - True - -It is also possible to name the combinations:: - - >>> class Perm(IntFlag): - ... _order_ = 'R W X' - ... R = 4 - ... W = 2 - ... X = 1 - ... RWX = 7 - >>> Perm.RWX - - >>> ~Perm.RWX - - -Another important difference between ``IntFlag`` and ``Enum`` is that -if no flags are set (the value is 0), its boolean evaluation is ``False``:: - - >>> Perm.R & Perm.X - - >>> bool(Perm.R & Perm.X) - False - -Because ``IntFlag`` members are also subclasses of ``int`` they can -be combined with them:: - - >>> Perm.X | 4 - - -If the result is not a ``Flag`` then, depending on the ``_boundary_`` setting, -an exception is raised (``STRICT``), the extra bits are lost (``CONFORM``), or -it reverts to an int (``EJECT``): - - >>> from aenum import STRICT, CONFORM, EJECT - >>> Perm._boundary_ = STRICT - >>> Perm.X | 8 - Traceback (most recent call last): - ... - ValueError: Perm: invalid value: 9 - given 0b0 1001 - allowed 0b0 0111 - - >>> Perm._boundary_ = EJECT - >>> Perm.X | 8 - 9 - - >>> Perm._boundary_ = CONFORM - >>> Perm.X | 8 - - - -Flag -^^^^ - -The last variation is ``Flag``. Like ``IntFlag``, ``Flag`` -members can be combined using the bitwise operators (&, \|, ^, ~). Unlike -``IntFlag``, they cannot be combined with, nor compared against, any -other ``Flag`` enumeration, nor ``int``. While it is possible to -specify the values directly it is recommended to use ``auto`` as the -value and let ``Flag`` select an appropriate value. - -Like ``IntFlag``, if a combination of ``Flag`` members results in no -flags being set, the boolean evaluation is ``False``:: - - >>> from aenum import Flag, auto - >>> class Color(Flag): - ... RED = auto() - ... BLUE = auto() - ... GREEN = auto() - ... - >>> Color.RED & Color.GREEN - - >>> bool(Color.RED & Color.GREEN) - False - -Individual flags should have values that are powers of two (1, 2, 4, 8, ...), -while combinations of flags won't:: - - --> class Color(Flag): - ... RED = auto() - ... BLUE = auto() - ... GREEN = auto() - ... WHITE = RED | BLUE | GREEN - ... - --> Color.WHITE - - -Giving a name to the "no flags set" condition does not change its boolean -value:: - - >>> class Color(Flag): - ... BLACK = 0 - ... RED = auto() - ... BLUE = auto() - ... GREEN = auto() - ... - >>> Color.BLACK - - >>> bool(Color.BLACK) - False - -Flags can be iterated over to retrieve the individual truthy flags in the value:: - - >>> class Color(Flag): - ... _order_ = 'BLACK RED BLUE GREEN WHITE' - ... BLACK = 0 - ... RED = auto() - ... BLUE = auto() - ... GREEN = auto() - ... WHITE = RED | BLUE | GREEN - ... - >>> list(Color.GREEN) - [] - >>> list(Color.WHITE) - [, , ] - -.. note:: - - For the majority of new code, ``Enum`` and ``Flag`` are strongly - recommended, since ``IntEnum`` and ``IntFlag`` break some - semantic promises of an enumeration (by being comparable to integers, and - thus by transitivity to other unrelated enumerations). ``IntEnum`` - and ``IntFlag`` should be used only in cases where ``Enum`` and - ``Flag`` will not do; for example, when integer constants are replaced - with enumerations, or for interoperability with other systems. - - -Others -^^^^^^ - -While ``IntEnum`` is part of the ``aenum`` module, it would be very -simple to implement independently:: - - class MyIntEnum(int, Enum): - pass - -This demonstrates how similar derived enumerations can be defined; for example -a ``MyStrEnum`` that mixes in ``str`` instead of ``int``. - -Some rules: - -1. When subclassing ``Enum``, mix-in types must appear before - ``Enum`` itself in the sequence of bases, as in the ``MyIntEnum`` - example above. -2. While ``Enum`` can have members of any type, once you mix in an - additional type, all the members must have values of that type or be - convertible into that type. This restriction does not apply to mix-ins - which only add methods and don't specify another data type. -3. When another data type is mixed in, the ``value`` attribute is *not the - same* as the enum member itself, although it is equivalant and will compare - equal. -4. %-style formatting: ``%s`` and ``%r`` call ``Enum``'s ``__str__`` and - ``__repr__`` respectively; other codes (such as ``%i`` or ``%h`` for - MyIntEnum) treat the enum member as its mixed-in type. -5. ``str.__format__`` (or ``format``) will use the mixed-in - type's ``__format__``. If the ``Enum``'s ``str`` or ``repr`` is desired - use the ``!s`` or ``!r`` ``str`` format codes. - -.. note:: - - If you override the ``__str__`` method, then it will be used to provide the - string portion of the ``format()`` call. - -.. note:: - - Prior to Python 3.4 there is a bug in ``str``'s %-formatting: ``int`` - subclasses are printed as strings and not numbers when the ``%d``, ``%i``, - or ``%u`` codes are used. - - -Extra Goodies -------------- - -aenum supports a few extra techniques not found in the stdlib version. - -enum -^^^^ - -If you have several items to initialize your ``Enum`` members with and -would like to use keyword arguments, the ``enum`` helper is for you:: - - >>> from aenum import enum - >>> class Presidents(Enum): - ... Washington = enum('George Washington', circa=1776, death=1797) - ... Jackson = enum('Andrew Jackson', circa=1830, death=1837) - ... Lincoln = enum('Abraham Lincoln', circa=1860, death=1865) - ... - >>> Presidents.Lincoln - - -extend_enum -^^^^^^^^^^^ - -For those rare cases when you need to create your ``Enum`` in pieces, you -can use ``extend_enum`` to add new members after the initial creation -(the new member is returned):: - - >>> from aenum import extend_enum - >>> class Color(Enum): - ... red = 1 - ... green = 2 - ... blue = 3 - ... - >>> list(Color) - [, , ] - >>> extend_enum(Color, 'opacity', 4) - - >>> list(Color) - [, , , ] - >>> Color.opacity in Color - True - >>> Color.opacity.name == 'opacity' - True - >>> Color.opacity.value == 4 - True - >>> Color(4) - - >>> Color['opacity'] - - - --> Color.__members__ - OrderedDict([ - ('red', ), - ('green', ), - ('blue', ), - ('opacity', ) - ]) - -constant -^^^^^^^^ - -If you need to have some constant value in your ``Enum`` that isn't a member, -use ``constant``:: - - >>> from aenum import constant - >>> class Planet(Enum): - ... MERCURY = (3.303e+23, 2.4397e6) - ... EARTH = (5.976e+24, 6.37814e6) - ... JUPITER = (1.9e+27, 7.1492e7) - ... URANUS = (8.686e+25, 2.5559e7) - ... G = constant(6.67300E-11) - ... 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) - ... return self.G * self.mass / (self.radius * self.radius) - ... - >>> Planet.EARTH.value - (5.976e+24, 6378140.0) - >>> Planet.EARTH.surface_gravity - 9.802652743337129 - >>> Planet.G - 6.673e-11 - >>> Planet.G = 9 - Traceback (most recent call last): - ... - AttributeError: Planet: cannot rebind constant 'G' - -skip -^^^^ - -If you need a standard attribute that is not converted into an ``Enum`` -member, use ``skip``:: - - >>> from aenum import skip - >>> class Color(Enum): - ... red = 1 - ... green = 2 - ... blue = 3 - ... opacity = skip(0.45) - ... - >>> Color.opacity - 0.45 - >>> Color.opacity = 0.77 - >>> Color.opacity - 0.77 - -start -^^^^^ - -``start`` can be used to turn on auto-numbering (useful for when you don't -care which numbers are assigned as long as they are consistent and in order) -The Python 3 version can look like this:: - - >>> class Color(Enum, start=1): # doctest: +SKIP - ... red, green, blue - ... - >>> Color.blue - - -This can also be done in Python 2, albeit not as elegantly (this also works in -Python 3):: - - >>> class Color(Enum): # doctest: +SKIP - ... _start_ = 1 - ... red = auto() - ... green = auto() - ... blue = auto() - ... - >>> Color.blue - - -init -^^^^ - -If you need an ``__init__`` method that does nothing besides save its -arguments, ``init`` is for you:: - - >>> class Planet(Enum, init='mass radius'): # doctest: +SKIP - ... MERCURY = (3.303e+23, 2.4397e6) - ... EARTH = (5.976e+24, 6.37814e6) - ... JUPITER = (1.9e+27, 7.1492e7) - ... URANUS = (8.686e+25, 2.5559e7) - ... G = constant(6.67300E-11) - ... @property - ... def surface_gravity(self): - ... # universal gravitational constant (m3 kg-1 s-2) - ... return self.G * self.mass / (self.radius * self.radius) - ... - >>> Planet.JUPITER.value - (1.9e+27, 71492000.0) - >>> Planet.JUPITER.mass - 1.9e+27 - -.. note:: - - Just as with ``start`` above, in Python 2 you must put the keyword as a - _sunder_ in the class body -- ``_init_ = 'mass radius'``. - -init and missing values -^^^^^^^^^^^^^^^^^^^^^^^ - -If ``_init_`` calls for values that are not supplied, ``_generate_next_value_`` -will be called in an effort to generate them. Here is an example in Python 2:: - - >>> from aenum import Enum - >>> 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 NotificationType(SelectionEnum): - ... # usually, name is the same as db - ... # but not for blanks - ... blank = '', '' - ... C = 'Catalog' - ... S = 'Sheet' - ... B = 'Both' - ... - >>> NotificationType.blank - - >>> NotificationType.B - - >>> NotificationType.B.db - 'B' - >>> NotificationType.B.user - 'Both' - -combining Flag with other data types -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Flag does support being combined with other data types. To support this you -need to provide a ``_create_pseudo_member_values_`` method which will be called -with the members in a composite flag. You may also need to provide a custom -``__new__`` method:: - - >>> class AnsiFlag(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, ) - ... _order_ = 'FG_Red FG_Green BG_Magenta BG_White' - ... FG_Red = '31' # ESC [ 31 m # red - ... FG_Green = '32' # ESC [ 32 m # green - ... BG_Magenta = '45' # ESC [ 35 m # magenta - ... BG_White = '47' # ESC [ 37 m # white - ... - >>> color = AnsiFlag.BG_White | AnsiFlag.FG_Red - >>> repr(color) - '' - >>> str.__repr__(color) - "'\\x1b[31;47m'" - -.. note:: - - If you do not provide your own ``_create_pseudo_member_values_`` the flags - may still combine, but may be missing functionality. - - -Decorators ----------- - -unique -^^^^^^ - -A ``class`` decorator specifically for enumerations. It searches an -enumeration's ``__members__`` gathering any aliases it finds; if any are -found ``ValueError`` is raised with the details:: - - >>> @unique - ... class NoDupes(Enum): - ... first = 'one' - ... second = 'two' - ... third = 'two' - Traceback (most recent call last): - ... - ValueError: duplicate names found in : third -> second - - -Interesting examples --------------------- - -While ``Enum`` and ``IntEnum`` are expected to cover the majority of -use-cases, they cannot cover them all. Here are recipes for some different -types of enumerations that can be used directly (the first three are included -in the module), or as examples for creating one's own. - - -AutoNumber -^^^^^^^^^^ - -Avoids having to specify the value for each enumeration member:: - - >>> class AutoNumber(Enum): - ... def __new__(cls): - ... value = len(cls.__members__) + 1 - ... obj = object.__new__(cls) - ... obj._value_ = value - ... return obj - ... - >>> class Color(AutoNumber): - ... _order_ = "red green blue" # only needed in 2.x - ... red = () - ... green = () - ... blue = () - ... - >>> Color.green.value == 2 - True - -.. note:: - - The `__new__` method, if defined, is used during creation of the Enum - members; it is then replaced by Enum's `__new__` which is used after - class creation for lookup of existing members. Due to the way Enums are - supposed to behave, there is no way to customize Enum's `__new__` without - modifying the class after it is created. - - -UniqueEnum -^^^^^^^^^^ - -Raises an error if a duplicate member name is found instead of creating an -alias:: - - >>> class UniqueEnum(Enum): - ... def __init__(self, *args): - ... cls = self.__class__ - ... if any(self.value == e.value for e in cls): - ... a = self.name - ... e = cls(self.value).name - ... raise ValueError( - ... "aliases not allowed in UniqueEnum: %r --> %r" - ... % (a, e)) - ... - >>> class Color(UniqueEnum): - ... _order_ = 'red green blue' - ... red = 1 - ... green = 2 - ... blue = 3 - ... grene = 2 - Traceback (most recent call last): - ... - ValueError: aliases not allowed in UniqueEnum: 'grene' --> 'green' - - -OrderedEnum -^^^^^^^^^^^ - -An ordered enumeration that is not based on ``IntEnum`` and so maintains -the normal ``Enum`` invariants (such as not being comparable to other -enumerations):: - - >>> class OrderedEnum(Enum): - ... def __ge__(self, other): - ... if self.__class__ is other.__class__: - ... return self._value_ >= other._value_ - ... return NotImplemented - ... def __gt__(self, other): - ... if self.__class__ is other.__class__: - ... return self._value_ > other._value_ - ... return NotImplemented - ... def __le__(self, other): - ... if self.__class__ is other.__class__: - ... return self._value_ <= other._value_ - ... return NotImplemented - ... def __lt__(self, other): - ... if self.__class__ is other.__class__: - ... return self._value_ < other._value_ - ... return NotImplemented - ... - >>> class Grade(OrderedEnum): - ... __ordered__ = 'A B C D F' - ... A = 5 - ... B = 4 - ... C = 3 - ... D = 2 - ... F = 1 - ... - >>> Grade.C < Grade.A - True - - -Planet -^^^^^^ - -If ``__new__`` or ``__init__`` is defined the value of the enum member -will be passed to those methods:: - - >>> 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) - ... - >>> Planet.EARTH.value - (5.976e+24, 6378140.0) - >>> Planet.EARTH.surface_gravity - 9.802652743337129 - - -How are Enums different? ------------------------- - -Enums have a custom metaclass that affects many aspects of both derived Enum -classes and their instances (members). - - -Enum Classes -^^^^^^^^^^^^ - -The ``EnumMeta`` metaclass is responsible for providing the -``__contains__``, ``__dir__``, ``__iter__`` and other methods that -allow one to do things with an ``Enum`` class that fail on a typical -class, such as ``list(Color)`` or ``some_var in Color``. ``EnumMeta`` is -responsible for ensuring that various other methods on the final ``Enum`` -class are correct (such as ``__new__``, ``__getnewargs__``, -``__str__`` and ``__repr__``). - -.. note:: - - ``__dir__`` is not changed in the Python 2 line as it messes up some - of the decorators included in the stdlib. - - -Enum Members (aka instances) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The most interesting thing about Enum members is that they are singletons. -``EnumMeta`` creates them all while it is creating the ``Enum`` -class itself, and then puts a custom ``__new__`` in place to ensure -that no new ones are ever instantiated by returning only the existing -member instances. - - -Finer Points -^^^^^^^^^^^^ - -``Enum`` members are instances of an ``Enum`` class, but are not -accessible as `EnumClass.member1.member2`. -(changed in version 1.1.1 to be accessible) -(changed in version 2.2.4 to be inaccessible):: - - >>> class FieldTypes(Enum): - ... name = 1 - ... value = 2 - ... size = 3 - ... - >>> FieldTypes.size.value - 3 - >>> FieldTypes.size - - >>> FieldTypes.value.size - Traceback (most recent call last): - ... - AttributeError: member has no attribute 'size' - -The ``__members__`` attribute is only available on the class. - - -``__members__`` is always an ``OrderedDict``, with the order being the -definition order in Python 3.x or the order in ``_order_`` in Python 2.7; -if no ``_order_`` was specified in Python 2.7 then the order of -``__members__`` is either increasing value or alphabetically by name. - -If you give your ``Enum`` subclass extra methods, like the `Planet`_ -class above, those methods will show up in a `dir` of the member, -but not of the class (in Python 3.x):: - - --> dir(Planet) - ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', - 'VENUS', '__class__', '__doc__', '__members__', '__module__'] - --> dir(Planet.EARTH) - ['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value'] - -A ``__new__`` method will only be used for the creation of the -``Enum`` members -- after that it is replaced. This means if you wish to -change how ``Enum`` members are looked up you either have to write a -helper function or a ``classmethod``. - -.. note:: - - If you create your own ``__new__`` you should set the ``_value_`` in it; - if you do not, aenum will try to, but will raise a ``TypeError`` if it - cannot. - -If the stdlib ``enum`` is available (Python 3.4+ and it hasn't been shadowed -by, for example, ``enum34``) then aenum will be a subclass of it. - -To use the ``AddValue``, ``MultiValue``, ``NoAlias``, and ``Unique`` flags -in Py2 or Py2/Py3 codebases, use ``_settings_ = ...`` in the class body. - -To use ``init`` in Py2 or Py2/Py3 codebases use ``_init_`` in the class body. - -To use ``start`` in Py2 or Py2/Py3 codebases use ``_start_`` in the class body. - -When creating class bodies dynamically, put any variables you need to use into -``_ignore_``:: - - >>> from datetime import timedelta - >>> from aenum import NoAlias - >>> 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' - ... - >>> hasattr(Period, '_ignore_') - False - >>> hasattr(Period, 'Period') - False - >>> hasattr(Period, 'i') - False - -The name listed in ``_ignore_``, as well as ``_ignore_`` itself, will not be -present in the final enumeration as neither attributes nor members. - -.. note:: - - except for __dunder__ attributes/methods, all _sunder_ attributes must - be before any thing else in the class body - -.. note:: - - all _sunder_ attributes that affect member creation are only looked up in - the last ``Enum`` class listed in the class header - - -Creating NamedTuples --------------------- - -Simple -^^^^^^ - -The most common way to create a new NamedTuple will be via the functional API:: - - >>> from aenum import NamedTuple - >>> Book = NamedTuple('Book', 'title author genre', module=__name__) - -This creates a ``NamedTuple`` called ``Book`` that will always contain three -items, each of which is also addressable as ``title``, ``author``, or ``genre``. - -``Book`` instances can be created using positional or keyword argements or a -mixture of the two:: - - >>> b1 = Book('Lord of the Rings', 'J.R.R. Tolkien', 'fantasy') - >>> b2 = Book(title='Jhereg', author='Steven Brust', genre='fantasy') - >>> b3 = Book('Empire', 'Orson Scott Card', genre='scifi') - -If too few or too many arguments are used a ``TypeError`` will be raised:: - - >>> b4 = Book('Hidden Empire') - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): author, genre - >>> b5 = Book(genre='business') - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): title, author - -As a ``class`` the above ``Book`` ``NamedTuple`` would look like:: - - >>> class Book(NamedTuple): - ... title = 0 - ... author = 1 - ... genre = 2 - ... - -For compatibility with the stdlib ``namedtuple``, NamedTuple also has the -``_asdict``, ``_make``, and ``_replace`` methods, and the ``_fields`` -attribute, which all function similarly:: - - >>> 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) - - >>> pixel._asdict() - OrderedDict([('x', 99), ('y', -101), ('r', 255), ('g', 128), ('b', 0)]) - - >>> Point._make((4, 5)) - Point(x=4, y=5) - - >>> purple = Color(127, 0, 127) - >>> mid_gray = purple._replace(g=127) - >>> mid_gray - Color(r=127, g=127, b=127) - - >>> pixel._fields - ['x', 'y', 'r', 'g', 'b'] - - >>> Pixel._fields - ['x', 'y', 'r', 'g', 'b'] - - -Advanced -^^^^^^^^ - -The simple method of creating ``NamedTuples`` requires always specifying all -possible arguments when creating instances; failure to do so will raise -exceptions:: - - >>> class Point(NamedTuple): - ... x = 0 - ... y = 1 - ... - >>> Point() - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): x, y - >>> Point(1) - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): y - >>> Point(y=2) - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): x - -However, it is possible to specify both docstrings and default values when -creating a ``NamedTuple`` using the class method:: - - >>> class Point(NamedTuple): - ... x = 0, 'horizontal coordinate', 0 - ... y = 1, 'vertical coordinate', 0 - ... - >>> Point() - Point(x=0, y=0) - >>> Point(1) - Point(x=1, y=0) - >>> Point(y=2) - Point(x=0, y=2) - -It is also possible to create ``NamedTuples`` that only have named attributes -for certain fields; any fields without names can still be accessed by index:: - - >>> class Person(NamedTuple): - ... fullname = 2 - ... phone = 5 - ... - >>> p = Person('Ethan', 'Furman', 'Ethan Furman', - ... 'ethan at stoneleaf dot us', - ... 'ethan.furman', '999.555.1212') - >>> p - Person('Ethan', 'Furman', 'Ethan Furman', 'ethan at stoneleaf dot us', - 'ethan.furman', '999.555.1212') - >>> p.fullname - 'Ethan Furman' - >>> p.phone - '999.555.1212' - >>> p[0] - 'Ethan' - -In the above example the last named field was also the last field possible; in -those cases where you don't need to have the last possible field named, you can -provide a ``_size_`` of ``TupleSize.minimum`` to declare that more fields are -okay:: - - >>> from aenum import TupleSize - >>> class Person(NamedTuple): - ... _size_ = TupleSize.minimum - ... first = 0 - ... last = 1 - ... - -or, optionally if using Python 3:: - - >>> class Person(NamedTuple, size=TupleSize.minimum): # doctest: +SKIP - ... first = 0 - ... last = 1 - -and in use:: - - >>> Person('Ethan', 'Furman') - Person(first='Ethan', last='Furman') - - >>> Person('Ethan', 'Furman', 'ethan.furman') - Person('Ethan', 'Furman', 'ethan.furman') - - >>> Person('Ethan', 'Furman', 'ethan.furman', 'yay Python!') - Person('Ethan', 'Furman', 'ethan.furman', 'yay Python!') - - >>> Person('Ethan') - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): last - -Also, for those cases where even named fields may not be present, you can -specify ``TupleSize.variable``:: - - >>> class Person(NamedTuple): - ... _size_ = TupleSize.variable - ... first = 0 - ... last = 1 - ... - - >>> Person('Ethan') - Person('Ethan') - - >>> Person(last='Furman') - Traceback (most recent call last): - ... - TypeError: values not provided for field(s): first - -Creating new ``NamedTuples`` from existing ``NamedTuples`` is simple:: - - >>> Point = NamedTuple('Point', 'x y') - >>> Color = NamedTuple('Color', 'r g b') - >>> Pixel = NamedTuple('Pixel', Point+Color, module=__name__) - >>> Pixel - - -The existing fields in the bases classes are renumbered to fit the new class, -but keep their doc strings and default values. If you use standard -subclassing:: - - >>> Point = NamedTuple('Point', 'x y') - >>> class Pixel(Point): - ... r = 2, 'red component', 11 - ... g = 3, 'green component', 29 - ... b = 4, 'blue component', 37 - ... - >>> Pixel.__fields__ - ['x', 'y', 'r', 'g', 'b'] - -You must manage the numbering yourself. - - -Creating NamedConstants ------------------------ - -A ``NamedConstant`` class is created much like an ``Enum``:: - - >>> from aenum import NamedConstant - >>> class Konstant(NamedConstant): - ... PI = 3.14159 - ... TAU = 2 * PI - - >>> Konstant.PI - - - >> print(Konstant.PI) - 3.14159 - - >>> Konstant.PI = 'apple' - Traceback (most recent call last): - ... - AttributeError: cannot rebind constant - - >>> del Konstant.PI - Traceback (most recent call last): - ... - AttributeError: cannot delete constant diff --git a/venv/Lib/site-packages/aenum/test.py b/venv/Lib/site-packages/aenum/test.py deleted file mode 100644 index 224293cb..00000000 --- a/venv/Lib/site-packages/aenum/test.py +++ /dev/null @@ -1,6832 +0,0 @@ -# -*- 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, 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), '') - 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), '') - 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), '') - self.assertEqual(repr(Perm.W), '') - self.assertEqual(repr(Perm.X), '') - self.assertEqual(repr(Perm.R | Perm.W), '') - self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') - self.assertEqual(repr(Perm(0)), '') - self.assertEqual(repr(~Perm.R), '') - self.assertEqual(repr(~Perm.W), '') - self.assertEqual(repr(~Perm.X), '') - self.assertEqual(repr(~(Perm.R | Perm.W)), '') - self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') - self.assertEqual(repr(Perm(~0)), '') - - Open = self.Open - self.assertEqual(repr(Open.RO), '') - self.assertEqual(repr(Open.WO), '') - self.assertEqual(repr(Open.AC), '') - self.assertEqual(repr(Open.RO | Open.CE), '') - self.assertEqual(repr(Open.WO | Open.CE), '') - self.assertEqual(repr(~Open.RO), '') - self.assertEqual(repr(~Open.WO), '') - self.assertEqual(repr(~Open.AC), '') - self.assertEqual(repr(~(Open.RO | Open.CE)), '') - self.assertEqual(repr(~(Open.WO | Open.CE)), '') - - 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<' % (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), '') - - 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), '') - self.assertEqual(repr(Perm.W), '') - self.assertEqual(repr(Perm.X), '') - self.assertEqual(repr(Perm.R | Perm.W), '') - self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') - self.assertEqual(repr(Perm(0)), '') - self.assertEqual(repr(~Perm.R), '') - self.assertEqual(repr(~Perm.W), '') - self.assertEqual(repr(~Perm.X), '') - self.assertEqual(repr(~(Perm.R | Perm.W)), '') - self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') - # - 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), '') - self.assertEqual(repr(Perm.W), '') - self.assertEqual(repr(Perm.X), '') - self.assertEqual(repr(Perm.R | Perm.W), '') - self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') - self.assertEqual(repr(Perm(0)), '') - self.assertEqual(repr(~Perm.R), '') - self.assertEqual(repr(~Perm.W), '') - self.assertEqual(repr(~Perm.X), '') - self.assertEqual(repr(~(Perm.R | Perm.W)), '') - self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') - self.assertEqual(repr(Perm.R | 8), '') - self.assertEqual(repr(Perm(8)), '') - self.assertEqual(repr(~(Perm.R | 8)), '') - self.assertEqual(repr(Perm(~8)), '') - - 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), '') - self.assertEqual(repr(Perm.W), '') - self.assertEqual(repr(Perm.X), '') - self.assertEqual(repr(Perm.R | Perm.W), '') - self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '') - self.assertEqual(repr(Perm(0)), '') - self.assertEqual(repr(~Perm.R), '') - self.assertEqual(repr(~Perm.W), '') - self.assertEqual(repr(~Perm.X), '') - self.assertEqual(repr(~(Perm.R | Perm.W)), '') - self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '') - 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), '') - self.assertEqual(repr(Open.WO), '') - self.assertEqual(repr(Open.AC), '') - self.assertEqual(repr(Open.RO | Open.CE), '') - self.assertEqual(repr(Open.WO | Open.CE), '') - self.assertEqual(repr(~Open.RO), '') - self.assertEqual(repr(~Open.WO), '') - self.assertEqual(repr(~Open.AC), '') - self.assertEqual(repr(~(Open.RO | Open.CE)), '') - self.assertEqual(repr(~(Open.WO | Open.CE)), '') - 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), '') - self.assertEqual(repr(Open.WO), '') - self.assertEqual(repr(Open.AC), '') - self.assertEqual(repr(Open.RO | Open.CE), '') - self.assertEqual(repr(Open.WO | Open.CE), '') - self.assertEqual(repr(~Open.RO), '') - self.assertEqual(repr(~Open.WO), '') - self.assertEqual(repr(~Open.AC), '') - self.assertEqual(repr(~(Open.RO | Open.CE)), '') - self.assertEqual(repr(~(Open.WO | Open.CE)), '') - self.assertEqual(repr(Open(~4)), '') - self.assertEqual(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.EJECT - self.assertEqual(repr(Open.RO), '') - self.assertEqual(repr(Open.WO), '') - self.assertEqual(repr(Open.AC), '') - self.assertEqual(repr(Open.RO | Open.CE), '') - self.assertEqual(repr(Open.WO | Open.CE), '') - self.assertEqual(repr(~Open.RO), '') - self.assertEqual(repr(~Open.WO), '') - self.assertEqual(repr(~Open.AC), '') - self.assertEqual(repr(~(Open.RO | Open.CE)), '') - self.assertEqual(repr(~(Open.WO | Open.CE)), '') - 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< 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' is a duplicate of ', 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' is a duplicate of ', 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) - diff --git a/venv/Lib/site-packages/aenum/test_v3.py b/venv/Lib/site-packages/aenum/test_v3.py deleted file mode 100644 index 62453df1..00000000 --- a/venv/Lib/site-packages/aenum/test_v3.py +++ /dev/null @@ -1,1982 +0,0 @@ -from . import EnumMeta, Enum, IntEnum, Flag, IntFlag, StrEnum, UniqueEnum, AutoEnum, AddValueEnum -from . import NamedTuple, TupleSize, MagicValue, AddValue, NoAlias, Unique, MultiValue -from . import AutoNumberEnum,MultiValueEnum, OrderedEnum, unique, skip, extend_enum, auto -from . import StdlibEnumMeta, StdlibEnum, StdlibIntEnum, StdlibFlag, StdlibIntFlag, StdlibStrEnum -from . import pyver, PY3_3, PY3_4, PY3_5, PY3_6, PY3_11 -from . import add_stdlib_integration, remove_stdlib_integration - -from collections import OrderedDict -from datetime import timedelta -from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL -from unittest import TestCase, main - -import os -import sys -import tempfile -import textwrap -import unittest - -try: - import pyparsing -except (ImportError, SyntaxError): - pyparsing = None - -try: - RecursionError -except NameError: - # python3.4 - RecursionError = RuntimeError - -class TestEnumV3(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 - - @unittest.skipUnless(StdlibEnumMeta, 'Stdlib enum not available') - def test_stdlib_inheritence(self): - # 3.4 - self.assertTrue(issubclass(self.Season, StdlibEnum)) - self.assertTrue(isinstance(self.Season.SPRING, StdlibEnum)) - # - if pyver >= PY3_6: - class AFlag(Flag): - one = 1 - self.assertTrue(issubclass(AFlag, StdlibEnum)) - self.assertTrue(isinstance(AFlag.one, StdlibEnum)) - self.assertTrue(issubclass(AFlag, StdlibFlag)) - self.assertTrue(isinstance(AFlag.one, StdlibFlag)) - # - class AnIntFlag(IntFlag): - one = 1 - self.assertTrue(issubclass(AnIntFlag, StdlibEnum)) - self.assertTrue(isinstance(AnIntFlag.one, StdlibEnum)) - self.assertTrue(issubclass(AnIntFlag, StdlibFlag)) - self.assertTrue(isinstance(AnIntFlag.one, StdlibFlag)) - self.assertTrue(issubclass(AnIntFlag, StdlibIntFlag)) - self.assertTrue(isinstance(AnIntFlag.one, StdlibIntFlag)) - # - if pyver >= PY3_11: - class AStrEnum(StrFlag): - one = '1' - self.assertTrue(issubclass(AStrEnum, StdlibEnum)) - self.assertTrue(isinstance(AStrEnum.one, StdlibEnum)) - self.assertTrue(issubclass(AStrEnum, StdlibStrEnum)) - self.assertTrue(isinstance(AStrEnum.one, StdlibStrEnum)) - - @unittest.skipUnless(StdlibEnumMeta, 'Stdlib enum not available') - def test_stdlib_bad_getattribute(self): - class BadEnumType(StdlibEnumMeta): - def __getattribute__(cls, name): - obj = super().__getattribute__(name) - if isinstance(obj, cls): - obj.deprecate() - return obj - with self.assertRaisesRegex(RecursionError, 'endless recursion'): - class BaseEnum(StdlibEnum): - pass - class BadEnum(BaseEnum, metaclass=BadEnumType): - FOO = 'bar' - try: - remove_stdlib_integration() - class OkayEnum(StdlibEnum, metaclass=BadEnumType): - FOO = 'bar' - finally: - add_stdlib_integration() - - @unittest.skipUnless(pyver >= PY3_5, '__qualname__ requires python 3.5 or greater') - def test_pickle_enum_function_with_qualname(self): - Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition') - globals()['spanish_inquisition'] = Theory - test_pickle_dump_load(self.assertTrue, Theory.rule) - test_pickle_dump_load(self.assertTrue, Theory) - - 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_auto_turns_off(self): - with self.assertRaises(NameError): - class Color(Enum, settings=MagicValue): - red - green - blue - def hello(self): - print('Hello! My serial is %s.' % self.value) - rose - with self.assertRaises(NameError): - class Color(Enum, settings=MagicValue): - red - green - blue - def __init__(self, *args): - pass - rose - - def test_magic(self): - class Color(Enum, settings=MagicValue): - red, green, blue - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) - self.assertEqual(Color.red.value, 1) - - def test_ignore_not_overridden(self): - with self.assertRaisesRegex(TypeError, 'object is not callable'): - class Color(Flag): - _ignore_ = 'irrelevent' - _settings_ = MagicValue - @property - def shade(self): - print('I am light', self.name.lower()) - - def test_magic_start(self): - class Color(Enum, settings=MagicValue, start=0): - red, green, blue - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) - self.assertEqual(Color.red.value, 0) - - def test_dir_on_class(self): - Season = self.Season - self.assertEqual( - set(dir(Season)), - set(['__class__', '__doc__', '__members__', '__module__', - 'SPRING', 'SUMMER', 'AUTUMN', 'WINTER', - '__init_subclass__', '__name__', '__getitem__', '__len__', - '__contains__', '__iter__', '__qualname__', - ])) - - def test_dir_on_item(self): - Season = self.Season - self.assertEqual( - set(dir(Season.WINTER)), - set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value', 'values']), - ) - - def test_dir_with_added_behavior(self): - class Test(Enum): - this = 'that' - these = 'those' - def wowser(self): - return ("Wowser! I'm %s!" % self.name) - self.assertEqual( - set(dir(Test)), - set([ - '__class__', '__doc__', '__members__', '__module__', 'this', 'these', - '__init_subclass__', '__name__', '__getitem__', '__len__', - '__contains__', '__iter__', '__qualname__', - ])) - self.assertEqual( - set(dir(Test.this)), - set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value', 'values', 'wowser']), - ) - - def test_dir_on_sub_with_behavior_on_super(self): - # see issue22506 - class SuperEnum(Enum): - def invisible(self): - return "did you see me?" - class SubEnum(SuperEnum): - sample = 5 - self.assertEqual( - set(dir(SubEnum.sample)), - set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value', 'values', 'invisible']), - ) - - def test_members_are_always_ordered(self): - class AlwaysOrdered(Enum): - first = 1 - second = 2 - third = 3 - self.assertTrue(type(AlwaysOrdered.__members__) is OrderedDict) - - def test_comparisons(self): - def bad_compare(): - Season.SPRING > 4 - Season = self.Season - self.assertNotEqual(Season.SPRING, 1) - self.assertRaises(TypeError, bad_compare) - - class Part(Enum): - SPRING = 1 - CLIP = 2 - BARREL = 3 - - self.assertNotEqual(Season.SPRING, Part.SPRING) - def bad_compare(): - Season.SPRING < Part.CLIP - self.assertRaises(TypeError, bad_compare) - - def test_duplicate_name(self): - with self.assertRaises(TypeError): - class Color1(Enum): - red = 1 - green = 2 - blue = 3 - red = 4 - - with self.assertRaises(TypeError): - class Color2(Enum): - red = 1 - green = 2 - blue = 3 - def red(self): - return 'red' - - with self.assertRaises(TypeError): - class Color3(Enum): - @property - def red(self): - return 'redder' - red = 1 - green = 2 - blue = 3 - - def test_duplicate_value_with_unique(self): - with self.assertRaises(ValueError): - class Color(Enum, settings=Unique): - red = 1 - green = 2 - blue = 3 - rojo = 1 - - def test_duplicate_value_with_noalias(self): - class Color(Enum, settings=NoAlias): - red = 1 - green = 2 - blue = 3 - rojo = 1 - self.assertFalse(Color.red is Color.rojo) - self.assertEqual(Color.red.value, 1) - self.assertEqual(Color.rojo.value, 1) - self.assertEqual(len(Color), 4) - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.rojo]) - - def test_noalias_value_lookup(self): - class Color(Enum, settings=NoAlias): - red = 1 - green = 2 - blue = 3 - rojo = 1 - self.assertRaises(TypeError, Color, 2) - - def test_multivalue(self): - class Color(Enum, settings=MultiValue): - red = 1, 'red' - green = 2, 'green' - blue = 3, 'blue' - self.assertEqual(Color.red.value, 1) - self.assertIs(Color('green'), Color.green) - self.assertEqual(Color.blue.values, (3, 'blue')) - - def test_multivalue_with_duplicate_values(self): - with self.assertRaises(ValueError): - class Color(Enum, settings=MultiValue): - red = 1, 'red' - green = 2, 'green' - blue = 3, 'blue', 'red' - - def test_multivalue_with_duplicate_values_and_noalias(self): - with self.assertRaises(TypeError): - class Color(Enum, settings=(MultiValue, NoAlias)): - red = 1, 'red' - green = 2, 'green' - blue = 3, 'blue', 'red' - - def test_multivalue_and_auto(self): - with self.assertRaisesRegex(TypeError, r'MultiValue and MagicValue are mutually exclusive'): - class Color(Enum, settings=(MultiValue, MagicValue)): - red - green = 3, 'green' - blue - - def test_autonumber_and_init(self): - class Field(IntEnum, settings=AddValue, init='__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') - self.assertFalse(hasattr(Field, '_order_')) - - def test_autovalue_and_init(self): - class Field(IntEnum, init='value __doc__'): - TYPE = "Char, Date, Logical, etc." - START = "Field offset in record" - self.assertEqual(Field.TYPE, 1) - self.assertEqual(Field.START.__doc__, 'Field offset in record') - - def test_autonumber_and_start(self): - class Field(IntEnum, init='__doc__', settings=AddValue, start=0): - 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_autonumber_and_init_and_some_values(self): - class Field(IntEnum, 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_autonumber_with_irregular_values(self): - class Point(AutoNumberEnum, init='x y'): - first = 7, 9 - second = 11, 13 - self.assertEqual(Point.first.value, 1) - self.assertEqual(Point.first.x, 7) - self.assertEqual(Point.first.y, 9) - self.assertEqual(Point.second.value, 2) - self.assertEqual(Point.second.x, 11) - self.assertEqual(Point.second.y, 13) - with self.assertRaisesRegex(TypeError, '.*number of fields provided do not match init ...x., .y.. != .3, 11, 13..'): - class Point(AutoNumberEnum, init='x y'): - first = 7, 9 - second = 3, 11, 13 - class Color(AutoNumberEnum, init='__doc__'): - # interactions between AutoNumberEnum and _generate_next_value_ may not be pretty - red = () - green = 'red' - blue = () - self.assertTrue(Color.red.__doc__, 1) - self.assertEqual(Color.green.__doc__, 'red') - self.assertTrue(Color.blue.__doc__, 2) - - def test_autonumber_and_property(self): - with self.assertRaises(TypeError): - class Color(AutoEnum): - _ignore_ = () - red = () - green = () - blue = () - @property - def cap_name(self) -> str: - return self.name.title() - - def test_autoenum(self): - class Color(AutoEnum): - red - green - blue - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) - self.assertEqual([m.value for m in Color], [1, 2, 3]) - self.assertEqual([m.name for m in Color], ['red', 'green', 'blue']) - - def test_autoenum_with_str(self): - class Color(AutoEnum): - def _generate_next_value_(name, start, count, last_values): - return name - red - green - blue - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue]) - self.assertEqual([m.value for m in Color], ['red', 'green', 'blue']) - self.assertEqual([m.name for m in Color], ['red', 'green', 'blue']) - - def test_autoenum_and_default_ignore(self): - class Color(AutoEnum): - red - green - blue - @property - def cap_name(self): - return self.name.title() - self.assertEqual(Color.blue.cap_name, 'Blue') - - def test_autonumber_and_overridden_ignore(self): - with self.assertRaises(TypeError): - class Color(AutoEnum): - _ignore_ = 'staticmethod' - red - green - blue - @property - def cap_name(self) -> str: - return self.name.title() - - def test_autonumber_and_multiple_assignment(self): - class Color(AutoEnum): - _ignore_ = 'property' - red - green - blue = cyan - @property - def cap_name(self) -> str: - return self.name.title() - self.assertEqual(Color.blue.cap_name, 'Cyan') - - def test_multivalue_and_autonumber_inherited(self): - class Measurement(int, Enum, settings=(MultiValue, AddValue), start=0): - one = "20110721" - two = "20120911" - three = "20110518" - M = Measurement - self.assertEqual(M.one, 0) - self.assertTrue(M.one is M(0) is M('20110721')) - - def test_combine_new_settings_with_old_settings(self): - class Auto(Enum, settings=Unique): - pass - with self.assertRaises(ValueError): - class AutoUnique(Auto, settings=MagicValue): - BLAH - BLUH - 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_extend_enum_plain(self): - class Color(UniqueEnum): - red = 1 - green = 2 - blue = 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(len(Color), 4) - - def test_extend_enum_shadow(self): - class Color(UniqueEnum): - 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(len(Color), 4) - self.assertEqual(Color.red.value, 1) - - def test_extend_enum_generate(self): - class Foo(AutoEnum): - def _generate_next_value_(name, start, count, values, *args, **kwds): - return name - a - b - # - extend_enum(Foo, 'c') - self.assertEqual(Foo.a.value, 'a') - self.assertEqual(Foo.b.value, 'b') - self.assertEqual(Foo.c.value, 'c') - - def test_extend_enum_unique_with_duplicate(self): - with self.assertRaises(ValueError): - class Color(Enum, settings=Unique): - red = 1 - green = 2 - blue = 3 - extend_enum(Color, 'value', 1) - - def test_extend_enum_multivalue_with_duplicate(self): - with self.assertRaises(ValueError): - class Color(Enum, settings=MultiValue): - red = 1, 'rojo' - green = 2, 'verde' - blue = 3, 'azul' - extend_enum(Color, 'value', 2) - - def test_extend_enum_noalias_with_duplicate(self): - class Color(Enum, settings=NoAlias): - red = 1 - green = 2 - blue = 3 - extend_enum(Color, 'value', 3, ) - self.assertRaises(TypeError, Color, 3) - self.assertFalse(Color.value is Color.blue) - self.assertTrue(Color.value.value, 3) - - def test_no_duplicates(self): - def bad_duplicates(): - class Color(UniqueEnum): - red = 1 - green = 2 - blue = 3 - class Color(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_auto_number(self): - class Color(Enum, settings=MagicValue): - red - blue - green - - 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, settings=MagicValue): - def _generate_next_value_(name, start, count, last): - return name - red - blue - green - - 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, settings=MagicValue): - red - blue - green - - 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): - _settings_ = MagicValue - red = 'red' - blue - self.assertEqual(Color.blue.value, 1) - - def test_auto_garbage_corrected(self): - class Color(Enum, settings=MagicValue): - red = 'red' - blue = 2 - green - - 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 Dupes(Enum, settings=MagicValue): - first = primero - second - third - self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes)) - - 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 - - if pyver >= PY3_3: - def test_missing(self): - class Color(Enum): - red = 1 - green = 2 - blue = 3 - @classmethod - def _missing_(cls, item): - if item == 'three': - return cls.blue - elif item == 'bad return': - # trigger internal error - return 5 - elif item == 'error out': - raise ZeroDivisionError - else: - # trigger not found - return None - self.assertIs(Color('three'), Color.blue) - self.assertRaises(ValueError, Color, 7) - try: - Color('bad return') - except TypeError as exc: - self.assertTrue(isinstance(exc.__cause__, ValueError)) - else: - raise Exception('Exception not raised.') - try: - Color('error out') - except ZeroDivisionError as exc: - self.assertTrue(isinstance(exc.__cause__, ValueError)) - else: - raise Exception('Exception not raised.') - - 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) - - def test_nested_classes_in_enum_do_not_create_members(self): - """Support locally-defined nested classes.""" - # manually set __qualname__ to remove testing framework noise - class Outer(Enum): - __qualname__ = "Outer" - a = 1 - b = 2 - 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], - ) - - if pyver == PY3_4: - def test_class_nested_enum_and_pickle_protocol_four(self): - # would normally just have this directly in the class namespace - class NestedEnum(Enum): - twigs = 'common' - shiny = 'rare' - - self.__class__.NestedEnum = NestedEnum - self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ - test_pickle_exception( - self.assertRaises, PicklingError, self.NestedEnum.twigs, - protocol=(0, 3)) - test_pickle_dump_load(self.assertTrue, self.NestedEnum.twigs, - protocol=(4, HIGHEST_PROTOCOL)) - - elif pyver >= PY3_5: - def test_class_nested_enum_and_pickle_protocol_four(self): - # would normally just have this directly in the class namespace - class NestedEnum(Enum): - twigs = 'common' - shiny = 'rare' - - self.__class__.NestedEnum = NestedEnum - self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__ - test_pickle_dump_load(self.assertTrue, self.NestedEnum.twigs, - protocol=(0, HIGHEST_PROTOCOL)) - - if pyver >= PY3_4: - def test_enum_injection(self): - class Color(Enum): - _order_ = 'BLACK WHITE' - BLACK = Color('black', '#000') - WHITE = Color('white', '#fff') - - def __init__(self, label, hex): - self.label = label - self.hex = hex - - self.assertEqual([Color.BLACK, Color.WHITE], list(Color)) - self.assertEqual(Color.WHITE.hex, '#fff') - self.assertEqual(Color.BLACK.label, 'black') - - def test_subclasses_with_getnewargs_ex(self): - class NamedInt(int): - __qualname__ = 'NamedInt' # needed for pickle protocol 4 - def __new__(cls, *args): - _args = args - if len(args) < 2: - 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_ex__(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 "{}({!r}, {})".format(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( - '({0} + {1})'.format(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.assertIs(NEI.__new__, 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, protocol=(4, HIGHEST_PROTOCOL)) - self.assertEqual(NEI.y.value, 2) - test_pickle_dump_load(self.assertTrue, NEI.y, protocol=(4, HIGHEST_PROTOCOL)) - - -class TestOrderV3(TestCase): - """ - Test definition order versus _order_ order. - """ - - 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_same_members_wrong_order(self): - with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): - class Color(Enum): - _order_ = 'red green blue' - red = 1 - blue = 3 - green = 2 - - def test_order_has_extra_members(self): - with self.assertRaisesRegex(TypeError, '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, '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, '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, '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_same_members_wrong_order_falg(self): - with self.assertRaisesRegex(TypeError, 'member order does not match _order_'): - class Color(Flag): - _order_ = 'red green blue' - red = 1 - blue = 4 - green = 2 - - def test_order_has_extra_members_flag(self): - with self.assertRaisesRegex(TypeError, '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, '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, '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, 'member order does not match _order_'): - class Color(Flag): - _order_ = 'red green blue' - red = 1 - green = 2 - blue = 4 - purple = 8 - verde = green - - -class TestNamedTupleV3(TestCase): - - 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') - self.assertEqual(b[2], '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(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') - - - -class TestStackoverflowAnswersV3(TestCase): - - def test_self_referential_directions(self): - # https://stackoverflow.com/a/64000706/208880 - class Directions(Enum): - # - 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): - # - 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): - __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_create_C_like_Enum(self): - # https://stackoverflow.com/a/35965438/208880 - class Id(Enum, settings=MagicValue, start=0): - # - NONE # 0x0 - HEARTBEAT # 0x1 - FLUID_TRANSFER_REQUEST - FLUID_TRANSFER_STATUS_MSG - FLUID_TRANSFER_ERROR_MSG - # ... - # - # Camera App Messages - START_SENDING_PICTURES = 0x010000 - STOP_SENDING_PICTURES - START_RECORDING_VIDEO_REQ - STOP_RECORDING_VIDEO_REQ - # ... - # - # Sensor Calibration - VOLUME_REQUEST = 0x020000 - START_CAL - CLI_COMMAND_REQUEST - CLI_COMMAND_RESPONSE - # - # File Mananger - NEW_DELIVERY_REQ = 0x30000 - GET_DELIVERY_FILE_REQ - GET_FILE_REQ - # - ACK_NACK - RESPONSE - # - LAST_ID - # - self.assertEqual(Id.NONE.value, 0) - self.assertEqual(Id.FLUID_TRANSFER_ERROR_MSG.value, 4) - self.assertEqual(Id.START_SENDING_PICTURES.value, 0x010000) - self.assertEqual(Id.STOP_RECORDING_VIDEO_REQ.value, 0x010003) - self.assertEqual(Id.START_CAL.value, 0x020001) - self.assertEqual(Id.LAST_ID.value, 0x30005) - - - @unittest.skipUnless(pyparsing, 'pyparsing not installed') - def test_c_header_scanner(self): - # https://stackoverflow.com/questions/58732872/208880 - with open(os.path.join(tempdir, 'c_plus_plus.h'), 'w') as fh: - fh.write(""" - stuff before - enum hello { - Zero, - One, - Two, - Three, - Five=5, - Six, - Ten=10 - }; - in the middle - enum blah - { - alpha, - beta, - gamma = 10 , - zeta = 50 - }; - at the end - """) - from pyparsing import Group, Optional, Suppress, Word, ZeroOrMore - from pyparsing import alphas, alphanums, nums - # - CPPEnum = None - class CPPEnumType(EnumMeta): - # - @classmethod - def __prepare__(metacls, clsname, bases, **kwds): - # return a standard dictionary for the initial processing - return {} - # - def __init__(clsname, *args , **kwds): - super(CPPEnumType, clsname).__init__(*args) - # - def __new__(metacls, clsname, bases, clsdict, **kwds): - if CPPEnum is None: - # first time through, ignore the rest - enum_dict = super(CPPEnumType, metacls).__prepare__(clsname, bases, **kwds) - enum_dict.update(clsdict) - return super(CPPEnumType, metacls).__new__(metacls, clsname, bases, enum_dict, **kwds) - members = [] - # - # remove _file and _name using `pop()` as they will cause problems in EnumMeta - try: - file = clsdict.pop('_file') - except KeyError: - raise TypeError('_file not specified') - cpp_enum_name = clsdict.pop('_name', clsname.lower()) - with open(file) as fh: - file_contents = fh.read() - # - # syntax we don't want to see in the final parse tree - LBRACE, RBRACE, EQ, COMMA = map(Suppress, "{}=,") - _enum = Suppress("enum") - identifier = Word(alphas, alphanums + "_") - integer = Word(nums) - enumValue = Group(identifier("name") + Optional(EQ + integer("value"))) - enumList = Group(enumValue + ZeroOrMore(COMMA + enumValue)) - enum = _enum + identifier("enum") + LBRACE + enumList("names") + RBRACE - # - # find the cpp_enum_name ignoring other syntax and other enums - for item, start, stop in enum.scanString(file_contents): - if item.enum != cpp_enum_name: - continue - id = 0 - for entry in item.names: - if entry.value != "": - id = int(entry.value) - members.append((entry.name.upper(), id)) - id += 1 - # - # get the real EnumDict - enum_dict = super(CPPEnumType, metacls).__prepare__(clsname, bases, **kwds) - # transfer the original dict content, names starting with '_' 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(CPPEnumType, metacls).__new__(metacls, clsname, bases, enum_dict, **kwds) - # - class CPPEnum(IntEnum, metaclass=CPPEnumType): - pass - # - class Hello(CPPEnum): - _file = os.path.join(tempdir, 'c_plus_plus.h') - # - class Blah(CPPEnum): - _file = os.path.join(tempdir, 'c_plus_plus.h') - _name = 'blah' - # - self.assertEqual( - list(Hello), - [Hello.ZERO, Hello.ONE, Hello.TWO, Hello.THREE, Hello.FIVE, Hello.SIX, Hello.TEN], - ) - self.assertEqual(Hello.ZERO.value, 0) - self.assertEqual(Hello.THREE.value, 3) - self.assertEqual(Hello.SIX.value, 6) - self.assertEqual(Hello.TEN.value, 10) - # - self.assertEqual( - list(Blah), - [Blah.ALPHA, Blah.BETA, Blah.GAMMA, Blah.ZETA], - ) - self.assertEqual(Blah.ALPHA.value, 0) - self.assertEqual(Blah.BETA.value, 1) - self.assertEqual(Blah.GAMMA.value, 10) - self.assertEqual(Blah.ZETA.value, 50) - -class TestIssuesV3(TestCase): - """ - Problems that were stated in issues. - """ - - def test_auto_multi_int_1(self): - class Measurement(int, AddValueEnum, MultiValueEnum, 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(0), Measurement.one) - self.assertIs(Measurement('20110721'), Measurement.one) - self.assertIs(Measurement(1), Measurement.two) - self.assertIs(Measurement('20120911'), Measurement.two) - self.assertIs(Measurement(2), Measurement.three) - self.assertIs(Measurement('20110518'), Measurement.three) - - def test_auto_multi_int_2(self): - class Measurement(int, Enum, settings=(MultiValue, AddValue), 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(0), Measurement.one) - self.assertIs(Measurement('20110721'), Measurement.one) - self.assertIs(Measurement(1), Measurement.two) - self.assertIs(Measurement('20120911'), Measurement.two) - self.assertIs(Measurement(2), Measurement.three) - self.assertIs(Measurement('20110518'), Measurement.three) - - def test_extend_enum_with_init(self): - class Color(Enum, settings=MultiValue, init='foo bar'): - red = '1', 'yes' - green = '2', 'no' - blue = '3', 'maybe' - self.assertEqual(Color.red.value, '1') - self.assertEqual(Color.red.foo, '1') - self.assertEqual(Color.red.bar, 'yes') - extend_enum(Color, 'opacity', '4', 'never') - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.opacity]) - self.assertEqual(Color.opacity.value, '4') - self.assertEqual(Color.opacity.name, 'opacity') - self.assertTrue(Color('4') is Color.opacity) - self.assertTrue(Color('never') is Color.opacity) - -class TestExtendEnumV3(TestCase): - - def test_extend_enum_plain(self): - class Color(Enum): - red = 1 - green = 2 - blue = 3 - self.assertRaisesRegex(TypeError, '.blue. already in use as property..Color.blue: 3.', 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' is a duplicate of ', 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, ' is a duplicate of ', 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' is a duplicate of ', 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): - 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) - - @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') - def test_extend_enum_stdlib(self): - class Color(StdlibEnum): - red = 1 - green = 2 - blue = 3 - self.assertEqual(getattr(Color.red, '_values_', None), None) - 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) - - @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') - def test_extend_enum_plain_stdlib(self): - class Color(StdlibEnum): - 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) - self.assertEqual(list(Color), [Color.red, Color.green, Color.blue, Color.brown]) - self.assertEqual([c.value for c in Color], [1, 2, 3, 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) - - @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') - def test_extend_enum_alias_stdlib(self): - class Color(StdlibEnum): - 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) - - @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') - def test_extend_enum_shadow_property_stdlib(self): - class Color(StdlibEnum): - 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) - - @unittest.skipUnless(StdlibEnum, 'Stdlib Enum not available') - def test_extend_enum_shadow_base_stdlib(self): - class hohum(object): - def cyan(self): - "cyanize a color" - return self.value - class Color(hohum, StdlibEnum): - 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]) - - @unittest.skipUnless(StdlibIntEnum, 'Stdlib IntEnum not available') - def test_extend_intenum_stdlib(self): - class Index(StdlibIntEnum): - 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) - - @unittest.skipUnless(StdlibIntEnum, 'Stdlib IntEnum not available') - def test_extend_multi_init_stdlib(self): - class HTTPStatus(StdlibIntEnum): - 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, '') - - @unittest.skipUnless(StdlibFlag, 'Stdlib Flag not available') - def test_extend_flag_stdlib(self): - class Color(StdlibFlag): - 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, StdlibFlag)) - - @unittest.skipUnless(StdlibFlag, 'Stdlib Flag not available') - def test_extend_flag_backwards_stdlib(self): - class Color(StdlibFlag): - 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, StdlibFlag)) - # - extend_enum(Color, 'MAGENTA') - self.assertTrue(Color(16) is Color.MAGENTA) - self.assertTrue(isinstance(Color.MAGENTA, Color)) - self.assertEqual(Color.MAGENTA.value,16) - # - extend_enum(Color, 'mauve') - self.assertEqual(Color.mauve.name, 'mauve') - self.assertEqual(Color.mauve.value, 32) - self.assertTrue(Color.mauve in Color) - self.assertEqual(Color(32), Color.mauve) - self.assertEqual(Color['mauve'], Color.mauve) - - @unittest.skipUnless(StdlibIntFlag, 'Stdlib IntFlag not available') - def test_extend_intflag_stdlib(self): - class Color(StdlibIntFlag): - 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, StdlibFlag)) - # - 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) - - @unittest.skipUnless(StdlibIntFlag, 'Stdlib IntFlag not available') - def test_extend_intflag_backwards_stdlib(self): - class Color(StdlibIntFlag): - BLACK = 0 - RED = 1 - GREEN = 2 - BLUE = 4 - if pyver >= PY3_11: - # flags make more sense in 3.11 - length = 5 - MAGENTA = 8 - mauve = 16 - else: - length = 7 - MAGENTA = 16 - mauve = 32 - 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, StdlibFlag)) - # - extend_enum(Color, 'MAGENTA') - self.assertTrue(Color(MAGENTA) is Color.MAGENTA) - self.assertTrue(isinstance(Color.MAGENTA, Color)) - self.assertEqual(Color.MAGENTA.value, MAGENTA) - # - extend_enum(Color, 'mauve') - self.assertEqual(Color.mauve.name, 'mauve') - self.assertEqual(Color.mauve.value, mauve) - self.assertTrue(Color.mauve in Color) - self.assertEqual(Color(mauve), Color.mauve) - self.assertEqual(Color['mauve'], Color.mauve) - self.assertEqual(len(Color), length, list(Color)) - - @unittest.skipUnless(StdlibStrEnum, 'Stdlib StrEnum not available') - def test_extend_strenum_stdlib(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) - - -if __name__ == '__main__': - raise RuntimeError("'test_v3.py' should not be run by itself; it's included in 'test.py'") diff --git a/venv/Lib/site-packages/blendmodes/__init__.py b/venv/Lib/site-packages/blendmodes/__init__.py deleted file mode 100644 index 2b6e91ad..00000000 --- a/venv/Lib/site-packages/blendmodes/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Use this module to apply a number of blending modes to a background and foreground image -""" diff --git a/venv/Lib/site-packages/blendmodes/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/blendmodes/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index da1d6a38859540c7045ecb683d0533d09663f8a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285 zcmYjMK~BUl3{3aJYNh>yuX`vDKnU@Iy#NPLP~0LCRtQI!8`a1FW4(jKwLQC z77kb%+ap*%tC#z`M34`hUav|*$_$^&+^+3%{;nK3Rj#=NOU|ekNO3AITqe&sHbSR7cU3|4A>V7DL(? U_MDA5kJD*=`J3cwj{GT5KLp5FlmGw# diff --git a/venv/Lib/site-packages/blendmodes/__pycache__/blend.cpython-39.pyc b/venv/Lib/site-packages/blendmodes/__pycache__/blend.cpython-39.pyc deleted file mode 100644 index 231846003cc72829e6134e11092b415beb764453..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13302 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 diff --git a/venv/Lib/site-packages/blendmodes/__pycache__/blendtype.cpython-39.pyc b/venv/Lib/site-packages/blendmodes/__pycache__/blendtype.cpython-39.pyc deleted file mode 100644 index c599cfb826eeeee7b7784bf75fcdf6e55c3f9253..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2850 zcmbVONpIUm6sA^^W7*mFG*NsgV4%*S$Dj?ONVFqVmI9h`(}7Td){Jc;6sdA?;#}K9 zZ~Yzp1^pBK1@GEZe?Tui_04dGWG_8bhB@C`W_fSkGXC~9G4S`-@4xuJ*@p3lAnLyk z60Z!Sk$#DQ8Ps46)(ji#CT%tZZiTINo315Odq5wthx9RfL_cGX z=@a%DeafEDK6^@^u|8V+4D8p!HV;knKeY|xzilVPp3dB(!KD9nfA@6#B8ro>AMSq9 z-&Kg%NArm{emnV2X{?1;HsO`fDKW7JqtVzKpEyd(XDrBqOD?oZOzh!oGMl@v=k8SL zt>Q4wlhZtjgl3J>x}(|XP%m1DS zVf;Y|gR zM*LhxmDsSv#GZ@~-*}Ez3WM{Dj7v9Yh?@@FZ%Pg3C+`adg@}DTbe&S3t`c6z6(aV# znX3%`7$;(TG2pb>fhTuY!Zbe10h&{4)+k~-?}n54aTQVg<0{NkEL7r*6@i{|j=ixCDaO+*kSYol^4VNx ziD1XM%n}XJYwmF1&ED$JNLGFpZ)9L7Sgcah5p%UtiHW_}{A8CU1-eB+LFN`Rb>#p{ zBPGzq0xXSCu#Gc{n-G-(NQF_jQwn8efUQC*2^13)s}caF0?0OzEs`JF;;Zyjwu7kv zvc=X_ZUd<>3WX&)p~2EfEhcZ0M_?*|Y~hX~ccEL1idiHqbc+$0UDU)}g%*C0>>*j^ zCD66WVQ~dgl~U*yCj?TJM6h(p15%YWsLB?uCJPgoV#ERjrYbXF z363ZxzZ%I9UsCe(_xIk5#VTfevAN1F;%MRLS-i%|z1qi8gO9g;k%zJZ?tkE?d9b+T z(d8lxP8V2_`ToXVz4y;~x{&WYyc-S0i|_g7D#3@5Vc~!JQh-K#x83-^e{!wqo|$}( zONmf8%dyK~C?ri}(2mdX^_aATu$5+sRIe;8&`3zFuZkdgDPERo7eDQ0ui0z;18nYT A{Qv*} diff --git a/venv/Lib/site-packages/blendmodes/blend.py b/venv/Lib/site-packages/blendmodes/blend.py deleted file mode 100644 index 4165bfa7..00000000 --- a/venv/Lib/site-packages/blendmodes/blend.py +++ /dev/null @@ -1,511 +0,0 @@ -"""Provide blending functions and types. - -Adapted from https://github.com/addisonElliott/pypdn/blob/master/pypdn/reader.py -and https://gitlab.com/inklabapp/pyora/-/blob/master/pyora/BlendNonSep.py -MIT License Copyright (c) 2020 FredHappyface - -Credits to: - -MIT License Copyright (c) 2019 Paul Jewell -For implementing blending from the Open Raster Image Spec - -MIT License Copyright (c) 2018 Addison Elliott -For implementing blending from Paint.NET - -MIT License Copyright (c) 2017 pashango -For implementing a number of blending functions used by other popular image -editors -""" - -from __future__ import annotations - -import warnings - -import numpy as np -from PIL import Image - -from .blendtype import BlendType - - -def normal(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.NORMAL.""" - del background # we don't care about this - return foreground - - -def multiply(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.MULTIPLY.""" - return np.clip(foreground * background, 0.0, 1.0) - - -def additive(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.ADDITIVE.""" - return np.minimum(background + foreground, 1.0) - - -def colourburn(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.COLOURBURN.""" - with np.errstate(divide="ignore"): - return np.where( - foreground != 0.0, np.maximum(1.0 - ((1.0 - background) / foreground), 0.0), 0.0 - ) - - -def colourdodge(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.COLOURDODGE.""" - with np.errstate(divide="ignore"): - return np.where(foreground != 1.0, np.minimum(background / (1.0 - foreground), 1.0), 1.0) - - -def reflect(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.REFLECT.""" - with np.errstate(divide="ignore"): - return np.where( - foreground != 1.0, np.minimum((background ** 2) / (1.0 - foreground), 1.0), 1.0 - ) - - -def glow(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.GLOW.""" - with np.errstate(divide="ignore"): - return np.where( - background != 1.0, np.minimum((foreground ** 2) / (1.0 - background), 1.0), 1.0 - ) - - -def overlay(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.OVERLAY.""" - return np.where( - background < 0.5, - 2 * background * foreground, - 1.0 - (2 * (1.0 - background) * (1.0 - foreground)), - ) - - -def difference(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.DIFFERENCE.""" - return np.abs(background - foreground) - - -def negation(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.NEGATION.""" - return np.maximum(background - foreground, 0.0) - - -def lighten(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.LIGHTEN.""" - return np.maximum(background, foreground) - - -def darken(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.DARKEN.""" - return np.minimum(background, foreground) - - -def screen(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.SCREEN.""" - return background + foreground - background * foreground - - -def xor(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.XOR.""" - # XOR requires int values so convert to uint8 - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - return imageIntToFloat(imageFloatToInt(background) ^ imageFloatToInt(foreground)) - - -def softlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.SOFTLIGHT.""" - return (1.0 - background) * background * foreground + background * ( - 1.0 - (1.0 - background) * (1.0 - foreground) - ) - - -def hardlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.HARDLIGHT.""" - return np.where( - foreground < 0.5, - np.minimum(background * 2 * foreground, 1.0), - np.minimum(1.0 - ((1.0 - background) * (1.0 - (foreground - 0.5) * 2.0)), 1.0), - ) - - -def grainextract(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.GRAINEXTRACT.""" - return np.clip(background - foreground + 0.5, 0.0, 1.0) - - -def grainmerge(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.GRAINMERGE.""" - return np.clip(background + foreground - 0.5, 0.0, 1.0) - - -def divide(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.DIVIDE.""" - return np.minimum((256.0 / 255.0 * background) / (1.0 / 255.0 + foreground), 1.0) - - -def pinlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.PINLIGHT.""" - return np.minimum(background, 2 * foreground) * (foreground < 0.5) + np.maximum( - background, 2 * (foreground - 0.5) - ) * (foreground >= 0.5) - - -def vividlight(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.VIVIDLIGHT.""" - return colourburn(background, foreground * 2) * (foreground < 0.5) + colourdodge( - background, 2 * (foreground - 0.5) - ) * (foreground >= 0.5) - - -def exclusion(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.EXCLUSION.""" - return background + foreground - (2.0 * background * foreground) - - -def _lum(colours: np.ndarray) -> np.ndarray: - """Luminosity. - - :param colours: x by x by 3 matrix of rgb color components of pixels - :return: x by x by 3 matrix of luminosity of pixels - """ - return (colours[:, :, 0] * 0.299) + (colours[:, :, 1] * 0.587) + (colours[:, :, 2] * 0.114) - - -def _setLum(originalColours: np.ndarray, newLuminosity: np.ndarray) -> np.ndarray: - """Set a new luminosity value for the matrix of color.""" - _colours = originalColours.copy() - _luminosity = _lum(_colours) - deltaLum = newLuminosity - _luminosity - _colours[:, :, 0] += deltaLum - _colours[:, :, 1] += deltaLum - _colours[:, :, 2] += deltaLum - _luminosity = _lum(_colours) - _minColours = np.min(_colours, axis=2) - _MaxColours = np.max(_colours, axis=2) - for i in range(_colours.shape[0]): - for j in range(_colours.shape[1]): - _colour = _colours[i][j] - newLuminosity = _luminosity[i, j] - minColour = _minColours[i, j] - maxColour = _MaxColours[i, j] - if minColour < 0: - _colours[i][j] = newLuminosity + ( - ((_colour - newLuminosity) * newLuminosity) / (newLuminosity - minColour) - ) - if maxColour > 1: - _colours[i][j] = newLuminosity + ( - ((_colour - newLuminosity) * (1 - newLuminosity)) / (maxColour - newLuminosity) - ) - return _colours - - -def _sat(colours: np.ndarray) -> np.ndarray: - """Saturation. - - :param colours: x by x by 3 matrix of rgb color components of pixels - :return: int of saturation of pixels - """ - return np.max(colours, axis=2) - np.min(colours, axis=2) - - -def _setSat(originalColours: np.ndarray, newSaturation: np.ndarray) -> np.ndarray: - """Set a new saturation value for the matrix of color. - - The current implementation cannot be vectorized in an efficient manner, - so it is very slow, - O(m*n) at least. This might be able to be improved with openCL if that is - the direction that the lib takes. - :param c: x by x by 3 matrix of rgb color components of pixels - :param s: int of the new saturation value for the matrix - :return: x by x by 3 matrix of luminosity of pixels - """ - _colours = originalColours.copy() - for i in range(_colours.shape[0]): - for j in range(_colours.shape[1]): - _colour = _colours[i][j] - minI = 0 - midI = 1 - maxI = 2 - if _colour[midI] < _colour[minI]: - minI, midI = midI, minI - if _colour[maxI] < _colour[midI]: - midI, maxI = maxI, midI - if _colour[midI] < _colour[minI]: - minI, midI = midI, minI - if _colour[maxI] - _colour[minI] > 0.0: - _colours[i][j][midI] = ((_colour[midI] - _colour[minI]) * newSaturation[i, j]) / ( - _colour[maxI] - _colour[minI] - ) - _colours[i][j][maxI] = newSaturation[i, j] - else: - _colours[i][j][midI] = 0 - _colours[i][j][maxI] = 0 - _colours[i][j][minI] = 0 - return _colours - - -def hue(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.HUE.""" - return _setLum(_setSat(foreground, _sat(background)), _lum(background)) - - -def saturation(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.SATURATION.""" - return _setLum(_setSat(background, _sat(foreground)), _lum(background)) - - -def colour(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.COLOUR.""" - return _setLum(foreground, _lum(background)) - - -def luminosity(background: np.ndarray, foreground: np.ndarray) -> np.ndarray: - """BlendType.LUMINOSITY.""" - return _setLum(background, _lum(foreground)) - - -def destin( - backgroundAlpha: np.ndarray, - foregroundAlpha: np.ndarray, - backgroundColour: np.ndarray, - foregroundColour: np.ndarray, -): - """'clip' composite mode. - - All parts of 'layer above' which are alpha in 'layer below' will be made - also alpha in 'layer above' - (to whatever degree of alpha they were) - - Destination which overlaps the source, replaces the source. - - Fa = 0; Fb = αs - co = αb x Cb x αs - αo = αb x αs - """ - del foregroundColour # Not used by function - outAlpha = backgroundAlpha * foregroundAlpha - with np.errstate(divide="ignore", invalid="ignore"): - outRGB = np.divide( - np.multiply((backgroundAlpha * foregroundAlpha)[:, :, None], backgroundColour), - outAlpha[:, :, None], - ) - return outRGB, outAlpha - - -def destout( - backgroundAlpha: np.ndarray, - foregroundAlpha: np.ndarray, - backgroundColour: np.ndarray, - foregroundColour: np.ndarray, -): - """Reverse 'Clip' composite mode. - - All parts of 'layer below' which are alpha in 'layer above' will be made - also alpha in 'layer below' - (to whatever degree of alpha they were) - - """ - del foregroundColour # Not used by function - outAlpha = backgroundAlpha * (1 - foregroundAlpha) - with np.errstate(divide="ignore", invalid="ignore"): - outRGB = np.divide( - np.multiply((backgroundAlpha * (1 - foregroundAlpha))[:, :, None], backgroundColour), - outAlpha[:, :, None], - ) - return outRGB, outAlpha - - -def destatop( - backgroundAlpha: np.ndarray, - foregroundAlpha: np.ndarray, - backgroundColour: np.ndarray, - foregroundColour: np.ndarray, -): - """Place the layer below above the 'layer above' in places where the 'layer above' exists... - - where 'layer below' does not exist, but 'layer above' does, place 'layer-above' - - """ - outAlpha = (foregroundAlpha * (1 - backgroundAlpha)) + (backgroundAlpha * foregroundAlpha) - with np.errstate(divide="ignore", invalid="ignore"): - outRGB = np.divide( - np.multiply((foregroundAlpha * (1 - backgroundAlpha))[:, :, None], foregroundColour) - + np.multiply((backgroundAlpha * foregroundAlpha)[:, :, None], backgroundColour), - outAlpha[:, :, None], - ) - return outRGB, outAlpha - - -def srcatop( - backgroundAlpha: np.ndarray, - foregroundAlpha: np.ndarray, - backgroundColour: np.ndarray, - foregroundColour: np.ndarray, -): - """Place the layer below above the 'layer above' in places where the 'layer above' exists.""" - outAlpha = (foregroundAlpha * backgroundAlpha) + (backgroundAlpha * (1 - foregroundAlpha)) - with np.errstate(divide="ignore", invalid="ignore"): - outRGB = np.divide( - np.multiply((foregroundAlpha * backgroundAlpha)[:, :, None], foregroundColour) - + np.multiply((backgroundAlpha * (1 - foregroundAlpha))[:, :, None], backgroundColour), - outAlpha[:, :, None], - ) - - return outRGB, outAlpha - - -def imageIntToFloat(image: np.ndarray) -> np.ndarray: - """Convert a numpy array representing an image to an array of floats. - - Args: - image (np.ndarray): numpy array of ints - - Returns: - np.ndarray: numpy array of floats - """ - return image / 255 - - -def imageFloatToInt(image: np.ndarray) -> np.ndarray: - """Convert a numpy array representing an image to an array of ints. - - Args: - image (np.ndarray): numpy array of floats - - Returns: - np.ndarray: numpy array of ints - """ - return (image * 255).astype(np.uint8) - - -def blend(background: np.ndarray, foreground: np.ndarray, blendType: BlendType) -> np.ndarray: - """Blend pixels. - - Args: - background (np.ndarray): background - foreground (np.ndarray): foreground - blendType (BlendType): the blend type - - Returns: - np.ndarray: new array representing the image - - background: np.ndarray, - foreground: np.ndarray and the return are in the form - - [[[0. 0. 0.] - [0. 0. 0.] - [0. 0. 0.] - ... - [0. 0. 0.] - [0. 0. 0.] - [0. 0. 0.]] - - ... - - [[0. 0. 0.] - [0. 0. 0.] - [0. 0. 0.] - ... - [0. 0. 0.] - [0. 0. 0.] - [0. 0. 0.]]] - """ - blendLookup = { - BlendType.NORMAL: normal, - BlendType.MULTIPLY: multiply, - BlendType.COLOURBURN: colourburn, - BlendType.COLOURDODGE: colourdodge, - BlendType.REFLECT: reflect, - BlendType.OVERLAY: overlay, - BlendType.DIFFERENCE: difference, - BlendType.LIGHTEN: lighten, - BlendType.DARKEN: darken, - BlendType.SCREEN: screen, - BlendType.SOFTLIGHT: softlight, - BlendType.HARDLIGHT: hardlight, - BlendType.GRAINEXTRACT: grainextract, - BlendType.GRAINMERGE: grainmerge, - BlendType.DIVIDE: divide, - BlendType.HUE: hue, - BlendType.SATURATION: saturation, - BlendType.COLOUR: colour, - BlendType.LUMINOSITY: luminosity, - BlendType.XOR: xor, - BlendType.NEGATION: negation, - BlendType.PINLIGHT: pinlight, - BlendType.VIVIDLIGHT: vividlight, - BlendType.EXCLUSION: exclusion, - } - - if blendType not in blendLookup: - return normal(background, foreground) - return blendLookup[blendType](background, foreground) - - -def blendLayers( - background: Image.Image, - foreground: Image.Image, - blendType: BlendType | tuple[str, ...], - opacity: float = 1.0, -) -> Image.Image: - """Blend layers using numpy array. - - Args: - background (Image.Image): background layer - foreground (Image.Image): foreground layer (must be same size as background) - blendType (BlendType): The blendtype - opacity (float): The opacity of the foreground image - - Returns: - Image.Image: combined image - """ - # Convert the Image.Image to a numpy array - npForeground: np.ndarray = imageIntToFloat(np.array(foreground.convert("RGBA"))) - npBackground: np.ndarray = imageIntToFloat(np.array(background.convert("RGBA"))) - - # Get the alpha from the layers - backgroundAlpha = npBackground[:, :, 3] - foregroundAlpha = npForeground[:, :, 3] * opacity - combinedAlpha = backgroundAlpha * foregroundAlpha - - # Get the colour from the layers - backgroundColor = npBackground[:, :, 0:3] - foregroundColor = npForeground[:, :, 0:3] - - # Some effects require alpha - alphaFunc = { - BlendType.DESTIN: destin, - BlendType.DESTOUT: destout, - BlendType.SRCATOP: srcatop, - BlendType.DESTATOP: destatop, - } - - if blendType in alphaFunc: - return Image.fromarray( - imageFloatToInt( - np.clip( - np.dstack( - alphaFunc[blendType]( - backgroundAlpha, foregroundAlpha, backgroundColor, foregroundColor - ) - ), - a_min=0, - a_max=1, - ) - ) - ) - - # Get the colours and the alpha for the new image - colorComponents = ( - (backgroundAlpha - combinedAlpha)[:, :, None] * backgroundColor - + (foregroundAlpha - combinedAlpha)[:, :, None] * foregroundColor - + combinedAlpha[:, :, None] * blend(backgroundColor, foregroundColor, blendType) - ) - alphaComponent = backgroundAlpha + foregroundAlpha - combinedAlpha - - return Image.fromarray( - imageFloatToInt(np.clip(np.dstack((colorComponents, alphaComponent)), a_min=0, a_max=1)) - ) diff --git a/venv/Lib/site-packages/blendmodes/blendtype.py b/venv/Lib/site-packages/blendmodes/blendtype.py deleted file mode 100644 index 1bde12a6..00000000 --- a/venv/Lib/site-packages/blendmodes/blendtype.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Specify supported blend types.""" - -from __future__ import annotations - -from aenum import MultiValueEnum - - -class BlendType(str, MultiValueEnum): - """Specify supported blend types. - - NORMAL = "bm:normal", "normal" - MULTIPLY = "bm:multiply", "multiply" - ADDITIVE = "bm:additive", "additive" - COLOURBURN = "bm:colourburn", "colourburn" - COLOURDODGE = "bm:colourdodge", "colourdodge" - REFLECT = "bm:reflect", "reflect" - GLOW = "bm:glow", "glow" - OVERLAY = "bm:overlay", "overlay" - DIFFERENCE = "bm:difference", "difference" - NEGATION = "bm:negation", "negation" - LIGHTEN = "bm:lighten", "lighten" - DARKEN = "bm:darken", "darken" - SCREEN = "bm:screen", "screen" - XOR = "bm:xor", "xor" - SOFTLIGHT = "bm:softlight", "softlight" - HARDLIGHT = "bm:hardlight", "hardlight" - GRAINEXTRACT = "bm:grainextract", "grainextract" - GRAINMERGE = "bm:grainmerge", "grainmerge" - DIVIDE = "bm:divide", "divide" - HUE = "bm:hue", "hue" - SATURATION = "bm:saturation", "saturation" - COLOUR = "bm:colour", "colour" - LUMINOSITY = "bm:luminosity", "luminosity" - PINLIGHT = "bm:pinlight", "pinlight" - VIVIDLIGHT = "bm:vividlight", "vividlight" - EXCLUSION = "bm:exclusion", "exclusion" - DESTIN = "bm:destin", "destin" - DESTOUT = "bm:destout", "destout" - SRCATOP = "bm:srcatop", "srcatop" - DESTATOP = "bm:destatop", "destatop" - """ - - NORMAL = "bm:normal", "normal" - MULTIPLY = "bm:multiply", "multiply" - ADDITIVE = "bm:additive", "additive" - COLOURBURN = "bm:colourburn", "colourburn" - COLOURDODGE = "bm:colourdodge", "colourdodge" - REFLECT = "bm:reflect", "reflect" - GLOW = "bm:glow", "glow" - OVERLAY = "bm:overlay", "overlay" - DIFFERENCE = "bm:difference", "difference" - NEGATION = "bm:negation", "negation" - LIGHTEN = "bm:lighten", "lighten" - DARKEN = "bm:darken", "darken" - SCREEN = "bm:screen", "screen" - XOR = "bm:xor", "xor" - SOFTLIGHT = "bm:softlight", "softlight" - HARDLIGHT = "bm:hardlight", "hardlight" - GRAINEXTRACT = "bm:grainextract", "grainextract" - GRAINMERGE = "bm:grainmerge", "grainmerge" - DIVIDE = "bm:divide", "divide" - HUE = "bm:hue", "hue" - SATURATION = "bm:saturation", "saturation" - COLOUR = "bm:colour", "colour" - LUMINOSITY = "bm:luminosity", "luminosity" - PINLIGHT = "bm:pinlight", "pinlight" - VIVIDLIGHT = "bm:vividlight", "vividlight" - EXCLUSION = "bm:exclusion", "exclusion" - DESTIN = "bm:destin", "destin" - DESTOUT = "bm:destout", "destout" - SRCATOP = "bm:srcatop", "srcatop" - DESTATOP = "bm:destatop", "destatop" diff --git a/venv/Lib/site-packages/blendmodes/imagetools.py b/venv/Lib/site-packages/blendmodes/imagetools.py deleted file mode 100644 index 834b7c86..00000000 --- a/venv/Lib/site-packages/blendmodes/imagetools.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Do stuff to images to prepare them. -""" -from __future__ import annotations - -import warnings - -from deprecation import deprecated -from PIL import Image - - -@deprecated(deprecated_in="2021.1", removed_in="", details="use renderWAlphaOffset") -def rasterImageOA( # pylint:disable=missing-function-docstring - image: Image.Image, size: tuple[int, int], alpha: float = 1.0, offsets: tuple[int, int] = (0, 0) -) -> Image.Image: - warnings.warn( - "Call to deprecated function rasterImageOA.", category=DeprecationWarning, stacklevel=2 - ) - return renderWAlphaOffset(image, size, alpha, offsets) - - -@deprecated(deprecated_in="2021.1", removed_in="", details="use renderWAlphaOffset") -def rasterImageOffset( # pylint:disable=missing-function-docstring - image: Image.Image, size: tuple[int, int], offsets: tuple[int, int] = (0, 0) -) -> Image.Image: - warnings.warn( - "Call to deprecated function rasterImageOffset.", category=DeprecationWarning, stacklevel=2 - ) - return renderWAlphaOffset(image, size, 1, offsets) - - -def renderWAlphaOffset( - image: Image.Image, size: tuple[int, int], alpha: float = 1.0, offsets: tuple[int, int] = (0, 0) -) -> Image.Image: - """Render an image with offset and alpha to a given size. - - Args: - image (Image.Image): pil image to draw - size (tuple[int, int]): width, height as a tuple - alpha (float, optional): alpha transparency. Defaults to 1.0. - offsets (tuple[int, int], optional): x, y offsets as a tuple. - Defaults to (0, 0). - - Returns: - Image.Image: new image - """ - imageOffset = Image.new("RGBA", size) - imageOffset.paste(image.convert("RGBA"), offsets, image.convert("RGBA")) - return Image.blend(Image.new("RGBA", size), imageOffset, alpha) From 9bcf4165f89e6706a25ef0c32149d1fd3f4e102a Mon Sep 17 00:00:00 2001 From: ThereforeGames <95403634+ThereforeGames@users.noreply.github.com> Date: Sun, 11 Dec 2022 18:09:18 -0500 Subject: [PATCH 4/4] Update requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 678acb4d..85e51575 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +aenum +blendmodes accelerate basicsr fairscale==0.4.4