summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2023-10-27 05:24:56 (GMT)
committerGitHub <noreply@github.com>2023-10-27 05:24:56 (GMT)
commit7f9a99e8549b792662f2cd28bf38a4d4625bd402 (patch)
tree3e31df6a620f6a41c9a3547187ee794bbe343823 /Doc
parentee2d22f06d8a4ca13b2dba5e8a7a639a3997cc69 (diff)
downloadcpython-7f9a99e8549b792662f2cd28bf38a4d4625bd402.zip
cpython-7f9a99e8549b792662f2cd28bf38a4d4625bd402.tar.gz
cpython-7f9a99e8549b792662f2cd28bf38a4d4625bd402.tar.bz2
gh-89519: Remove classmethod descriptor chaining, deprecated since 3.11 (gh-110163)
Diffstat (limited to 'Doc')
-rw-r--r--Doc/howto/descriptor.rst41
-rw-r--r--Doc/library/functions.rst2
-rw-r--r--Doc/whatsnew/3.13.rst8
3 files changed, 19 insertions, 32 deletions
diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst
index 1d9424c..024c1eb 100644
--- a/Doc/howto/descriptor.rst
+++ b/Doc/howto/descriptor.rst
@@ -1141,6 +1141,16 @@ roughly equivalent to:
obj = self.__self__
return func(obj, *args, **kwargs)
+ def __getattribute__(self, name):
+ "Emulate method_getset() in Objects/classobject.c"
+ if name == '__doc__':
+ return self.__func__.__doc__
+ return object.__getattribute__(self, name)
+
+ def __getattr__(self, name):
+ "Emulate method_getattro() in Objects/classobject.c"
+ return getattr(self.__func__, name)
+
To support automatic creation of methods, functions include the
:meth:`__get__` method for binding methods during attribute access. This
means that functions are non-data descriptors that return bound methods
@@ -1420,10 +1430,6 @@ Using the non-data descriptor protocol, a pure Python version of
def __get__(self, obj, cls=None):
if cls is None:
cls = type(obj)
- if hasattr(type(self.f), '__get__'):
- # This code path was added in Python 3.9
- # and was deprecated in Python 3.11.
- return self.f.__get__(cls, cls)
return MethodType(self.f, cls)
.. testcode::
@@ -1436,11 +1442,6 @@ Using the non-data descriptor protocol, a pure Python version of
"Class method that returns a tuple"
return (cls.__name__, x, y)
- @ClassMethod
- @property
- def __doc__(cls):
- return f'A doc for {cls.__name__!r}'
-
.. doctest::
:hide:
@@ -1453,10 +1454,6 @@ Using the non-data descriptor protocol, a pure Python version of
>>> t.cm(11, 22)
('T', 11, 22)
- # Check the alternate path for chained descriptors
- >>> T.__doc__
- "A doc for 'T'"
-
# Verify that T uses our emulation
>>> type(vars(T)['cm']).__name__
'ClassMethod'
@@ -1481,24 +1478,6 @@ Using the non-data descriptor protocol, a pure Python version of
('T', 11, 22)
-The code path for ``hasattr(type(self.f), '__get__')`` was added in
-Python 3.9 and makes it possible for :func:`classmethod` to support
-chained decorators. For example, a classmethod and property could be
-chained together. In Python 3.11, this functionality was deprecated.
-
-.. testcode::
-
- class G:
- @classmethod
- @property
- def __doc__(cls):
- return f'A doc for {cls.__name__!r}'
-
-.. doctest::
-
- >>> G.__doc__
- "A doc for 'G'"
-
The :func:`functools.update_wrapper` call in ``ClassMethod`` adds a
``__wrapped__`` attribute that refers to the underlying function. Also
it carries forward the attributes necessary to make the wrapper look
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index a5f580c..a72f779 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -285,7 +285,7 @@ are always available. They are listed here in alphabetical order.
``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``) and
have a new ``__wrapped__`` attribute.
- .. versionchanged:: 3.11
+ .. deprecated-removed:: 3.11 3.13
Class methods can no longer wrap other :term:`descriptors <descriptor>` such as
:func:`property`.
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 1053aa5..34dd3ea 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -1228,6 +1228,14 @@ Deprecated
Removed
-------
+* Removed chained :class:`classmethod` descriptors (introduced in
+ :issue:`19072`). This can no longer be used to wrap other descriptors
+ such as :class:`property`. The core design of this feature was flawed
+ and caused a number of downstream problems. To "pass-through" a
+ :class:`classmethod`, consider using the :attr:`!__wrapped__`
+ attribute that was added in Python 3.10. (Contributed by Raymond
+ Hettinger in :gh:`89519`.)
+
* Remove many APIs (functions, macros, variables) with names prefixed by
``_Py`` or ``_PY`` (considered as private API). If your project is affected
by one of these removals and you consider that the removed API should remain