Treat annotated assignments in class and module scopes as runtime (#2667)
This commit is contained in:
16
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH004_10.py
vendored
Normal file
16
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH004_10.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Tuple, List, Dict
|
||||
|
||||
x: Tuple
|
||||
|
||||
|
||||
class C:
|
||||
x: List
|
||||
|
||||
|
||||
def f():
|
||||
x: Dict
|
||||
14
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH004_9.py
vendored
Normal file
14
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH004_9.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Tuple, List, Dict
|
||||
|
||||
x: Tuple
|
||||
|
||||
|
||||
class C:
|
||||
x: List
|
||||
|
||||
|
||||
def f():
|
||||
x: Dict
|
||||
@@ -1945,7 +1945,21 @@ where
|
||||
value,
|
||||
..
|
||||
} => {
|
||||
self.visit_annotation(annotation);
|
||||
// If we're in a class or module scope, then the annotation needs to be available
|
||||
// at runtime.
|
||||
// See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements
|
||||
if !self.annotations_future_enabled
|
||||
&& matches!(
|
||||
self.current_scope().kind,
|
||||
ScopeKind::Class(..) | ScopeKind::Module
|
||||
)
|
||||
{
|
||||
self.in_type_definition = true;
|
||||
self.visit_expr(annotation);
|
||||
self.in_type_definition = false;
|
||||
} else {
|
||||
self.visit_annotation(annotation);
|
||||
}
|
||||
if let Some(expr) = value {
|
||||
if self.match_typing_expr(annotation, "TypeAlias") {
|
||||
self.in_type_definition = true;
|
||||
|
||||
@@ -26,6 +26,8 @@ mod tests {
|
||||
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_6.py"); "TCH004_6")]
|
||||
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_7.py"); "TCH004_7")]
|
||||
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_8.py"); "TCH004_8")]
|
||||
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_9.py"); "TCH004_9")]
|
||||
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_10.py"); "TCH004_10")]
|
||||
#[test_case(Rule::EmptyTypeCheckingBlock, Path::new("TCH005.py"); "TCH005")]
|
||||
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"); "strict")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
---
|
||||
source: src/rules/flake8_type_checking/mod.rs
|
||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
- kind:
|
||||
RuntimeImportInTypeCheckingBlock:
|
||||
full_name: typing.Any
|
||||
location:
|
||||
row: 4
|
||||
column: 23
|
||||
end_location:
|
||||
row: 4
|
||||
column: 26
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_type_checking/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
RuntimeImportInTypeCheckingBlock:
|
||||
full_name: typing.Tuple
|
||||
location:
|
||||
row: 4
|
||||
column: 23
|
||||
end_location:
|
||||
row: 4
|
||||
column: 28
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
RuntimeImportInTypeCheckingBlock:
|
||||
full_name: typing.List
|
||||
location:
|
||||
row: 4
|
||||
column: 30
|
||||
end_location:
|
||||
row: 4
|
||||
column: 34
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
Reference in New Issue
Block a user