[Enum] reformat and add doc strings (GH-23705)
This commit is contained in:
parent
37440eef7f
commit
6d3dfee271
187
Lib/enum.py
187
Lib/enum.py
|
@ -10,31 +10,41 @@ __all__ = [
|
||||||
|
|
||||||
|
|
||||||
def _is_descriptor(obj):
|
def _is_descriptor(obj):
|
||||||
"""Returns True if obj is a descriptor, False otherwise."""
|
"""
|
||||||
|
Returns True if obj is a descriptor, False otherwise.
|
||||||
|
"""
|
||||||
return (
|
return (
|
||||||
hasattr(obj, '__get__') or
|
hasattr(obj, '__get__') or
|
||||||
hasattr(obj, '__set__') or
|
hasattr(obj, '__set__') or
|
||||||
hasattr(obj, '__delete__'))
|
hasattr(obj, '__delete__')
|
||||||
|
)
|
||||||
|
|
||||||
def _is_dunder(name):
|
def _is_dunder(name):
|
||||||
"""Returns True if a __dunder__ name, False otherwise."""
|
"""
|
||||||
return (len(name) > 4 and
|
Returns True if a __dunder__ name, False otherwise.
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
len(name) > 4 and
|
||||||
name[:2] == name[-2:] == '__' and
|
name[:2] == name[-2:] == '__' and
|
||||||
name[2] != '_' and
|
name[2] != '_' and
|
||||||
name[-3] != '_')
|
name[-3] != '_'
|
||||||
|
)
|
||||||
|
|
||||||
def _is_sunder(name):
|
def _is_sunder(name):
|
||||||
"""Returns True if a _sunder_ name, False otherwise."""
|
"""
|
||||||
return (len(name) > 2 and
|
Returns True if a _sunder_ name, False otherwise.
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
len(name) > 2 and
|
||||||
name[0] == name[-1] == '_' and
|
name[0] == name[-1] == '_' and
|
||||||
name[1:2] != '_' and
|
name[1:2] != '_' and
|
||||||
name[-2:-1] != '_')
|
name[-2:-1] != '_'
|
||||||
|
)
|
||||||
|
|
||||||
def _make_class_unpicklable(cls):
|
def _make_class_unpicklable(cls):
|
||||||
"""Make the given class un-picklable."""
|
"""
|
||||||
|
Make the given class un-picklable.
|
||||||
|
"""
|
||||||
def _break_on_call_reduce(self, proto):
|
def _break_on_call_reduce(self, proto):
|
||||||
raise TypeError('%r cannot be pickled' % self)
|
raise TypeError('%r cannot be pickled' % self)
|
||||||
cls.__reduce_ex__ = _break_on_call_reduce
|
cls.__reduce_ex__ = _break_on_call_reduce
|
||||||
|
@ -49,11 +59,11 @@ class auto:
|
||||||
|
|
||||||
|
|
||||||
class _EnumDict(dict):
|
class _EnumDict(dict):
|
||||||
"""Track enum member order and ensure member names are not reused.
|
"""
|
||||||
|
Track enum member order and ensure member names are not reused.
|
||||||
|
|
||||||
EnumMeta will use the names found in self._member_names as the
|
EnumMeta will use the names found in self._member_names as the
|
||||||
enumeration member names.
|
enumeration member names.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -63,21 +73,23 @@ class _EnumDict(dict):
|
||||||
self._auto_called = False
|
self._auto_called = False
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
"""Changes anything not dundered or not a descriptor.
|
"""
|
||||||
|
Changes anything not dundered or not a descriptor.
|
||||||
|
|
||||||
If an enum member name is used twice, an error is raised; duplicate
|
If an enum member name is used twice, an error is raised; duplicate
|
||||||
values are not checked for.
|
values are not checked for.
|
||||||
|
|
||||||
Single underscore (sunder) names are reserved.
|
Single underscore (sunder) names are reserved.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if _is_sunder(key):
|
if _is_sunder(key):
|
||||||
if key not in (
|
if key not in (
|
||||||
'_order_', '_create_pseudo_member_',
|
'_order_', '_create_pseudo_member_',
|
||||||
'_generate_next_value_', '_missing_', '_ignore_',
|
'_generate_next_value_', '_missing_', '_ignore_',
|
||||||
):
|
):
|
||||||
raise ValueError(f'_sunder_ names, such as "{key}", are '
|
raise ValueError(
|
||||||
'reserved for future Enum use')
|
'_sunder_ names, such as %r, are reserved for future Enum use'
|
||||||
|
% (key, )
|
||||||
|
)
|
||||||
if key == '_generate_next_value_':
|
if key == '_generate_next_value_':
|
||||||
# check if members already defined as auto()
|
# check if members already defined as auto()
|
||||||
if self._auto_called:
|
if self._auto_called:
|
||||||
|
@ -91,7 +103,10 @@ class _EnumDict(dict):
|
||||||
self._ignore = value
|
self._ignore = value
|
||||||
already = set(value) & set(self._member_names)
|
already = set(value) & set(self._member_names)
|
||||||
if already:
|
if already:
|
||||||
raise ValueError('_ignore_ cannot specify already set names: %r' % (already, ))
|
raise ValueError(
|
||||||
|
'_ignore_ cannot specify already set names: %r'
|
||||||
|
% (already, )
|
||||||
|
)
|
||||||
elif _is_dunder(key):
|
elif _is_dunder(key):
|
||||||
if key == '__order__':
|
if key == '__order__':
|
||||||
key = '_order_'
|
key = '_order_'
|
||||||
|
@ -106,7 +121,12 @@ class _EnumDict(dict):
|
||||||
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 isinstance(value, auto):
|
||||||
if value.value == _auto_null:
|
if value.value == _auto_null:
|
||||||
value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:])
|
value.value = self._generate_next_value(
|
||||||
|
key,
|
||||||
|
1,
|
||||||
|
len(self._member_names),
|
||||||
|
self._last_values[:],
|
||||||
|
)
|
||||||
self._auto_called = True
|
self._auto_called = True
|
||||||
value = value.value
|
value = value.value
|
||||||
self._member_names.append(key)
|
self._member_names.append(key)
|
||||||
|
@ -119,9 +139,10 @@ class _EnumDict(dict):
|
||||||
# This is also why there are checks in EnumMeta like `if Enum is not None`
|
# This is also why there are checks in EnumMeta like `if Enum is not None`
|
||||||
Enum = None
|
Enum = None
|
||||||
|
|
||||||
|
|
||||||
class EnumMeta(type):
|
class EnumMeta(type):
|
||||||
"""Metaclass for Enum"""
|
"""
|
||||||
|
Metaclass for Enum
|
||||||
|
"""
|
||||||
@classmethod
|
@classmethod
|
||||||
def __prepare__(metacls, cls, bases):
|
def __prepare__(metacls, cls, bases):
|
||||||
# check that previous enum members do not exist
|
# check that previous enum members do not exist
|
||||||
|
@ -131,7 +152,9 @@ class EnumMeta(type):
|
||||||
# inherit previous flags and _generate_next_value_ function
|
# inherit previous flags and _generate_next_value_ function
|
||||||
member_type, first_enum = metacls._get_mixins_(cls, bases)
|
member_type, first_enum = metacls._get_mixins_(cls, bases)
|
||||||
if first_enum is not None:
|
if first_enum is not None:
|
||||||
enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
|
enum_dict['_generate_next_value_'] = getattr(
|
||||||
|
first_enum, '_generate_next_value_', None,
|
||||||
|
)
|
||||||
return enum_dict
|
return enum_dict
|
||||||
|
|
||||||
def __new__(metacls, cls, bases, classdict):
|
def __new__(metacls, cls, bases, classdict):
|
||||||
|
@ -177,9 +200,11 @@ class EnumMeta(type):
|
||||||
|
|
||||||
# save DynamicClassAttribute attributes from super classes so we know
|
# save DynamicClassAttribute attributes from super classes so we know
|
||||||
# if we can take the shortcut of storing members in the class dict
|
# if we can take the shortcut of storing members in the class dict
|
||||||
dynamic_attributes = {k for c in enum_class.mro()
|
dynamic_attributes = {
|
||||||
for k, v in c.__dict__.items()
|
k for c in enum_class.mro()
|
||||||
if isinstance(v, DynamicClassAttribute)}
|
for k, v in c.__dict__.items()
|
||||||
|
if isinstance(v, DynamicClassAttribute)
|
||||||
|
}
|
||||||
|
|
||||||
# Reverse value->name map for hashable values.
|
# Reverse value->name map for hashable values.
|
||||||
enum_class._value2member_map_ = {}
|
enum_class._value2member_map_ = {}
|
||||||
|
@ -289,7 +314,8 @@ class EnumMeta(type):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
|
def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
|
||||||
"""Either returns an existing member, or creates a new enum class.
|
"""
|
||||||
|
Either returns an existing member, or creates a new enum class.
|
||||||
|
|
||||||
This method is used both when an enum class is given a value to match
|
This method is used both when an enum class is given a value to match
|
||||||
to an enumeration member (i.e. Color(3)) and for the functional API
|
to an enumeration member (i.e. Color(3)) and for the functional API
|
||||||
|
@ -311,12 +337,18 @@ class EnumMeta(type):
|
||||||
not correct, unpickling will fail in some circumstances.
|
not correct, unpickling will fail in some circumstances.
|
||||||
|
|
||||||
`type`, if set, will be mixed in as the first base class.
|
`type`, if set, will be mixed in as the first base class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if names is None: # simple value lookup
|
if names is None: # simple value lookup
|
||||||
return cls.__new__(cls, value)
|
return cls.__new__(cls, value)
|
||||||
# otherwise, functional API: we're creating a new Enum type
|
# otherwise, functional API: we're creating a new Enum type
|
||||||
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
|
return cls._create_(
|
||||||
|
value,
|
||||||
|
names,
|
||||||
|
module=module,
|
||||||
|
qualname=qualname,
|
||||||
|
type=type,
|
||||||
|
start=start,
|
||||||
|
)
|
||||||
|
|
||||||
def __contains__(cls, member):
|
def __contains__(cls, member):
|
||||||
if not isinstance(member, Enum):
|
if not isinstance(member, Enum):
|
||||||
|
@ -329,22 +361,23 @@ class EnumMeta(type):
|
||||||
# nicer error message when someone tries to delete an attribute
|
# nicer error message when someone tries to delete an attribute
|
||||||
# (see issue19025).
|
# (see issue19025).
|
||||||
if attr in cls._member_map_:
|
if attr in cls._member_map_:
|
||||||
raise AttributeError(
|
raise AttributeError("%s: cannot delete Enum member %r." % (cls.__name__, attr))
|
||||||
"%s: cannot delete Enum member." % cls.__name__)
|
|
||||||
super().__delattr__(attr)
|
super().__delattr__(attr)
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return (['__class__', '__doc__', '__members__', '__module__'] +
|
return (
|
||||||
self._member_names_)
|
['__class__', '__doc__', '__members__', '__module__']
|
||||||
|
+ self._member_names_
|
||||||
|
)
|
||||||
|
|
||||||
def __getattr__(cls, name):
|
def __getattr__(cls, name):
|
||||||
"""Return the enum member matching `name`
|
"""
|
||||||
|
Return the enum member matching `name`
|
||||||
|
|
||||||
We use __getattr__ instead of descriptors or inserting into the enum
|
We use __getattr__ instead of descriptors or inserting into the enum
|
||||||
class' __dict__ in order to support `name` and `value` being both
|
class' __dict__ in order to support `name` and `value` being both
|
||||||
properties for enum members (which live in the class' __dict__) and
|
properties for enum members (which live in the class' __dict__) and
|
||||||
enum members themselves.
|
enum members themselves.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if _is_dunder(name):
|
if _is_dunder(name):
|
||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
@ -357,6 +390,9 @@ class EnumMeta(type):
|
||||||
return cls._member_map_[name]
|
return cls._member_map_[name]
|
||||||
|
|
||||||
def __iter__(cls):
|
def __iter__(cls):
|
||||||
|
"""
|
||||||
|
Returns members in definition order.
|
||||||
|
"""
|
||||||
return (cls._member_map_[name] for name in cls._member_names_)
|
return (cls._member_map_[name] for name in cls._member_names_)
|
||||||
|
|
||||||
def __len__(cls):
|
def __len__(cls):
|
||||||
|
@ -364,11 +400,11 @@ class EnumMeta(type):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def __members__(cls):
|
def __members__(cls):
|
||||||
"""Returns a mapping of member name->value.
|
"""
|
||||||
|
Returns a mapping of member name->value.
|
||||||
|
|
||||||
This mapping lists all enum members, including aliases. Note that this
|
This mapping lists all enum members, including aliases. Note that this
|
||||||
is a read-only view of the internal mapping.
|
is a read-only view of the internal mapping.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return MappingProxyType(cls._member_map_)
|
return MappingProxyType(cls._member_map_)
|
||||||
|
|
||||||
|
@ -376,15 +412,18 @@ class EnumMeta(type):
|
||||||
return "<enum %r>" % cls.__name__
|
return "<enum %r>" % cls.__name__
|
||||||
|
|
||||||
def __reversed__(cls):
|
def __reversed__(cls):
|
||||||
|
"""
|
||||||
|
Returns members in reverse definition order.
|
||||||
|
"""
|
||||||
return (cls._member_map_[name] for name in reversed(cls._member_names_))
|
return (cls._member_map_[name] for name in reversed(cls._member_names_))
|
||||||
|
|
||||||
def __setattr__(cls, name, value):
|
def __setattr__(cls, name, value):
|
||||||
"""Block attempts to reassign Enum members.
|
"""
|
||||||
|
Block attempts to reassign Enum members.
|
||||||
|
|
||||||
A simple assignment to the class namespace only changes one of the
|
A simple assignment to the class namespace only changes one of the
|
||||||
several possible ways to get an Enum member from the Enum class,
|
several possible ways to get an Enum member from the Enum class,
|
||||||
resulting in an inconsistent Enumeration.
|
resulting in an inconsistent Enumeration.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
member_map = cls.__dict__.get('_member_map_', {})
|
member_map = cls.__dict__.get('_member_map_', {})
|
||||||
if name in member_map:
|
if name in member_map:
|
||||||
|
@ -392,7 +431,8 @@ class EnumMeta(type):
|
||||||
super().__setattr__(name, value)
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1):
|
def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1):
|
||||||
"""Convenience method to create a new Enum class.
|
"""
|
||||||
|
Convenience method to create a new Enum class.
|
||||||
|
|
||||||
`names` can be:
|
`names` can be:
|
||||||
|
|
||||||
|
@ -401,7 +441,6 @@ class EnumMeta(type):
|
||||||
* An iterable of member names. Values are incremented by 1 from `start`.
|
* An iterable of member names. Values are incremented by 1 from `start`.
|
||||||
* An iterable of (member name, value) pairs.
|
* An iterable of (member name, value) pairs.
|
||||||
* A mapping of member name -> value pairs.
|
* A mapping of member name -> value pairs.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
metacls = cls.__class__
|
metacls = cls.__class__
|
||||||
bases = (cls, ) if type is None else (type, cls)
|
bases = (cls, ) if type is None else (type, cls)
|
||||||
|
@ -482,15 +521,18 @@ class EnumMeta(type):
|
||||||
for chain in bases:
|
for chain in bases:
|
||||||
for base in chain.__mro__:
|
for base in chain.__mro__:
|
||||||
if issubclass(base, Enum) and base._member_names_:
|
if issubclass(base, Enum) and base._member_names_:
|
||||||
raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__))
|
raise TypeError(
|
||||||
|
"%s: cannot extend enumeration %r"
|
||||||
|
% (class_name, base.__name__)
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_mixins_(class_name, bases):
|
def _get_mixins_(class_name, bases):
|
||||||
"""Returns the type for creating enum members, and the first inherited
|
"""
|
||||||
|
Returns the type for creating enum members, and the first inherited
|
||||||
enum class.
|
enum class.
|
||||||
|
|
||||||
bases: the tuple of bases that was given to __new__
|
bases: the tuple of bases that was given to __new__
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not bases:
|
if not bases:
|
||||||
return object, Enum
|
return object, Enum
|
||||||
|
@ -533,12 +575,12 @@ class EnumMeta(type):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _find_new_(classdict, member_type, first_enum):
|
def _find_new_(classdict, member_type, first_enum):
|
||||||
"""Returns the __new__ to be used for creating the enum members.
|
"""
|
||||||
|
Returns the __new__ to be used for creating the enum members.
|
||||||
|
|
||||||
classdict: the class dictionary given to __new__
|
classdict: the class dictionary given to __new__
|
||||||
member_type: the data type whose __new__ will be used by default
|
member_type: the data type whose __new__ will be used by default
|
||||||
first_enum: enumeration to check for an overriding __new__
|
first_enum: enumeration to check for an overriding __new__
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# now find the correct __new__, checking to see of one was defined
|
# now find the correct __new__, checking to see of one was defined
|
||||||
# by the user; also check earlier enum classes in case a __new__ was
|
# by the user; also check earlier enum classes in case a __new__ was
|
||||||
|
@ -578,10 +620,10 @@ class EnumMeta(type):
|
||||||
|
|
||||||
|
|
||||||
class Enum(metaclass=EnumMeta):
|
class Enum(metaclass=EnumMeta):
|
||||||
"""Generic enumeration.
|
"""
|
||||||
|
Generic enumeration.
|
||||||
|
|
||||||
Derive from this class to define new enumerations.
|
Derive from this class to define new enumerations.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __new__(cls, value):
|
def __new__(cls, value):
|
||||||
# all enum instances are actually created during class construction
|
# all enum instances are actually created during class construction
|
||||||
|
@ -624,6 +666,14 @@ class Enum(metaclass=EnumMeta):
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
def _generate_next_value_(name, start, count, last_values):
|
def _generate_next_value_(name, start, count, last_values):
|
||||||
|
"""
|
||||||
|
Generate the next value when not given.
|
||||||
|
|
||||||
|
name: the name of the member
|
||||||
|
start: the initial start value or None
|
||||||
|
count: the number of existing members
|
||||||
|
last_value: the last value assigned or None
|
||||||
|
"""
|
||||||
for last_value in reversed(last_values):
|
for last_value in reversed(last_values):
|
||||||
try:
|
try:
|
||||||
return last_value + 1
|
return last_value + 1
|
||||||
|
@ -644,6 +694,9 @@ class Enum(metaclass=EnumMeta):
|
||||||
return "%s.%s" % (self.__class__.__name__, self._name_)
|
return "%s.%s" % (self.__class__.__name__, self._name_)
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
|
"""
|
||||||
|
Returns all members and all public methods
|
||||||
|
"""
|
||||||
added_behavior = [
|
added_behavior = [
|
||||||
m
|
m
|
||||||
for cls in self.__class__.mro()
|
for cls in self.__class__.mro()
|
||||||
|
@ -653,6 +706,9 @@ class Enum(metaclass=EnumMeta):
|
||||||
return (['__class__', '__doc__', '__module__'] + added_behavior)
|
return (['__class__', '__doc__', '__module__'] + added_behavior)
|
||||||
|
|
||||||
def __format__(self, format_spec):
|
def __format__(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
|
# 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
|
# we can get strange results with the Enum name showing up instead of
|
||||||
# the value
|
# the value
|
||||||
|
@ -730,7 +786,9 @@ def _reduce_ex_by_name(self, proto):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Flag(Enum):
|
class Flag(Enum):
|
||||||
"""Support for flags"""
|
"""
|
||||||
|
Support for flags
|
||||||
|
"""
|
||||||
|
|
||||||
def _generate_next_value_(name, start, count, last_values):
|
def _generate_next_value_(name, start, count, last_values):
|
||||||
"""
|
"""
|
||||||
|
@ -753,6 +811,9 @@ class Flag(Enum):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _missing_(cls, value):
|
def _missing_(cls, value):
|
||||||
|
"""
|
||||||
|
Returns member (possibly creating it) if one can be found for value.
|
||||||
|
"""
|
||||||
original_value = value
|
original_value = value
|
||||||
if value < 0:
|
if value < 0:
|
||||||
value = ~value
|
value = ~value
|
||||||
|
@ -782,6 +843,9 @@ class Flag(Enum):
|
||||||
return pseudo_member
|
return pseudo_member
|
||||||
|
|
||||||
def __contains__(self, other):
|
def __contains__(self, other):
|
||||||
|
"""
|
||||||
|
Returns True if self has at least the same flags set as other.
|
||||||
|
"""
|
||||||
if not isinstance(other, self.__class__):
|
if not isinstance(other, self.__class__):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"unsupported operand type(s) for 'in': '%s' and '%s'" % (
|
"unsupported operand type(s) for 'in': '%s' and '%s'" % (
|
||||||
|
@ -789,6 +853,9 @@ class Flag(Enum):
|
||||||
return other._value_ & self._value_ == other._value_
|
return other._value_ & self._value_ == other._value_
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
|
"""
|
||||||
|
Returns flags in decreasing value order.
|
||||||
|
"""
|
||||||
members, extra_flags = _decompose(self.__class__, self.value)
|
members, extra_flags = _decompose(self.__class__, self.value)
|
||||||
return (m for m in members if m._value_ != 0)
|
return (m for m in members if m._value_ != 0)
|
||||||
|
|
||||||
|
@ -844,10 +911,15 @@ class Flag(Enum):
|
||||||
|
|
||||||
|
|
||||||
class IntFlag(int, Flag):
|
class IntFlag(int, Flag):
|
||||||
"""Support for integer-based Flags"""
|
"""
|
||||||
|
Support for integer-based Flags
|
||||||
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _missing_(cls, value):
|
def _missing_(cls, value):
|
||||||
|
"""
|
||||||
|
Returns member (possibly creating it) if one can be found for value.
|
||||||
|
"""
|
||||||
if not isinstance(value, int):
|
if not isinstance(value, int):
|
||||||
raise ValueError("%r is not a valid %s" % (value, cls.__qualname__))
|
raise ValueError("%r is not a valid %s" % (value, cls.__qualname__))
|
||||||
new_member = cls._create_pseudo_member_(value)
|
new_member = cls._create_pseudo_member_(value)
|
||||||
|
@ -855,6 +927,9 @@ class IntFlag(int, Flag):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _create_pseudo_member_(cls, value):
|
def _create_pseudo_member_(cls, value):
|
||||||
|
"""
|
||||||
|
Create a composite member iff value contains only members.
|
||||||
|
"""
|
||||||
pseudo_member = cls._value2member_map_.get(value, None)
|
pseudo_member = cls._value2member_map_.get(value, None)
|
||||||
if pseudo_member is None:
|
if pseudo_member is None:
|
||||||
need_to_create = [value]
|
need_to_create = [value]
|
||||||
|
@ -909,11 +984,15 @@ class IntFlag(int, Flag):
|
||||||
|
|
||||||
|
|
||||||
def _high_bit(value):
|
def _high_bit(value):
|
||||||
"""returns index of highest bit, or -1 if value is zero or negative"""
|
"""
|
||||||
|
returns index of highest bit, or -1 if value is zero or negative
|
||||||
|
"""
|
||||||
return value.bit_length() - 1
|
return value.bit_length() - 1
|
||||||
|
|
||||||
def unique(enumeration):
|
def unique(enumeration):
|
||||||
"""Class decorator for enumerations ensuring unique member values."""
|
"""
|
||||||
|
Class decorator for enumerations ensuring unique member values.
|
||||||
|
"""
|
||||||
duplicates = []
|
duplicates = []
|
||||||
for name, member in enumeration.__members__.items():
|
for name, member in enumeration.__members__.items():
|
||||||
if name != member.name:
|
if name != member.name:
|
||||||
|
@ -926,7 +1005,9 @@ def unique(enumeration):
|
||||||
return enumeration
|
return enumeration
|
||||||
|
|
||||||
def _decompose(flag, value):
|
def _decompose(flag, value):
|
||||||
"""Extract all members from the value."""
|
"""
|
||||||
|
Extract all members from the value.
|
||||||
|
"""
|
||||||
# _decompose is only called if the value is not named
|
# _decompose is only called if the value is not named
|
||||||
not_covered = value
|
not_covered = value
|
||||||
negative = value < 0
|
negative = value < 0
|
||||||
|
|
|
@ -429,7 +429,7 @@ class TestEnum(unittest.TestCase):
|
||||||
def test_reserved__sunder_(self):
|
def test_reserved__sunder_(self):
|
||||||
with self.assertRaisesRegex(
|
with self.assertRaisesRegex(
|
||||||
ValueError,
|
ValueError,
|
||||||
'_sunder_ names, such as "_bad_", are reserved',
|
"_sunder_ names, such as '_bad_', are reserved",
|
||||||
):
|
):
|
||||||
class Bad(Enum):
|
class Bad(Enum):
|
||||||
_bad_ = 1
|
_bad_ = 1
|
||||||
|
|
Loading…
Reference in New Issue