aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/enum.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.com>2024-02-12 07:53:52 +0300
committerDaniil Cherednik <dcherednik@ydb.tech>2024-02-14 14:26:16 +0000
commit31f2a419764a8ba77c2a970cfc80056c6cd06756 (patch)
treec1995d239eba8571cefc640f6648e1d5dd4ce9e2 /contrib/tools/python3/src/Lib/enum.py
parentfe2ef02b38d9c85d80060963b265a1df9f38c3bb (diff)
downloadydb-31f2a419764a8ba77c2a970cfc80056c6cd06756.tar.gz
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Lib/enum.py')
-rw-r--r--contrib/tools/python3/src/Lib/enum.py257
1 files changed, 146 insertions, 111 deletions
diff --git a/contrib/tools/python3/src/Lib/enum.py b/contrib/tools/python3/src/Lib/enum.py
index 63833aaa71..1502bfe915 100644
--- a/contrib/tools/python3/src/Lib/enum.py
+++ b/contrib/tools/python3/src/Lib/enum.py
@@ -190,41 +190,48 @@ class property(DynamicClassAttribute):
a corresponding enum member.
"""
+ member = None
+ _attr_type = None
+ _cls_type = None
+
def __get__(self, instance, ownerclass=None):
if instance is None:
- try:
- return ownerclass._member_map_[self.name]
- except KeyError:
+ if self.member is not None:
+ return self.member
+ else:
raise AttributeError(
'%r has no attribute %r' % (ownerclass, self.name)
)
- else:
- if self.fget is None:
- # look for a member by this name.
- try:
- return ownerclass._member_map_[self.name]
- except KeyError:
- raise AttributeError(
- '%r has no attribute %r' % (ownerclass, self.name)
- ) from None
- else:
- return self.fget(instance)
+ if self.fget is not None:
+ # use previous enum.property
+ return self.fget(instance)
+ elif self._attr_type == 'attr':
+ # look up previous attibute
+ return getattr(self._cls_type, self.name)
+ elif self._attr_type == 'desc':
+ # use previous descriptor
+ return getattr(instance._value_, self.name)
+ # look for a member by this name.
+ try:
+ return ownerclass._member_map_[self.name]
+ except KeyError:
+ raise AttributeError(
+ '%r has no attribute %r' % (ownerclass, self.name)
+ ) from None
def __set__(self, instance, value):
- if self.fset is None:
- raise AttributeError(
- "<enum %r> cannot set attribute %r" % (self.clsname, self.name)
- )
- else:
+ if self.fset is not None:
return self.fset(instance, value)
+ raise AttributeError(
+ "<enum %r> cannot set attribute %r" % (self.clsname, self.name)
+ )
def __delete__(self, instance):
- if self.fdel is None:
- raise AttributeError(
- "<enum %r> cannot delete attribute %r" % (self.clsname, self.name)
- )
- else:
+ if self.fdel is not None:
return self.fdel(instance)
+ raise AttributeError(
+ "<enum %r> cannot delete attribute %r" % (self.clsname, self.name)
+ )
def __set_name__(self, ownerclass, name):
self.name = name
@@ -312,27 +319,38 @@ class _proto_member:
enum_class._member_names_.append(member_name)
# if necessary, get redirect in place and then add it to _member_map_
found_descriptor = None
+ descriptor_type = None
+ class_type = None
for base in enum_class.__mro__[1:]:
- descriptor = base.__dict__.get(member_name)
- if descriptor is not None:
- if isinstance(descriptor, (property, DynamicClassAttribute)):
- found_descriptor = descriptor
+ attr = base.__dict__.get(member_name)
+ if attr is not None:
+ if isinstance(attr, (property, DynamicClassAttribute)):
+ found_descriptor = attr
+ class_type = base
+ descriptor_type = 'enum'
break
- elif (
- hasattr(descriptor, 'fget') and
- hasattr(descriptor, 'fset') and
- hasattr(descriptor, 'fdel')
- ):
- found_descriptor = descriptor
+ elif _is_descriptor(attr):
+ found_descriptor = attr
+ descriptor_type = descriptor_type or 'desc'
+ class_type = class_type or base
continue
+ else:
+ descriptor_type = 'attr'
+ class_type = base
if found_descriptor:
redirect = property()
redirect.member = enum_member
redirect.__set_name__(enum_class, member_name)
- # earlier descriptor found; copy fget, fset, fdel to this one.
- redirect.fget = found_descriptor.fget
- redirect.fset = found_descriptor.fset
- redirect.fdel = found_descriptor.fdel
+ if descriptor_type in ('enum','desc'):
+ # earlier descriptor found; copy fget, fset, fdel to this one.
+ redirect.fget = getattr(found_descriptor, 'fget', None)
+ redirect._get = getattr(found_descriptor, '__get__', None)
+ redirect.fset = getattr(found_descriptor, 'fset', None)
+ redirect._set = getattr(found_descriptor, '__set__', None)
+ redirect.fdel = getattr(found_descriptor, 'fdel', None)
+ redirect._del = getattr(found_descriptor, '__delete__', None)
+ redirect._attr_type = descriptor_type
+ redirect._cls_type = class_type
setattr(enum_class, member_name, redirect)
else:
setattr(enum_class, member_name, enum_member)
@@ -521,8 +539,13 @@ class EnumType(type):
#
# adjust the sunders
_order_ = classdict.pop('_order_', None)
+ _gnv = classdict.get('_generate_next_value_')
+ if _gnv is not None and type(_gnv) is not staticmethod:
+ _gnv = staticmethod(_gnv)
# convert to normal dict
classdict = dict(classdict.items())
+ if _gnv is not None:
+ classdict['_generate_next_value_'] = _gnv
#
# data type of member and the controlling Enum class
member_type, first_enum = metacls._get_mixins_(cls, bases)
@@ -558,12 +581,16 @@ class EnumType(type):
try:
exc = None
enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
- except RuntimeError as e:
- # any exceptions raised by member.__new__ will get converted to a
- # RuntimeError, so get that original exception back and raise it instead
- exc = e.__cause__ or e
+ except Exception as e:
+ # since 3.12 the line "Error calling __set_name__ on '_proto_member' instance ..."
+ # is tacked on to the error instead of raising a RuntimeError
+ # recreate the exception to discard
+ exc = type(e)(str(e))
+ exc.__cause__ = e.__cause__
+ exc.__context__ = e.__context__
+ tb = e.__traceback__
if exc is not None:
- raise exc
+ raise exc.with_traceback(tb)
#
# update classdict with any changes made by __init_subclass__
classdict.update(enum_class.__dict__)
@@ -674,7 +701,7 @@ class EnumType(type):
'member order does not match _order_:\n %r\n %r'
% (enum_class._member_names_, _order_)
)
-
+ #
return enum_class
def __bool__(cls):
@@ -683,7 +710,7 @@ class EnumType(type):
"""
return True
- def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None):
+ def __call__(cls, value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None):
"""
Either returns an existing member, or creates a new enum class.
@@ -691,6 +718,8 @@ class EnumType(type):
to an enumeration member (i.e. Color(3)) and for the functional API
(i.e. Color = Enum('Color', names='RED GREEN BLUE')).
+ The value lookup branch is chosen if the enum is final.
+
When used for the functional API:
`value` will be the name of the new class.
@@ -708,12 +737,20 @@ class EnumType(type):
`type`, if set, will be mixed in as the first base class.
"""
- if names is None: # simple value lookup
+ if cls._member_map_:
+ # simple value lookup if members exist
+ if names:
+ value = (value, names) + values
return cls.__new__(cls, value)
# otherwise, functional API: we're creating a new Enum type
+ if names is None and type is None:
+ # no body? no data-type? possibly wrong usage
+ raise TypeError(
+ f"{cls} has no members; specify `names=()` if you meant to create a new, empty, enum"
+ )
return cls._create_(
- value,
- names,
+ class_name=value,
+ names=names,
module=module,
qualname=qualname,
type=type,
@@ -721,26 +758,16 @@ class EnumType(type):
boundary=boundary,
)
- def __contains__(cls, member):
- """
- Return True if member is a member of this enum
- raises TypeError if member is not an enum member
+ def __contains__(cls, value):
+ """Return True if `value` is in `cls`.
- 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
+ `value` is in `cls` if:
+ 1) `value` is a member of `cls`, or
+ 2) `value` is the value of one of the `cls`'s members.
"""
- if not isinstance(member, Enum):
- import warnings
- warnings.warn(
- "in 3.12 __contains__ will no longer raise TypeError, but will return True or\n"
- "False depending on whether the value is a member or the value of a member",
- DeprecationWarning,
- stacklevel=2,
- )
- raise TypeError(
- "unsupported operand type(s) for 'in': '%s' and '%s'" % (
- type(member).__qualname__, cls.__class__.__qualname__))
- return isinstance(member, cls) and member._name_ in cls._member_map_
+ if isinstance(value, cls):
+ return True
+ return value in cls._value2member_map_ or value in cls._unhashable_values_
def __delattr__(cls, attr):
# nicer error message when someone tries to delete an attribute
@@ -767,22 +794,6 @@ class EnumType(type):
# return whatever mixed-in data type has
return sorted(set(dir(cls._member_type_)) | interesting)
- def __getattr__(cls, name):
- """
- Return the enum member matching `name`
-
- We use __getattr__ instead of descriptors or inserting into the enum
- class' __dict__ in order to support `name` and `value` being both
- properties for enum members (which live in the class' __dict__) and
- enum members themselves.
- """
- if _is_dunder(name):
- raise AttributeError(name)
- try:
- return cls._member_map_[name]
- except KeyError:
- raise AttributeError(name) from None
-
def __getitem__(cls, name):
"""
Return the member matching `name`.
@@ -874,13 +885,15 @@ class EnumType(type):
member_name, member_value = item
classdict[member_name] = member_value
- # TODO: replace the frame hack if a blessed way to know the calling
- # module is ever developed
if module is None:
try:
- module = sys._getframe(2).f_globals['__name__']
- except (AttributeError, ValueError, KeyError):
- pass
+ module = sys._getframemodulename(2)
+ except AttributeError:
+ # Fall back on _getframe if _getframemodulename is missing
+ try:
+ module = sys._getframe(2).f_globals['__name__']
+ except (AttributeError, ValueError, KeyError):
+ pass
if module is None:
_make_class_unpicklable(classdict)
else:
@@ -948,9 +961,6 @@ class EnumType(type):
"""
if not bases:
return object, Enum
-
- mcls._check_for_existing_members_(class_name, bases)
-
# ensure final parent class is an Enum derivative, find any concrete
# data type, and check that Enum has no members
first_enum = bases[-1]
@@ -971,12 +981,20 @@ class EnumType(type):
return base._value_repr_
elif '__repr__' in base.__dict__:
# this is our data repr
- return base.__dict__['__repr__']
+ # double-check if a dataclass with a default __repr__
+ if (
+ '__dataclass_fields__' in base.__dict__
+ and '__dataclass_params__' in base.__dict__
+ and base.__dict__['__dataclass_params__'].repr
+ ):
+ return _dataclass_repr
+ else:
+ return base.__dict__['__repr__']
return None
@classmethod
def _find_data_type_(mcls, class_name, bases):
- # a datatype has a __new__ method
+ # a datatype has a __new__ method, or a __dataclass_fields__ attribute
data_types = set()
base_chain = set()
for chain in bases:
@@ -990,8 +1008,6 @@ class EnumType(type):
data_types.add(base._member_type_)
break
elif '__new__' in base.__dict__ or '__dataclass_fields__' in base.__dict__:
- if isinstance(base, EnumType):
- continue
data_types.add(candidate or base)
break
else:
@@ -1063,20 +1079,20 @@ class Enum(metaclass=EnumType):
Access them by:
- - attribute access::
+ - attribute access:
- >>> Color.RED
- <Color.RED: 1>
+ >>> Color.RED
+ <Color.RED: 1>
- value lookup:
- >>> Color(1)
- <Color.RED: 1>
+ >>> Color(1)
+ <Color.RED: 1>
- name lookup:
- >>> Color['RED']
- <Color.RED: 1>
+ >>> Color['RED']
+ <Color.RED: 1>
Enumerations can be iterated over, and know how many members they have:
@@ -1090,6 +1106,13 @@ class Enum(metaclass=EnumType):
attributes -- see the documentation for details.
"""
+ @classmethod
+ def __signature__(cls):
+ if cls._member_names_:
+ return '(*values)'
+ else:
+ return '(new_class_name, /, names, *, module=None, qualname=None, type=None, start=1, boundary=None)'
+
def __new__(cls, value):
# all enum instances are actually created during class construction
# without calling this method; this method is called by the metaclass'
@@ -1149,6 +1172,7 @@ class Enum(metaclass=EnumType):
def __init__(self, *args, **kwds):
pass
+ @staticmethod
def _generate_next_value_(name, start, count, last_values):
"""
Generate the next value when not given.
@@ -1242,10 +1266,10 @@ class Enum(metaclass=EnumType):
# enum.property is used to provide access to the `name` and
# `value` attributes of enum members while keeping some measure of
# protection from modification, while still allowing for an enumeration
- # to have members named `name` and `value`. This works because enumeration
- # members are not set directly on the enum class; they are kept in a
- # separate structure, _member_map_, which is where enum.property looks for
- # them
+ # to have members named `name` and `value`. This works because each
+ # instance of enum.property saves its companion member, which it returns
+ # on class lookup; on instance lookup it either executes a provided function
+ # or raises an AttributeError.
@property
def name(self):
@@ -1296,6 +1320,7 @@ class StrEnum(str, ReprEnum):
member._value_ = value
return member
+ @staticmethod
def _generate_next_value_(name, start, count, last_values):
"""
Return the lower-cased version of the member name.
@@ -1334,6 +1359,7 @@ class Flag(Enum, boundary=STRICT):
_numeric_repr_ = repr
+ @staticmethod
def _generate_next_value_(name, start, count, last_values):
"""
Generate the next value when not given.
@@ -1572,10 +1598,13 @@ def unique(enumeration):
(enumeration, alias_details))
return enumeration
-def _power_of_two(value):
- if value < 1:
- return False
- return value == 2 ** _high_bit(value)
+def _dataclass_repr(self):
+ dcf = self.__dataclass_fields__
+ return ', '.join(
+ '%s=%r' % (k, getattr(self, k))
+ for k in dcf.keys()
+ if dcf[k].repr
+ )
def global_enum_repr(self):
"""
@@ -1719,10 +1748,12 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
value = gnv(name, 1, len(member_names), gnv_last_values)
if value in value2member_map:
# an alias to an existing member
+ member = value2member_map[value]
redirect = property()
+ redirect.member = member
redirect.__set_name__(enum_class, name)
setattr(enum_class, name, redirect)
- member_map[name] = value2member_map[value]
+ member_map[name] = member
else:
# create the member
if use_args:
@@ -1738,6 +1769,7 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
member.__objclass__ = enum_class
member.__init__(value)
redirect = property()
+ redirect.member = member
redirect.__set_name__(enum_class, name)
setattr(enum_class, name, redirect)
member_map[name] = member
@@ -1766,10 +1798,12 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
value = value.value
if value in value2member_map:
# an alias to an existing member
+ member = value2member_map[value]
redirect = property()
+ redirect.member = member
redirect.__set_name__(enum_class, name)
setattr(enum_class, name, redirect)
- member_map[name] = value2member_map[value]
+ member_map[name] = member
else:
# create the member
if use_args:
@@ -1786,6 +1820,7 @@ def _simple_enum(etype=Enum, *, boundary=None, use_args=None):
member.__init__(value)
member._sort_order_ = len(member_names)
redirect = property()
+ redirect.member = member
redirect.__set_name__(enum_class, name)
setattr(enum_class, name, redirect)
member_map[name] = member