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

Skip to content

gh-93910: [Enum] remove member.member deprecation #103236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions Doc/howto/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -988,12 +988,11 @@ but remain normal attributes.
""""""""""""""""""""

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

.. versionchanged:: 3.5
.. versionchanged:: 3.12


Creating members that are mixed with other data types
Expand Down
50 changes: 25 additions & 25 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,23 +201,13 @@ def __get__(self, instance, ownerclass=None):
)
else:
if self.fget is None:
if self.member is None: # not sure this can happen, but just in case
# 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)
)
# issue warning deprecating this behavior
import warnings
warnings.warn(
"`member.member` access (e.g. `Color.RED.BLUE`) is "
"deprecated and will be removed in 3.14.",
DeprecationWarning,
stacklevel=2,
)
return self.member
# XXX: uncomment in 3.14 and remove warning above
# raise AttributeError(
# '%r member has no attribute %r' % (ownerclass, self.name)
# )
else:
return self.fget(instance)

Expand Down Expand Up @@ -314,22 +304,32 @@ def __set_name__(self, enum_class, member_name):
):
# no other instances found, record this member in _member_names_
enum_class._member_names_.append(member_name)
# get redirect in place before adding to _member_map_
# but check for other instances in parent classes first
descriptor = None
# if necessary, get redirect in place and then add it to _member_map_
found_descriptor = 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
break
redirect = property()
redirect.member = enum_member
redirect.__set_name__(enum_class, member_name)
if descriptor:
redirect.fget = getattr(descriptor, 'fget', None)
redirect.fset = getattr(descriptor, 'fset', None)
redirect.fdel = getattr(descriptor, 'fdel', None)
setattr(enum_class, member_name, redirect)
elif (
hasattr(descriptor, 'fget') and
hasattr(descriptor, 'fset') and
hasattr(descriptor, 'fdel')
):
found_descriptor = descriptor
continue
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
setattr(enum_class, member_name, redirect)
else:
setattr(enum_class, member_name, enum_member)
# now add to _member_map_ (even aliases)
enum_class._member_map_[member_name] = enum_member
try:
Expand Down
29 changes: 8 additions & 21 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -2686,28 +2686,15 @@ class Private(Enum):
self.assertEqual(Private._Private__corporal, 'Radar')
self.assertEqual(Private._Private__major_, 'Hoolihan')

@unittest.skipIf(
python_version <= (3, 13),
'member.member access currently deprecated',
)
def test_exception_for_member_from_member_access(self):
with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
class Di(Enum):
YES = 1
NO = 0
nope = Di.YES.NO

@unittest.skipIf(
python_version > (3, 13),
'member.member access now raises',
)
def test_warning_for_member_from_member_access(self):
with self.assertWarnsRegex(DeprecationWarning, '`member.member` access .* is deprecated and will be removed in 3.14'):
class Di(Enum):
YES = 1
NO = 0
warn = Di.YES.NO
def test_member_from_member_access(self):
class Di(Enum):
YES = 1
NO = 0
name = 3
warn = Di.YES.NO
self.assertIs(warn, Di.NO)
self.assertIs(Di.name, Di['name'])
self.assertEqual(Di.name.name, 'name')

def test_dynamic_members_with_static_methods(self):
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove deprecation of enum ``memmber.member`` access.