This is an intentional change done in #121089, following #121027. That PR disregarded PEP-387 and breaks compatibility with less than a version warning (less than because the FutureWarning that was added was late in the python 3.13 release cycle)
I don't know if there is much more to add to this bug report - this change should not have been done without a proper deprecation period and IMO a proper discussion outside of two github issues. It should be reverted for 3.14 and a deprecation warning be added instead, with the final change, if being done at all, the earliest in 3.16.
It also already caused other issues, at least #125316. The reason I noticed this is because it broke actual tests on a project I am maintainer on: lark-parser/lark#1480
The reason why this change does not follow the letter of PEP-387 is because this was impossible. The added warning itself causes a breaking change. #125316 was caused not by this change, but by the code necessary to produce a warning. This is a catch-22 situation -- to produce a warning about the future turn of partial() into descriptor, it should be turned into descriptor, and this breaks some code that does not use the descriptor protocol, but only checks if the object is a descriptor. Such code needs a special handling of the partial object. Several such places was fixed in the stdlib, but we do not want to keep such problematic code any longer. Alternatives to this are:
prolong the warning period, during which some code is broken, without bringing the benefits of the final change.
remove the warning, making the change more abrupt for most users.
While true that adding a warning itself is already a breaking change, actually implementing the behavior is an additional, different breaking change for people who relied on the behavior on partial - E.g. lark. IMO it would be better to just produce a warning for now and mirror the behavior of before.
Or even better, don't introduce a random, unnecessary breaking change whos only mentioned benefit is keeping an already fundamentally flawed comparison alive a bit more.
The fact that we have tests that are broken by this is not random - we actually find the behavior of partial as a non-method descriptor useful. And partialmethod exists - there is no functional need for partial to behave like a method, and in fact it would be more useful if it didn't.
And partialmethod exists - there is no functional need for partial to behave like a method, and in fact it would be more useful if it didn't.
Why is that? The former does not necessarily imply the latter.
It was decided for partial to behave as an ordinary function, i.e. as descriptor. This was done to bring lambda/def and partial mental models in line.
IMO it would be better to just produce a warning for now and mirror the behavior of before.
I appreciate the inconvenience. But given the situation at hand, which is for partial to behave as descriptor and the fact that it was already merged, there are 2 options:
a) Rewind and extend deprecation period
b) Adapt to it by using staticmethod
(a) would be a fair amount of inconvenience and disruption in development pipeline in this direction.
Does (b) have any complications beyond straight forward adaptation by wrapping in staticmethod?
I didn't reply because I don't know what more to say.
This is an unnecessary break in backwards compatibility (i.e. it doesn't allow anything new) and I don't consider any of the mentioned arguments even relevant.
A prior discussion with motivation was discussed in #121027 (comment). The reason for this change is due to the new presence of Placeholder, introduced in Python 3.14.
Now, delaying this change would likely require delaying the introduction of functools.Placeholder for 3.15 and this is probably not what we wanted. If you want to revert that change, I suggest opening a post on DPO: https://discuss.python.org/c/ideas/6 or maybe https://discuss.python.org/c/core-dev/23 since it affects the current releases.
However, considering how the release manager and other core devs considered this feature to be acceptable, I doubt there will be a revert.
Activity
Eclips4 commented on Oct 25, 2024
cc @serhiy-storchaka @rhettinger
serhiy-storchaka commented on Oct 25, 2024
The reason why this change does not follow the letter of PEP-387 is because this was impossible. The added warning itself causes a breaking change. #125316 was caused not by this change, but by the code necessary to produce a warning. This is a catch-22 situation -- to produce a warning about the future turn of partial() into descriptor, it should be turned into descriptor, and this breaks some code that does not use the descriptor protocol, but only checks if the object is a descriptor. Such code needs a special handling of the partial object. Several such places was fixed in the stdlib, but we do not want to keep such problematic code any longer. Alternatives to this are:
MegaIng commented on Oct 25, 2024
While true that adding a warning itself is already a breaking change, actually implementing the behavior is an additional, different breaking change for people who relied on the behavior on partial - E.g. lark. IMO it would be better to just produce a warning for now and mirror the behavior of before.
Or even better, don't introduce a random, unnecessary breaking change whos only mentioned benefit is keeping an already fundamentally flawed comparison alive a bit more.
The fact that we have tests that are broken by this is not random - we actually find the behavior of partial as a non-method descriptor useful. And partialmethod exists - there is no functional need for partial to behave like a method, and in fact it would be more useful if it didn't.
dg-pb commented on Oct 25, 2024
Why is that? The former does not necessarily imply the latter.
It was decided for partial to behave as an ordinary function, i.e. as descriptor. This was done to bring lambda/def and partial mental models in line.
I appreciate the inconvenience. But given the situation at hand, which is for partial to behave as descriptor and the fact that it was already merged, there are 2 options:
a) Rewind and extend deprecation period
b) Adapt to it by using staticmethod
(a) would be a fair amount of inconvenience and disruption in development pipeline in this direction.
Does (b) have any complications beyond straight forward adaptation by wrapping in staticmethod?
picnixz commented on Dec 2, 2024
Considering the lack of reply, I'll close this one as wont fix. Alternatives should be discussed first on DPO I think.
MegaIng commented on Dec 2, 2024
I didn't reply because I don't know what more to say.
This is an unnecessary break in backwards compatibility (i.e. it doesn't allow anything new) and I don't consider any of the mentioned arguments even relevant.
picnixz commented on Dec 2, 2024
A prior discussion with motivation was discussed in #121027 (comment). The reason for this change is due to the new presence of Placeholder, introduced in Python 3.14.
Now, delaying this change would likely require delaying the introduction of functools.Placeholder for 3.15 and this is probably not what we wanted. If you want to revert that change, I suggest opening a post on DPO: https://discuss.python.org/c/ideas/6 or maybe https://discuss.python.org/c/core-dev/23 since it affects the current releases.
However, considering how the release manager and other core devs considered this feature to be acceptable, I doubt there will be a revert.