diff --git a/crates/ruff/tests/lint.rs b/crates/ruff/tests/lint.rs index efa9b084294955..fc2d8cc2813060 100644 --- a/crates/ruff/tests/lint.rs +++ b/crates/ruff/tests/lint.rs @@ -5059,6 +5059,59 @@ fn flake8_import_convention_unused_aliased_import_no_conflict() { ); } +// https://github.com/astral-sh/ruff/issues/19842 +#[test] +fn pyupgrade_up026_respects_isort_required_import_fix() { + assert_cmd_snapshot!( + Command::new(get_cargo_bin(BIN_NAME)) + .arg("--isolated") + .arg("check") + .arg("-") + .args(["--select", "I002,UP026"]) + .arg("--config") + .arg(r#"lint.isort.required-imports=["import mock"]"#) + .arg("--fix") + .arg("--no-cache") + .pass_stdin("1\n"), + @r" + success: true + exit_code: 0 + ----- stdout ----- + import mock + 1 + + ----- stderr ----- + Found 1 error (1 fixed, 0 remaining). + " + ); +} + +// https://github.com/astral-sh/ruff/issues/19842 +#[test] +fn pyupgrade_up026_respects_isort_required_import_from_fix() { + assert_cmd_snapshot!( + Command::new(get_cargo_bin(BIN_NAME)) + .arg("--isolated") + .arg("check") + .arg("-") + .args(["--select", "I002,UP026"]) + .arg("--config") + .arg(r#"lint.isort.required-imports = ["from mock import mock"]"#) + .arg("--fix") + .arg("--no-cache") + .pass_stdin("from mock import mock\n"), + @r" + success: true + exit_code: 0 + ----- stdout ----- + from mock import mock + + ----- stderr ----- + All checks passed! + " + ); +} + // See: https://github.com/astral-sh/ruff/issues/16177 #[test] fn flake8_pyi_redundant_none_literal() { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_mock_import.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_mock_import.rs index 0ef84304fc41a2..5a77e36dbb4ff1 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_mock_import.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_mock_import.rs @@ -17,6 +17,7 @@ use crate::Locator; use crate::checkers::ast::Checker; use crate::cst::matchers::{match_import, match_import_from, match_statement}; use crate::fix::codemods::CodegenStylist; +use crate::rules::pyupgrade::rules::is_import_required_by_isort; use crate::{AlwaysFixableViolation, Edit, Fix}; #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -299,7 +300,13 @@ pub(crate) fn deprecated_mock_import(checker: &Checker, stmt: &Stmt) { // Add a `Diagnostic` for each `mock` import. for name in names { - if &name.name == "mock" || &name.name == "mock.mock" { + if (&name.name == "mock" || &name.name == "mock.mock") + && !is_import_required_by_isort( + &checker.settings().isort.required_imports, + stmt.into(), + name, + ) + { let mut diagnostic = checker.report_diagnostic( DeprecatedMockImport { reference_type: MockReference::Import, @@ -319,6 +326,7 @@ pub(crate) fn deprecated_mock_import(checker: &Checker, stmt: &Stmt) { Stmt::ImportFrom(ast::StmtImportFrom { module: Some(module), level, + names, .. }) => { if *level > 0 { @@ -326,6 +334,17 @@ pub(crate) fn deprecated_mock_import(checker: &Checker, stmt: &Stmt) { } if module == "mock" { + if names.iter().any(|alias| { + alias.name.as_str() == "mock" + && is_import_required_by_isort( + &checker.settings().isort.required_imports, + stmt.into(), + alias, + ) + }) { + return; + } + let mut diagnostic = checker.report_diagnostic( DeprecatedMockImport { reference_type: MockReference::Import,