mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:04 +00:00
Detect runtime-evaluated base classes defined in the current file (#8572)
Closes https://github.com/astral-sh/ruff/issues/8250. Closes https://github.com/astral-sh/ruff/issues/5486.
This commit is contained in:
parent
4760af3dcb
commit
722687ad72
10 changed files with 103 additions and 0 deletions
0
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/__init__.py
vendored
Normal file
0
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/__init__.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/direct.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/direct.py
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
class MyBaseClass:
|
||||
pass
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/import.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/import.py
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from module.direct import MyBaseClass
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/undefined.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/undefined.py
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
|
@ -0,0 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence # TCH003
|
||||
|
||||
|
||||
class MyBaseClass:
|
||||
pass
|
||||
|
||||
|
||||
class Foo(MyBaseClass):
|
||||
foo: Sequence
|
|
@ -144,6 +144,28 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("module/direct.py"))]
|
||||
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("module/import.py"))]
|
||||
#[test_case(
|
||||
Rule::TypingOnlyStandardLibraryImport,
|
||||
Path::new("module/undefined.py")
|
||||
)]
|
||||
fn base_class_same_file(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_type_checking").join(path).as_path(),
|
||||
&settings::LinterSettings {
|
||||
flake8_type_checking: super::settings::Settings {
|
||||
runtime_evaluated_base_classes: vec!["module.direct.MyBaseClass".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
..settings::LinterSettings::for_rule(rule_code)
|
||||
},
|
||||
)?;
|
||||
assert_messages!(snapshot, diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(
|
||||
r#"
|
||||
from __future__ import annotations
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
|
||||
---
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
|
||||
---
|
||||
undefined.py:3:29: TCH003 [*] Move standard library import `collections.abc.Sequence` into a type-checking block
|
||||
|
|
||||
1 | from __future__ import annotations
|
||||
2 |
|
||||
3 | from collections.abc import Sequence
|
||||
| ^^^^^^^^ TCH003
|
||||
|
|
||||
= help: Move into type-checking block
|
||||
|
||||
ℹ Unsafe fix
|
||||
1 1 | from __future__ import annotations
|
||||
2 2 |
|
||||
3 |-from collections.abc import Sequence
|
||||
3 |+from typing import TYPE_CHECKING
|
||||
4 |+
|
||||
5 |+if TYPE_CHECKING:
|
||||
6 |+ from collections.abc import Sequence
|
||||
4 7 |
|
||||
5 8 |
|
||||
6 9 | class Foo(MyBaseClass):
|
||||
|
||||
|
|
@ -686,6 +686,16 @@ impl<'a> SemanticModel<'a> {
|
|||
Some(resolved)
|
||||
}
|
||||
BindingKind::Builtin => Some(smallvec!["", head.id.as_str()]),
|
||||
BindingKind::ClassDefinition(_) | BindingKind::FunctionDefinition(_) => {
|
||||
let value_path = collect_call_path(value)?;
|
||||
let resolved: CallPath = self
|
||||
.module_path?
|
||||
.iter()
|
||||
.map(String::as_str)
|
||||
.chain(value_path)
|
||||
.collect();
|
||||
Some(resolved)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue