-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
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
3.11.4: ValueError when inverting enum.Flag member with mask member #105497
Comments
Take a detour via .value if on Qt 6, because Python 3.11.4 seems to be unable to invert enum.Flag values with a mask set. Fixes #7735 See: - python/cpython#105497 - https://www.riverbankcomputing.com/pipermail/pyqt/2023-June/045323.html
…H-105542) When inverting a Flag member (or boundary STRICT), only consider other canonical flags; when inverting an IntFlag member (or boundary KEEP), also consider aliases.
…ist. (pythonGH-105542) When inverting a Flag member (or boundary STRICT), only consider other canonical flags; when inverting an IntFlag member (or boundary KEEP), also consider aliases. (cherry picked from commit 59f009e) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
…ist. (pythonGH-105542) When inverting a Flag member (or boundary STRICT), only consider other canonical flags; when inverting an IntFlag member (or boundary KEEP), also consider aliases. (cherry picked from commit 59f009e) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Thanks @ethanfurman for the quick fix! I can confirm this fixes things for my project (qutebrowser) as well. I suppose this can be closed then? |
May be worth noting that there are still a few subtle differences between the new Flag behavior and the behavior from 3.10. In Python 3.10, I think this change is probably fine for most cases, but it would be a good idea to add some more test cases. |
Good catch, @benburrill -- I definitely want |
…xist. (GH-105542) (#105572) gh-105497: [Enum] Fix Flag inversion when alias/mask members exist. (GH-105542) When inverting a Flag member (or boundary STRICT), only consider other canonical flags; when inverting an IntFlag member (or boundary KEEP), also consider aliases. (cherry picked from commit 59f009e) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
I merged the 3.12 and 3.11 backports. To follow up on the ~Flag.Mask issue, I ran some tests to see what changed over time. Expected results~Flag.A=<Flag.B: 2> ~Flag.Mask=<Flag.0: 0> 3.10.12As expected 3.11.0 - 3.11.3As expected 3.11.4~Flag.A raises ValueError: <flag 'Flag'>: no members with value 252 ~Flag.Mask=<Flag: 0> 3.11 after 3f244b2~Flag.A=<Flag.B: 2> ~Flag.Mask=<Flag: 252> 3.12.0 alpha 1 - alpha 7As expected 3.12.0 beta 1 - beta 3~Flag.A raises ValueError: <flag 'Flag'>: no members with value 252 ~Flag.Mask=<Flag: 0> 3.12.0 beta after 74d84cf~Flag.A=<Flag.B: 2> ~Flag.Mask=<Flag: 252> ~Flag.Mask needs an urgent fixIn sum, before the last beta of 3.12 we need to restore behavior of |
…106468) For example: class Flag(enum.Flag): A = 0x01 B = 0x02 MASK = 0xff ~Flag.MASK is Flag(0)
…ist (pythonGH-106468) For example: class Flag(enum.Flag): A = 0x01 B = 0x02 MASK = 0xff ~Flag.MASK is Flag(0) (cherry picked from commit 95b7426) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
…ist (pythonGH-106468) For example: class Flag(enum.Flag): A = 0x01 B = 0x02 MASK = 0xff ~Flag.MASK is Flag(0) (cherry picked from commit 95b7426) Co-authored-by: Ethan Furman <ethan@stoneleaf.us>
Can this be release-blocker be closed now? The linked PRs have been merged and backported. Using Python 3.11.5, 3.12.0rc3 and 3.13.0a0 (heads/main:29c3a445d99, Oct 2 2023, 11:14:10), I get the expected import enum
class Flag(enum.Flag):
A = 0x01
B = 0x02
Mask = 0xff
print(~Flag.A) |
Didn't realize there was a patch. At the risk of stating the obvious, I'll point out that Python 3.10 behavior is still not restored. For example:
In Python 3.10, Again, arguably either behavior is fine, but the Python 3.10 way is more intuitive, and there are use cases for weird flags that are not (at least fully) single-bit supported. And also, as I mentioned earlier, in Python 3.10 I can understand losing some of the Python 3.10 functionality in favor of performance, but I think we need to be more clear about what we want to keep and what the intended semantics of the new enums are. |
It occurs to me also that this new patch breaks DNE. Sure DNE was technically violated in 3.11.4 since In Python 3.11.5 that is no longer true. Instead |
What is DNE? |
Double |
The 3.10 behavior is maintained with class Example(enum.Flag, boundary=KEEP):
A = 0b001
B = 0b110
|
Good point, although the now default STRICT boundary is the closest to Python 3.10's behavior overall (albeit not identical). Also |
@benburrill: any other concerns with this patch, or are we good? |
My concern that the default STRICT boundary mode does not match the 3.10 behavior, and that this patch has resulted in further disparity has not really been addressed. The KEEP and EJECT boundary modes can't be used in previous versions and are both effectively just IntFlag. Thankfully IntFlag is backwards compatible, and does provide a way to write cross-version compatible code in cases where the version-dependent default behavior of Flag is problematic. However, I don't think this is an ideal situation. To reiterate, I acknowledge that these issues (which really only show up if you have flags that are not fully single-bit-supported) are somewhat esoteric, and considering that enum has deliberately broken backwards compatibility in various other ways for Python 3.11, these few extra quirks are probably not going to break all that much now that the ValueError issue is resolved. Although I think the old behavior was more intuitive, personally I am fine with the new behavior so long as IntFlag remains as it is. However, I think the documentation is lacking on the differences between the FlagBoundary modes and what the intended behavior really is. The documentation says that non-canonical flags are excluded from iteration, but not much beyond that. I also have some concerns about the Python release process. I'm not sure how, while this issue was marked as a release-blocker, it was possible for release candidates, let alone a full 3.X version to be released before the release-blocker status was removed. Sure, the ValueError issue has been fixed, but that was true even before the issue was marked as release-blocker. If my concerns have drifted too far from the original focus of this issue (the ValueError problem), I'm fine with closing this issue and opening a new one. My biggest concern though, more than any specific issue, is on stabilizing enum on something consistent, understandable, explicitly documented, and preferably similar to how it was in 3.10. I don't want to see enum's behavior change every patch release, so I'm hesitant to pursue some of these smaller quirks at this point. I think the most immediate issue is one of documentation so that in the areas where enum differs across versions we can be more clear as to what is a bug and what is an intended feature / "advancement" of the new enums. |
Closing as original concern has been addressed. Please open a new issue if any issues remain in 3.13. |
With code such as:
Python 3.10.11 prints
Flag.B
, and so does Python 3.11.3. However, with Python 3.11.4, this happens instead:As a workaround, a detour via
.value
works in this case:This causes issues with PyQt, which has the following flags (as bindings from C++):
(Output from Python 3.10 - with Python 3.11,
KeyboardModifierMask
goes missing in the output, and so doesFlag.Mask
above, but that seems like a different issue?)With my project, I'm trying to remove a modifier from the given flags. With Python 3.10.11 and 3.11.3:
But with Python 3.11.4, same issue as above:
As a culprit, I suspect:
cc @ethanfurman @benburrill
Linked PRs
The text was updated successfully, but these errors were encountered: