Skip to content

PEP 702 (@deprecated): improve the handling of explicit type annotations of assignment statements #17899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2930,14 +2930,10 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
Handle all kinds of assignment statements (simple, indexed, multiple).
"""

if isinstance(s.rvalue, TempNode) and s.rvalue.no_rhs:
if s.unanalyzed_type is not None:
for lvalue in s.lvalues:
if (
isinstance(lvalue, NameExpr)
and isinstance(var := lvalue.node, Var)
and isinstance(instance := get_proper_type(var.type), Instance)
):
self.check_deprecated(instance.type, s)
if isinstance(lvalue, NameExpr) and isinstance(var := lvalue.node, Var):
self.search_deprecated(var.type, s, set())

# Avoid type checking type aliases in stubs to avoid false
# positives about modern type syntax available in stubs such
Expand Down Expand Up @@ -7581,6 +7577,20 @@ def warn_deprecated(self, node: SymbolNode | None, context: Context) -> None:
warn = self.msg.fail if self.options.report_deprecated_as_error else self.msg.note
warn(deprecated, context, code=codes.DEPRECATED)

def search_deprecated(
self, typ: Type | None, s: AssignmentStmt, visited: set[Type | None]
) -> None:

if typ not in visited:
visited.add(typ)
if isinstance(typ := get_proper_type(typ), Instance):
self.check_deprecated(typ.type, s)
for arg in typ.args:
self.search_deprecated(arg, s, visited)
elif isinstance(typ, (UnionType, TupleType)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a robust way to do it. You should write a simple visitor instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced search_deprecated with InstanceDeprecatedVisitor, which additionally considers CallableType and TypeAliasType. Do you see other relevant cases?

for item in typ.items:
self.search_deprecated(item, s, visited)


class CollectArgTypeVarTypes(TypeTraverserVisitor):
"""Collects the non-nested argument types in a set."""
Expand Down
21 changes: 21 additions & 0 deletions test-data/unit/check-deprecated.test
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def h() -> None: ...

[case testDeprecatedClass]

from typing import List, Optional, Tuple, Union
from typing_extensions import deprecated

@deprecated("use C2 instead")
Expand All @@ -114,10 +115,30 @@ C.missing() # N: class __main__.C is deprecated: use C2 instead \
C.__init__(c) # N: class __main__.C is deprecated: use C2 instead
C(1) # N: class __main__.C is deprecated: use C2 instead \
# E: Too many arguments for "C"

D = C # N: class __main__.C is deprecated: use C2 instead
D()
t = (C, C, D) # N: class __main__.C is deprecated: use C2 instead

u1: Union[C, int] = 1 # N: class __main__.C is deprecated: use C2 instead
u1 = 1
u2 = 1 # type: Union[C, int] # N: class __main__.C is deprecated: use C2 instead
u2 = 1

c1 = c2 = C() # N: class __main__.C is deprecated: use C2 instead
i, c3 = 1, C() # N: class __main__.C is deprecated: use C2 instead

class E: ...

x1: Optional[C] # N: class __main__.C is deprecated: use C2 instead
x2: Union[D, C, E] # N: class __main__.C is deprecated: use C2 instead
x3: Union[D, Optional[C], E] # N: class __main__.C is deprecated: use C2 instead
x4: Tuple[D, C, E] # N: class __main__.C is deprecated: use C2 instead
x5: Tuple[Tuple[D, C], E] # N: class __main__.C is deprecated: use C2 instead
x6: List[C] # N: class __main__.C is deprecated: use C2 instead
x7: List[List[C]] # N: class __main__.C is deprecated: use C2 instead
x8: List[Optional[Tuple[Union[List[C], int]]]] # N: class __main__.C is deprecated: use C2 instead
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a test case involving type aliases (including generic and/or recursive ones).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


[builtins fixtures/tuple.pyi]


Expand Down
Loading