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

Skip to content

Commit 58e330a

Browse files
authored
[3.11] gh-93910: [Enum] remove member.member deprecation (GH-103236) (GH-103299)
i.e. Color.RED.BLUE is now officially supported.. (cherry picked from commit 4ec8dd1) Co-authored-by: Ethan Furman <[email protected]>
1 parent 0291397 commit 58e330a

File tree

4 files changed

+36
-42
lines changed

4 files changed

+36
-42
lines changed

Doc/howto/enum.rst

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -960,23 +960,11 @@ but remain normal attributes.
960960
""""""""""""""""""""
961961

962962
Enum members are instances of their enum class, and are normally accessed as
963-
``EnumClass.member``. In Python versions ``3.5`` to ``3.10`` you could access
964-
members from other members -- this practice was discouraged, and in ``3.11``
965-
:class:`Enum` returns to not allowing it::
966-
967-
>>> class FieldTypes(Enum):
968-
... name = 0
969-
... value = 1
970-
... size = 2
971-
...
972-
>>> FieldTypes.value.size
973-
Traceback (most recent call last):
974-
...
975-
AttributeError: <enum 'FieldTypes'> member has no attribute 'size'
976-
963+
``EnumClass.member``. In certain situations, such as writing custom enum
964+
behavior, being able to access one member directly from another is useful,
965+
and is supported.
977966

978967
.. versionchanged:: 3.5
979-
.. versionchanged:: 3.11
980968

981969

982970
Creating members that are mixed with other data types

Lib/enum.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,13 @@ def __get__(self, instance, ownerclass=None):
199199
)
200200
else:
201201
if self.fget is None:
202-
raise AttributeError(
203-
'%r member has no attribute %r' % (ownerclass, self.name)
204-
)
202+
# look for a member by this name.
203+
try:
204+
return ownerclass._member_map_[self.name]
205+
except KeyError:
206+
raise AttributeError(
207+
'%r has no attribute %r' % (ownerclass, self.name)
208+
) from None
205209
else:
206210
return self.fget(instance)
207211

@@ -298,29 +302,29 @@ def __set_name__(self, enum_class, member_name):
298302
):
299303
# no other instances found, record this member in _member_names_
300304
enum_class._member_names_.append(member_name)
301-
# get redirect in place before adding to _member_map_
302-
# but check for other instances in parent classes first
303-
need_override = False
304-
descriptor = None
305+
# if necessary, get redirect in place and then add it to _member_map_
306+
found_descriptor = None
305307
for base in enum_class.__mro__[1:]:
306308
descriptor = base.__dict__.get(member_name)
307309
if descriptor is not None:
308310
if isinstance(descriptor, (property, DynamicClassAttribute)):
311+
found_descriptor = descriptor
309312
break
310-
else:
311-
need_override = True
312-
# keep looking for an enum.property
313-
if descriptor and not need_override:
314-
# previous enum.property found, no further action needed
315-
pass
316-
elif descriptor and need_override:
313+
elif (
314+
hasattr(descriptor, 'fget') and
315+
hasattr(descriptor, 'fset') and
316+
hasattr(descriptor, 'fdel')
317+
):
318+
found_descriptor = descriptor
319+
continue
320+
if found_descriptor:
317321
redirect = property()
322+
redirect.member = enum_member
318323
redirect.__set_name__(enum_class, member_name)
319-
# Previous enum.property found, but some other inherited attribute
320-
# is in the way; copy fget, fset, fdel to this one.
321-
redirect.fget = descriptor.fget
322-
redirect.fset = descriptor.fset
323-
redirect.fdel = descriptor.fdel
324+
# earlier descriptor found; copy fget, fset, fdel to this one.
325+
redirect.fget = found_descriptor.fget
326+
redirect.fset = found_descriptor.fset
327+
redirect.fdel = found_descriptor.fdel
324328
setattr(enum_class, member_name, redirect)
325329
else:
326330
setattr(enum_class, member_name, enum_member)

Lib/test/test_enum.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,14 +2621,15 @@ class Private(Enum):
26212621
self.assertEqual(Private._Private__corporal, 'Radar')
26222622
self.assertEqual(Private._Private__major_, 'Hoolihan')
26232623

2624-
@unittest.skip("Accessing all values retained for performance reasons, see GH-93910")
2625-
def test_exception_for_member_from_member_access(self):
2626-
with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
2627-
class Di(Enum):
2628-
YES = 1
2629-
NO = 0
2630-
nope = Di.YES.NO
2631-
2624+
def test_member_from_member_access(self):
2625+
class Di(Enum):
2626+
YES = 1
2627+
NO = 0
2628+
name = 3
2629+
warn = Di.YES.NO
2630+
self.assertIs(warn, Di.NO)
2631+
self.assertIs(Di.name, Di['name'])
2632+
self.assertEqual(Di.name.name, 'name')
26322633

26332634
def test_dynamic_members_with_static_methods(self):
26342635
#
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove deprecation of enum ``memmber.member`` access.

0 commit comments

Comments
 (0)