Skip to content

Commit

Permalink
Detect runtime-evaluated base classes defined in the current file (#8572
Browse files Browse the repository at this point in the history
)

Closes #8250.

Closes #5486.
  • Loading branch information
charliermarsh committed Nov 9, 2023
1 parent 4760af3 commit 722687a
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 0 deletions.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from __future__ import annotations

from collections.abc import Sequence


class MyBaseClass:
pass


class Foo(MyBaseClass):
foo: Sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from __future__ import annotations

from collections.abc import Sequence

from module.direct import MyBaseClass


class Foo(MyBaseClass):
foo: Sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from __future__ import annotations

from collections.abc import Sequence


class Foo(MyBaseClass):
foo: Sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from __future__ import annotations

from collections.abc import Sequence # TCH003


class MyBaseClass:
pass


class Foo(MyBaseClass):
foo: Sequence
22 changes: 22 additions & 0 deletions crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---

Original file line number Diff line number Diff line change
@@ -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):


10 changes: 10 additions & 0 deletions crates/ruff_python_semantic/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand Down

0 comments on commit 722687a

Please sign in to comment.