diff --git a/Lib/enum.py b/Lib/enum.py index d4b11521ab27..55299c578824 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -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) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 96de878faf72..3982d1d64304 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -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() diff --git a/Misc/NEWS.d/next/Library/2021-02-08-16-27-00.bpo-43162.t-W7h3.rst b/Misc/NEWS.d/next/Library/2021-02-08-16-27-00.bpo-43162.t-W7h3.rst new file mode 100644 index 000000000000..fef5915e762e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-02-08-16-27-00.bpo-43162.t-W7h3.rst @@ -0,0 +1,2 @@ +deprecate unsupported ability to access enum members as attributes of other +enum members