summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorƁukasz Langa <lukasz@langa.pl>2021-07-15 13:16:19 (GMT)
committerGitHub <noreply@github.com>2021-07-15 13:16:19 (GMT)
commitb83861f0265e07207a6ae2c49c40fa8f447893f2 (patch)
tree2524698435840e4ffdf2446d67b8853933d9e12d /Objects
parent641345d636320a6fca04a5271fa4c4c5ba3e5437 (diff)
downloadcpython-b83861f0265e07207a6ae2c49c40fa8f447893f2.zip
cpython-b83861f0265e07207a6ae2c49c40fa8f447893f2.tar.gz
cpython-b83861f0265e07207a6ae2c49c40fa8f447893f2.tar.bz2
bpo-42073: allow classmethod to wrap other classmethod-like descriptors (#27115)
Patch by Erik Welch. bpo-19072 (#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 #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>
Diffstat (limited to 'Objects')
-rw-r--r--Objects/funcobject.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index f74d96d..5a17038 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -851,7 +851,7 @@ cm_descr_get(PyObject *self, PyObject *obj, PyObject *type)
type = (PyObject *)(Py_TYPE(obj));
if (Py_TYPE(cm->cm_callable)->tp_descr_get != NULL) {
return Py_TYPE(cm->cm_callable)->tp_descr_get(cm->cm_callable, type,
- NULL);
+ type);
}
return PyMethod_New(cm->cm_callable, type);
}