mirror of
https://github.com/python/cpython.git
synced 2025-10-28 12:15:13 +00:00
[3.13] gh-138010: Fix __init_subclass__ forwarding by warnings.deprecated (GH-138210) (#138564)
(cherry picked from commit e2c038f5be)
This commit is contained in:
parent
4e25f012e7
commit
cf62144f45
3 changed files with 36 additions and 13 deletions
|
|
@ -1683,6 +1683,25 @@ class D(C, x=3):
|
||||||
|
|
||||||
self.assertEqual(D.inited, 3)
|
self.assertEqual(D.inited, 3)
|
||||||
|
|
||||||
|
def test_existing_init_subclass_in_sibling_base(self):
|
||||||
|
@deprecated("A will go away soon")
|
||||||
|
class A:
|
||||||
|
pass
|
||||||
|
class B:
|
||||||
|
def __init_subclass__(cls, x):
|
||||||
|
super().__init_subclass__()
|
||||||
|
cls.inited = x
|
||||||
|
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"):
|
||||||
|
class C(A, B, x=42):
|
||||||
|
pass
|
||||||
|
self.assertEqual(C.inited, 42)
|
||||||
|
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"):
|
||||||
|
class D(B, A, x=42):
|
||||||
|
pass
|
||||||
|
self.assertEqual(D.inited, 42)
|
||||||
|
|
||||||
def test_init_subclass_has_correct_cls(self):
|
def test_init_subclass_has_correct_cls(self):
|
||||||
init_subclass_saw = None
|
init_subclass_saw = None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -602,27 +602,27 @@ def __new__(cls, /, *args, **kwargs):
|
||||||
|
|
||||||
arg.__new__ = staticmethod(__new__)
|
arg.__new__ = staticmethod(__new__)
|
||||||
|
|
||||||
original_init_subclass = arg.__init_subclass__
|
if "__init_subclass__" in arg.__dict__:
|
||||||
# We need slightly different behavior if __init_subclass__
|
# __init_subclass__ is directly present on the decorated class.
|
||||||
# is a bound method (likely if it was implemented in Python)
|
# Synthesize a wrapper that calls this method directly.
|
||||||
if isinstance(original_init_subclass, MethodType):
|
original_init_subclass = arg.__init_subclass__
|
||||||
original_init_subclass = original_init_subclass.__func__
|
# We need slightly different behavior if __init_subclass__
|
||||||
|
# is a bound method (likely if it was implemented in Python).
|
||||||
|
# Otherwise, it likely means it's a builtin such as
|
||||||
|
# object's implementation of __init_subclass__.
|
||||||
|
if isinstance(original_init_subclass, MethodType):
|
||||||
|
original_init_subclass = original_init_subclass.__func__
|
||||||
|
|
||||||
@functools.wraps(original_init_subclass)
|
@functools.wraps(original_init_subclass)
|
||||||
def __init_subclass__(*args, **kwargs):
|
def __init_subclass__(*args, **kwargs):
|
||||||
warn(msg, category=category, stacklevel=stacklevel + 1)
|
warn(msg, category=category, stacklevel=stacklevel + 1)
|
||||||
return original_init_subclass(*args, **kwargs)
|
return original_init_subclass(*args, **kwargs)
|
||||||
|
|
||||||
arg.__init_subclass__ = classmethod(__init_subclass__)
|
|
||||||
# Or otherwise, which likely means it's a builtin such as
|
|
||||||
# object's implementation of __init_subclass__.
|
|
||||||
else:
|
else:
|
||||||
@functools.wraps(original_init_subclass)
|
def __init_subclass__(cls, *args, **kwargs):
|
||||||
def __init_subclass__(*args, **kwargs):
|
|
||||||
warn(msg, category=category, stacklevel=stacklevel + 1)
|
warn(msg, category=category, stacklevel=stacklevel + 1)
|
||||||
return original_init_subclass(*args, **kwargs)
|
return super(arg, cls).__init_subclass__(*args, **kwargs)
|
||||||
|
|
||||||
arg.__init_subclass__ = __init_subclass__
|
arg.__init_subclass__ = classmethod(__init_subclass__)
|
||||||
|
|
||||||
arg.__deprecated__ = __new__.__deprecated__ = msg
|
arg.__deprecated__ = __new__.__deprecated__ = msg
|
||||||
__init_subclass__.__deprecated__ = msg
|
__init_subclass__.__deprecated__ = msg
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
Fix an issue where defining a class with an :func:`@warnings.deprecated
|
||||||
|
<warnings.deprecated>`-decorated base class may not invoke the correct
|
||||||
|
:meth:`~object.__init_subclass__` method in cases involving multiple
|
||||||
|
inheritance. Patch by Brian Schubert.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue