Skip to content

Commit 151ba49

Browse files
authored
[pyupgrade] Prevent infinite loop with I002 and UP026 (#20327)
## Summary Fixes #19842 Prevent infinite loop with I002 and UP026 - Implement isort-aware handling for UP026 (deprecated mock import): - Add CLI integration tests in crates/ruff/tests/lint.rs: ## Test Plan I have added two integration tests `pyupgrade_up026_respects_isort_required_import_fix` and `pyupgrade_up026_respects_isort_required_import_from_fix` in `crates/ruff/tests/lint.rs`.
1 parent 82796df commit 151ba49

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

crates/ruff/tests/lint.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5059,6 +5059,59 @@ fn flake8_import_convention_unused_aliased_import_no_conflict() {
50595059
);
50605060
}
50615061

5062+
// https://github.com/astral-sh/ruff/issues/19842
5063+
#[test]
5064+
fn pyupgrade_up026_respects_isort_required_import_fix() {
5065+
assert_cmd_snapshot!(
5066+
Command::new(get_cargo_bin(BIN_NAME))
5067+
.arg("--isolated")
5068+
.arg("check")
5069+
.arg("-")
5070+
.args(["--select", "I002,UP026"])
5071+
.arg("--config")
5072+
.arg(r#"lint.isort.required-imports=["import mock"]"#)
5073+
.arg("--fix")
5074+
.arg("--no-cache")
5075+
.pass_stdin("1\n"),
5076+
@r"
5077+
success: true
5078+
exit_code: 0
5079+
----- stdout -----
5080+
import mock
5081+
1
5082+
5083+
----- stderr -----
5084+
Found 1 error (1 fixed, 0 remaining).
5085+
"
5086+
);
5087+
}
5088+
5089+
// https://github.com/astral-sh/ruff/issues/19842
5090+
#[test]
5091+
fn pyupgrade_up026_respects_isort_required_import_from_fix() {
5092+
assert_cmd_snapshot!(
5093+
Command::new(get_cargo_bin(BIN_NAME))
5094+
.arg("--isolated")
5095+
.arg("check")
5096+
.arg("-")
5097+
.args(["--select", "I002,UP026"])
5098+
.arg("--config")
5099+
.arg(r#"lint.isort.required-imports = ["from mock import mock"]"#)
5100+
.arg("--fix")
5101+
.arg("--no-cache")
5102+
.pass_stdin("from mock import mock\n"),
5103+
@r"
5104+
success: true
5105+
exit_code: 0
5106+
----- stdout -----
5107+
from mock import mock
5108+
5109+
----- stderr -----
5110+
All checks passed!
5111+
"
5112+
);
5113+
}
5114+
50625115
// See: https://github.com/astral-sh/ruff/issues/16177
50635116
#[test]
50645117
fn flake8_pyi_redundant_none_literal() {

crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_mock_import.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::Locator;
1717
use crate::checkers::ast::Checker;
1818
use crate::cst::matchers::{match_import, match_import_from, match_statement};
1919
use crate::fix::codemods::CodegenStylist;
20+
use crate::rules::pyupgrade::rules::is_import_required_by_isort;
2021
use crate::{AlwaysFixableViolation, Edit, Fix};
2122

2223
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -299,7 +300,13 @@ pub(crate) fn deprecated_mock_import(checker: &Checker, stmt: &Stmt) {
299300

300301
// Add a `Diagnostic` for each `mock` import.
301302
for name in names {
302-
if &name.name == "mock" || &name.name == "mock.mock" {
303+
if (&name.name == "mock" || &name.name == "mock.mock")
304+
&& !is_import_required_by_isort(
305+
&checker.settings().isort.required_imports,
306+
stmt.into(),
307+
name,
308+
)
309+
{
303310
let mut diagnostic = checker.report_diagnostic(
304311
DeprecatedMockImport {
305312
reference_type: MockReference::Import,
@@ -319,13 +326,25 @@ pub(crate) fn deprecated_mock_import(checker: &Checker, stmt: &Stmt) {
319326
Stmt::ImportFrom(ast::StmtImportFrom {
320327
module: Some(module),
321328
level,
329+
names,
322330
..
323331
}) => {
324332
if *level > 0 {
325333
return;
326334
}
327335

328336
if module == "mock" {
337+
if names.iter().any(|alias| {
338+
alias.name.as_str() == "mock"
339+
&& is_import_required_by_isort(
340+
&checker.settings().isort.required_imports,
341+
stmt.into(),
342+
alias,
343+
)
344+
}) {
345+
return;
346+
}
347+
329348
let mut diagnostic = checker.report_diagnostic(
330349
DeprecatedMockImport {
331350
reference_type: MockReference::Import,

0 commit comments

Comments
 (0)