Skip to content

Commit

Permalink
bpo-43162: [Enum] deprecate enum member.member access (GH-24486)
Browse files Browse the repository at this point in the history
In 3.5 (?) a speed optimization made it possible to access members as
attributes of other members, i.e. ``Color.RED.BLUE``.  This was always
discouraged in the docs, and other recent optimizations has made that
one no longer necessary.  Because some may be relying on it anyway, it
is being deprecated in 3.10, and will be removed in 3.11.
  • Loading branch information
ethanfurman authored Feb 9, 2021
1 parent e1f7769 commit d65b903
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
18 changes: 14 additions & 4 deletions Lib/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,28 +139,38 @@ def __get__(self, instance, ownerclass=None):
return ownerclass._member_map_[self.name]
except KeyError:
raise AttributeError(
'%s: no attribute %r' % (ownerclass.__name__, self.name)
'%s: no class attribute %r' % (ownerclass.__name__, self.name)
)
else:
if self.fget is None:
# check for member
if self.name in ownerclass._member_map_:
import warnings
warnings.warn(
"accessing one member from another is not supported, "
" and will be disabled in 3.11",
DeprecationWarning,
stacklevel=2,
)
return ownerclass._member_map_[self.name]
raise AttributeError(
'%s: no attribute %r' % (ownerclass.__name__, self.name)
'%s: no instance attribute %r' % (ownerclass.__name__, self.name)
)
else:
return self.fget(instance)

def __set__(self, instance, value):
if self.fset is None:
raise AttributeError(
"%s: cannot set attribute %r" % (self.clsname, self.name)
"%s: cannot set instance attribute %r" % (self.clsname, self.name)
)
else:
return self.fset(instance, value)

def __delete__(self, instance):
if self.fdel is None:
raise AttributeError(
"%s: cannot delete attribute %r" % (self.clsname, self.name)
"%s: cannot delete instance attribute %r" % (self.clsname, self.name)
)
else:
return self.fdel(instance)
Expand Down
23 changes: 23 additions & 0 deletions Lib/test/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -2185,6 +2185,29 @@ class Private(Enum):
self.assertEqual(Private._Private__corporal, 'Radar')
self.assertEqual(Private._Private__major_, 'Hoolihan')

@unittest.skipUnless(
sys.version_info[:2] == (3, 10),
'member-member access now raises an exception',
)
def test_warning_for_member_from_member_access(self):
with self.assertWarns(DeprecationWarning):
class Di(Enum):
YES = 1
NO = 0
nope = Di.YES.NO
self.assertIs(Di.NO, nope)

@unittest.skipUnless(
sys.version_info[:2] > (3, 10),
'member-member access currently issues a warning',
)
def test_exception_for_member_from_member_access(self):
with self.assertRaisesRegex(AttributeError, "Di: no instance attribute .NO."):
class Di(Enum):
YES = 1
NO = 0
nope = Di.YES.NO

def test_strenum_auto(self):
class Strings(StrEnum):
ONE = auto()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
deprecate unsupported ability to access enum members as attributes of other
enum members

0 comments on commit d65b903

Please sign in to comment.