-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Description
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:
Lines 589 to 603 in 2268289
| 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:
Lines 605 to 625 in 2268289
| 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:
passIn [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_methodExpected 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