Bug report
Bug description:
PEP 702 – Marking deprecations using the type system introduces a new API warnings.deprecated for deprecation.
While decorating a class object, it will update the __new__ method:
|
original_new = arg.__new__ |
|
|
|
@functools.wraps(original_new) |
|
def __new__(cls, *args, **kwargs): |
|
if cls is arg: |
|
warn(msg, category=category, stacklevel=stacklevel + 1) |
|
if original_new is not object.__new__: |
|
return original_new(cls, *args, **kwargs) |
|
# Mirrors a similar check in object.__new__. |
|
elif cls.__init__ is object.__init__ and (args or kwargs): |
|
raise TypeError(f"{cls.__name__}() takes no arguments") |
|
else: |
|
return original_new(cls) |
|
|
|
arg.__new__ = staticmethod(__new__) |
and the __init_subclass__ method:
|
original_init_subclass = arg.__init_subclass__ |
|
# We need slightly different behavior if __init_subclass__ |
|
# is a bound method (likely if it was implemented in Python) |
|
if isinstance(original_init_subclass, MethodType): |
|
original_init_subclass = original_init_subclass.__func__ |
|
|
|
@functools.wraps(original_init_subclass) |
|
def __init_subclass__(*args, **kwargs): |
|
warn(msg, category=category, stacklevel=stacklevel + 1) |
|
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: |
|
@functools.wraps(original_init_subclass) |
|
def __init_subclass__(*args, **kwargs): |
|
warn(msg, category=category, stacklevel=stacklevel + 1) |
|
return original_init_subclass(*args, **kwargs) |
|
|
|
arg.__init_subclass__ = __init_subclass__ |
For a class (cls) that does not implement the __new__ and __init_subclass__ methods, the warnings.deprecated decorator will generate these two methods (based on object.__new__ and type.__init_subclass__ ) and assign them to cls.__dict__.
However, if users want to inspect the methods in cls.__dict__, the inspect module fails to get the correct definition of cls.__new__. It is defined in warnings.py rather than object.__new__.
# test.py
from warnings import deprecated # or from typing_extensions import deprecated
class Foo:
def __new__(cls):
return super().__new__(cls)
@deprecated("test")
class Bar:
pass
In [1]: import inspect
In [2]: from test import Foo, Bar
In [3]: inspect.getsourcelines(Foo.__new__)
Out[3]: ([' def __new__(cls):\n', ' return super().__new__(cls)\n'], 7)
In [4]: inspect.getsourcelines(Bar.__new__)
TypeError: module, class, method, function, traceback, frame, or code object was expected, got builtin_function_or_method
Expected to have inspect.getsourcelines(Bar.__new__) to be source code in /.../lib/python3.13/warnings.py.
CPython versions tested on:
3.13
Operating systems tested on:
Linux
Linked PRs
Bug report
Bug description:
PEP 702 – Marking deprecations using the type system introduces a new API
warnings.deprecatedfor deprecation.While decorating a class object, it will update the
__new__method:cpython/Lib/warnings.py
Lines 589 to 603 in 2268289
and the
__init_subclass__method:cpython/Lib/warnings.py
Lines 605 to 625 in 2268289
For a class (
cls) that does not implement the__new__and__init_subclass__methods, thewarnings.deprecateddecorator will generate these two methods (based onobject.__new__andtype.__init_subclass__) and assign them tocls.__dict__.However, if users want to inspect the methods in
cls.__dict__, theinspectmodule fails to get the correct definition ofcls.__new__. It is defined inwarnings.pyrather thanobject.__new__.Expected to have
inspect.getsourcelines(Bar.__new__)to be source code in/.../lib/python3.13/warnings.py.CPython versions tested on:
3.13
Operating systems tested on:
Linux
Linked PRs
follow_wrappedfor__init__and__new__when getting class signature withinspect.signature#132055follow_wrappedfor__init__and__new__when getting class signature withinspect.signature(GH-132055) #133277