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:
Charlie Marsh 2023-11-08 19:38:06 -08:00 committed by GitHub
parent 4760af3dcb
commit 722687ad72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 103 additions and 0 deletions

View file

@ -0,0 +1,11 @@
from __future__ import annotations
from collections.abc import Sequence
class MyBaseClass:
pass
class Foo(MyBaseClass):
foo: Sequence

View file

@ -0,0 +1,9 @@
from __future__ import annotations
from collections.abc import Sequence
from module.direct import MyBaseClass
class Foo(MyBaseClass):
foo: Sequence

View file

@ -0,0 +1,7 @@
from __future__ import annotations
from collections.abc import Sequence
class Foo(MyBaseClass):
foo: Sequence

View file

@ -0,0 +1,11 @@
from __future__ import annotations
from collections.abc import Sequence # TCH003
class MyBaseClass:
pass
class Foo(MyBaseClass):
foo: Sequence

View file

@ -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

View file

@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---

View file

@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---

View file

@ -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):

View file

@ -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,
}
}