bpo-43162: [Enum] deprecate enum member.member access (GH-24486)

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.
This commit is contained in:
Ethan Furman 2021-02-08 17:32:38 -08:00 committed by GitHub
parent e1f7769513
commit d65b9033d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 4 deletions

View File

@ -139,12 +139,22 @@ class property(DynamicClassAttribute):
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)
@ -152,7 +162,7 @@ class property(DynamicClassAttribute):
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)
@ -160,7 +170,7 @@ class property(DynamicClassAttribute):
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)

View File

@ -2185,6 +2185,29 @@ class TestEnum(unittest.TestCase):
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()

View File

@ -0,0 +1,2 @@
deprecate unsupported ability to access enum members as attributes of other
enum members