Skip to content

Commit 8ad7519

Browse files
committed
Use _is_object
* Supports typing_extension * Error message is now attached to decorator, not function
1 parent 2fd34f0 commit 8ad7519

File tree

2 files changed

+24
-45
lines changed

2 files changed

+24
-45
lines changed

flake8_pyi/visitor.py

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -146,22 +146,6 @@ def _ast_node_for(string: str) -> ast.AST:
146146
return expr.value
147147

148148

149-
def _flatten_name(node: ast.expr) -> str | None:
150-
"""Return the flattened name of an expression, or None.
151-
152-
E.g.:
153-
* ast.Name(id="Any") -> "Any"
154-
* ast.Attribute(value=ast.Name(id="typing"), attr="Any") -> "typing.Any"
155-
"""
156-
157-
if isinstance(node, ast.Name):
158-
return node.id
159-
elif isinstance(node, ast.Attribute):
160-
parent = _flatten_name(node.value)
161-
return f"{parent}.{node.attr}" if parent else None
162-
return None
163-
164-
165149
def _is_name(node: ast.AST | None, name: str) -> bool:
166150
"""Return True if `node` is an `ast.Name` node with id `name`.
167151
@@ -242,6 +226,7 @@ def _is_object(node: ast.AST | None, name: str, *, from_: Container[str]) -> boo
242226
)
243227
_is_Generic = partial(_is_object, name="Generic", from_=_TYPING_MODULES)
244228
_is_Unpack = partial(_is_object, name="Unpack", from_=_TYPING_MODULES)
229+
_is_override = partial(_is_object, name="override", from_=_TYPING_MODULES)
245230

246231

247232
def _is_union(node: ast.expr | None) -> TypeIs[ast.BinOp]:
@@ -2050,11 +2035,12 @@ def check_protocol_param_kinds(
20502035

20512036
def check_for_override(
20522037
self,
2053-
node: ast.FunctionDef | ast.AsyncFunctionDef,
2054-
decorator_names: Container[str],
2038+
node: ast.FunctionDef | ast.AsyncFunctionDef
20552039
) -> None:
2056-
if "override" in decorator_names or "typing.override" in decorator_names:
2057-
self.error(node, errors.Y068)
2040+
for deco in node.decorator_list:
2041+
if _is_override(deco):
2042+
self.error(deco, errors.Y068)
2043+
return
20582044

20592045
@staticmethod
20602046
def _is_positional_pre_570_argname(name: str) -> bool:
@@ -2110,26 +2096,15 @@ def _visit_function(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None:
21102096

21112097
self._check_pep570_syntax_used_where_applicable(node)
21122098
if self.enclosing_class_ctx is not None:
2113-
decorator_names = self._decorator_names(node)
2099+
decorator_names = {
2100+
decorator.id
2101+
for decorator in node.decorator_list
2102+
if isinstance(decorator, ast.Name)
2103+
}
21142104
self.check_self_typevars(node, decorator_names)
21152105
if self.enclosing_class_ctx.is_protocol_class:
21162106
self.check_protocol_param_kinds(node, decorator_names)
2117-
self.check_for_override(node, decorator_names)
2118-
2119-
@staticmethod
2120-
def _decorator_names(node: ast.FunctionDef | ast.AsyncFunctionDef) -> list[str]:
2121-
"""Return the decorator names applied to this function.
2122-
2123-
No normalization will be done.
2124-
2125-
E.g. "staticmethod", "override", or "typing.override"
2126-
"""
2127-
names = []
2128-
for decorator in node.decorator_list:
2129-
name = _flatten_name(decorator)
2130-
if name is not None:
2131-
names.append(name)
2132-
return names
2107+
self.check_for_override(node)
21332108

21342109
def visit_arg(self, node: ast.arg) -> None:
21352110
if _is_NoReturn(node.annotation):

tests/override.pyi

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import typing
22
import typing as t
3+
import typing_extensions
34
from typing import override, override as over
45

56
class Foo:
67
def f(self) -> None: ...
78
def g(self) -> None: ...
89
def h(self) -> None: ...
910
def j(self) -> None: ...
11+
def k(self) -> None: ...
1012

1113
class Bar(Foo):
12-
@override
13-
def f(self) -> None: ... # Y068 Do not use "@override" in stub files.
14-
@typing.override
15-
def g(self) -> None: ... # Y068 Do not use "@override" in stub files.
16-
@t.override
17-
def h(self) -> None: ... # Ideally we'd catch this too, but the infrastructure is not in place.
18-
@over
19-
def j(self) -> None: ... # Ideally we'd catch this too, but the infrastructure is not in place.
14+
@override # Y068 Do not use "@override" in stub files.
15+
def f(self) -> None: ...
16+
@typing.override # Y068 Do not use "@override" in stub files.
17+
def g(self) -> None: ...
18+
@t.override # Ideally we'd catch this too, but the infrastructure is not in place.
19+
def h(self) -> None: ...
20+
@over # Ideally we'd catch this too, but the infrastructure is not in place.
21+
def j(self) -> None: ...
22+
@typing_extensions.override # Y068 Do not use "@override" in stub files.
23+
def k(self) -> None: ...

0 commit comments

Comments
 (0)