From c7d988ef50f8582aad114a1fdc487dd75ff4f8e9 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 7 Nov 2023 23:21:45 -0800 Subject: [PATCH] Do not emit Y053 for the argument to @deprecated() (#444) --- CHANGELOG.md | 1 + pyi.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9b3614c..1029da30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Other changes: reduce the number of false positives from this check. * Attempting to import `typing_extensions.Text` now causes Y039 to be emitted rather than Y023. +* Y053 will no longer be emitted for the argument to `@typing_extensions.deprecated`. ## 23.10.0 diff --git a/pyi.py b/pyi.py index 18aa8c7a..c8f8e731 100644 --- a/pyi.py +++ b/pyi.py @@ -308,6 +308,9 @@ def _is_object(node: ast.AST | None, name: str, *, from_: Container[str]) -> boo _is_BaseException = partial(_is_object, name="BaseException", from_={"builtins"}) _is_TypeAlias = partial(_is_object, name="TypeAlias", from_=_TYPING_MODULES) _is_NamedTuple = partial(_is_object, name="NamedTuple", from_=_TYPING_MODULES) +_is_deprecated = partial( + _is_object, name="deprecated", from_={"typing_extensions", "warnings"} +) _is_TypedDict = partial( _is_object, name="TypedDict", from_=_TYPING_MODULES | {"mypy_extensions"} ) @@ -958,6 +961,7 @@ class PyiVisitor(ast.NodeVisitor): all_name_occurrences: Counter[str] string_literals_allowed: NestingCounter + long_strings_allowed: NestingCounter in_function: NestingCounter in_class: NestingCounter visiting_arg: NestingCounter @@ -975,6 +979,7 @@ def __init__(self, filename: str) -> None: self.typealias_decls = defaultdict(list) self.all_name_occurrences = Counter() self.string_literals_allowed = NestingCounter() + self.long_strings_allowed = NestingCounter() self.in_function = NestingCounter() self.in_class = NestingCounter() self.visiting_arg = NestingCounter() @@ -1156,6 +1161,11 @@ def visit_Call(self, node: ast.Call) -> None: if _is_bad_TypedDict(node): self.error(node, Y031) return + elif _is_deprecated(function): + with self.string_literals_allowed.enabled(), self.long_strings_allowed.enabled(): + for arg in chain(node.args, node.keywords): + self.visit(arg) + return elif ( isinstance(function, ast.Attribute) and isinstance(function.value, ast.Name) @@ -1176,7 +1186,10 @@ def visit_Call(self, node: ast.Call) -> None: def visit_Constant(self, node: ast.Constant) -> None: if isinstance(node.value, str) and not self.string_literals_allowed.active: self.error(node, Y020) - elif isinstance(node.value, (str, bytes)): + elif ( + isinstance(node.value, (str, bytes)) + and not self.long_strings_allowed.active + ): if len(node.value) > 50: self.error(node, Y053) elif isinstance(node.value, (int, float, complex)):