Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 22758a3

Browse files
Merge branch 'main' into per-interpreter-alloc
2 parents df77a64 + 03089fd commit 22758a3

File tree

4 files changed

+37
-50
lines changed

4 files changed

+37
-50
lines changed

Doc/howto/enum.rst

+3-4
Original file line numberDiff line numberDiff line change
@@ -988,12 +988,11 @@ but remain normal attributes.
988988
""""""""""""""""""""
989989

990990
Enum members are instances of their enum class, and are normally accessed as
991-
``EnumClass.member``. In Python versions starting with ``3.5`` you could access
992-
members from other members -- this practice is discouraged, is deprecated
993-
in ``3.12``, and will be removed in ``3.14``.
991+
``EnumClass.member``. In certain situations, such as writing custom enum
992+
behavior, being able to access one member directly from another is useful,
993+
and is supported.
994994

995995
.. versionchanged:: 3.5
996-
.. versionchanged:: 3.12
997996

998997

999998
Creating members that are mixed with other data types

Lib/enum.py

+25-25
Original file line numberDiff line numberDiff line change
@@ -201,23 +201,13 @@ def __get__(self, instance, ownerclass=None):
201201
)
202202
else:
203203
if self.fget is None:
204-
if self.member is None: # not sure this can happen, but just in case
204+
# look for a member by this name.
205+
try:
206+
return ownerclass._member_map_[self.name]
207+
except KeyError:
205208
raise AttributeError(
206209
'%r has no attribute %r' % (ownerclass, self.name)
207210
)
208-
# issue warning deprecating this behavior
209-
import warnings
210-
warnings.warn(
211-
"`member.member` access (e.g. `Color.RED.BLUE`) is "
212-
"deprecated and will be removed in 3.14.",
213-
DeprecationWarning,
214-
stacklevel=2,
215-
)
216-
return self.member
217-
# XXX: uncomment in 3.14 and remove warning above
218-
# raise AttributeError(
219-
# '%r member has no attribute %r' % (ownerclass, self.name)
220-
# )
221211
else:
222212
return self.fget(instance)
223213

@@ -314,22 +304,32 @@ def __set_name__(self, enum_class, member_name):
314304
):
315305
# no other instances found, record this member in _member_names_
316306
enum_class._member_names_.append(member_name)
317-
# get redirect in place before adding to _member_map_
318-
# but check for other instances in parent classes first
319-
descriptor = None
307+
# if necessary, get redirect in place and then add it to _member_map_
308+
found_descriptor = None
320309
for base in enum_class.__mro__[1:]:
321310
descriptor = base.__dict__.get(member_name)
322311
if descriptor is not None:
323312
if isinstance(descriptor, (property, DynamicClassAttribute)):
313+
found_descriptor = descriptor
324314
break
325-
redirect = property()
326-
redirect.member = enum_member
327-
redirect.__set_name__(enum_class, member_name)
328-
if descriptor:
329-
redirect.fget = getattr(descriptor, 'fget', None)
330-
redirect.fset = getattr(descriptor, 'fset', None)
331-
redirect.fdel = getattr(descriptor, 'fdel', None)
332-
setattr(enum_class, member_name, redirect)
315+
elif (
316+
hasattr(descriptor, 'fget') and
317+
hasattr(descriptor, 'fset') and
318+
hasattr(descriptor, 'fdel')
319+
):
320+
found_descriptor = descriptor
321+
continue
322+
if found_descriptor:
323+
redirect = property()
324+
redirect.member = enum_member
325+
redirect.__set_name__(enum_class, member_name)
326+
# earlier descriptor found; copy fget, fset, fdel to this one.
327+
redirect.fget = found_descriptor.fget
328+
redirect.fset = found_descriptor.fset
329+
redirect.fdel = found_descriptor.fdel
330+
setattr(enum_class, member_name, redirect)
331+
else:
332+
setattr(enum_class, member_name, enum_member)
333333
# now add to _member_map_ (even aliases)
334334
enum_class._member_map_[member_name] = enum_member
335335
try:

Lib/test/test_enum.py

+8-21
Original file line numberDiff line numberDiff line change
@@ -2686,28 +2686,15 @@ class Private(Enum):
26862686
self.assertEqual(Private._Private__corporal, 'Radar')
26872687
self.assertEqual(Private._Private__major_, 'Hoolihan')
26882688

2689-
@unittest.skipIf(
2690-
python_version <= (3, 13),
2691-
'member.member access currently deprecated',
2692-
)
2693-
def test_exception_for_member_from_member_access(self):
2694-
with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
2695-
class Di(Enum):
2696-
YES = 1
2697-
NO = 0
2698-
nope = Di.YES.NO
2699-
2700-
@unittest.skipIf(
2701-
python_version > (3, 13),
2702-
'member.member access now raises',
2703-
)
2704-
def test_warning_for_member_from_member_access(self):
2705-
with self.assertWarnsRegex(DeprecationWarning, '`member.member` access .* is deprecated and will be removed in 3.14'):
2706-
class Di(Enum):
2707-
YES = 1
2708-
NO = 0
2709-
warn = Di.YES.NO
2689+
def test_member_from_member_access(self):
2690+
class Di(Enum):
2691+
YES = 1
2692+
NO = 0
2693+
name = 3
2694+
warn = Di.YES.NO
27102695
self.assertIs(warn, Di.NO)
2696+
self.assertIs(Di.name, Di['name'])
2697+
self.assertEqual(Di.name.name, 'name')
27112698

27122699
def test_dynamic_members_with_static_methods(self):
27132700
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove deprecation of enum ``memmber.member`` access.

0 commit comments

Comments
 (0)