Skip to content

Commit 11dbe33

Browse files
authored
feat: report @deprecated() on non-overloaded class constructors
1 parent b266dd1 commit 11dbe33

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

mypy/checkexpr.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,14 @@ def check_callable_call(
16641664
16651665
See the docstring of check_call for more information.
16661666
"""
1667+
# Check implicit calls to deprecated class constructors.
1668+
# Only the non-overload case is handled here. Overloaded constructors are handled
1669+
# separately during overload resolution. `callable_node` is `None` for an overload
1670+
# item so deprecation checks are not duplicated.
1671+
if isinstance(callable_node, RefExpr) and isinstance(callable_node.node, TypeInfo):
1672+
self.chk.check_deprecated(callable_node.node.get_method("__new__"), context)
1673+
self.chk.check_deprecated(callable_node.node.get_method("__init__"), context)
1674+
16671675
# Always unpack **kwargs before checking a call.
16681676
callee = callee.with_unpacked_kwargs().with_normalized_var_args()
16691677
if callable_name is None and callee.name:

test-data/unit/check-deprecated.test

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,18 +315,51 @@ class E: ...
315315
[builtins fixtures/tuple.pyi]
316316

317317

318-
[case testDeprecatedClassInitMethod]
318+
[case testDeprecatedClassConstructor]
319319
# flags: --enable-error-code=deprecated
320320

321321
from typing_extensions import deprecated
322322

323-
@deprecated("use C2 instead")
324323
class C:
324+
@deprecated("call `make_c()` instead")
325325
def __init__(self) -> None: ...
326+
@classmethod
327+
def make_c(cls) -> C: ...
326328

327-
c: C # E: class __main__.C is deprecated: use C2 instead
328-
C() # E: class __main__.C is deprecated: use C2 instead
329-
C.__init__(c) # E: class __main__.C is deprecated: use C2 instead
329+
C() # E: function __main__.C.__init__ is deprecated: call `make_c()` instead
330+
331+
class D:
332+
@deprecated("call `make_d()` instead")
333+
def __new__(cls) -> D: ...
334+
@classmethod
335+
def make_d(cls) -> D: ...
336+
337+
D() # E: function __main__.D.__new__ is deprecated: call `make_d()` instead
338+
339+
[builtins fixtures/tuple.pyi]
340+
341+
342+
[case testDeprecatedSuperClassConstructor]
343+
# flags: --enable-error-code=deprecated
344+
345+
from typing_extensions import deprecated, Self
346+
347+
class A:
348+
@deprecated("call `self.initialise()` instead")
349+
def __init__(self) -> None: ...
350+
def initialise(self) -> None: ...
351+
352+
class B(A):
353+
def __init__(self) -> None:
354+
super().__init__() # E: function __main__.A.__init__ is deprecated: call `self.initialise()` instead
355+
356+
class C:
357+
@deprecated("call `object.__new__(cls)` instead")
358+
def __new__(cls) -> Self: ...
359+
360+
class D(C):
361+
def __new__(cls) -> Self:
362+
return super().__new__(cls) # E: function __main__.C.__new__ is deprecated: call `object.__new__(cls)` instead
330363

331364
[builtins fixtures/tuple.pyi]
332365

0 commit comments

Comments
 (0)