summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2022-01-17 12:58:40 (GMT)
committerGitHub <noreply@github.com>2022-01-17 12:58:40 (GMT)
commit42a64c03ec5c443f2a5c2ee4284622f5d1f5326c (patch)
treed5fffd97234c4a8481ee3f07a69107188f1faa7d /Lib
parent7f4b69b9076bdbcea31f6ad16eb125ee99cf0175 (diff)
downloadcpython-42a64c03ec5c443f2a5c2ee4284622f5d1f5326c.zip
cpython-42a64c03ec5c443f2a5c2ee4284622f5d1f5326c.tar.gz
cpython-42a64c03ec5c443f2a5c2ee4284622f5d1f5326c.tar.bz2
Revert "bpo-40066: [Enum] update str() and format() output (GH-30582)" (GH-30632)
This reverts commit acf7403f9baea3ae1119fc6b4a3298522188bf96.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/enum.py603
-rw-r--r--Lib/inspect.py30
-rw-r--r--Lib/plistlib.py3
-rw-r--r--Lib/re.py2
-rw-r--r--Lib/ssl.py1
-rw-r--r--Lib/test/test_enum.py2864
-rw-r--r--Lib/test/test_signal.py2
-rwxr-xr-xLib/test/test_socket.py12
-rw-r--r--Lib/test/test_ssl.py8
-rw-r--r--Lib/test/test_unicode.py6
10 files changed, 1764 insertions, 1767 deletions
diff --git a/Lib/enum.py b/Lib/enum.py
index 772e1ea..93ea1be 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -1,16 +1,16 @@
import sys
-import builtins as bltns
from types import MappingProxyType, DynamicClassAttribute
from operator import or_ as _or_
from functools import reduce
+from builtins import property as _bltin_property, bin as _bltin_bin
__all__ = [
'EnumType', 'EnumMeta',
- 'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag', 'ReprEnum',
+ 'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag',
'auto', 'unique', 'property', 'verify',
'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP',
- 'global_flag_repr', 'global_enum_repr', 'global_str', 'global_enum',
+ 'global_flag_repr', 'global_enum_repr', 'global_enum',
'EnumCheck', 'CONTINUOUS', 'NAMED_FLAGS', 'UNIQUE',
]
@@ -18,7 +18,7 @@ __all__ = [
# Dummy value for Enum and Flag as there are explicit checks for them
# before they have been created.
# This is also why there are checks in EnumType like `if Enum is not None`
-Enum = Flag = EJECT = _stdlib_enums = ReprEnum = None
+Enum = Flag = EJECT = None
def _is_descriptor(obj):
"""
@@ -116,9 +116,9 @@ def bin(num, max_bits=None):
ceiling = 2 ** (num).bit_length()
if num >= 0:
- s = bltns.bin(num + ceiling).replace('1', '0', 1)
+ s = _bltin_bin(num + ceiling).replace('1', '0', 1)
else:
- s = bltns.bin(~num ^ (ceiling - 1) + ceiling)
+ s = _bltin_bin(~num ^ (ceiling - 1) + ceiling)
sign = s[:3]
digits = s[3:]
if max_bits is not None:
@@ -126,19 +126,6 @@ def bin(num, max_bits=None):
digits = (sign[-1] * max_bits + digits)[-max_bits:]
return "%s %s" % (sign, digits)
-def _dedent(text):
- """
- Like textwrap.dedent. Rewritten because we cannot import textwrap.
- """
- lines = text.split('\n')
- blanks = 0
- for i, ch in enumerate(lines[0]):
- if ch != ' ':
- break
- for j, l in enumerate(lines):
- lines[j] = l[i:]
- return '\n'.join(lines)
-
_auto_null = object()
class auto:
@@ -162,12 +149,22 @@ class property(DynamicClassAttribute):
return ownerclass._member_map_[self.name]
except KeyError:
raise AttributeError(
- '%r has no attribute %r' % (ownerclass, self.name)
+ '%s: no class attribute %r' % (ownerclass.__name__, self.name)
)
else:
if self.fget is None:
+ # check for member
+ if self.name in ownerclass._member_map_:
+ import warnings
+ warnings.warn(
+ "accessing one member from another is not supported, "
+ " and will be disabled in 3.12",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return ownerclass._member_map_[self.name]
raise AttributeError(
- '%r member has no attribute %r' % (ownerclass, self.name)
+ '%s: no instance attribute %r' % (ownerclass.__name__, self.name)
)
else:
return self.fget(instance)
@@ -175,7 +172,7 @@ class property(DynamicClassAttribute):
def __set__(self, instance, value):
if self.fset is None:
raise AttributeError(
- "<enum %r> cannot set attribute %r" % (self.clsname, self.name)
+ "%s: cannot set instance attribute %r" % (self.clsname, self.name)
)
else:
return self.fset(instance, value)
@@ -183,7 +180,7 @@ class property(DynamicClassAttribute):
def __delete__(self, instance):
if self.fdel is None:
raise AttributeError(
- "<enum %r> cannot delete attribute %r" % (self.clsname, self.name)
+ "%s: cannot delete instance attribute %r" % (self.clsname, self.name)
)
else:
return self.fdel(instance)
@@ -331,7 +328,7 @@ class _EnumDict(dict):
elif _is_sunder(key):
if key not in (
'_order_',
- '_generate_next_value_', '_numeric_repr_', '_missing_', '_ignore_',
+ '_generate_next_value_', '_missing_', '_ignore_',
'_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_',
):
raise ValueError(
@@ -361,13 +358,13 @@ class _EnumDict(dict):
key = '_order_'
elif key in self._member_names:
# descriptor overwriting an enum?
- raise TypeError('%r already defined as %r' % (key, self[key]))
+ raise TypeError('%r already defined as: %r' % (key, self[key]))
elif key in self._ignore:
pass
elif not _is_descriptor(value):
if key in self:
# enum overwriting a descriptor?
- raise TypeError('%r already defined as %r' % (key, self[key]))
+ raise TypeError('%r already defined as: %r' % (key, self[key]))
if isinstance(value, auto):
if value.value == _auto_null:
value.value = self._generate_next_value(
@@ -398,7 +395,7 @@ class EnumType(type):
@classmethod
def __prepare__(metacls, cls, bases, **kwds):
# check that previous enum members do not exist
- metacls._check_for_existing_members_(cls, bases)
+ metacls._check_for_existing_members(cls, bases)
# create the namespace dict
enum_dict = _EnumDict()
enum_dict._cls_name = cls
@@ -416,10 +413,9 @@ class EnumType(type):
# inherited __new__ unless a new __new__ is defined (or the resulting
# class will fail).
#
+ # remove any keys listed in _ignore_
if _simple:
return super().__new__(metacls, cls, bases, classdict, **kwds)
- #
- # remove any keys listed in _ignore_
classdict.setdefault('_ignore_', []).append('_ignore_')
ignore = classdict['_ignore_']
for key in ignore:
@@ -431,8 +427,8 @@ class EnumType(type):
# check for illegal enum names (any others?)
invalid_names = set(member_names) & {'mro', ''}
if invalid_names:
- raise ValueError('invalid enum member name(s) '.format(
- ','.join(repr(n) for n in invalid_names)))
+ raise ValueError('Invalid enum member name: {0}'.format(
+ ','.join(invalid_names)))
#
# adjust the sunders
_order_ = classdict.pop('_order_', None)
@@ -462,8 +458,6 @@ class EnumType(type):
classdict['_value2member_map_'] = {}
classdict['_unhashable_values_'] = []
classdict['_member_type_'] = member_type
- # now set the __repr__ for the value
- classdict['_value_repr_'] = metacls._find_data_repr_(cls, bases)
#
# Flag structures (will be removed if final class is not a Flag
classdict['_boundary_'] = (
@@ -473,6 +467,10 @@ class EnumType(type):
classdict['_flag_mask_'] = flag_mask
classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1
classdict['_inverted_'] = None
+ #
+ # create a default docstring if one has not been provided
+ if '__doc__' not in classdict:
+ classdict['__doc__'] = 'An enumeration.'
try:
exc = None
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
@@ -483,140 +481,18 @@ class EnumType(type):
if exc is not None:
raise exc
#
- # update classdict with any changes made by __init_subclass__
- classdict.update(enum_class.__dict__)
- #
- # create a default docstring if one has not been provided
- if enum_class.__doc__ is None:
- if not member_names:
- enum_class.__doc__ = classdict['__doc__'] = _dedent("""\
- Create a collection of name/value pairs.
-
- Example enumeration:
-
- >>> class Color(Enum):
- ... RED = 1
- ... BLUE = 2
- ... GREEN = 3
-
- Access them by:
-
- - attribute access::
-
- >>> Color.RED
- <Color.RED: 1>
-
- - value lookup:
-
- >>> Color(1)
- <Color.RED: 1>
-
- - name lookup:
-
- >>> Color['RED']
- <Color.RED: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Color)
- 3
-
- >>> list(Color)
- [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """)
- else:
- member = list(enum_class)[0]
- enum_length = len(enum_class)
- cls_name = enum_class.__name__
- if enum_length == 1:
- list_line = 'list(%s)' % cls_name
- list_repr = '[<%s.%s: %r>]' % (cls_name, member.name, member.value)
- elif enum_length == 2:
- member2 = list(enum_class)[1]
- list_line = 'list(%s)' % cls_name
- list_repr = '[<%s.%s: %r>, <%s.%s: %r>]' % (
- cls_name, member.name, member.value,
- cls_name, member2.name, member2.value,
- )
- else:
- member2 = list(enum_class)[1]
- member3 = list(enum_class)[2]
- list_line = 'list(%s)%s' % (cls_name, ('','[:3]')[enum_length > 3])
- list_repr = '[<%s.%s: %r>, <%s.%s: %r>, <%s.%s: %r>]' % (
- cls_name, member.name, member.value,
- cls_name, member2.name, member2.value,
- cls_name, member3.name, member3.value,
- )
- enum_class.__doc__ = classdict['__doc__'] = _dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> %s.%s
- <%s.%s: %r>
-
- - value lookup:
-
- >>> %s(%r)
- <%s.%s: %r>
-
- - name lookup:
-
- >>> %s[%r]
- <%s.%s: %r>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(%s)
- %r
-
- >>> %s
- %s
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """
- % (cls_name, member.name,
- cls_name, member.name, member.value,
- cls_name, member.value,
- cls_name, member.name, member.value,
- cls_name, member.name,
- cls_name, member.name, member.value,
- cls_name, enum_length,
- list_line, list_repr,
- ))
- #
# double check that repr and friends are not the mixin's or various
# things break (such as pickle)
# however, if the method is defined in the Enum itself, don't replace
# it
- #
- # 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 classdict:
- enum_class.__format__ = member_type.__format__
- classdict['__format__'] = enum_class.__format__
- if '__str__' not in classdict:
- 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
- classdict['__str__'] = enum_class.__str__
for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
- if name not in classdict:
- setattr(enum_class, name, getattr(first_enum, name))
+ if name in classdict:
+ 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 is class_method:
+ setattr(enum_class, name, enum_method)
#
# replace any other __new__ with our own (as long as Enum is not None,
# anyway) -- again, this is to support pickle
@@ -687,13 +563,13 @@ class EnumType(type):
# _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'
+ 'member order does not match _order_:\n%r\n%r'
% (enum_class._member_names_, _order_)
)
#
return enum_class
- def __bool__(cls):
+ def __bool__(self):
"""
classes/types should always be True.
"""
@@ -738,13 +614,6 @@ class EnumType(type):
)
def __contains__(cls, member):
- """
- Return True if member is a member of this enum
- raises TypeError if member is not an enum member
-
- note: in 3.12 TypeError will no longer be raised, and True will also be
- returned if member is the value of a member in this enum
- """
if not isinstance(member, Enum):
import warnings
warnings.warn(
@@ -762,33 +631,60 @@ class EnumType(type):
# nicer error message when someone tries to delete an attribute
# (see issue19025).
if attr in cls._member_map_:
- raise AttributeError("%r cannot delete member %r." % (cls.__name__, attr))
+ raise AttributeError("%s: cannot delete Enum member %r." % (cls.__name__, attr))
super().__delattr__(attr)
- def __dir__(cls):
- # TODO: check for custom __init__, __new__, __format__, __repr__, __str__, __init_subclass__
- # on object-based enums
- if cls._member_type_ is object:
- interesting = set(cls._member_names_)
- if cls._new_member_ is not object.__new__:
- interesting.add('__new__')
- if cls.__init_subclass__ is not object.__init_subclass__:
- interesting.add('__init_subclass__')
- for method in ('__init__', '__format__', '__repr__', '__str__'):
- if getattr(cls, method) not in (getattr(Enum, method), getattr(Flag, method)):
- interesting.add(method)
- return sorted(set([
- '__class__', '__contains__', '__doc__', '__getitem__',
- '__iter__', '__len__', '__members__', '__module__',
- '__name__', '__qualname__',
- ]) | interesting
- )
- else:
- # return whatever mixed-in data type has
- return sorted(set(
- dir(cls._member_type_)
- + cls._member_names_
- ))
+ def __dir__(self):
+ # Start off with the desired result for dir(Enum)
+ cls_dir = {'__class__', '__doc__', '__members__', '__module__'}
+ add_to_dir = cls_dir.add
+ mro = self.__mro__
+ this_module = globals().values()
+ is_from_this_module = lambda cls: any(cls is thing for thing in this_module)
+ first_enum_base = next(cls for cls in mro if is_from_this_module(cls))
+ enum_dict = Enum.__dict__
+ sentinel = object()
+ # special-case __new__
+ ignored = {'__new__', *filter(_is_sunder, enum_dict)}
+ add_to_ignored = ignored.add
+
+ # We want these added to __dir__
+ # if and only if they have been user-overridden
+ enum_dunders = set(filter(_is_dunder, enum_dict))
+
+ for cls in mro:
+ # Ignore any classes defined in this module
+ if cls is object or is_from_this_module(cls):
+ continue
+
+ cls_lookup = cls.__dict__
+
+ # If not an instance of EnumType,
+ # ensure all attributes excluded from that class's `dir()` are ignored here.
+ if not isinstance(cls, EnumType):
+ cls_lookup = set(cls_lookup).intersection(dir(cls))
+
+ for attr_name in cls_lookup:
+ # Already seen it? Carry on
+ if attr_name in cls_dir or attr_name in ignored:
+ continue
+ # Sunders defined in Enum.__dict__ are already in `ignored`,
+ # But sunders defined in a subclass won't be (we want all sunders excluded).
+ elif _is_sunder(attr_name):
+ add_to_ignored(attr_name)
+ # Not an "enum dunder"? Add it to dir() output.
+ elif attr_name not in enum_dunders:
+ add_to_dir(attr_name)
+ # Is an "enum dunder", and is defined by a class from enum.py? Ignore it.
+ elif getattr(self, attr_name) is getattr(first_enum_base, attr_name, sentinel):
+ add_to_ignored(attr_name)
+ # Is an "enum dunder", and is either user-defined or defined by a mixin class?
+ # Add it to dir() output.
+ else:
+ add_to_dir(attr_name)
+
+ # sort the output before returning it, so that the result is deterministic.
+ return sorted(cls_dir)
def __getattr__(cls, name):
"""
@@ -807,24 +703,18 @@ class EnumType(type):
raise AttributeError(name) from None
def __getitem__(cls, name):
- """
- Return the member matching `name`.
- """
return cls._member_map_[name]
def __iter__(cls):
"""
- Return members in definition order.
+ Returns members in definition order.
"""
return (cls._member_map_[name] for name in cls._member_names_)
def __len__(cls):
- """
- Return the number of members (no aliases)
- """
return len(cls._member_names_)
- @bltns.property
+ @_bltin_property
def __members__(cls):
"""
Returns a mapping of member name->value.
@@ -842,7 +732,7 @@ class EnumType(type):
def __reversed__(cls):
"""
- Return members in reverse definition order.
+ Returns members in reverse definition order.
"""
return (cls._member_map_[name] for name in reversed(cls._member_names_))
@@ -856,7 +746,7 @@ class EnumType(type):
"""
member_map = cls.__dict__.get('_member_map_', {})
if name in member_map:
- raise AttributeError('cannot reassign member %r' % (name, ))
+ raise AttributeError('Cannot reassign member %r.' % (name, ))
super().__setattr__(name, value)
def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1, boundary=None):
@@ -911,7 +801,8 @@ class EnumType(type):
return metacls.__new__(metacls, class_name, bases, classdict, boundary=boundary)
- def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_global=False):
+ def _convert_(cls, name, module, filter, source=None, *, boundary=None):
+
"""
Create a new Enum subclass that replaces a collection of global constants
"""
@@ -943,25 +834,22 @@ class EnumType(type):
tmp_cls = type(name, (object, ), body)
cls = _simple_enum(etype=cls, boundary=boundary or KEEP)(tmp_cls)
cls.__reduce_ex__ = _reduce_ex_by_global_name
- if as_global:
- global_enum(cls)
- else:
- sys.modules[cls.__module__].__dict__.update(cls.__members__)
+ global_enum(cls)
module_globals[name] = cls
return cls
- @classmethod
- def _check_for_existing_members_(mcls, class_name, bases):
+ @staticmethod
+ def _check_for_existing_members(class_name, bases):
for chain in bases:
for base in chain.__mro__:
if issubclass(base, Enum) and base._member_names_:
raise TypeError(
- "<enum %r> cannot extend %r"
- % (class_name, base)
+ "%s: cannot extend enumeration %r"
+ % (class_name, base.__name__)
)
@classmethod
- def _get_mixins_(mcls, class_name, bases):
+ def _get_mixins_(cls, class_name, bases):
"""
Returns the type for creating enum members, and the first inherited
enum class.
@@ -971,7 +859,30 @@ class EnumType(type):
if not bases:
return object, Enum
- mcls._check_for_existing_members_(class_name, bases)
+ def _find_data_type(bases):
+ data_types = set()
+ for chain in bases:
+ candidate = None
+ for base in chain.__mro__:
+ if base is object:
+ continue
+ elif issubclass(base, Enum):
+ if base._member_type_ is not object:
+ data_types.add(base._member_type_)
+ break
+ elif '__new__' in base.__dict__:
+ if issubclass(base, Enum):
+ 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
# ensure final parent class is an Enum derivative, find any concrete
# data type, and check that Enum has no members
@@ -979,51 +890,12 @@ class EnumType(type):
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
+ cls._check_for_existing_members(class_name, bases)
+ member_type = _find_data_type(bases) or object
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:
- continue
- elif issubclass(base, Enum):
- if base._member_type_ is not object:
- data_types.add(base._member_type_)
- break
- elif '__new__' in base.__dict__:
- if issubclass(base, Enum):
- continue
- data_types.add(candidate or base)
- break
- else:
- candidate = candidate or base
- if len(data_types) > 1:
- raise TypeError('too many data types for %r: %r' % (class_name, data_types))
- elif data_types:
- return data_types.pop()
- else:
- return None
-
- @classmethod
- def _find_new_(mcls, classdict, member_type, first_enum):
+ @staticmethod
+ def _find_new_(classdict, member_type, first_enum):
"""
Returns the __new__ to be used for creating the enum members.
@@ -1071,42 +943,9 @@ EnumMeta = EnumType
class Enum(metaclass=EnumType):
"""
- Create a collection of name/value pairs.
-
- Example enumeration:
-
- >>> class Color(Enum):
- ... RED = 1
- ... BLUE = 2
- ... GREEN = 3
-
- Access them by:
-
- - attribute access::
-
- >>> Color.RED
- <Color.RED: 1>
-
- - value lookup:
-
- >>> Color(1)
- <Color.RED: 1>
+ Generic enumeration.
- - name lookup:
-
- >>> Color['RED']
- <Color.RED: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Color)
- 3
-
- >>> list(Color)
- [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
+ Derive from this class to define new enumerations.
"""
def __new__(cls, value):
@@ -1160,9 +999,6 @@ class Enum(metaclass=EnumType):
exc = None
ve_exc = None
- def __init__(self, *args, **kwds):
- pass
-
def _generate_next_value_(name, start, count, last_values):
"""
Generate the next value when not given.
@@ -1185,44 +1021,47 @@ class Enum(metaclass=EnumType):
return None
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_))
+ return "%s.%s" % ( self.__class__.__name__, self._name_)
def __str__(self):
- return "%s.%s" % (self.__class__.__name__, self._name_, )
+ return "%s" % (self._name_, )
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)
- names = sorted(
- set(['__class__', '__doc__', '__eq__', '__hash__', '__module__'])
- | interesting
- )
- return names
+ cls = type(self)
+ to_exclude = {'__members__', '__init__', '__new__', *cls._member_names_}
+ filtered_self_dict = (name for name in self.__dict__ if not name.startswith('_'))
+ return sorted({'name', 'value', *dir(cls), *filtered_self_dict} - to_exclude)
def __format__(self, format_spec):
- return str.__format__(str(self), format_spec)
+ """
+ Returns format using actual value type unless __str__ has been overridden.
+ """
+ # 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, or branch with __str__ explicitly overridden
+ str_overridden = type(self).__str__ not in (Enum.__str__, IntEnum.__str__, Flag.__str__)
+ if self._member_type_ is object or str_overridden:
+ cls = str
+ val = str(self)
+ # mix-in branch
+ else:
+ if not format_spec or format_spec in ('{}','{:}'):
+ import warnings
+ warnings.warn(
+ "in 3.12 format() will use the enum member, not the enum member's value;\n"
+ "use a format specifier, such as :d for an integer-based Enum, to maintain "
+ "the current display",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ cls = self._member_type_
+ val = self._value_
+ return cls.__format__(val, format_spec)
def __hash__(self):
return hash(self._name_)
@@ -1249,25 +1088,34 @@ class Enum(metaclass=EnumType):
return self._value_
-class ReprEnum(Enum):
+class IntEnum(int, Enum):
"""
- Only changes the repr(), leaving str() and format() to the mixed-in type.
+ Enum where members are also (and must be) ints
"""
+ def __str__(self):
+ return "%s" % (self._name_, )
-class IntEnum(int, ReprEnum):
- """
- Enum where members are also (and must be) ints
- """
+ def __format__(self, format_spec):
+ """
+ Returns format using actual value unless __str__ has been overridden.
+ """
+ str_overridden = type(self).__str__ != IntEnum.__str__
+ if str_overridden:
+ cls = str
+ val = str(self)
+ else:
+ cls = self._member_type_
+ val = self._value_
+ return cls.__format__(val, format_spec)
-class StrEnum(str, ReprEnum):
+class StrEnum(str, Enum):
"""
Enum where members are also (and must be) strings
"""
def __new__(cls, *values):
- "values must already be of type `str`"
if len(values) > 3:
raise TypeError('too many arguments for str(): %r' % (values, ))
if len(values) == 1:
@@ -1287,6 +1135,10 @@ class StrEnum(str, ReprEnum):
member._value_ = value
return member
+ __str__ = str.__str__
+
+ __format__ = str.__format__
+
def _generate_next_value_(name, start, count, last_values):
"""
Return the lower-cased version of the member name.
@@ -1317,8 +1169,6 @@ class Flag(Enum, boundary=STRICT):
Support for flags
"""
- _numeric_repr_ = repr
-
def _generate_next_value_(name, start, count, last_values):
"""
Generate the next value when not given.
@@ -1334,7 +1184,7 @@ class Flag(Enum, boundary=STRICT):
try:
high_bit = _high_bit(last_value)
except Exception:
- raise TypeError('invalid flag value %r' % last_value) from None
+ raise TypeError('Invalid Flag value: %r' % last_value) from None
return 2 ** (high_bit+1)
@classmethod
@@ -1382,8 +1232,8 @@ class Flag(Enum, boundary=STRICT):
if cls._boundary_ is STRICT:
max_bits = max(value.bit_length(), flag_mask.bit_length())
raise ValueError(
- "%r invalid value %r\n given %s\n allowed %s" % (
- cls, value, bin(value, max_bits), bin(flag_mask, max_bits),
+ "%s: invalid value: %r\n given %s\n allowed %s" % (
+ cls.__name__, value, bin(value, max_bits), bin(flag_mask, max_bits),
))
elif cls._boundary_ is CONFORM:
value = value & flag_mask
@@ -1397,7 +1247,7 @@ class Flag(Enum, boundary=STRICT):
)
else:
raise ValueError(
- '%r unknown flag boundary %r' % (cls, cls._boundary_, )
+ 'unknown flag boundary: %r' % (cls._boundary_, )
)
if value < 0:
neg_value = value
@@ -1424,7 +1274,7 @@ class Flag(Enum, boundary=STRICT):
m._name_ for m in cls._iter_member_(member_value)
])
if unknown:
- pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown)
+ pseudo_member._name_ += '|0x%x' % unknown
else:
pseudo_member._name_ = None
# use setdefault in case another thread already created a composite
@@ -1442,8 +1292,10 @@ class Flag(Enum, boundary=STRICT):
"""
if not isinstance(other, self.__class__):
raise TypeError(
- "unsupported operand type(s) for 'in': %r and %r" % (
+ "unsupported operand type(s) for 'in': '%s' and '%s'" % (
type(other).__qualname__, self.__class__.__qualname__))
+ if other._value_ == 0 or self._value_ == 0:
+ return False
return other._value_ & self._value_ == other._value_
def __iter__(self):
@@ -1457,18 +1309,27 @@ class Flag(Enum, boundary=STRICT):
def __repr__(self):
cls_name = self.__class__.__name__
- v_repr = self.__class__._value_repr_ or self._value_.__class__.__repr__
if self._name_ is None:
- return "<%s: %s>" % (cls_name, v_repr(self._value_))
+ return "0x%x" % (self._value_, )
+ if _is_single_bit(self._value_):
+ return '%s.%s' % (cls_name, self._name_)
+ if self._boundary_ is not FlagBoundary.KEEP:
+ return '%s.' % cls_name + ('|%s.' % cls_name).join(self.name.split('|'))
else:
- return "<%s.%s: %s>" % (cls_name, self._name_, v_repr(self._value_))
+ name = []
+ for n in self._name_.split('|'):
+ if n.startswith('0'):
+ name.append(n)
+ else:
+ name.append('%s.%s' % (cls_name, n))
+ return '|'.join(name)
def __str__(self):
- cls_name = self.__class__.__name__
+ cls = self.__class__
if self._name_ is None:
- return '%s(%r)' % (cls_name, self._value_)
+ return '%s(%x)' % (cls.__name__, self._value_)
else:
- return "%s.%s" % (cls_name, self._name_)
+ return self._name_
def __bool__(self):
return bool(self._value_)
@@ -1501,11 +1362,20 @@ class Flag(Enum, boundary=STRICT):
return self._inverted_
-class IntFlag(int, ReprEnum, Flag, boundary=EJECT):
+class IntFlag(int, Flag, boundary=EJECT):
"""
Support for integer-based Flags
"""
+ def __format__(self, format_spec):
+ """
+ Returns format using actual value unless __str__ has been overridden.
+ """
+ str_overridden = type(self).__str__ != Flag.__str__
+ value = self
+ if not str_overridden:
+ value = self._value_
+ return int.__format__(value, format_spec)
def __or__(self, other):
if isinstance(other, self.__class__):
@@ -1542,7 +1412,6 @@ class IntFlag(int, ReprEnum, Flag, boundary=EJECT):
__rxor__ = __xor__
__invert__ = Flag.__invert__
-
def _high_bit(value):
"""
returns index of highest bit, or -1 if value is zero or negative
@@ -1587,7 +1456,7 @@ def global_flag_repr(self):
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_)
+ return "%s.%s(0x%x)" % (module, cls_name, self._value_)
if _is_single_bit(self):
return '%s.%s' % (module, self._name_)
if self._boundary_ is not FlagBoundary.KEEP:
@@ -1595,22 +1464,14 @@ def global_flag_repr(self):
else:
name = []
for n in self._name_.split('|'):
- if n[0].isdigit():
+ if n.startswith('0'):
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):
+def global_enum(cls):
"""
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
@@ -1620,8 +1481,6 @@ def global_enum(cls, update_str=False):
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
@@ -1663,7 +1522,6 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
body['_value2member_map_'] = value2member_map = {}
body['_unhashable_values_'] = []
body['_member_type_'] = member_type = etype._member_type_
- body['_value_repr_'] = etype._value_repr_
if issubclass(etype, Flag):
body['_boundary_'] = boundary or etype._boundary_
body['_flag_mask_'] = None
@@ -1685,8 +1543,13 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
# it
enum_class = type(cls_name, (etype, ), body, boundary=boundary, _simple=True)
for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
- if name not in body:
- setattr(enum_class, name, getattr(etype, name))
+ if name in body:
+ continue
+ class_method = getattr(enum_class, name)
+ obj_method = getattr(member_type, name, None)
+ enum_method = getattr(etype, name, None)
+ if obj_method is not None and obj_method is class_method:
+ setattr(enum_class, name, enum_method)
gnv_last_values = []
if issubclass(enum_class, Flag):
# Flag / IntFlag
@@ -1897,8 +1760,8 @@ def _test_simple_enum(checked_enum, simple_enum):
+ list(simple_enum._member_map_.keys())
)
for key in set(checked_keys + simple_keys):
- if key in ('__module__', '_member_map_', '_value2member_map_', '__doc__'):
- # keys known to be different, or very long
+ if key in ('__module__', '_member_map_', '_value2member_map_'):
+ # keys known to be different
continue
elif key in member_names:
# members are checked below
@@ -2019,5 +1882,3 @@ def _old_convert_(etype, name, module, filter, source=None, *, boundary=None):
cls.__reduce_ex__ = _reduce_ex_by_global_name
cls.__repr__ = global_enum_repr
return cls
-
-_stdlib_enums = IntEnum, StrEnum, IntFlag
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 8236698..5d33f0d 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -2567,21 +2567,15 @@ class _empty:
class _ParameterKind(enum.IntEnum):
- POSITIONAL_ONLY = 'positional-only'
- POSITIONAL_OR_KEYWORD = 'positional or keyword'
- VAR_POSITIONAL = 'variadic positional'
- KEYWORD_ONLY = 'keyword-only'
- VAR_KEYWORD = 'variadic keyword'
-
- def __new__(cls, description):
- value = len(cls.__members__)
- member = int.__new__(cls, value)
- member._value_ = value
- member.description = description
- return member
+ POSITIONAL_ONLY = 0
+ POSITIONAL_OR_KEYWORD = 1
+ VAR_POSITIONAL = 2
+ KEYWORD_ONLY = 3
+ VAR_KEYWORD = 4
- def __str__(self):
- return self.name
+ @property
+ def description(self):
+ return _PARAM_NAME_MAPPING[self]
_POSITIONAL_ONLY = _ParameterKind.POSITIONAL_ONLY
_POSITIONAL_OR_KEYWORD = _ParameterKind.POSITIONAL_OR_KEYWORD
@@ -2589,6 +2583,14 @@ _VAR_POSITIONAL = _ParameterKind.VAR_POSITIONAL
_KEYWORD_ONLY = _ParameterKind.KEYWORD_ONLY
_VAR_KEYWORD = _ParameterKind.VAR_KEYWORD
+_PARAM_NAME_MAPPING = {
+ _POSITIONAL_ONLY: 'positional-only',
+ _POSITIONAL_OR_KEYWORD: 'positional or keyword',
+ _VAR_POSITIONAL: 'variadic positional',
+ _KEYWORD_ONLY: 'keyword-only',
+ _VAR_KEYWORD: 'variadic keyword'
+}
+
class Parameter:
"""Represents a parameter in a function signature.
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
index 4862355..3ab71ed 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -61,8 +61,7 @@ import struct
from xml.parsers.expat import ParserCreate
-PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
-globals().update(PlistFormat.__members__)
+PlistFormat = enum.global_enum(enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__))
class UID:
diff --git a/Lib/re.py b/Lib/re.py
index a7ab9b3..ea41217 100644
--- a/Lib/re.py
+++ b/Lib/re.py
@@ -155,8 +155,6 @@ class RegexFlag:
# sre extensions (experimental, don't rely on these)
TEMPLATE = T = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking
DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation
- __str__ = object.__str__
- _numeric_repr_ = hex
# sre exception
error = sre_compile.error
diff --git a/Lib/ssl.py b/Lib/ssl.py
index dafb70a..2079251 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -119,6 +119,7 @@ from _ssl import (
)
from _ssl import _DEFAULT_CIPHERS, _OPENSSL_API_VERSION
+
_IntEnum._convert_(
'_SSLMethod', __name__,
lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index a0953fb..43f98c1 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -6,18 +6,15 @@ import pydoc
import sys
import unittest
import threading
-import builtins as bltns
from collections import OrderedDict
-from datetime import date
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
-from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
+from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS
from io import StringIO
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
from test import support
from test.support import ALWAYS_EQ
from test.support import threading_helper
-from textwrap import dedent
from datetime import timedelta
python_version = sys.version_info[:2]
@@ -110,12 +107,6 @@ def test_pickle_exception(assertion, exception, obj):
class TestHelpers(unittest.TestCase):
# _is_descriptor, _is_sunder, _is_dunder
- sunder_names = '_bad_', '_good_', '_what_ho_'
- dunder_names = '__mal__', '__bien__', '__que_que__'
- private_names = '_MyEnum__private', '_MyEnum__still_private'
- private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
- random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
-
def test_is_descriptor(self):
class foo:
pass
@@ -125,36 +116,21 @@ class TestHelpers(unittest.TestCase):
setattr(obj, attr, 1)
self.assertTrue(enum._is_descriptor(obj))
- def test_sunder(self):
- for name in self.sunder_names + self.private_and_sunder_names:
- self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
- for name in self.dunder_names + self.private_names + self.random_names:
- self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
+ def test_is_sunder(self):
for s in ('_a_', '_aa_'):
self.assertTrue(enum._is_sunder(s))
+
for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
'__', '___', '____', '_____',):
self.assertFalse(enum._is_sunder(s))
- def test_dunder(self):
- for name in self.dunder_names:
- self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
- for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
- self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
+ def test_is_dunder(self):
for s in ('__a__', '__aa__'):
self.assertTrue(enum._is_dunder(s))
for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
'__', '___', '____', '_____',):
self.assertFalse(enum._is_dunder(s))
-
- def test_is_private(self):
- for name in self.private_names + self.private_and_sunder_names:
- self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
- for name in self.sunder_names + self.dunder_names + self.random_names:
- self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
-
-
# for subclassing tests
class classproperty:
@@ -190,658 +166,473 @@ class HeadlightsC(IntFlag, boundary=enum.CONFORM):
# tests
-class _EnumTests:
- """
- Test for behavior that is the same across the different types of enumerations.
- """
-
- values = None
+class TestEnum(unittest.TestCase):
def setUp(self):
- class BaseEnum(self.enum_type):
- @enum.property
- def first(self):
- return '%s is first!' % self.name
- class MainEnum(BaseEnum):
- first = auto()
- second = auto()
- third = auto()
- if issubclass(self.enum_type, Flag):
- dupe = 3
- else:
- dupe = third
- self.MainEnum = MainEnum
- #
- class NewStrEnum(self.enum_type):
- def __str__(self):
- return self.name.upper()
- first = auto()
- self.NewStrEnum = NewStrEnum
- #
- class NewFormatEnum(self.enum_type):
- def __format__(self, spec):
- return self.name.upper()
- first = auto()
- self.NewFormatEnum = NewFormatEnum
- #
- class NewStrFormatEnum(self.enum_type):
- def __str__(self):
- return self.name.title()
- def __format__(self, spec):
- return ''.join(reversed(self.name))
- first = auto()
- self.NewStrFormatEnum = NewStrFormatEnum
- #
- class NewBaseEnum(self.enum_type):
- def __str__(self):
- return self.name.title()
- def __format__(self, spec):
- return ''.join(reversed(self.name))
- class NewSubEnum(NewBaseEnum):
- first = auto()
- self.NewSubEnum = NewSubEnum
- #
- self.is_flag = False
- self.names = ['first', 'second', 'third']
- if issubclass(MainEnum, StrEnum):
- self.values = self.names
- elif MainEnum._member_type_ is str:
- self.values = ['1', '2', '3']
- elif issubclass(self.enum_type, Flag):
- self.values = [1, 2, 4]
- self.is_flag = True
- self.dupe2 = MainEnum(5)
- else:
- self.values = self.values or [1, 2, 3]
- #
- if not getattr(self, 'source_values', False):
- self.source_values = self.values
-
- def assertFormatIsValue(self, spec, member):
- self.assertEqual(spec.format(member), spec.format(member.value))
-
- def assertFormatIsStr(self, spec, member):
- self.assertEqual(spec.format(member), spec.format(str(member)))
-
- def test_attribute_deletion(self):
- class Season(self.enum_type):
- SPRING = auto()
- SUMMER = auto()
- AUTUMN = auto()
- #
- def spam(cls):
- pass
- #
- self.assertTrue(hasattr(Season, 'spam'))
- del Season.spam
- self.assertFalse(hasattr(Season, 'spam'))
- #
- with self.assertRaises(AttributeError):
- del Season.SPRING
- with self.assertRaises(AttributeError):
- del Season.DRY
- with self.assertRaises(AttributeError):
- del Season.SPRING.name
-
- def test_basics(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(repr(TE), "<flag 'MainEnum'>")
- self.assertEqual(str(TE), "<flag 'MainEnum'>")
- self.assertEqual(format(TE), "<flag 'MainEnum'>")
- self.assertTrue(TE(5) is self.dupe2)
- else:
- self.assertEqual(repr(TE), "<enum 'MainEnum'>")
- self.assertEqual(str(TE), "<enum 'MainEnum'>")
- self.assertEqual(format(TE), "<enum 'MainEnum'>")
- self.assertEqual(list(TE), [TE.first, TE.second, TE.third])
- self.assertEqual(
- [m.name for m in TE],
- self.names,
- )
- self.assertEqual(
- [m.value for m in TE],
- self.values,
- )
- self.assertEqual(
- [m.first for m in TE],
- ['first is first!', 'second is first!', 'third is first!']
- )
- for member, name in zip(TE, self.names, strict=True):
- self.assertIs(TE[name], member)
- for member, value in zip(TE, self.values, strict=True):
- self.assertIs(TE(value), member)
- if issubclass(TE, StrEnum):
- self.assertTrue(TE.dupe is TE('third') is TE['dupe'])
- elif TE._member_type_ is str:
- self.assertTrue(TE.dupe is TE('3') is TE['dupe'])
- elif issubclass(TE, Flag):
- self.assertTrue(TE.dupe is TE(3) is TE['dupe'])
- else:
- self.assertTrue(TE.dupe is TE(self.values[2]) is TE['dupe'])
+ class Season(Enum):
+ SPRING = 1
+ SUMMER = 2
+ AUTUMN = 3
+ WINTER = 4
+ self.Season = Season
- def test_bool_is_true(self):
- class Empty(self.enum_type):
- pass
- self.assertTrue(Empty)
- #
- self.assertTrue(self.MainEnum)
- for member in self.MainEnum:
- self.assertTrue(member)
+ class Konstants(float, Enum):
+ E = 2.7182818
+ PI = 3.1415926
+ TAU = 2 * PI
+ self.Konstants = Konstants
- def test_changing_member_fails(self):
- MainEnum = self.MainEnum
- with self.assertRaises(AttributeError):
- self.MainEnum.second = 'really first'
+ class Grades(IntEnum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ self.Grades = Grades
- @unittest.skipIf(
- python_version >= (3, 12),
- '__contains__ now returns True/False for all inputs',
- )
- def test_contains_er(self):
- MainEnum = self.MainEnum
- self.assertIn(MainEnum.third, MainEnum)
- with self.assertRaises(TypeError):
- with self.assertWarns(DeprecationWarning):
- self.source_values[1] in MainEnum
- with self.assertRaises(TypeError):
- with self.assertWarns(DeprecationWarning):
- 'first' in MainEnum
- val = MainEnum.dupe
- self.assertIn(val, MainEnum)
- #
- class OtherEnum(Enum):
- one = auto()
- two = auto()
- self.assertNotIn(OtherEnum.two, MainEnum)
+ class Directional(str, Enum):
+ EAST = 'east'
+ WEST = 'west'
+ NORTH = 'north'
+ SOUTH = 'south'
+ self.Directional = Directional
- @unittest.skipIf(
- python_version < (3, 12),
- '__contains__ works only with enum memmbers before 3.12',
- )
- def test_contains_tf(self):
- MainEnum = self.MainEnum
- self.assertIn(MainEnum.first, MainEnum)
- self.assertTrue(self.source_values[0] in MainEnum)
- self.assertFalse('first' in MainEnum)
- val = MainEnum.dupe
- self.assertIn(val, MainEnum)
- #
- class OtherEnum(Enum):
- one = auto()
- two = auto()
- self.assertNotIn(OtherEnum.two, MainEnum)
+ from datetime import date
+ class Holiday(date, Enum):
+ NEW_YEAR = 2013, 1, 1
+ IDES_OF_MARCH = 2013, 3, 15
+ self.Holiday = Holiday
- def test_dir_on_class(self):
- TE = self.MainEnum
- self.assertEqual(set(dir(TE)), set(enum_dir(TE)))
+ class DateEnum(date, Enum): pass
+ self.DateEnum = DateEnum
- def test_dir_on_item(self):
- TE = self.MainEnum
- self.assertEqual(set(dir(TE.first)), set(member_dir(TE.first)))
+ class FloatEnum(float, Enum): pass
+ self.FloatEnum = FloatEnum
- def test_dir_with_added_behavior(self):
- class Test(self.enum_type):
- this = auto()
- these = auto()
+ class Wowser(Enum):
+ this = 'that'
+ these = 'those'
def wowser(self):
+ """Wowser docstring"""
return ("Wowser! I'm %s!" % self.name)
- self.assertTrue('wowser' not in dir(Test))
- self.assertTrue('wowser' in dir(Test.this))
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.Wowser = Wowser
+
+ class IntWowser(IntEnum):
+ this = 1
+ these = 2
+ def wowser(self):
+ """Wowser docstring"""
+ return ("Wowser! I'm %s!" % self.name)
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.IntWowser = IntWowser
+
+ class FloatWowser(float, Enum):
+ this = 3.14
+ these = 4.2
+ def wowser(self):
+ """Wowser docstring"""
+ return ("Wowser! I'm %s!" % self.name)
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.FloatWowser = FloatWowser
+
+ class WowserNoMembers(Enum):
+ def wowser(self): pass
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ class SubclassOfWowserNoMembers(WowserNoMembers): pass
+ self.WowserNoMembers = WowserNoMembers
+ self.SubclassOfWowserNoMembers = SubclassOfWowserNoMembers
+
+ class IntWowserNoMembers(IntEnum):
+ def wowser(self): pass
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.IntWowserNoMembers = IntWowserNoMembers
+
+ class FloatWowserNoMembers(float, Enum):
+ def wowser(self): pass
+ @classmethod
+ def classmethod_wowser(cls): pass
+ @staticmethod
+ def staticmethod_wowser(): pass
+ self.FloatWowserNoMembers = FloatWowserNoMembers
+
+ class EnumWithInit(Enum):
+ def __init__(self, greeting, farewell):
+ self.greeting = greeting
+ self.farewell = farewell
+ ENGLISH = 'hello', 'goodbye'
+ GERMAN = 'Guten Morgen', 'Auf Wiedersehen'
+ def some_method(self): pass
+ self.EnumWithInit = EnumWithInit
- def test_dir_on_sub_with_behavior_on_super(self):
# see issue22506
- class SuperEnum(self.enum_type):
+ class SuperEnum1(Enum):
def invisible(self):
return "did you see me?"
- class SubEnum(SuperEnum):
- sample = auto()
- self.assertTrue('invisible' not in dir(SubEnum))
- self.assertTrue('invisible' in dir(SubEnum.sample))
+ class SubEnum1(SuperEnum1):
+ sample = 5
+ self.SubEnum1 = SubEnum1
- def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
- # see issue40084
- class SuperEnum(self.enum_type):
- def __new__(cls, *value, **kwds):
- new = self.enum_type._member_type_.__new__
- if self.enum_type._member_type_ is object:
- obj = new(cls)
- else:
- if isinstance(value[0], tuple):
- create_value ,= value[0]
- else:
- create_value = value
- obj = new(cls, *create_value)
- obj._value_ = value[0] if len(value) == 1 else value
- obj.description = 'test description'
+ class SuperEnum2(IntEnum):
+ def __new__(cls, value, description=""):
+ obj = int.__new__(cls, value)
+ obj._value_ = value
+ obj.description = description
return obj
- class SubEnum(SuperEnum):
- sample = self.source_values[1]
- self.assertTrue('description' not in dir(SubEnum))
- self.assertTrue('description' in dir(SubEnum.sample), dir(SubEnum.sample))
-
- def test_enum_in_enum_out(self):
- Main = self.MainEnum
- self.assertIs(Main(Main.first), Main.first)
-
- def test_hash(self):
- MainEnum = self.MainEnum
- mapping = {}
- mapping[MainEnum.first] = '1225'
- mapping[MainEnum.second] = '0315'
- mapping[MainEnum.third] = '0704'
- self.assertEqual(mapping[MainEnum.second], '0315')
-
- def test_invalid_names(self):
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- mro = 9
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _create_= 11
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _get_mixins_ = 9
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _find_new_ = 1
- with self.assertRaises(ValueError):
- class Wrong(self.enum_type):
- _any_name_ = 9
-
- def test_object_str_override(self):
- "check that setting __str__ to object's is not reset to Enum's"
- class Generic(self.enum_type):
- item = self.source_values[2]
- def __repr__(self):
- return "%s.test" % (self._name_, )
- __str__ = object.__str__
- self.assertEqual(str(Generic.item), 'item.test')
-
- def test_overridden_str(self):
- NS = self.NewStrEnum
- self.assertEqual(str(NS.first), NS.first.name.upper())
- self.assertEqual(format(NS.first), NS.first.name.upper())
+ class SubEnum2(SuperEnum2):
+ sample = 5
+ self.SubEnum2 = SubEnum2
+
+ def test_dir_basics_for_all_enums(self):
+ enums_for_tests = (
+ # Generic enums in enum.py
+ Enum,
+ IntEnum,
+ StrEnum,
+ # Generic enums defined outside of enum.py
+ self.DateEnum,
+ self.FloatEnum,
+ # Concrete enums derived from enum.py generics
+ self.Grades,
+ self.Season,
+ # Concrete enums derived from generics defined outside of enum.py
+ self.Konstants,
+ self.Holiday,
+ # Standard enum with added behaviour & members
+ self.Wowser,
+ # Mixin-enum-from-enum.py with added behaviour & members
+ self.IntWowser,
+ # Mixin-enum-from-oustide-enum.py with added behaviour & members
+ self.FloatWowser,
+ # Equivalents of the three immediately above, but with no members
+ self.WowserNoMembers,
+ self.IntWowserNoMembers,
+ self.FloatWowserNoMembers,
+ # Enum with members and an __init__ method
+ self.EnumWithInit,
+ # Special cases to test
+ self.SubEnum1,
+ self.SubEnum2
+ )
+
+ for cls in enums_for_tests:
+ with self.subTest(cls=cls):
+ cls_dir = dir(cls)
+ # test that dir is deterministic
+ self.assertEqual(cls_dir, dir(cls))
+ # test that dir is sorted
+ self.assertEqual(list(cls_dir), sorted(cls_dir))
+ # test that there are no dupes in dir
+ self.assertEqual(len(cls_dir), len(set(cls_dir)))
+ # test that there are no sunders in dir
+ self.assertFalse(any(enum._is_sunder(attr) for attr in cls_dir))
+ self.assertNotIn('__new__', cls_dir)
+
+ for attr in ('__class__', '__doc__', '__members__', '__module__'):
+ with self.subTest(attr=attr):
+ self.assertIn(attr, cls_dir)
+
+ def test_dir_for_enum_with_members(self):
+ enums_for_test = (
+ # Enum with members
+ self.Season,
+ # IntEnum with members
+ self.Grades,
+ # Two custom-mixin enums with members
+ self.Konstants,
+ self.Holiday,
+ # several enums-with-added-behaviour and members
+ self.Wowser,
+ self.IntWowser,
+ self.FloatWowser,
+ # An enum with an __init__ method and members
+ self.EnumWithInit,
+ # Special cases to test
+ self.SubEnum1,
+ self.SubEnum2
+ )
+
+ for cls in enums_for_test:
+ cls_dir = dir(cls)
+ member_names = cls._member_names_
+ with self.subTest(cls=cls):
+ self.assertTrue(all(member_name in cls_dir for member_name in member_names))
+ for member in cls:
+ member_dir = dir(member)
+ # test that dir is deterministic
+ self.assertEqual(member_dir, dir(member))
+ # test that dir is sorted
+ self.assertEqual(list(member_dir), sorted(member_dir))
+ # test that there are no dupes in dir
+ self.assertEqual(len(member_dir), len(set(member_dir)))
+
+ for attr_name in cls_dir:
+ with self.subTest(attr_name=attr_name):
+ if attr_name in {'__members__', '__init__', '__new__', *member_names}:
+ self.assertNotIn(attr_name, member_dir)
+ else:
+ self.assertIn(attr_name, member_dir)
+
+ self.assertFalse(any(enum._is_sunder(attr) for attr in member_dir))
+
+ def test_dir_for_enums_with_added_behaviour(self):
+ enums_for_test = (
+ self.Wowser,
+ self.IntWowser,
+ self.FloatWowser,
+ self.WowserNoMembers,
+ self.SubclassOfWowserNoMembers,
+ self.IntWowserNoMembers,
+ self.FloatWowserNoMembers
+ )
+
+ for cls in enums_for_test:
+ with self.subTest(cls=cls):
+ self.assertIn('wowser', dir(cls))
+ self.assertIn('classmethod_wowser', dir(cls))
+ self.assertIn('staticmethod_wowser', dir(cls))
+ self.assertTrue(all(
+ all(attr in dir(member) for attr in ('wowser', 'classmethod_wowser', 'staticmethod_wowser'))
+ for member in cls
+ ))
- def test_overridden_str_format(self):
- NSF = self.NewStrFormatEnum
- self.assertEqual(str(NSF.first), NSF.first.name.title())
- self.assertEqual(format(NSF.first), ''.join(reversed(NSF.first.name)))
+ self.assertEqual(dir(self.WowserNoMembers), dir(self.SubclassOfWowserNoMembers))
+ # Check classmethods are present
+ self.assertIn('from_bytes', dir(self.IntWowser))
+ self.assertIn('from_bytes', dir(self.IntWowserNoMembers))
+
+ def test_help_output_on_enum_members(self):
+ added_behaviour_enums = (
+ self.Wowser,
+ self.IntWowser,
+ self.FloatWowser
+ )
+
+ for cls in added_behaviour_enums:
+ with self.subTest(cls=cls):
+ rendered_doc = pydoc.render_doc(cls.this)
+ self.assertIn('Wowser docstring', rendered_doc)
+ if cls in {self.IntWowser, self.FloatWowser}:
+ self.assertIn('float(self)', rendered_doc)
+
+ def test_dir_for_enum_with_init(self):
+ EnumWithInit = self.EnumWithInit
+
+ cls_dir = dir(EnumWithInit)
+ self.assertIn('__init__', cls_dir)
+ self.assertIn('some_method', cls_dir)
+ self.assertNotIn('greeting', cls_dir)
+ self.assertNotIn('farewell', cls_dir)
+
+ member_dir = dir(EnumWithInit.ENGLISH)
+ self.assertNotIn('__init__', member_dir)
+ self.assertIn('some_method', member_dir)
+ self.assertIn('greeting', member_dir)
+ self.assertIn('farewell', member_dir)
+
+ def test_mixin_dirs(self):
+ from datetime import date
- def test_overridden_str_format_inherited(self):
- NSE = self.NewSubEnum
- self.assertEqual(str(NSE.first), NSE.first.name.title())
- self.assertEqual(format(NSE.first), ''.join(reversed(NSE.first.name)))
+ enums_for_test = (
+ # generic mixins from enum.py
+ (IntEnum, int),
+ (StrEnum, str),
+ # generic mixins from outside enum.py
+ (self.FloatEnum, float),
+ (self.DateEnum, date),
+ # concrete mixin from enum.py
+ (self.Grades, int),
+ # concrete mixin from outside enum.py
+ (self.Holiday, date),
+ # concrete mixin from enum.py with added behaviour
+ (self.IntWowser, int),
+ # concrete mixin from outside enum.py with added behaviour
+ (self.FloatWowser, float)
+ )
+
+ enum_dict = Enum.__dict__
+ enum_dir = dir(Enum)
+ enum_module_names = enum.__all__
+ is_from_enum_module = lambda cls: cls.__name__ in enum_module_names
+ is_enum_dunder = lambda attr: enum._is_dunder(attr) and attr in enum_dict
+
+ def attr_is_inherited_from_object(cls, attr_name):
+ for base in cls.__mro__:
+ if attr_name in base.__dict__:
+ return base is object
+ return False
+
+ # General tests
+ for enum_cls, mixin_cls in enums_for_test:
+ with self.subTest(enum_cls=enum_cls):
+ cls_dir = dir(enum_cls)
+ cls_dict = enum_cls.__dict__
+
+ mixin_attrs = [
+ x for x in dir(mixin_cls)
+ if not attr_is_inherited_from_object(cls=mixin_cls, attr_name=x)
+ ]
- def test_programmatic_function_string(self):
- MinorEnum = self.enum_type('MinorEnum', 'june july august')
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
+ first_enum_base = next(
+ base for base in enum_cls.__mro__
+ if is_from_enum_module(base)
)
- values = self.values
- if self.enum_type is StrEnum:
- values = ['june','july','august']
- for month, av in zip('june july august'.split(), values):
- e = MinorEnum[month]
- self.assertEqual(e.value, av, list(MinorEnum))
- self.assertEqual(e.name, month)
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
- def test_programmatic_function_string_list(self):
- MinorEnum = self.enum_type('MinorEnum', ['june', 'july', 'august'])
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- values = self.values
- if self.enum_type is StrEnum:
- values = ['june','july','august']
- for month, av in zip('june july august'.split(), values):
- e = MinorEnum[month]
- self.assertEqual(e.value, av)
- self.assertEqual(e.name, month)
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
+ for attr in mixin_attrs:
+ with self.subTest(attr=attr):
+ if enum._is_sunder(attr):
+ # Unlikely, but no harm in testing
+ self.assertNotIn(attr, cls_dir)
+ elif attr in {'__class__', '__doc__', '__members__', '__module__'}:
+ self.assertIn(attr, cls_dir)
+ elif is_enum_dunder(attr):
+ if is_from_enum_module(enum_cls):
+ self.assertNotIn(attr, cls_dir)
+ elif getattr(enum_cls, attr) is getattr(first_enum_base, attr):
+ self.assertNotIn(attr, cls_dir)
+ else:
+ self.assertIn(attr, cls_dir)
+ else:
+ self.assertIn(attr, cls_dir)
+
+ # Some specific examples
+ int_enum_dir = dir(IntEnum)
+ self.assertIn('imag', int_enum_dir)
+ self.assertIn('__rfloordiv__', int_enum_dir)
+ self.assertNotIn('__format__', int_enum_dir)
+ self.assertNotIn('__hash__', int_enum_dir)
+ self.assertNotIn('__init_subclass__', int_enum_dir)
+ self.assertNotIn('__subclasshook__', int_enum_dir)
+
+ class OverridesFormatOutsideEnumModule(Enum):
+ def __format__(self, *args, **kwargs):
+ return super().__format__(*args, **kwargs)
+ SOME_MEMBER = 1
+
+ self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule))
+ self.assertIn('__format__', dir(OverridesFormatOutsideEnumModule.SOME_MEMBER))
- def test_programmatic_function_iterable(self):
- MinorEnum = self.enum_type(
- 'MinorEnum',
- (('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2]))
- )
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
+ def test_dir_on_sub_with_behavior_on_super(self):
+ # see issue22506
self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
+ set(dir(self.SubEnum1.sample)),
+ set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
)
- for month, av in zip('june july august'.split(), self.values):
- e = MinorEnum[month]
- self.assertEqual(e.value, av)
- self.assertEqual(e.name, month)
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
- def test_programmatic_function_from_dict(self):
- MinorEnum = self.enum_type(
- 'MinorEnum',
- OrderedDict((('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2])))
- )
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for month, av in zip('june july august'.split(), self.values):
- e = MinorEnum[month]
- if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
- self.assertEqual(e, av)
- else:
- self.assertNotEqual(e, av)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
- self.assertIs(e, MinorEnum(av))
+ def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
+ # see issue40084
+ self.assertTrue({'description'} <= set(dir(self.SubEnum2.sample)))
- def test_repr(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(repr(TE(0)), "<MainEnum: 0>")
- self.assertEqual(repr(TE.dupe), "<MainEnum.dupe: 3>")
- self.assertEqual(repr(self.dupe2), "<MainEnum.first|third: 5>")
- elif issubclass(TE, StrEnum):
- self.assertEqual(repr(TE.dupe), "<MainEnum.third: 'third'>")
- else:
- self.assertEqual(repr(TE.dupe), "<MainEnum.third: %r>" % (self.values[2], ), TE._value_repr_)
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(repr(member), "<MainEnum.%s: %r>" % (member.name, member.value))
+ def test_enum_in_enum_out(self):
+ Season = self.Season
+ self.assertIs(Season(Season.WINTER), Season.WINTER)
- def test_repr_override(self):
- class Generic(self.enum_type):
- first = auto()
- second = auto()
- third = auto()
- def __repr__(self):
- return "don't you just love shades of %s?" % self.name
- self.assertEqual(
- repr(Generic.third),
- "don't you just love shades of third?",
- )
+ def test_enum_value(self):
+ Season = self.Season
+ self.assertEqual(Season.SPRING.value, 1)
- def test_inherited_repr(self):
- class MyEnum(self.enum_type):
- def __repr__(self):
- return "My name is %s." % self.name
- class MySubEnum(MyEnum):
- this = auto()
- that = auto()
- theother = auto()
- self.assertEqual(repr(MySubEnum.that), "My name is that.")
+ def test_intenum_value(self):
+ self.assertEqual(IntStooges.CURLY.value, 2)
- def test_reversed_iteration_order(self):
+ def test_enum(self):
+ Season = self.Season
+ lst = list(Season)
+ self.assertEqual(len(lst), len(Season))
+ self.assertEqual(len(Season), 4, Season)
self.assertEqual(
- list(reversed(self.MainEnum)),
- [self.MainEnum.third, self.MainEnum.second, self.MainEnum.first],
- )
+ [Season.SPRING, Season.SUMMER, Season.AUTUMN, Season.WINTER], lst)
-class _PlainOutputTests:
-
- def test_str(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(str(TE.dupe), "MainEnum.dupe")
- self.assertEqual(str(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(str(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
-
- def test_format(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(format(TE.dupe), "MainEnum.dupe")
- self.assertEqual(format(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(format(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
-
- def test_overridden_format(self):
- NF = self.NewFormatEnum
- self.assertEqual(str(NF.first), "NewFormatEnum.first", '%s %r' % (NF.__str__, NF.first))
- self.assertEqual(format(NF.first), "FIRST")
-
- def test_format_specs(self):
- TE = self.MainEnum
- self.assertFormatIsStr('{}', TE.second)
- self.assertFormatIsStr('{:}', TE.second)
- self.assertFormatIsStr('{:20}', TE.second)
- self.assertFormatIsStr('{:^20}', TE.second)
- self.assertFormatIsStr('{:>20}', TE.second)
- self.assertFormatIsStr('{:<20}', TE.second)
- self.assertFormatIsStr('{:5.2}', TE.second)
-
-
-class _MixedOutputTests:
-
- def test_str(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(str(TE.dupe), "MainEnum.dupe")
- self.assertEqual(str(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(str(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
-
- def test_format(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(format(TE.dupe), "MainEnum.dupe")
- self.assertEqual(format(self.dupe2), "MainEnum.first|third")
- else:
- self.assertEqual(format(TE.dupe), "MainEnum.third")
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
-
- def test_overridden_format(self):
- NF = self.NewFormatEnum
- self.assertEqual(str(NF.first), "NewFormatEnum.first")
- self.assertEqual(format(NF.first), "FIRST")
-
- def test_format_specs(self):
- TE = self.MainEnum
- self.assertFormatIsStr('{}', TE.first)
- self.assertFormatIsStr('{:}', TE.first)
- self.assertFormatIsStr('{:20}', TE.first)
- self.assertFormatIsStr('{:^20}', TE.first)
- self.assertFormatIsStr('{:>20}', TE.first)
- self.assertFormatIsStr('{:<20}', TE.first)
- self.assertFormatIsStr('{:5.2}', TE.first)
-
-
-class _MinimalOutputTests:
-
- def test_str(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(str(TE.dupe), "3")
- self.assertEqual(str(self.dupe2), "5")
- else:
- self.assertEqual(str(TE.dupe), str(self.values[2]))
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(str(member), str(value))
-
- def test_format(self):
- TE = self.MainEnum
- if self.is_flag:
- self.assertEqual(format(TE.dupe), "3")
- self.assertEqual(format(self.dupe2), "5")
- else:
- self.assertEqual(format(TE.dupe), format(self.values[2]))
- for name, value, member in zip(self.names, self.values, TE, strict=True):
- self.assertEqual(format(member), format(value))
-
- def test_overridden_format(self):
- NF = self.NewFormatEnum
- self.assertEqual(str(NF.first), str(self.values[0]))
- self.assertEqual(format(NF.first), "FIRST")
-
- def test_format_specs(self):
- TE = self.MainEnum
- self.assertFormatIsValue('{}', TE.third)
- self.assertFormatIsValue('{:}', TE.third)
- self.assertFormatIsValue('{:20}', TE.third)
- self.assertFormatIsValue('{:^20}', TE.third)
- self.assertFormatIsValue('{:>20}', TE.third)
- self.assertFormatIsValue('{:<20}', TE.third)
- if TE._member_type_ is float:
- self.assertFormatIsValue('{:n}', TE.third)
- self.assertFormatIsValue('{:5.2}', TE.third)
- self.assertFormatIsValue('{:f}', TE.third)
-
-
-class _FlagTests:
-
- def test_default_missing_with_wrong_type_value(self):
- with self.assertRaisesRegex(
- ValueError,
- "'RED' is not a valid TestFlag.Color",
- ) as ctx:
- self.MainEnum('RED')
- self.assertIs(ctx.exception.__context__, None)
-
-class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase):
- enum_type = Enum
-
-
-class TestPlainFlag(_EnumTests, _PlainOutputTests, unittest.TestCase):
- enum_type = Flag
-
-
-class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
- enum_type = IntEnum
-
-
-class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
- enum_type = StrEnum
-
-
-class TestIntFlag(_EnumTests, _MinimalOutputTests, unittest.TestCase):
- enum_type = IntFlag
-
-
-class TestMixedInt(_EnumTests, _MixedOutputTests, unittest.TestCase):
- class enum_type(int, Enum): pass
-
-
-class TestMixedStr(_EnumTests, _MixedOutputTests, unittest.TestCase):
- class enum_type(str, Enum): pass
-
-
-class TestMixedIntFlag(_EnumTests, _MixedOutputTests, unittest.TestCase):
- class enum_type(int, Flag): pass
-
-
-class TestMixedDate(_EnumTests, _MixedOutputTests, unittest.TestCase):
-
- values = [date(2021, 12, 25), date(2020, 3, 15), date(2019, 11, 27)]
- source_values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
-
- class enum_type(date, Enum):
- def _generate_next_value_(name, start, count, last_values):
- values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
- return values[count]
-
-
-class TestMinimalDate(_EnumTests, _MinimalOutputTests, unittest.TestCase):
-
- values = [date(2023, 12, 1), date(2016, 2, 29), date(2009, 1, 1)]
- source_values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
-
- class enum_type(date, ReprEnum):
- def _generate_next_value_(name, start, count, last_values):
- values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
- return values[count]
-
-
-class TestMixedFloat(_EnumTests, _MixedOutputTests, unittest.TestCase):
-
- values = [1.1, 2.2, 3.3]
+ for i, season in enumerate('SPRING SUMMER AUTUMN WINTER'.split(), 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.assertIn(e, Season)
+ self.assertIs(type(e), Season)
+ self.assertIsInstance(e, Season)
+ self.assertEqual(str(e), season)
+ self.assertEqual(repr(e), 'Season.{0}'.format(season))
+
+ def test_value_name(self):
+ Season = self.Season
+ self.assertEqual(Season.SPRING.name, 'SPRING')
+ self.assertEqual(Season.SPRING.value, 1)
+ with self.assertRaises(AttributeError):
+ Season.SPRING.name = 'invierno'
+ with self.assertRaises(AttributeError):
+ Season.SPRING.value = 2
- class enum_type(float, Enum):
- def _generate_next_value_(name, start, count, last_values):
- values = [1.1, 2.2, 3.3]
- return values[count]
+ def test_changing_member(self):
+ Season = self.Season
+ with self.assertRaises(AttributeError):
+ Season.WINTER = 'really cold'
+ def test_attribute_deletion(self):
+ class Season(Enum):
+ SPRING = 1
+ SUMMER = 2
+ AUTUMN = 3
+ WINTER = 4
-class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase):
+ def spam(cls):
+ pass
- values = [4.4, 5.5, 6.6]
+ self.assertTrue(hasattr(Season, 'spam'))
+ del Season.spam
+ self.assertFalse(hasattr(Season, 'spam'))
- class enum_type(float, ReprEnum):
- def _generate_next_value_(name, start, count, last_values):
- values = [4.4, 5.5, 6.6]
- return values[count]
+ with self.assertRaises(AttributeError):
+ del Season.SPRING
+ with self.assertRaises(AttributeError):
+ del Season.DRY
+ with self.assertRaises(AttributeError):
+ del Season.SPRING.name
+ def test_bool_of_class(self):
+ class Empty(Enum):
+ pass
+ self.assertTrue(bool(Empty))
-class TestSpecial(unittest.TestCase):
- """
- various operations that are not attributable to every possible enum
- """
+ def test_bool_of_member(self):
+ class Count(Enum):
+ zero = 0
+ one = 1
+ two = 2
+ for member in Count:
+ self.assertTrue(bool(member))
- def setUp(self):
- class Season(Enum):
- SPRING = 1
- SUMMER = 2
- AUTUMN = 3
- WINTER = 4
- self.Season = Season
- #
- 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_invalid_names(self):
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ mro = 9
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _create_= 11
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _get_mixins_ = 9
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _find_new_ = 1
+ with self.assertRaises(ValueError):
+ class Wrong(Enum):
+ _any_name_ = 9
def test_bool(self):
# plain Enum members are always True
@@ -865,56 +656,92 @@ class TestSpecial(unittest.TestCase):
self.assertTrue(IntLogic.true)
self.assertFalse(IntLogic.false)
+ @unittest.skipIf(
+ python_version >= (3, 12),
+ '__contains__ now returns True/False for all inputs',
+ )
+ def test_contains_er(self):
+ Season = self.Season
+ self.assertIn(Season.AUTUMN, Season)
+ with self.assertRaises(TypeError):
+ with self.assertWarns(DeprecationWarning):
+ 3 in Season
+ with self.assertRaises(TypeError):
+ with self.assertWarns(DeprecationWarning):
+ 'AUTUMN' in Season
+ val = Season(3)
+ self.assertIn(val, Season)
+ #
+ class OtherEnum(Enum):
+ one = 1; two = 2
+ self.assertNotIn(OtherEnum.two, Season)
+
+ @unittest.skipIf(
+ python_version < (3, 12),
+ '__contains__ only works with enum memmbers before 3.12',
+ )
+ def test_contains_tf(self):
+ Season = self.Season
+ self.assertIn(Season.AUTUMN, Season)
+ self.assertTrue(3 in Season)
+ self.assertFalse('AUTUMN' in Season)
+ val = Season(3)
+ self.assertIn(val, Season)
+ #
+ class OtherEnum(Enum):
+ one = 1; two = 2
+ self.assertNotIn(OtherEnum.two, Season)
+
def test_comparisons(self):
Season = self.Season
with self.assertRaises(TypeError):
Season.SPRING < Season.WINTER
with self.assertRaises(TypeError):
Season.SPRING > 4
- #
+
self.assertNotEqual(Season.SPRING, 1)
- #
+
class Part(Enum):
SPRING = 1
CLIP = 2
BARREL = 3
- #
+
self.assertNotEqual(Season.SPRING, Part.SPRING)
with self.assertRaises(TypeError):
Season.SPRING < Part.CLIP
- def test_dir_with_custom_dunders(self):
- class PlainEnum(Enum):
- pass
- cls_dir = dir(PlainEnum)
- self.assertNotIn('__repr__', cls_dir)
- self.assertNotIn('__str__', cls_dir)
- self.assertNotIn('__repr__', cls_dir)
- self.assertNotIn('__repr__', cls_dir)
- #
- class MyEnum(Enum):
- def __repr__(self):
- return object.__repr__(self)
- def __str__(self):
- return object.__repr__(self)
- def __format__(self):
- return object.__repr__(self)
- def __init__(self):
- pass
- cls_dir = dir(MyEnum)
- self.assertIn('__repr__', cls_dir)
- self.assertIn('__str__', cls_dir)
- self.assertIn('__repr__', cls_dir)
- self.assertIn('__repr__', cls_dir)
+ def test_enum_duplicates(self):
+ class Season(Enum):
+ 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.assertIs(Season.FALL, Season.AUTUMN)
+ self.assertEqual(Season.FALL.value, 3)
+ self.assertEqual(Season.AUTUMN.value, 3)
+ self.assertIs(Season(3), Season.AUTUMN)
+ self.assertIs(Season(1), Season.SPRING)
+ self.assertEqual(Season.FALL.name, 'AUTUMN')
+ self.assertEqual(
+ [k for k,v in Season.__members__.items() if v.name != k],
+ ['FALL', 'ANOTHER_SPRING'],
+ )
- def test_duplicate_name_error(self):
+ def test_duplicate_name(self):
with self.assertRaises(TypeError):
class Color(Enum):
red = 1
green = 2
blue = 3
red = 4
- #
+
with self.assertRaises(TypeError):
class Color(Enum):
red = 1
@@ -922,45 +749,232 @@ class TestSpecial(unittest.TestCase):
blue = 3
def red(self):
return 'red'
- #
+
with self.assertRaises(TypeError):
class Color(Enum):
- @enum.property
+ @property
def red(self):
return 'redder'
red = 1
green = 2
blue = 3
- def test_enum_function_with_qualname(self):
- if isinstance(Theory, Exception):
- raise Theory
- self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
+ def test_reserved__sunder_(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ '_sunder_ names, such as ._bad_., are reserved',
+ ):
+ class Bad(Enum):
+ _bad_ = 1
def test_enum_with_value_name(self):
class Huh(Enum):
name = 1
value = 2
- self.assertEqual(list(Huh), [Huh.name, Huh.value])
+ self.assertEqual(
+ list(Huh),
+ [Huh.name, Huh.value],
+ )
self.assertIs(type(Huh.name), Huh)
self.assertEqual(Huh.name.name, 'name')
self.assertEqual(Huh.name.value, 1)
+ def test_format_enum(self):
+ Season = self.Season
+ self.assertEqual('{}'.format(Season.SPRING),
+ '{}'.format(str(Season.SPRING)))
+ self.assertEqual( '{:}'.format(Season.SPRING),
+ '{:}'.format(str(Season.SPRING)))
+ self.assertEqual('{:20}'.format(Season.SPRING),
+ '{:20}'.format(str(Season.SPRING)))
+ self.assertEqual('{:^20}'.format(Season.SPRING),
+ '{:^20}'.format(str(Season.SPRING)))
+ self.assertEqual('{:>20}'.format(Season.SPRING),
+ '{:>20}'.format(str(Season.SPRING)))
+ self.assertEqual('{:<20}'.format(Season.SPRING),
+ '{:<20}'.format(str(Season.SPRING)))
+
+ def test_str_override_enum(self):
+ class EnumWithStrOverrides(Enum):
+ one = auto()
+ two = auto()
+
+ def __str__(self):
+ return 'Str!'
+ self.assertEqual(str(EnumWithStrOverrides.one), 'Str!')
+ self.assertEqual('{}'.format(EnumWithStrOverrides.one), 'Str!')
+
+ def test_format_override_enum(self):
+ class EnumWithFormatOverride(Enum):
+ one = 1.0
+ two = 2.0
+ def __format__(self, spec):
+ return 'Format!!'
+ self.assertEqual(str(EnumWithFormatOverride.one), 'one')
+ self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
+
+ def test_str_and_format_override_enum(self):
+ class EnumWithStrFormatOverrides(Enum):
+ one = auto()
+ two = auto()
+ def __str__(self):
+ return 'Str!'
+ def __format__(self, spec):
+ return 'Format!'
+ self.assertEqual(str(EnumWithStrFormatOverrides.one), 'Str!')
+ self.assertEqual('{}'.format(EnumWithStrFormatOverrides.one), 'Format!')
+
+ def test_str_override_mixin(self):
+ class MixinEnumWithStrOverride(float, Enum):
+ one = 1.0
+ two = 2.0
+ def __str__(self):
+ return 'Overridden!'
+ self.assertEqual(str(MixinEnumWithStrOverride.one), 'Overridden!')
+ self.assertEqual('{}'.format(MixinEnumWithStrOverride.one), 'Overridden!')
+
+ def test_str_and_format_override_mixin(self):
+ class MixinWithStrFormatOverrides(float, Enum):
+ one = 1.0
+ two = 2.0
+ def __str__(self):
+ return 'Str!'
+ def __format__(self, spec):
+ return 'Format!'
+ self.assertEqual(str(MixinWithStrFormatOverrides.one), 'Str!')
+ self.assertEqual('{}'.format(MixinWithStrFormatOverrides.one), 'Format!')
+
+ def test_format_override_mixin(self):
+ class TestFloat(float, Enum):
+ one = 1.0
+ two = 2.0
+ def __format__(self, spec):
+ return 'TestFloat success!'
+ self.assertEqual(str(TestFloat.one), 'one')
+ self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
+
+ @unittest.skipIf(
+ python_version < (3, 12),
+ 'mixin-format is still using member.value',
+ )
+ def test_mixin_format_warning(self):
+ class Grades(int, Enum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ self.assertEqual(f'{self.Grades.B}', 'B')
+
+ @unittest.skipIf(
+ python_version >= (3, 12),
+ 'mixin-format now uses member instead of member.value',
+ )
+ def test_mixin_format_warning(self):
+ class Grades(int, Enum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(f'{Grades.B}', '4')
+
+ def assertFormatIsValue(self, spec, member):
+ if python_version < (3, 12) and (not spec or spec in ('{}','{:}')):
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(spec.format(member), spec.format(member.value))
+ else:
+ self.assertEqual(spec.format(member), spec.format(member.value))
+
+ def test_format_enum_date(self):
+ Holiday = self.Holiday
+ self.assertFormatIsValue('{}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:^20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:>20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:<20}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:%Y %m}', Holiday.IDES_OF_MARCH)
+ self.assertFormatIsValue('{:%Y %m %M:00}', Holiday.IDES_OF_MARCH)
+
+ def test_format_enum_float(self):
+ Konstants = self.Konstants
+ self.assertFormatIsValue('{}', Konstants.TAU)
+ self.assertFormatIsValue('{:}', Konstants.TAU)
+ self.assertFormatIsValue('{:20}', Konstants.TAU)
+ self.assertFormatIsValue('{:^20}', Konstants.TAU)
+ self.assertFormatIsValue('{:>20}', Konstants.TAU)
+ self.assertFormatIsValue('{:<20}', Konstants.TAU)
+ self.assertFormatIsValue('{:n}', Konstants.TAU)
+ self.assertFormatIsValue('{:5.2}', Konstants.TAU)
+ self.assertFormatIsValue('{:f}', Konstants.TAU)
+
+ def test_format_enum_int(self):
+ class Grades(int, Enum):
+ A = 5
+ B = 4
+ C = 3
+ D = 2
+ F = 0
+ self.assertFormatIsValue('{}', Grades.C)
+ self.assertFormatIsValue('{:}', Grades.C)
+ self.assertFormatIsValue('{:20}', Grades.C)
+ self.assertFormatIsValue('{:^20}', Grades.C)
+ self.assertFormatIsValue('{:>20}', Grades.C)
+ self.assertFormatIsValue('{:<20}', Grades.C)
+ self.assertFormatIsValue('{:+}', Grades.C)
+ self.assertFormatIsValue('{:08X}', Grades.C)
+ self.assertFormatIsValue('{:b}', Grades.C)
+
+ def test_format_enum_str(self):
+ Directional = self.Directional
+ self.assertFormatIsValue('{}', Directional.WEST)
+ self.assertFormatIsValue('{:}', Directional.WEST)
+ self.assertFormatIsValue('{:20}', Directional.WEST)
+ self.assertFormatIsValue('{:^20}', Directional.WEST)
+ self.assertFormatIsValue('{:>20}', Directional.WEST)
+ self.assertFormatIsValue('{:<20}', Directional.WEST)
+
+ def test_object_str_override(self):
+ class Colors(Enum):
+ RED, GREEN, BLUE = 1, 2, 3
+ def __repr__(self):
+ return "test.%s" % (self._name_, )
+ __str__ = object.__str__
+ self.assertEqual(str(Colors.RED), 'test.RED')
+
+ def test_enum_str_override(self):
+ class MyStrEnum(Enum):
+ def __str__(self):
+ return 'MyStr'
+ class MyMethodEnum(Enum):
+ def hello(self):
+ return 'Hello! My name is %s' % self.name
+ class Test1Enum(MyMethodEnum, int, MyStrEnum):
+ One = 1
+ Two = 2
+ self.assertTrue(Test1Enum._member_type_ is int)
+ self.assertEqual(str(Test1Enum.One), 'MyStr')
+ self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
+ #
+ class Test2Enum(MyStrEnum, MyMethodEnum):
+ One = 1
+ Two = 2
+ self.assertEqual(str(Test2Enum.One), 'MyStr')
+ self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
+
def test_inherited_data_type(self):
class HexInt(int):
- __qualname__ = 'HexInt'
def __repr__(self):
return hex(self)
class MyEnum(HexInt, enum.Enum):
- __qualname__ = 'MyEnum'
A = 1
B = 2
C = 3
+ def __repr__(self):
+ return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
- globals()['HexInt'] = HexInt
- globals()['MyEnum'] = MyEnum
- test_pickle_dump_load(self.assertIs, MyEnum.A)
- test_pickle_dump_load(self.assertIs, MyEnum)
#
class SillyInt(HexInt):
__qualname__ = 'SillyInt'
@@ -976,7 +990,7 @@ class TestSpecial(unittest.TestCase):
test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
test_pickle_dump_load(self.assertIs, MyOtherEnum)
#
- # This did not work in 3.10, but does now with pickling by name
+ # This did not work in 3.9, but does now with pickling by name
class UnBrokenInt(int):
__qualname__ = 'UnBrokenInt'
def __new__(cls, value):
@@ -993,124 +1007,6 @@ class TestSpecial(unittest.TestCase):
test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
- 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_programmatic_function_type(self):
- MinorEnum = Enum('MinorEnum', 'june july august', type=int)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 1):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_string_with_start(self):
- MinorEnum = Enum('MinorEnum', 'june july august', start=10)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 10):
- e = MinorEnum(i)
- self.assertEqual(int(e.value), i)
- self.assertNotEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_type_with_start(self):
- MinorEnum = Enum('MinorEnum', 'june july august', type=int, start=30)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 30):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_string_list_with_start(self):
- MinorEnum = Enum('MinorEnum', ['june', 'july', 'august'], start=20)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 20):
- e = MinorEnum(i)
- self.assertEqual(int(e.value), i)
- self.assertNotEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_type_from_subclass(self):
- MinorEnum = IntEnum('MinorEnum', 'june july august')
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 1):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_programmatic_function_type_from_subclass_with_start(self):
- MinorEnum = IntEnum('MinorEnum', 'june july august', start=40)
- lst = list(MinorEnum)
- self.assertEqual(len(lst), len(MinorEnum))
- self.assertEqual(len(MinorEnum), 3, MinorEnum)
- self.assertEqual(
- [MinorEnum.june, MinorEnum.july, MinorEnum.august],
- lst,
- )
- for i, month in enumerate('june july august'.split(), 40):
- e = MinorEnum(i)
- self.assertEqual(e, i)
- self.assertEqual(e.name, month)
- self.assertIn(e, MinorEnum)
- self.assertIs(type(e), MinorEnum)
-
- def test_intenum_from_bytes(self):
- self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
- with self.assertRaises(ValueError):
- IntStooges.from_bytes(b'\x00\x05', 'big')
-
- def test_reserved_sunder_error(self):
- with self.assertRaisesRegex(
- ValueError,
- '_sunder_ names, such as ._bad_., are reserved',
- ):
- class Bad(Enum):
- _bad_ = 1
-
def test_too_many_data_types(self):
with self.assertRaisesRegex(TypeError, 'too many data types'):
class Huh(str, int, Enum):
@@ -1126,6 +1022,122 @@ class TestSpecial(unittest.TestCase):
class Huh(MyStr, MyInt, Enum):
One = 1
+ 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_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_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_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_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, 1):
+ e = WeekDay(i)
+ self.assertEqual(e, i)
+ self.assertEqual(int(e), i)
+ self.assertEqual(e.name, weekday)
+ self.assertIn(e, WeekDay)
+ self.assertEqual(lst.index(e)+1, i)
+ self.assertTrue(0 < e < 8)
+ self.assertIs(type(e), WeekDay)
+ self.assertIsInstance(e, int)
+ self.assertIsInstance(e, Enum)
+
+ def test_intenum_duplicates(self):
+ class WeekDay(IntEnum):
+ SUNDAY = 1
+ MONDAY = 2
+ TUESDAY = TEUSDAY = 3
+ WEDNESDAY = 4
+ THURSDAY = 5
+ FRIDAY = 6
+ SATURDAY = 7
+ self.assertIs(WeekDay.TEUSDAY, 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_intenum_from_bytes(self):
+ self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
+ with self.assertRaises(ValueError):
+ IntStooges.from_bytes(b'\x00\x05', 'big')
+
+ 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):
@@ -1157,7 +1169,12 @@ class TestSpecial(unittest.TestCase):
test_pickle_dump_load(self.assertIs, Question.who)
test_pickle_dump_load(self.assertIs, Question)
- def test_pickle_nested_class(self):
+ def test_enum_function_with_qualname(self):
+ if isinstance(Theory, Exception):
+ raise Theory
+ self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
+
+ 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'
@@ -1175,7 +1192,7 @@ class TestSpecial(unittest.TestCase):
for proto in range(HIGHEST_PROTOCOL):
self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
- def test_pickle_explodes(self):
+ def test_exploding_pickle(self):
BadPickle = Enum(
'BadPickle', 'dill sweet bread-n-butter', module=__name__)
globals()['BadPickle'] = BadPickle
@@ -1216,6 +1233,185 @@ class TestSpecial(unittest.TestCase):
[Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
)
+ def test_reversed_iteration_order(self):
+ self.assertEqual(
+ list(reversed(self.Season)),
+ [self.Season.WINTER, self.Season.AUTUMN, self.Season.SUMMER,
+ self.Season.SPRING]
+ )
+
+ def test_programmatic_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(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_function_from_dict(self):
+ SummerMonth = Enum(
+ 'SummerMonth',
+ OrderedDict((('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(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(int(e.value), i)
+ self.assertNotEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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(), 1):
+ e = SummerMonth(i)
+ self.assertEqual(e, i)
+ self.assertEqual(e.name, month)
+ self.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
+ def test_programmatic_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.assertIn(e, SummerMonth)
+ self.assertIs(type(e), SummerMonth)
+
def test_subclassing(self):
if isinstance(Name, Exception):
raise Name
@@ -1229,18 +1425,15 @@ class TestSpecial(unittest.TestCase):
red = 1
green = 2
blue = 3
- #
with self.assertRaises(TypeError):
class MoreColor(Color):
cyan = 4
magenta = 5
yellow = 6
- #
- with self.assertRaisesRegex(TypeError, "<enum .EvenMoreColor.> cannot extend <enum .Color.>"):
+ with self.assertRaisesRegex(TypeError, "EvenMoreColor: cannot extend enumeration 'Color'"):
class EvenMoreColor(Color, IntEnum):
chartruese = 7
- #
- with self.assertRaisesRegex(TypeError, "<enum .Foo.> cannot extend <enum .Color.>"):
+ with self.assertRaisesRegex(TypeError, "Foo: cannot extend enumeration 'Color'"):
Color('Foo', ('pink', 'black'))
def test_exclude_methods(self):
@@ -1344,7 +1537,27 @@ class TestSpecial(unittest.TestCase):
with self.assertRaises(KeyError):
Color['chartreuse']
- # tests that need to be evalualted for moving
+ 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(type(Enum)):
@@ -1397,7 +1610,7 @@ class TestSpecial(unittest.TestCase):
return self
def __getnewargs__(self):
return self._args
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1457,7 +1670,7 @@ class TestSpecial(unittest.TestCase):
return self
def __getnewargs_ex__(self):
return self._args, {}
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1517,7 +1730,7 @@ class TestSpecial(unittest.TestCase):
return self
def __reduce__(self):
return self.__class__, self._args
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1577,7 +1790,7 @@ class TestSpecial(unittest.TestCase):
return self
def __reduce_ex__(self, proto):
return self.__class__, self._args
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1634,7 +1847,7 @@ class TestSpecial(unittest.TestCase):
self._intname = name
self._args = _args
return self
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1689,7 +1902,7 @@ class TestSpecial(unittest.TestCase):
self._intname = name
self._args = _args
return self
- @bltns.property
+ @property
def __name__(self):
return self._intname
def __repr__(self):
@@ -1878,7 +2091,6 @@ class TestSpecial(unittest.TestCase):
class Test(Base):
test = 1
self.assertEqual(Test.test.test, 'dynamic')
- self.assertEqual(Test.test.value, 1)
class Base2(Enum):
@enum.property
def flash(self):
@@ -1886,7 +2098,6 @@ class TestSpecial(unittest.TestCase):
class Test(Base2):
flash = 1
self.assertEqual(Test.flash.flash, 'flashy dynamic')
- self.assertEqual(Test.flash.value, 1)
def test_no_duplicates(self):
class UniqueEnum(Enum):
@@ -1923,7 +2134,7 @@ class TestSpecial(unittest.TestCase):
def __init__(self, mass, radius):
self.mass = mass # in kilograms
self.radius = radius # in meters
- @enum.property
+ @property
def surface_gravity(self):
# universal gravitational constant (m3 kg-1 s-2)
G = 6.67300E-11
@@ -1993,7 +2204,90 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(LabelledList.unprocessed, 1)
self.assertEqual(LabelledList(1), LabelledList.unprocessed)
- def test_default_missing_no_chained_exception(self):
+ def test_auto_number(self):
+ class Color(Enum):
+ 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):
+ 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):
+ 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):
+ red = 'red'
+ blue = auto()
+ self.assertEqual(Color.blue.value, 1)
+
+ def test_auto_garbage_corrected(self):
+ class Color(Enum):
+ 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_auto_order(self):
+ with self.assertRaises(TypeError):
+ class Color(Enum):
+ red = auto()
+ green = auto()
+ blue = auto()
+ def _generate_next_value_(name, start, count, last):
+ return name
+
+ def test_auto_order_wierd(self):
+ weird_auto = auto()
+ weird_auto.value = 'pathological case'
+ class Color(Enum):
+ red = weird_auto
+ def _generate_next_value_(name, start, count, last):
+ return name
+ blue = auto()
+ self.assertEqual(list(Color), [Color.red, Color.blue])
+ self.assertEqual(Color.red.value, 'pathological case')
+ self.assertEqual(Color.blue.value, 'blue')
+
+ def test_duplicate_auto(self):
+ class Dupes(Enum):
+ first = primero = auto()
+ second = auto()
+ third = auto()
+ self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
+
+ def test_default_missing(self):
class Color(Enum):
RED = 1
GREEN = 2
@@ -2005,7 +2299,7 @@ class TestSpecial(unittest.TestCase):
else:
raise Exception('Exception not raised.')
- def test_missing_override(self):
+ def test_missing(self):
class Color(Enum):
red = 1
green = 2
@@ -2069,9 +2363,9 @@ class TestSpecial(unittest.TestCase):
class_1_ref = weakref.ref(Class1())
class_2_ref = weakref.ref(Class2())
#
- # The exception raised by Enum used to create a reference loop and thus
- # Class2 instances would stick around until the next garbage collection
- # cycle, unlike Class1. Verify Class2 no longer does this.
+ # The exception raised by Enum creates a reference loop and thus
+ # Class2 instances will stick around until the next garbage collection
+ # cycle, unlike Class1.
gc.collect() # For PyPy or other GCs.
self.assertIs(class_1_ref(), None)
self.assertIs(class_2_ref(), None)
@@ -2102,12 +2396,11 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
self.assertEqual(Color.MAX, 3)
- self.assertEqual(str(Color.BLUE), 'Color.BLUE')
+ self.assertEqual(str(Color.BLUE), 'BLUE')
class Color(MaxMixin, StrMixin, Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
@@ -2117,7 +2410,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 3)
@@ -2127,7 +2419,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(CoolColor.RED.value, 1)
self.assertEqual(CoolColor.GREEN.value, 2)
self.assertEqual(CoolColor.BLUE.value, 3)
@@ -2137,7 +2428,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(CoolerColor.RED.value, 1)
self.assertEqual(CoolerColor.GREEN.value, 2)
self.assertEqual(CoolerColor.BLUE.value, 3)
@@ -2148,7 +2438,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(CoolestColor.RED.value, 1)
self.assertEqual(CoolestColor.GREEN.value, 2)
self.assertEqual(CoolestColor.BLUE.value, 3)
@@ -2159,7 +2448,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(ConfusedColor.RED.value, 1)
self.assertEqual(ConfusedColor.GREEN.value, 2)
self.assertEqual(ConfusedColor.BLUE.value, 3)
@@ -2170,7 +2458,6 @@ class TestSpecial(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__ # needed as of 3.11
self.assertEqual(ReformedColor.RED.value, 1)
self.assertEqual(ReformedColor.GREEN.value, 2)
self.assertEqual(ReformedColor.BLUE.value, 3)
@@ -2203,12 +2490,11 @@ class TestSpecial(unittest.TestCase):
return hex(self)
class MyIntEnum(HexMixin, MyInt, enum.Enum):
- __repr__ = HexMixin.__repr__
+ pass
class Foo(MyIntEnum):
TEST = 1
self.assertTrue(isinstance(Foo.TEST, MyInt))
- self.assertEqual(Foo._member_type_, MyInt)
self.assertEqual(repr(Foo.TEST), "0x1")
class Fee(MyIntEnum):
@@ -2220,7 +2506,7 @@ class TestSpecial(unittest.TestCase):
return member
self.assertEqual(Fee.TEST, 2)
- def test_multiple_mixin_with_common_data_type(self):
+ def test_miltuple_mixin_with_common_data_type(self):
class CaseInsensitiveStrEnum(str, Enum):
@classmethod
def _missing_(cls, value):
@@ -2240,7 +2526,7 @@ class TestSpecial(unittest.TestCase):
unknown._value_ = value
cls._member_map_[value] = unknown
return unknown
- @enum.property
+ @property
def valid(self):
return self._valid
#
@@ -2284,7 +2570,7 @@ class TestSpecial(unittest.TestCase):
self.assertEqual('{}'.format(GoodStrEnum.one), '1')
self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
- self.assertEqual(repr(GoodStrEnum.one), "<GoodStrEnum.one: '1'>")
+ self.assertEqual(repr(GoodStrEnum.one), 'GoodStrEnum.one')
#
class DumbMixin:
def __str__(self):
@@ -2293,7 +2579,6 @@ class TestSpecial(unittest.TestCase):
five = '5'
six = '6'
seven = '7'
- __str__ = DumbMixin.__str__ # needed as of 3.11
self.assertEqual(DumbStrEnum.seven, '7')
self.assertEqual(str(DumbStrEnum.seven), "don't do this")
#
@@ -2335,6 +2620,74 @@ class TestSpecial(unittest.TestCase):
one = '1'
two = b'2', 'ascii', 9
+ @unittest.skipIf(
+ python_version >= (3, 12),
+ 'mixin-format now uses member instead of member.value',
+ )
+ def test_custom_strenum_with_warning(self):
+ class CustomStrEnum(str, Enum):
+ pass
+ class OkayEnum(CustomStrEnum):
+ one = '1'
+ two = '2'
+ three = b'3', 'ascii'
+ four = b'4', 'latin1', 'strict'
+ self.assertEqual(OkayEnum.one, '1')
+ self.assertEqual(str(OkayEnum.one), 'one')
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual('{}'.format(OkayEnum.one), '1')
+ self.assertEqual(OkayEnum.one, '{}'.format(OkayEnum.one))
+ self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
+ #
+ class DumbMixin:
+ def __str__(self):
+ return "don't do this"
+ class DumbStrEnum(DumbMixin, CustomStrEnum):
+ five = '5'
+ six = '6'
+ seven = '7'
+ self.assertEqual(DumbStrEnum.seven, '7')
+ self.assertEqual(str(DumbStrEnum.seven), "don't do this")
+ #
+ class EnumMixin(Enum):
+ def hello(self):
+ print('hello from %s' % (self, ))
+ class HelloEnum(EnumMixin, CustomStrEnum):
+ eight = '8'
+ self.assertEqual(HelloEnum.eight, '8')
+ self.assertEqual(str(HelloEnum.eight), 'eight')
+ #
+ class GoodbyeMixin:
+ def goodbye(self):
+ print('%s wishes you a fond farewell')
+ class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
+ nine = '9'
+ self.assertEqual(GoodbyeEnum.nine, '9')
+ self.assertEqual(str(GoodbyeEnum.nine), 'nine')
+ #
+ class FirstFailedStrEnum(CustomStrEnum):
+ one = 1 # this will become '1'
+ two = '2'
+ class SecondFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = 2, # this will become '2'
+ three = '3'
+ class ThirdFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = 2 # this will become '2'
+ with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
+ class ThirdFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = b'2', sys.getdefaultencoding
+ with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
+ class ThirdFailedStrEnum(CustomStrEnum):
+ one = '1'
+ two = b'2', 'ascii', 9
+
+ @unittest.skipIf(
+ python_version < (3, 12),
+ 'mixin-format currently uses member.value',
+ )
def test_custom_strenum(self):
class CustomStrEnum(str, Enum):
pass
@@ -2344,9 +2697,9 @@ class TestSpecial(unittest.TestCase):
three = b'3', 'ascii'
four = b'4', 'latin1', 'strict'
self.assertEqual(OkayEnum.one, '1')
- self.assertEqual(str(OkayEnum.one), 'OkayEnum.one')
- self.assertEqual('{}'.format(OkayEnum.one), 'OkayEnum.one')
- self.assertEqual(repr(OkayEnum.one), "<OkayEnum.one: '1'>")
+ self.assertEqual(str(OkayEnum.one), 'one')
+ self.assertEqual('{}'.format(OkayEnum.one), 'one')
+ self.assertEqual(repr(OkayEnum.one), 'OkayEnum.one')
#
class DumbMixin:
def __str__(self):
@@ -2355,7 +2708,6 @@ class TestSpecial(unittest.TestCase):
five = '5'
six = '6'
seven = '7'
- __str__ = DumbMixin.__str__ # needed as of 3.11
self.assertEqual(DumbStrEnum.seven, '7')
self.assertEqual(str(DumbStrEnum.seven), "don't do this")
#
@@ -2365,7 +2717,7 @@ class TestSpecial(unittest.TestCase):
class HelloEnum(EnumMixin, CustomStrEnum):
eight = '8'
self.assertEqual(HelloEnum.eight, '8')
- self.assertEqual(str(HelloEnum.eight), 'HelloEnum.eight')
+ self.assertEqual(str(HelloEnum.eight), 'eight')
#
class GoodbyeMixin:
def goodbye(self):
@@ -2373,7 +2725,7 @@ class TestSpecial(unittest.TestCase):
class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
nine = '9'
self.assertEqual(GoodbyeEnum.nine, '9')
- self.assertEqual(str(GoodbyeEnum.nine), 'GoodbyeEnum.nine')
+ self.assertEqual(str(GoodbyeEnum.nine), 'nine')
#
class FirstFailedStrEnum(CustomStrEnum):
one = 1 # this will become '1'
@@ -2419,6 +2771,21 @@ class TestSpecial(unittest.TestCase):
code = 'An$(5,1)', 2
description = 'Bn$', 3
+ @unittest.skipUnless(
+ python_version == (3, 9),
+ 'private variables are now normal attributes',
+ )
+ def test_warning_for_private_variables(self):
+ with self.assertWarns(DeprecationWarning):
+ class Private(Enum):
+ __corporal = 'Radar'
+ self.assertEqual(Private._Private__corporal.value, 'Radar')
+ try:
+ with self.assertWarns(DeprecationWarning):
+ class Private(Enum):
+ __major_ = 'Hoolihan'
+ except ValueError:
+ pass
def test_private_variable_is_normal_attribute(self):
class Private(Enum):
@@ -2427,13 +2794,35 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(Private._Private__corporal, 'Radar')
self.assertEqual(Private._Private__major_, 'Hoolihan')
+ @unittest.skipUnless(
+ python_version < (3, 12),
+ 'member-member access now raises an exception',
+ )
+ def test_warning_for_member_from_member_access(self):
+ with self.assertWarns(DeprecationWarning):
+ class Di(Enum):
+ YES = 1
+ NO = 0
+ nope = Di.YES.NO
+ self.assertIs(Di.NO, nope)
+
+ @unittest.skipUnless(
+ python_version >= (3, 12),
+ 'member-member access currently issues a warning',
+ )
def test_exception_for_member_from_member_access(self):
- with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
+ with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
class Di(Enum):
YES = 1
NO = 0
nope = Di.YES.NO
+ def test_strenum_auto(self):
+ class Strings(StrEnum):
+ ONE = auto()
+ TWO = auto()
+ self.assertEqual([Strings.ONE, Strings.TWO], ['one', 'two'])
+
def test_dynamic_members_with_static_methods(self):
#
@@ -2450,7 +2839,7 @@ class TestSpecial(unittest.TestCase):
self.assertEqual(Foo.FOO_CAT.value, 'aloof')
self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
#
- with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as 'aloof'"):
+ with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as: 'aloof'"):
class FooBar(Enum):
vars().update({
k: v
@@ -2462,42 +2851,8 @@ class TestSpecial(unittest.TestCase):
def upper(self):
return self.value.upper()
- def test_repr_with_dataclass(self):
- "ensure dataclass-mixin has correct repr()"
- from dataclasses import dataclass
- @dataclass
- class Foo:
- __qualname__ = 'Foo'
- a: int = 0
- class Entries(Foo, Enum):
- ENTRY1 = Foo(1)
- self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
-
- def test_repr_with_non_data_type_mixin(self):
- # non-data_type is a mixin that doesn't define __new__
- class Foo:
- def __init__(self, a):
- self.a = a
- def __repr__(self):
- return f'Foo(a={self.a!r})'
- class Entries(Foo, Enum):
- ENTRY1 = Foo(1)
-
- self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
-
- def test_value_backup_assign(self):
- # check that enum will add missing values when custom __new__ does not
- 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)
-
class TestOrder(unittest.TestCase):
- "test usage of the `_order_` attribute"
def test_same_members(self):
class Color(Enum):
@@ -2559,7 +2914,7 @@ class TestOrder(unittest.TestCase):
verde = green
-class OldTestFlag(unittest.TestCase):
+class TestFlag(unittest.TestCase):
"""Tests of the Flags."""
class Perm(Flag):
@@ -2582,6 +2937,65 @@ class OldTestFlag(unittest.TestCase):
WHITE = RED|GREEN|BLUE
BLANCO = RED|GREEN|BLUE
+ def test_str(self):
+ Perm = self.Perm
+ self.assertEqual(str(Perm.R), 'R')
+ self.assertEqual(str(Perm.W), 'W')
+ self.assertEqual(str(Perm.X), 'X')
+ self.assertEqual(str(Perm.R | Perm.W), 'R|W')
+ self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
+ self.assertEqual(str(Perm(0)), 'Perm(0)')
+ self.assertEqual(str(~Perm.R), 'W|X')
+ self.assertEqual(str(~Perm.W), 'R|X')
+ self.assertEqual(str(~Perm.X), 'R|W')
+ self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
+ self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
+ self.assertEqual(str(Perm(~0)), 'R|W|X')
+
+ Open = self.Open
+ self.assertEqual(str(Open.RO), 'RO')
+ self.assertEqual(str(Open.WO), 'WO')
+ self.assertEqual(str(Open.AC), 'AC')
+ self.assertEqual(str(Open.RO | Open.CE), 'CE')
+ self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
+ self.assertEqual(str(~Open.RO), 'WO|RW|CE')
+ self.assertEqual(str(~Open.WO), 'RW|CE')
+ self.assertEqual(str(~Open.AC), 'CE')
+ self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
+ self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
+
+ def test_repr(self):
+ Perm = self.Perm
+ self.assertEqual(repr(Perm.R), 'Perm.R')
+ self.assertEqual(repr(Perm.W), 'Perm.W')
+ self.assertEqual(repr(Perm.X), 'Perm.X')
+ self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
+ self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
+ self.assertEqual(repr(Perm(0)), '0x0')
+ self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
+ self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
+ self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
+ self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
+ self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
+ self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
+
+ Open = self.Open
+ self.assertEqual(repr(Open.RO), 'Open.RO')
+ self.assertEqual(repr(Open.WO), 'Open.WO')
+ self.assertEqual(repr(Open.AC), 'Open.AC')
+ self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
+ self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
+ self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.AC), 'Open.CE')
+ self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
+ self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
+
+ def test_format(self):
+ Perm = self.Perm
+ self.assertEqual(format(Perm.R, ''), 'R')
+ self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
+
def test_or(self):
Perm = self.Perm
for i in Perm:
@@ -2674,7 +3088,7 @@ class OldTestFlag(unittest.TestCase):
c = 4
d = 6
#
- self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7)
+ self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
#
self.assertIs(Water(7), Water.ONE|Water.TWO)
self.assertIs(Water(~9), Water.TWO)
@@ -2883,7 +3297,7 @@ class OldTestFlag(unittest.TestCase):
self.assertEqual(Color.green.value, 4)
def test_auto_number_garbage(self):
- with self.assertRaisesRegex(TypeError, 'invalid flag value .not an int.'):
+ with self.assertRaisesRegex(TypeError, 'Invalid Flag value: .not an int.'):
class Color(Flag):
red = 'not an int'
blue = auto()
@@ -2918,12 +3332,11 @@ class OldTestFlag(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
self.assertEqual(Color.ALL.value, 7)
- self.assertEqual(str(Color.BLUE), 'Color.BLUE')
+ self.assertEqual(str(Color.BLUE), 'BLUE')
class Color(AllMixin, StrMixin, Flag):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -2933,7 +3346,6 @@ class OldTestFlag(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -3014,8 +3426,21 @@ class OldTestFlag(unittest.TestCase):
self.assertFalse(NeverEnum.__dict__.get('_test1', False))
self.assertFalse(NeverEnum.__dict__.get('_test2', False))
+ def test_default_missing(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ "'RED' is not a valid TestFlag.Color",
+ ) as ctx:
+ self.Color('RED')
+ self.assertIs(ctx.exception.__context__, None)
+
+ P = Flag('P', 'X Y')
+ with self.assertRaisesRegex(ValueError, "'X' is not a valid P") as ctx:
+ P('X')
+ self.assertIs(ctx.exception.__context__, None)
+
-class OldTestIntFlag(unittest.TestCase):
+class TestIntFlag(unittest.TestCase):
"""Tests of the IntFlags."""
class Perm(IntFlag):
@@ -3060,6 +3485,73 @@ class OldTestIntFlag(unittest.TestCase):
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), 'R')
+ self.assertEqual(str(Perm.W), 'W')
+ self.assertEqual(str(Perm.X), 'X')
+ self.assertEqual(str(Perm.R | Perm.W), 'R|W')
+ self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
+ self.assertEqual(str(Perm.R | 8), '12')
+ self.assertEqual(str(Perm(0)), 'Perm(0)')
+ self.assertEqual(str(Perm(8)), '8')
+ self.assertEqual(str(~Perm.R), 'W|X')
+ self.assertEqual(str(~Perm.W), 'R|X')
+ self.assertEqual(str(~Perm.X), 'R|W')
+ self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
+ self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
+ self.assertEqual(str(~(Perm.R | 8)), '-13')
+ self.assertEqual(str(Perm(~0)), 'R|W|X')
+ self.assertEqual(str(Perm(~8)), '-9')
+
+ Open = self.Open
+ self.assertEqual(str(Open.RO), 'RO')
+ self.assertEqual(str(Open.WO), 'WO')
+ self.assertEqual(str(Open.AC), 'AC')
+ self.assertEqual(str(Open.RO | Open.CE), 'CE')
+ self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
+ self.assertEqual(str(Open(4)), '4')
+ self.assertEqual(str(~Open.RO), 'WO|RW|CE')
+ self.assertEqual(str(~Open.WO), 'RW|CE')
+ self.assertEqual(str(~Open.AC), 'CE')
+ self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
+ self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
+ self.assertEqual(str(Open(~4)), '-5')
+
+ def test_repr(self):
+ Perm = self.Perm
+ self.assertEqual(repr(Perm.R), 'Perm.R')
+ self.assertEqual(repr(Perm.W), 'Perm.W')
+ self.assertEqual(repr(Perm.X), 'Perm.X')
+ self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
+ self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
+ self.assertEqual(repr(Perm.R | 8), '12')
+ self.assertEqual(repr(Perm(0)), '0x0')
+ self.assertEqual(repr(Perm(8)), '8')
+ self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
+ self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
+ self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
+ self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
+ self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
+ self.assertEqual(repr(~(Perm.R | 8)), '-13')
+ self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
+ self.assertEqual(repr(Perm(~8)), '-9')
+
+ Open = self.Open
+ self.assertEqual(repr(Open.RO), 'Open.RO')
+ self.assertEqual(repr(Open.WO), 'Open.WO')
+ self.assertEqual(repr(Open.AC), 'Open.AC')
+ self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
+ self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
+ self.assertEqual(repr(Open(4)), '4')
+ self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
+ self.assertEqual(repr(~Open.AC), 'Open.CE')
+ self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
+ self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
+ self.assertEqual(repr(Open(~4)), '-5')
+
def test_global_repr_keep(self):
self.assertEqual(
repr(HeadlightsK(0)),
@@ -3067,11 +3559,11 @@ class OldTestIntFlag(unittest.TestCase):
)
self.assertEqual(
repr(HeadlightsK(2**0 + 2**2 + 2**3)),
- '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|8' % {'m': SHORT_MODULE},
+ '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|0x8' % {'m': SHORT_MODULE},
)
self.assertEqual(
repr(HeadlightsK(2**3)),
- '%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
+ '%(m)s.HeadlightsK(0x8)' % {'m': SHORT_MODULE},
)
def test_global_repr_conform1(self):
@@ -3213,7 +3705,7 @@ class OldTestIntFlag(unittest.TestCase):
c = 4
d = 6
#
- self.assertRaisesRegex(ValueError, 'invalid value 5', Iron, 5)
+ self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
#
self.assertIs(Water(7), Water.ONE|Water.TWO)
self.assertIs(Water(~9), Water.TWO)
@@ -3450,12 +3942,11 @@ class OldTestIntFlag(unittest.TestCase):
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
self.assertEqual(Color.ALL.value, 7)
- self.assertEqual(str(Color.BLUE), '4')
+ self.assertEqual(str(Color.BLUE), 'BLUE')
class Color(AllMixin, StrMixin, IntFlag):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -3465,7 +3956,6 @@ class OldTestIntFlag(unittest.TestCase):
RED = auto()
GREEN = auto()
BLUE = auto()
- __str__ = StrMixin.__str__
self.assertEqual(Color.RED.value, 1)
self.assertEqual(Color.GREEN.value, 2)
self.assertEqual(Color.BLUE.value, 4)
@@ -3510,6 +4000,19 @@ class OldTestIntFlag(unittest.TestCase):
'at least one thread failed while creating composite members')
self.assertEqual(256, len(seen), 'too many composite members created')
+ def test_default_missing(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ "'RED' is not a valid TestIntFlag.Color",
+ ) as ctx:
+ self.Color('RED')
+ self.assertIs(ctx.exception.__context__, None)
+
+ P = IntFlag('P', 'X Y')
+ with self.assertRaisesRegex(ValueError, "'X' is not a valid P") as ctx:
+ P('X')
+ self.assertIs(ctx.exception.__context__, None)
+
class TestEmptyAndNonLatinStrings(unittest.TestCase):
@@ -3726,89 +4229,6 @@ class TestHelpers(unittest.TestCase):
for name in self.sunder_names + self.dunder_names + self.random_names:
self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
- def test_auto_number(self):
- class Color(Enum):
- 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):
- 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):
- 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):
- red = 'red'
- blue = auto()
- self.assertEqual(Color.blue.value, 1)
-
- def test_auto_garbage_corrected(self):
- class Color(Enum):
- 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_auto_order(self):
- with self.assertRaises(TypeError):
- class Color(Enum):
- red = auto()
- green = auto()
- blue = auto()
- def _generate_next_value_(name, start, count, last):
- return name
-
- def test_auto_order_wierd(self):
- weird_auto = auto()
- weird_auto.value = 'pathological case'
- class Color(Enum):
- red = weird_auto
- def _generate_next_value_(name, start, count, last):
- return name
- blue = auto()
- self.assertEqual(list(Color), [Color.red, Color.blue])
- self.assertEqual(Color.red.value, 'pathological case')
- self.assertEqual(Color.blue.value, 'blue')
-
- def test_duplicate_auto(self):
- class Dupes(Enum):
- first = primero = auto()
- second = auto()
- third = auto()
- self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
-
class TestEnumTypeSubclassing(unittest.TestCase):
pass
@@ -3818,35 +4238,7 @@ Help on class Color in module %s:
class Color(enum.Enum)
| Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
|\x20\x20
- | A collection of name/value pairs.
- |\x20\x20
- | Access them by:
- |\x20\x20
- | - attribute access::
- |\x20\x20
- | >>> Color.CYAN
- | <Color.CYAN: 1>
- |\x20\x20
- | - value lookup:
- |\x20\x20
- | >>> Color(1)
- | <Color.CYAN: 1>
- |\x20\x20
- | - name lookup:
- |\x20\x20
- | >>> Color['CYAN']
- | <Color.CYAN: 1>
- |\x20\x20
- | Enumerations can be iterated over, and know how many members they have:
- |\x20\x20
- | >>> len(Color)
- | 3
- |\x20\x20
- | >>> list(Color)
- | [<Color.CYAN: 1>, <Color.MAGENTA: 2>, <Color.YELLOW: 3>]
- |\x20\x20
- | Methods can be added to enumerations, and members can have their own
- | attributes -- see the documentation for details.
+ | An enumeration.
|\x20\x20
| Method resolution order:
| Color
@@ -3855,11 +4247,11 @@ class Color(enum.Enum)
|\x20\x20
| Data and other attributes defined here:
|\x20\x20
- | CYAN = <Color.CYAN: 1>
+ | blue = Color.blue
|\x20\x20
- | MAGENTA = <Color.MAGENTA: 2>
+ | green = Color.green
|\x20\x20
- | YELLOW = <Color.YELLOW: 3>
+ | red = Color.red
|\x20\x20
| ----------------------------------------------------------------------
| Data descriptors inherited from enum.Enum:
@@ -3871,25 +4263,6 @@ class Color(enum.Enum)
| The value of the Enum member.
|\x20\x20
| ----------------------------------------------------------------------
- | Methods inherited from enum.EnumType:
- |\x20\x20
- | __contains__(member) from enum.EnumType
- | Return True if member is a member of this enum
- | raises TypeError if member is not an enum member
- |\x20\x20\x20\x20\x20\x20
- | note: in 3.12 TypeError will no longer be raised, and True will also be
- | returned if member is the value of a member in this enum
- |\x20\x20
- | __getitem__(name) from enum.EnumType
- | Return the member matching `name`.
- |\x20\x20
- | __iter__() from enum.EnumType
- | Return members in definition order.
- |\x20\x20
- | __len__() from enum.EnumType
- | Return the number of members (no aliases)
- |\x20\x20
- | ----------------------------------------------------------------------
| Readonly properties inherited from enum.EnumType:
|\x20\x20
| __members__
@@ -3911,11 +4284,11 @@ class Color(enum.Enum)
|\x20\x20
| Data and other attributes defined here:
|\x20\x20
- | YELLOW = <Color.YELLOW: 3>
+ | blue = Color.blue
|\x20\x20
- | MAGENTA = <Color.MAGENTA: 2>
+ | green = Color.green
|\x20\x20
- | CYAN = <Color.CYAN: 1>
+ | red = Color.red
|\x20\x20
| ----------------------------------------------------------------------
| Data descriptors inherited from enum.Enum:
@@ -3934,9 +4307,9 @@ class TestStdLib(unittest.TestCase):
maxDiff = None
class Color(Enum):
- CYAN = 1
- MAGENTA = 2
- YELLOW = 3
+ red = 1
+ green = 2
+ blue = 3
def test_pydoc(self):
# indirectly test __objclass__
@@ -3948,34 +4321,24 @@ class TestStdLib(unittest.TestCase):
helper = pydoc.Helper(output=output)
helper(self.Color)
result = output.getvalue().strip()
- self.assertEqual(result, expected_text, result)
+ self.assertEqual(result, expected_text)
def test_inspect_getmembers(self):
values = dict((
('__class__', EnumType),
- ('__doc__', '...'),
+ ('__doc__', 'An enumeration.'),
('__members__', self.Color.__members__),
('__module__', __name__),
- ('YELLOW', self.Color.YELLOW),
- ('MAGENTA', self.Color.MAGENTA),
- ('CYAN', self.Color.CYAN),
+ ('blue', self.Color.blue),
+ ('green', self.Color.green),
('name', Enum.__dict__['name']),
+ ('red', self.Color.red),
('value', Enum.__dict__['value']),
- ('__len__', self.Color.__len__),
- ('__contains__', self.Color.__contains__),
- ('__name__', 'Color'),
- ('__getitem__', self.Color.__getitem__),
- ('__qualname__', 'TestStdLib.Color'),
- ('__init_subclass__', getattr(self.Color, '__init_subclass__')),
- ('__iter__', self.Color.__iter__),
))
result = dict(inspect.getmembers(self.Color))
self.assertEqual(set(values.keys()), set(result.keys()))
failed = False
for k in values.keys():
- if k == '__doc__':
- # __doc__ is huge, not comparing
- continue
if result[k] != values[k]:
print()
print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
@@ -3990,42 +4353,23 @@ class TestStdLib(unittest.TestCase):
values = [
Attribute(name='__class__', kind='data',
defining_class=object, object=EnumType),
- Attribute(name='__contains__', kind='method',
- defining_class=EnumType, object=self.Color.__contains__),
Attribute(name='__doc__', kind='data',
- defining_class=self.Color, object='...'),
- Attribute(name='__getitem__', kind='method',
- defining_class=EnumType, object=self.Color.__getitem__),
- Attribute(name='__iter__', kind='method',
- defining_class=EnumType, object=self.Color.__iter__),
- Attribute(name='__init_subclass__', kind='class method',
- defining_class=object, object=getattr(self.Color, '__init_subclass__')),
- Attribute(name='__len__', kind='method',
- defining_class=EnumType, object=self.Color.__len__),
+ defining_class=self.Color, object='An enumeration.'),
Attribute(name='__members__', kind='property',
defining_class=EnumType, object=EnumType.__members__),
Attribute(name='__module__', kind='data',
defining_class=self.Color, object=__name__),
- Attribute(name='__name__', kind='data',
- defining_class=self.Color, object='Color'),
- Attribute(name='__qualname__', kind='data',
- defining_class=self.Color, object='TestStdLib.Color'),
- Attribute(name='YELLOW', kind='data',
- defining_class=self.Color, object=self.Color.YELLOW),
- Attribute(name='MAGENTA', kind='data',
- defining_class=self.Color, object=self.Color.MAGENTA),
- Attribute(name='CYAN', kind='data',
- defining_class=self.Color, object=self.Color.CYAN),
+ Attribute(name='blue', kind='data',
+ defining_class=self.Color, object=self.Color.blue),
+ Attribute(name='green', kind='data',
+ defining_class=self.Color, object=self.Color.green),
+ Attribute(name='red', kind='data',
+ defining_class=self.Color, object=self.Color.red),
Attribute(name='name', kind='data',
defining_class=Enum, object=Enum.__dict__['name']),
Attribute(name='value', kind='data',
defining_class=Enum, object=Enum.__dict__['value']),
]
- for v in values:
- try:
- v.name
- except AttributeError:
- print(v)
values.sort(key=lambda item: item.name)
result = list(inspect.classify_class_attrs(self.Color))
result.sort(key=lambda item: item.name)
@@ -4035,15 +4379,7 @@ class TestStdLib(unittest.TestCase):
)
failed = False
for v, r in zip(values, result):
- if r.name in ('__init_subclass__', '__doc__'):
- # not sure how to make the __init_subclass_ Attributes match
- # so as long as there is one, call it good
- # __doc__ is too big to check exactly, so treat the same as __init_subclass__
- for name in ('name','kind','defining_class'):
- if getattr(v, name) != getattr(r, name):
- print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
- failed = True
- elif r != v:
+ if r != v:
print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
failed = True
if failed:
@@ -4052,15 +4388,15 @@ class TestStdLib(unittest.TestCase):
def test_test_simple_enum(self):
@_simple_enum(Enum)
class SimpleColor:
- CYAN = 1
- MAGENTA = 2
- YELLOW = 3
+ RED = 1
+ GREEN = 2
+ BLUE = 3
class CheckedColor(Enum):
- CYAN = 1
- MAGENTA = 2
- YELLOW = 3
+ RED = 1
+ GREEN = 2
+ BLUE = 3
self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
- SimpleColor.MAGENTA._value_ = 9
+ SimpleColor.GREEN._value_ = 9
self.assertRaisesRegex(
TypeError, "enum mismatch",
_test_simple_enum, CheckedColor, SimpleColor,
@@ -4086,165 +4422,9 @@ class TestStdLib(unittest.TestCase):
class MiscTestCase(unittest.TestCase):
-
def test__all__(self):
support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
- def test_doc_1(self):
- class Single(Enum):
- ONE = 1
- self.assertEqual(
- Single.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Single.ONE
- <Single.ONE: 1>
-
- - value lookup:
-
- >>> Single(1)
- <Single.ONE: 1>
-
- - name lookup:
-
- >>> Single['ONE']
- <Single.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Single)
- 1
-
- >>> list(Single)
- [<Single.ONE: 1>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
- def test_doc_2(self):
- class Double(Enum):
- ONE = 1
- TWO = 2
- self.assertEqual(
- Double.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Double.ONE
- <Double.ONE: 1>
-
- - value lookup:
-
- >>> Double(1)
- <Double.ONE: 1>
-
- - name lookup:
-
- >>> Double['ONE']
- <Double.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Double)
- 2
-
- >>> list(Double)
- [<Double.ONE: 1>, <Double.TWO: 2>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
-
- def test_doc_1(self):
- class Triple(Enum):
- ONE = 1
- TWO = 2
- THREE = 3
- self.assertEqual(
- Triple.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Triple.ONE
- <Triple.ONE: 1>
-
- - value lookup:
-
- >>> Triple(1)
- <Triple.ONE: 1>
-
- - name lookup:
-
- >>> Triple['ONE']
- <Triple.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Triple)
- 3
-
- >>> list(Triple)
- [<Triple.ONE: 1>, <Triple.TWO: 2>, <Triple.THREE: 3>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
- def test_doc_1(self):
- class Quadruple(Enum):
- ONE = 1
- TWO = 2
- THREE = 3
- FOUR = 4
- self.assertEqual(
- Quadruple.__doc__,
- dedent("""\
- A collection of name/value pairs.
-
- Access them by:
-
- - attribute access::
-
- >>> Quadruple.ONE
- <Quadruple.ONE: 1>
-
- - value lookup:
-
- >>> Quadruple(1)
- <Quadruple.ONE: 1>
-
- - name lookup:
-
- >>> Quadruple['ONE']
- <Quadruple.ONE: 1>
-
- Enumerations can be iterated over, and know how many members they have:
-
- >>> len(Quadruple)
- 4
-
- >>> list(Quadruple)[:3]
- [<Quadruple.ONE: 1>, <Quadruple.TWO: 2>, <Quadruple.THREE: 3>]
-
- Methods can be added to enumerations, and members can have their own
- attributes -- see the documentation for details.
- """))
-
# These are unordered here on purpose to ensure that declaration order
# makes no difference.
@@ -4262,10 +4442,6 @@ 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
@@ -4277,40 +4453,32 @@ COMPLEX_B = 3j
class _ModuleWrapper:
"""We use this class as a namespace for swapping modules."""
+
def __init__(self, module):
self.__dict__.update(module.__dict__)
-class TestConvert(unittest.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
-
+class TestIntEnumConvert(unittest.TestCase):
def test_convert_value_lookup_priority(self):
- test_type = enum.IntEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_TEST_'))
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.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')
- def test_convert_int(self):
- test_type = enum.IntEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_TEST_'))
+ def test_convert(self):
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.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)
@@ -4319,57 +4487,43 @@ class TestConvert(unittest.TestCase):
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',
- ]
- self.assertEqual(
- [name for name in dir(test_type) if name not in int_dir],
- [],
- msg='Names other than CONVERT_TEST_* found.',
- )
+ self.assertEqual([name for name in dir(test_type)
+ if name[0:2] not in ('CO', '__')
+ and name not in dir(IntEnum)],
+ [], msg='Names other than CONVERT_TEST_* found.')
def test_convert_uncomparable(self):
- uncomp = enum.Enum._convert_(
- 'Uncomparable',
- MODULE,
- filter=lambda x: x.startswith('UNCOMPARABLE_'))
+ # We swap a module to some other object with `__dict__`
+ # because otherwise refleak is created.
+ # `_convert_` uses a module side effect that does this. See 30472
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ uncomp = enum.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],
- )
+ )
def test_convert_complex(self):
- uncomp = enum.Enum._convert_(
- 'Uncomparable',
- MODULE,
- filter=lambda x: x.startswith('COMPLEX_'))
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ uncomp = enum.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 = enum.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.
- str_dir = dir(str) + ['CONVERT_STR_TEST_1', 'CONVERT_STR_TEST_2']
- self.assertEqual(
- [name for name in dir(test_type) if name not in str_dir],
- [],
- msg='Names other than CONVERT_STR_* found.',
- )
- 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_raise(self):
with self.assertRaises(AttributeError):
@@ -4379,58 +4533,50 @@ class TestConvert(unittest.TestCase):
filter=lambda x: x.startswith('CONVERT_TEST_'))
def test_convert_repr_and_str(self):
- test_type = enum.IntEnum._convert_(
- 'UnittestConvert',
- MODULE,
- filter=lambda x: x.startswith('CONVERT_STRING_TEST_'),
- as_global=True)
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.IntEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
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(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
+# global names for StrEnum._convert_ test
+CONVERT_STR_TEST_2 = 'goodbye'
+CONVERT_STR_TEST_1 = 'hello'
-# helpers
-
-def enum_dir(cls):
- # TODO: check for custom __init__, __new__, __format__, __repr__, __str__, __init_subclass__
- if cls._member_type_ is object:
- interesting = set()
- if cls.__init_subclass__ is not object.__init_subclass__:
- interesting.add('__init_subclass__')
- return sorted(set([
- '__class__', '__contains__', '__doc__', '__getitem__',
- '__iter__', '__len__', '__members__', '__module__',
- '__name__', '__qualname__',
- ]
- + cls._member_names_
- ) | interesting
- )
- else:
- # return whatever mixed-in data type has
- return sorted(set(
- dir(cls._member_type_)
- + cls._member_names_
- ))
-
-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)
+class TestStrEnumConvert(unittest.TestCase):
+ def test_convert(self):
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.StrEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STR_'))
+ # 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.
+ self.assertEqual([name for name in dir(test_type)
+ if name[0:2] not in ('CO', '__')
+ and name not in dir(StrEnum)],
+ [], msg='Names other than CONVERT_STR_* found.')
-missing = object()
+ def test_convert_repr_and_str(self):
+ with support.swap_item(
+ sys.modules, MODULE, _ModuleWrapper(sys.modules[MODULE]),
+ ):
+ test_type = enum.StrEnum._convert_(
+ 'UnittestConvert',
+ MODULE,
+ filter=lambda x: x.startswith('CONVERT_STR_'))
+ 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')
if __name__ == '__main__':
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index ac4626d..3f0e727 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -908,7 +908,7 @@ class PendingSignalsTests(unittest.TestCase):
%s
- blocked = %s
+ blocked = %r
signum = signal.SIGALRM
# child: block and wait the signal
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 56cc23d..394d294 100755
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1517,11 +1517,9 @@ class GeneralModuleTests(unittest.TestCase):
infos = socket.getaddrinfo(HOST, 80, socket.AF_INET, socket.SOCK_STREAM)
for family, type, _, _, _ in infos:
self.assertEqual(family, socket.AF_INET)
- self.assertEqual(repr(family), '<AddressFamily.AF_INET: 2>')
- self.assertEqual(str(family), '2')
+ self.assertEqual(str(family), 'AF_INET')
self.assertEqual(type, socket.SOCK_STREAM)
- self.assertEqual(repr(type), '<SocketKind.SOCK_STREAM: 1>')
- self.assertEqual(str(type), '1')
+ self.assertEqual(str(type), 'SOCK_STREAM')
infos = socket.getaddrinfo(HOST, None, 0, socket.SOCK_STREAM)
for _, socktype, _, _, _ in infos:
self.assertEqual(socktype, socket.SOCK_STREAM)
@@ -1795,10 +1793,8 @@ class GeneralModuleTests(unittest.TestCase):
# Make sure that the AF_* and SOCK_* constants have enum-like string
# reprs.
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
- self.assertEqual(repr(s.family), '<AddressFamily.AF_INET: 2>')
- self.assertEqual(repr(s.type), '<SocketKind.SOCK_STREAM: 1>')
- self.assertEqual(str(s.family), '2')
- self.assertEqual(str(s.type), '1')
+ self.assertEqual(str(s.family), 'AF_INET')
+ self.assertEqual(str(s.type), 'SOCK_STREAM')
def test_socket_consistent_sock_type(self):
SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 64f4bce..f99a3e8 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -373,8 +373,7 @@ class BasicSocketTests(unittest.TestCase):
# Make sure that the PROTOCOL_* constants have enum-like string
# reprs.
proto = ssl.PROTOCOL_TLS_CLIENT
- self.assertEqual(repr(proto), '<_SSLMethod.PROTOCOL_TLS_CLIENT: 16>')
- self.assertEqual(str(proto), '16')
+ self.assertEqual(str(proto), 'PROTOCOL_TLS_CLIENT')
ctx = ssl.SSLContext(proto)
self.assertIs(ctx.protocol, proto)
@@ -623,7 +622,7 @@ class BasicSocketTests(unittest.TestCase):
with self.assertWarns(DeprecationWarning) as cm:
ssl.SSLContext(protocol)
self.assertEqual(
- f'ssl.{protocol.name} is deprecated',
+ f'{protocol!r} is deprecated',
str(cm.warning)
)
@@ -632,9 +631,8 @@ class BasicSocketTests(unittest.TestCase):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
with self.assertWarns(DeprecationWarning) as cm:
ctx.minimum_version = version
- version_text = '%s.%s' % (version.__class__.__name__, version.name)
self.assertEqual(
- f'ssl.{version_text} is deprecated',
+ f'ssl.{version!r} is deprecated',
str(cm.warning)
)
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 8e4e648..d5e2c52 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -1490,10 +1490,8 @@ class UnicodeTest(string_tests.CommonTest,
# issue18780
import enum
class Float(float, enum.Enum):
- # a mixed-in type will use the name for %s etc.
PI = 3.1415926
class Int(enum.IntEnum):
- # IntEnum uses the value and not the name for %s etc.
IDES = 15
class Str(enum.StrEnum):
# StrEnum uses the value and not the name for %s etc.
@@ -1510,10 +1508,8 @@ class UnicodeTest(string_tests.CommonTest,
# formatting jobs delegated from the string implementation:
self.assertEqual('...%(foo)s...' % {'foo':Str.ABC},
'...abc...')
- self.assertEqual('...%(foo)r...' % {'foo':Int.IDES},
- '...<Int.IDES: 15>...')
self.assertEqual('...%(foo)s...' % {'foo':Int.IDES},
- '...15...')
+ '...IDES...')
self.assertEqual('...%(foo)i...' % {'foo':Int.IDES},
'...15...')
self.assertEqual('...%(foo)d...' % {'foo':Int.IDES},