Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Regression test for https://github.com/astral-sh/ruff/issues/23185.
#
# With `future-annotations = true` and `strict = false`, a typing-only import
# that is implicitly loaded by a valid runtime-used sibling import from the
# same module should NOT be flagged as TC001/TC002/TC003.


def from_collections_abc():
# `Set` is used at runtime, so `Iterable` is implicitly available at runtime.
from collections.abc import Iterable, Set

def f(x: Iterable[int]) -> Set[int]:
return Set(x)


def from_pkg():
# `pkg` is used at runtime, `A` is typing-only but implicitly runtime-available
# via `pkg`.
import pkg
from pkg import A

def test(value: A):
return pkg.B()


def submodule_implicit():
# `pkg.bar` is used at runtime, which implicitly makes `pkg` available.
import pkg
import pkg.bar

def test(value: pkg.A):
return pkg.bar.B()
23 changes: 23 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 @@ -118,6 +118,29 @@ mod tests {
Ok(())
}

#[test]
fn future_annotations_respects_non_strict_mode() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_type_checking")
.join("TC001-3_future_strict.py")
.as_path(),
&settings::LinterSettings {
future_annotations: true,
flake8_type_checking: super::settings::Settings {
strict: false,
..Default::default()
},
..settings::LinterSettings::for_rules([
Rule::TypingOnlyFirstPartyImport,
Rule::TypingOnlyThirdPartyImport,
Rule::TypingOnlyStandardLibraryImport,
])
},
)?;
assert_diagnostics!(diagnostics);
Ok(())
}

// we test these rules as a pair, since they're opposites of one another
// so we want to make sure their fixes are not going around in circles.
#[test_case(Rule::UnquotedTypeAlias, Path::new("TC007.py"))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,9 @@ pub(crate) fn typing_only_runtime_import(
for binding_id in scope.binding_ids() {
let binding = checker.semantic().binding(binding_id);

// If we can't add a `__future__` import and in un-strict mode, don't flag typing-only
// imports that are implicitly loaded by way of a valid runtime import.
if !checker.settings().future_annotations
&& !checker.settings().flake8_type_checking.strict
// If we're in un-strict mode, don't flag typing-only imports that are
// implicitly loaded by way of a valid runtime import.
if !checker.settings().flake8_type_checking.strict
&& runtime_imports
.iter()
.any(|import| is_implicit_import(binding, import))
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
---

Loading