Skip to content
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

Using functools.partial to make functions not considered as methods when given as enum values no longer works #125316

Closed
bluthej opened this issue Oct 11, 2024 · 12 comments
Labels
3.13 bugs and security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@bluthej
Copy link

bluthej commented Oct 11, 2024

Bug report

Bug description:

On python 3.10-3.12, the following snippet prints True, while on Python 3.13.0 it prints False:

from enum import Enum
from functools import partial


def a():
    pass


def b():
    pass


class MyCallables(Enum):
    A = a
    B = partial(b)


print(MyCallables.B in MyCallables)

This is because MyCallables.B is considered to be functools.partial(<function b at 0x756d7f0065c0>) on 3.13.0, when it used to be <MyCallables.B: functools.partial(<function b at 0x71f7cbc407c0>)> before.

This is something I've been using to allow function values in enums not to be considered methods, which I most likely got from this thread. In the example above, A would always be considered a method.

It seems like on 3.13.0, the "wrapper class" approach is the only one that works.

CPython versions tested on:

3.10, 3.11, 3.12, 3.13

Operating systems tested on:

Linux, Windows

Linked PRs

@bluthej bluthej added the type-bug An unexpected behavior, bug, or error label Oct 11, 2024
@ericvsmith
Copy link
Member

@rhettinger

@ZeroIntensity ZeroIntensity added stdlib Python modules in the Lib dir 3.13 bugs and security fixes 3.14 new features, bugs and security fixes labels Oct 11, 2024
@ZeroIntensity
Copy link
Member

ZeroIntensity commented Oct 11, 2024

Confirmed on current main as well, technically a 3.13 regression.

@serhiy-storchaka
Copy link
Member

This is an intentional change, and it is documented. See #121027.

Using staticmethod() to set a callable attribute without making it a method is more common idiom.

@bluthej
Copy link
Author

bluthej commented Oct 11, 2024

@serhiy-storchaka maybe my title was not well formulated. This is what my issue boiled down to in my mind but I realize this is not exactly my problem, my problem is with the behavior I laid out in the snippet.

It used to be that we could use partial in order to use a function as the value for an enum variant while still having that variant act like one. With the breaking change you mentioned this is no longer possible, the enum variant is considered to be the function itself. But that's just a consequence (maybe even unintended, I don't know).

At least there is still the wrapper class approach that works! I guess I'll just update the stackoverflow thread I mentioned in case people run into that.

@bluthej
Copy link
Author

bluthej commented Oct 11, 2024

I should probably add that using staticmethod in that context doesn't do the trick.

@serhiy-storchaka
Copy link
Member

As was mentioned in other answer, there is a better solution -- use enum.member() (I did not know about it!).

@bluthej
Copy link
Author

bluthej commented Oct 11, 2024

Thanks for the tip! I had seen that answer but since it wasn't upvoted much I didn't try 😅

serhiy-storchaka added a commit to serhiy-storchaka/cpython that referenced this issue Oct 12, 2024
A FutureWarning with suggestion to use enum.member() is now emitted
when the partial instance is used as an enum member.
@serhiy-storchaka
Copy link
Member

#125361 should fix this for 3.13. It restores the old behavior of partial in enums and adds a runtime warning. In 3.14 the behavior will be changed in any case.

We tried to emit a warning about future behavior change, but adding a warning already changed the behavior in some cases.

@hacscred

This comment was marked as off-topic.

@ZeroIntensity
Copy link
Member

@hacscred This kind of feedback isn't helpful--we don't intentionally break code, this is a regression. Please read PEP-387 for our backwards compatibility policy.

serhiy-storchaka added a commit that referenced this issue Oct 21, 2024
A FutureWarning with suggestion to use enum.member() is now emitted
when the partial instance is used as an enum member.
@serhiy-storchaka serhiy-storchaka removed the 3.14 new features, bugs and security fixes label Oct 21, 2024
@MegaIng
Copy link

MegaIng commented Oct 25, 2024

This kind of feedback isn't helpful--we don't intentionally break code, this is a regression. Please read PEP-387 for our backwards compatibility policy.

No, this is clearly wrong. #121089 was an intentional break in backwards compatibility, disregarding PEP-387 with the argument that "this will only rarely break code".

@ZeroIntensity
Copy link
Member

Yes, but this specific case with Enum was a regression and was fixed for this case. If that PR is causing more problems, open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.13 bugs and security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

6 participants