gh-89519: Remove classmethod descriptor chaining, deprecated since 3.11 (gh-110163)

This commit is contained in:
Raymond Hettinger 2023-10-27 00:24:56 -05:00 committed by GitHub
parent ee2d22f06d
commit 7f9a99e854
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 25 additions and 193 deletions

View file

@ -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