-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
bpo-42073: allow classmethod to wrap other classmethod-like descriptors #27115
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
Conversation
This is weird, the Intel Windows builds are reliably failing on Azure Pipelines on |
Sigh. I spent time today installing a Windows 10 VM, running updates, installing Visual Studio, configuring a CPython dev environment, and running this PR to test why it fails. I cannot reproduce the Azure Pipelines PR failure on |
Patch by Erik Welch. bpo-19072 (python#8405) allows `classmethod` to wrap other descriptors, but this does not work when the wrapped descriptor mimics classmethod. The current PR fixes this. In Python 3.8 and before, one could create a callable descriptor such that this works as expected (see Lib/test/test_decorators.py for examples): ```python class A: @myclassmethod def f1(cls): return cls @classmethod @myclassmethod def f2(cls): return cls ``` In Python 3.8 and before, `A.f2()` return `A`. Currently in Python 3.9, it returns `type(A)`. This PR make `A.f2()` return `A` again. As of python#8405, classmethod calls `obj.__get__(type)` if `obj` has `__get__`. This allows one to chain `@classmethod` and `@property` together. When using classmethod-like descriptors, it's the second argument to `__get__`--the owner or the type--that is important, but this argument is currently missing. Since it is None, the "owner" argument is assumed to be the type of the first argument, which, in this case, is wrong (we want `A`, not `type(A)`). This PR updates classmethod to call `obj.__get__(type, type)` if `obj` has `__get__`. Co-authored-by: Erik Welch <erik.n.welch@gmail.com>
Very suspicious. The latest commit essentially undoes the change in the PR so it's a PR of |
This reverts commit a3a65a0.
Merging this since GH-27161 demonstrated that the Azure Pipelines-specific |
@ambv: Please replace |
Thanks @ambv for the PR 🌮🎉.. I'm working now to backport this PR to: 3.10. |
GH-27162 is a backport of this pull request to the 3.10 branch. |
…rs (pythonGH-27115) Patch by Erik Welch. bpo-19072 (pythonGH-8405) allows `classmethod` to wrap other descriptors, but this does not work when the wrapped descriptor mimics classmethod. The current PR fixes this. In Python 3.8 and before, one could create a callable descriptor such that this works as expected (see Lib/test/test_decorators.py for examples): ```python class A: @myclassmethod def f1(cls): return cls @classmethod @myclassmethod def f2(cls): return cls ``` In Python 3.8 and before, `A.f2()` return `A`. Currently in Python 3.9, it returns `type(A)`. This PR make `A.f2()` return `A` again. As of pythonGH-8405, classmethod calls `obj.__get__(type)` if `obj` has `__get__`. This allows one to chain `@classmethod` and `@property` together. When using classmethod-like descriptors, it's the second argument to `__get__`--the owner or the type--that is important, but this argument is currently missing. Since it is None, the "owner" argument is assumed to be the type of the first argument, which, in this case, is wrong (we want `A`, not `type(A)`). This PR updates classmethod to call `obj.__get__(type, type)` if `obj` has `__get__`. Co-authored-by: Erik Welch <erik.n.welch@gmail.com> (cherry picked from commit b83861f) Co-authored-by: Łukasz Langa <lukasz@langa.pl>
…rs (GH-27115) (GH-27162) Patch by Erik Welch. bpo-19072 (GH-8405) allows `classmethod` to wrap other descriptors, but this does not work when the wrapped descriptor mimics classmethod. The current PR fixes this. In Python 3.8 and before, one could create a callable descriptor such that this works as expected (see Lib/test/test_decorators.py for examples): ```python class A: @myclassmethod def f1(cls): return cls @classmethod @myclassmethod def f2(cls): return cls ``` In Python 3.8 and before, `A.f2()` return `A`. Currently in Python 3.9, it returns `type(A)`. This PR make `A.f2()` return `A` again. As of GH-8405, classmethod calls `obj.__get__(type)` if `obj` has `__get__`. This allows one to chain `@classmethod` and `@property` together. When using classmethod-like descriptors, it's the second argument to `__get__`--the owner or the type--that is important, but this argument is currently missing. Since it is None, the "owner" argument is assumed to be the type of the first argument, which, in this case, is wrong (we want `A`, not `type(A)`). This PR updates classmethod to call `obj.__get__(type, type)` if `obj` has `__get__`. Co-authored-by: Erik Welch <erik.n.welch@gmail.com> (cherry picked from commit b83861f)
Patch by Erik Welch.
bpo-19072 (#8405) allows
classmethod
to wrap other descriptors, but this doesnot work when the wrapped descriptor mimics classmethod. The current PR fixes
this.
In Python 3.8 and before, one could create a callable descriptor such that this
works as expected (see Lib/test/test_decorators.py for examples):
In Python 3.8 and before,
A.f2()
returnA
. Currently in Python 3.9, itreturns
type(A)
. This PR makeA.f2()
returnA
again.As of #8405, classmethod calls
obj.__get__(type)
ifobj
has__get__
.This allows one to chain
@classmethod
and@property
together. Whenusing classmethod-like descriptors, it's the second argument to
__get__
--theowner or the type--that is important, but this argument is currently missing.
Since it is None, the "owner" argument is assumed to be the type of the first
argument, which, in this case, is wrong (we want
A
, nottype(A)
).This PR updates classmethod to call
obj.__get__(type, type)
ifobj
has__get__
.Co-authored-by: Erik Welch erik.n.welch@gmail.com
Original patch was on the
3.9
branch so I recreated it onmain
. Passes-uall
.https://bugs.python.org/issue42073