Skip to content

Commit

Permalink
Support @deprecated() on overloaded __get__ for generic descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
Viicos committed Dec 23, 2024
1 parent 9ff9946 commit 3e0684b
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
11 changes: 9 additions & 2 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -7714,7 +7714,12 @@ def warn_deprecated(self, node: Node | None, context: Context) -> None:
warn(deprecated, context, code=codes.DEPRECATED)

def warn_deprecated_overload_item(
self, node: Node | None, context: Context, *, target: Type, selftype: Type | None = None
self,
node: Node | None,
context: Context,
*,
target: Type,
selftype: Instance | None = None,
) -> None:
"""Warn if the overload item corresponding to the given callable is deprecated."""
target = get_proper_type(target)
Expand All @@ -7724,7 +7729,9 @@ def warn_deprecated_overload_item(
candidate := item.func.type, CallableType
):
if selftype is not None:
candidate = bind_self(candidate, selftype)
candidate = bind_self(
expand_type_by_instance(candidate, selftype), selftype
)
if candidate == target:
self.warn_deprecated(item.func, context)

Expand Down
15 changes: 14 additions & 1 deletion test-data/unit/check-deprecated.test
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,11 @@ C().g = "x" # E: function __main__.C.g is deprecated: use g2 instead \
[case testDeprecatedDescriptor]
# flags: --enable-error-code=deprecated

from typing import Any, Optional, Union
from typing import Any, Generic, Optional, TypeVar, Union
from typing_extensions import deprecated, overload

T = TypeVar("T")

@deprecated("use E1 instead")
class D1:
def __get__(self, obj: Optional[C], objtype: Any) -> Union[D1, int]: ...
Expand Down Expand Up @@ -536,10 +538,18 @@ class D3:
def __set__(self, obj: C, value: str) -> None: ...
def __set__(self, obj: C, value: Union[int, str]) -> None: ...

class D4(Generic[T]):
@overload
def __get__(self, obj: None, objtype: Any) -> T: ...
@overload
@deprecated("deprecated instance access")
def __get__(self, obj: C, objtype: Any) -> T: ...

class C:
d1 = D1() # E: class __main__.D1 is deprecated: use E1 instead
d2 = D2()
d3 = D3()
d4 = D4[int]()

c: C
C.d1
Expand All @@ -554,6 +564,9 @@ C.d3 # E: overload def (self: __main__.D3, obj: None, objtype: Any) -> __main__
c.d3 # E: overload def (self: __main__.D3, obj: __main__.C, objtype: Any) -> builtins.int of function __main__.D3.__get__ is deprecated: use E3.__get__ instead
c.d3 = 1
c.d3 = "x" # E: overload def (self: __main__.D3, obj: __main__.C, value: builtins.str) of function __main__.D3.__set__ is deprecated: use E3.__set__ instead

C.d4
c.d4 # E: overload def (self: __main__.D4[T`1], obj: __main__.C, objtype: Any) -> T`1 of function __main__.D4.__get__ is deprecated: deprecated instance access
[builtins fixtures/property.pyi]


Expand Down

0 comments on commit 3e0684b

Please sign in to comment.