You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Enum regression: AttributeError when accessing class variables on instances #87328
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee='https://github.com/ethanfurman'closed_at=<Date2021-03-03.19:42:57.050>created_at=<Date2021-02-08.12:22:59.718>labels= ['type-bug', 'library', '3.10']
title='Enum regression: AttributeError when accessing class variables on instances'updated_at=<Date2021-03-03.22:22:26.284>user='https://github.com/hroncok'
AttributeError: TestProtocol: no attribute 'EXITCODE'
This worked with 3.10.0a4.
If this is a deliberate backwards incompatible change of behavior, I don't think it is documented in the changelog or what's new in Python 3.10, nor that it was deprecated in Python 3.9 and 3.8.
bpo-42901: [Enum] move member creation to `__set_name__` (GH-24196)
`type.__new__` calls `__set_name__` and `__init_subclass__`, which means
that any work metaclasses do after calling `super().__new__()` will not
be available to those two methods. In particular, `Enum` classes that
want to make use of `__init_subclass__` will not see any members.
Almost all customization is therefore moved to before the
`type.__new__()` call, including changing all members to a proto member
descriptor with a `__set_name__` that will do the final conversion of a
member to be an instance of the `Enum` class.
The code for that __str__ seems very inefficient -- why doesn't it just do:
returnself.name
?
-----
The issue is not being able to access class attributes, the issue is whether one enum member should be seen as an attribute of another:
EnumClass.RED.BLUE
and the answer is no. That wasn't possible when Enum was first introduced in 3.4, and was an unfortunate side-effect of speeding up member access in 3.5 (or 3.6). The docs have always warned against it.
A deprecation warning is an easier transition, though, so I'll do that for 3.10, and in 3.11 it will become an error.
Author of said meson code here. I use this pattern when the enum names and values are implementation details, but the string values are user visible. In this case the enum itself is used internally to represent what kind of test we're doing, but we're initializing it from user input. There might be reasons in the future that the names of the enum members and the string values being passed in aren't the same anymore, say because we map two string values to one enum value. I guess I could accomplish the same thing with a staticmethod or helper function, but the code is effectively an alternate initializer, and follows that pattern using a classmethod.
hroncok commented on Feb 9, 2021
hroncokmannequin
MannequinAuthor
More actions
Ethan, should the depreciation exist for 2 releases prior to removal?
Dylan, even in that case, I guess the proper way to access the other members is supposed to be type(self).FOO or ClassName.FOO, not self.FOO.
Activity
hroncok commentedon Feb 8, 2021
I believe I found a regression in Enum in Python 3.10.0a5.
This is Python 3.9:
The Enum instances can access class-attributes via dot, like normal instances do.
While in Python 3.10.0a5:
In real word situations, it breaks meson:
https://github.com/mesonbuild/meson/blob/398df5629863e913fa603cbf02c525a9f501f8a8/mesonbuild/backend/backends.py#L52-L78
The __str__ method does:
And it fails with:
This worked with 3.10.0a4.
If this is a deliberate backwards incompatible change of behavior, I don't think it is documented in the changelog or what's new in Python 3.10, nor that it was deprecated in Python 3.9 and 3.8.
hroncok commentedon Feb 8, 2021
Git bisect:
c314e60 is the first new commit
commit c314e60
Author: Ethan Furman <ethan@stoneleaf.us>
Date: Tue Jan 12 23:47:57 2021 -0800
Lib/enum.py | 297 +++++++++++++--------
Lib/inspect.py | 2 +-
Lib/test/test_enum.py | 15 +-
.../2021-01-11-17-36-59.bpo-42901.gFd-ta.rst | 3 +
4 files changed, 207 insertions(+), 110 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2021-01-11-17-36-59.bpo-42901.gFd-ta.rst
ethanfurman commentedon Feb 8, 2021
The code for that
__str__seems very inefficient -- why doesn't it just do:?
-----
The issue is not being able to access class attributes, the issue is whether one enum member should be seen as an attribute of another:
EnumClass.RED.BLUE
and the answer is no. That wasn't possible when Enum was first introduced in 3.4, and was an unfortunate side-effect of speeding up member access in 3.5 (or 3.6). The docs have always warned against it.
A deprecation warning is an easier transition, though, so I'll do that for 3.10, and in 3.11 it will become an error.
Thank you for reporting! :-)
hroncok commentedon Feb 8, 2021
Thanks. In the meantime, I've opened mesonbuild/meson#8318
bakerdylanc commentedon Feb 9, 2021
Author of said meson code here. I use this pattern when the enum names and values are implementation details, but the string values are user visible. In this case the enum itself is used internally to represent what kind of test we're doing, but we're initializing it from user input. There might be reasons in the future that the names of the enum members and the string values being passed in aren't the same anymore, say because we map two string values to one enum value. I guess I could accomplish the same thing with a staticmethod or helper function, but the code is effectively an alternate initializer, and follows that pattern using a classmethod.
hroncok commentedon Feb 9, 2021
Ethan, should the depreciation exist for 2 releases prior to removal?
Dylan, even in that case, I guess the proper way to access the other members is supposed to be type(self).FOO or ClassName.FOO, not self.FOO.
ethanfurman commentedon Feb 9, 2021
New changeset d65b903 by Ethan Furman in branch 'master':
bpo-43162: [Enum] deprecate enum member.member access (GH-24486)
d65b903
ethanfurman commentedon Feb 9, 2021
Dylan, it's not the
from_str()method, but the__str__method that is the problem. Instead ofit should be
hroncok commentedon Feb 9, 2021
"Wait for the warning to appear in at least two major Python versions. It's fine to wait more than two releases."
https://www.python.org/dev/peps/pep-0387/#basic-policy-for-backwards-compatibility
So indeed, if you add the warning in 3.10, the behavior can be removed from 3.12 earliest.
ethanfurman commentedon Mar 2, 2021
DeprecationWarning will be active in 3.10 and 3.11 with removal in 3.12.
ethanfurman commentedon Mar 3, 2021
New changeset 44e580f by Ethan Furman in branch 'master':
bpo-43162: [Enum] update docs, renable doc tests (GH-24487)
44e580f
hroncok commentedon Mar 3, 2021
Thank you, Ethan.
ethanfurman commentedon Mar 3, 2021
You're welcome. Thank you for pushing the issue! :-)