This commit is contained in:
Takayuki Maeda 2025-11-16 19:20:03 +01:00 committed by GitHub
commit c089bfd645
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 0 deletions

View file

@ -3710,3 +3710,33 @@ fn supported_file_extensions_preview_enabled() -> Result<()> {
");
Ok(())
}
// Regression test for https://github.com/astral-sh/ruff/issues/20891
#[test]
fn required_import_skips_pyi025() {
assert_cmd_snapshot!(
Command::new(get_cargo_bin(BIN_NAME))
.arg("--isolated")
.arg("check")
.args(["--select", "F401,I002,PYI025"])
.arg("--config")
.arg(r#"lint.isort.required-imports=["from collections.abc import Set"]"#)
.arg("-")
.arg("--unsafe-fixes")
.arg("--no-cache")
.pass_stdin("1"),
@r"
success: false
exit_code: 1
----- stdout -----
I002 [*] Missing required import: `from collections.abc import Set`
--> -:1:1
help: Insert required import: `from collections.abc import Set`
Found 1 error.
[*] 1 fixable with the --fix option.
----- stderr -----
"
);
}

View file

@ -1,10 +1,12 @@
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::{Stmt, StmtImportFrom};
use ruff_python_semantic::Imported;
use ruff_python_semantic::{Binding, BindingKind, Scope};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::renamer::Renamer;
use crate::rules::pyupgrade::rules::is_import_required_by_isort;
use crate::{Applicability, Fix, FixAvailability, Violation};
/// ## What it does
@ -73,6 +75,20 @@ pub(crate) fn unaliased_collections_abc_set_import(checker: &Checker, binding: &
return;
}
// Skip if this import is required by isort to prevent infinite loops with I002 and F401
if let Some(stmt @ Stmt::ImportFrom(StmtImportFrom { names, .. })) =
binding.statement(checker.semantic())
&& names.iter().any(|alias| {
is_import_required_by_isort(
&checker.settings().isort.required_imports,
stmt.into(),
alias,
)
})
{
return;
}
let mut diagnostic =
checker.report_diagnostic(UnaliasedCollectionsAbcSetImport, binding.range());
if checker.semantic().is_available("AbstractSet") {