bpo-44559: [Enum] restore fixes lost in 3.9 reversion (GH-29114)

- fix exception leaks
- re-add deprecation warnings
This commit is contained in:
Ethan Furman 2021-10-20 19:48:37 -07:00 committed by GitHub
parent 64e83c711e
commit 2a9ab75af3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 194 additions and 42 deletions

View file

@ -44,10 +44,11 @@ def _is_sunder(name):
def _is_private(cls_name, name):
# do not use `re` as `re` imports `enum`
pattern = '_%s__' % (cls_name, )
pat_len = len(pattern)
if (
len(name) >= 5
len(name) > pat_len
and name.startswith(pattern)
and name[len(pattern)] != '_'
and name[pat_len:pat_len+1] != ['_']
and (name[-1] != '_' or name[-2] != '_')
):
return True
@ -392,12 +393,19 @@ def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, s
start=start,
)
def __contains__(cls, member):
if not isinstance(member, Enum):
def __contains__(cls, obj):
if not isinstance(obj, Enum):
import warnings
warnings.warn(
"in 3.12 __contains__ will no longer raise TypeError, but will return True if\n"
"obj is a member or a member's value",
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_
type(obj).__qualname__, cls.__class__.__qualname__))
return isinstance(obj, cls) and obj._name_ in cls._member_map_
def __delattr__(cls, attr):
# nicer error message when someone tries to delete an attribute
@ -580,7 +588,7 @@ def _get_mixins_(class_name, bases):
return object, Enum
def _find_data_type(bases):
data_types = []
data_types = set()
for chain in bases:
candidate = None
for base in chain.__mro__:
@ -588,19 +596,19 @@ def _find_data_type(bases):
continue
elif issubclass(base, Enum):
if base._member_type_ is not object:
data_types.append(base._member_type_)
data_types.add(base._member_type_)
break
elif '__new__' in base.__dict__:
if issubclass(base, Enum):
continue
data_types.append(candidate or base)
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[0]
return data_types.pop()
else:
return None
@ -693,19 +701,25 @@ def __new__(cls, value):
except Exception as e:
exc = e
result = None
if isinstance(result, cls):
return result
else:
ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
if result is None and exc is None:
raise ve_exc
elif exc is None:
exc = TypeError(
'error in %s._missing_: returned %r instead of None or a valid member'
% (cls.__name__, result)
)
exc.__context__ = ve_exc
raise exc
try:
if isinstance(result, cls):
return result
else:
ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
if result is None and exc is None:
raise ve_exc
elif exc is None:
exc = TypeError(
'error in %s._missing_: returned %r instead of None or a valid member'
% (cls.__name__, result)
)
if not isinstance(exc, ValueError):
exc.__context__ = ve_exc
raise exc
finally:
# ensure all variables that could hold an exception are destroyed
exc = None
ve_exc = None
def _generate_next_value_(name, start, count, last_values):
"""