Avoid infinite loop between I002 and PYI025 #23352
Conversation
Fixes astral-sh#20891. When `lint.isort.required-imports` includes `from collections.abc import Set` (unaliased) and PYI025 is enabled, the two rules conflict: I002 inserts the unaliased import, while PYI025 demands it be aliased as `AbstractSet`. This causes an infinite autofix loop. Rather than patching the import-insertion logic, reject this contradictory configuration at startup in `Configuration::into_settings`, following the existing pattern of `conflicting_import_settings()`. The new `conflicting_required_import_pyi025()` function checks for the specific conflict and emits a clear error message with a suggested fix. Aliasing the required import as `AbstractSet` (satisfying both rules) or disabling PYI025 are both accepted configurations.
2d42908 to
f19b5e7
Compare
|
|
Gentle ping — this has been open since Feb 16 with clean CI and zero ecosystem impact. The approach follows the pattern suggested in #20891 (reject conflicting configuration at startup rather than working around it at the rule level). Would appreciate a review when someone has a chance. |
ntBre
left a comment
There was a problem hiding this comment.
Thanks, this looks good overall. I just had one testing suggestion.
| Ok(()) | ||
| } | ||
|
|
||
| mod pyi025_conflict { |
There was a problem hiding this comment.
Let's just add CLI tests like these:
ruff/crates/ruff/tests/cli/lint.rs
Lines 2842 to 2872 in 7778f65
That will also get us snapshots to verify the full contents of the error message.
There was a problem hiding this comment.
Done — replaced the unit tests with CLI snapshot tests in crates/ruff/tests/cli/lint.rs, following the pattern from the existing flake8_import_convention_unused_aliased_import tests. Three tests:
required_import_set_conflicts_with_pyi025— unaliasedSet+ PYI025 → exit code 2 with error messagerequired_import_set_aliased_as_abstract_set_no_conflict— aliased asAbstractSet→ no config errorrequired_import_set_without_pyi025_no_conflict— PYI025 not selected → no config error
Move PYI025 conflict tests from ruff_workspace unit tests to CLI integration tests using assert_cmd_snapshot!, matching the pattern used by the existing flake8-import-conventions conflict tests.
I002 and PYI025
Summary
Fixes #20891.
When
lint.isort.required-importsincludesfrom collections.abc import Set(unaliased) and PYI025 is enabled, the two rules conflict: I002 inserts the unaliased import, while PYI025 demands it be aliased asAbstractSet. This causes an infinite autofix loop ("Failed to converge after 100 iterations").Rather than patching the import-insertion logic at the rule level, this PR rejects the contradictory configuration at startup in
Configuration::into_settings(), following the existing pattern established byconflicting_import_settings(). The error message explains the conflict and suggests two resolutions: alias the required import asAbstractSet, or disable PYI025.Prior art
PR #21115 took a different approach (modifying
add_required_imports.rsandimports.rsto relax alias matching). As noted in review, the better fix is to "reject this configuration entirely at an earlier stage" since it doesn't make sense to simultaneously require an unaliased import and forbid it. This PR implements that suggestion directly.Test plan
AbstractSet→ ok, PYI025 not enabled → okruff check --config ruff.toml --unsafe-fixes --fixnow emits a clear configuration error instead of entering the infinite loopcargo test -p ruff_workspace— all 26 tests pass