[ruff] Prevent PYI025 from clashing with isort-required check#21115
[ruff] Prevent PYI025 from clashing with isort-required check#21115TaKO8Ki wants to merge 1 commit intoastral-sh:mainfrom
ruff] Prevent PYI025 from clashing with isort-required check#21115Conversation
remove new line
|
ntBre
left a comment
There was a problem hiding this comment.
Thank you!
I confirmed locally that this fixes the issue, but this test doesn't reproduce the error from the issue when I revert the rule change. I think you need to include a flag like --fix or --diff in the Command to reproduce the infinite loop.
| // 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; | ||
| } |
There was a problem hiding this comment.
I don't think this is the best fix. To me I think it would make more sense to reject this configuration entirely at an earlier stage. Fundamentally, it just doesn't make sense to tell Ruff that you simultaneously want from collections.abc import Set to always appear in every module, and also from collections.abc import Set to never appear in any module.
That implies that we'd want to edit this part of the code:
ruff/crates/ruff_workspace/src/configuration.rs
Lines 1614 to 1651 in aca8ba7
There was a problem hiding this comment.
I thought about that too. This seemed like a pretty niche issue, so I didn't feel too strongly, but this also makes sense to me.
There was a problem hiding this comment.
I generally have a pretty strong preference towards rejecting invalid configurations rather than silently accepting them and assuming we understand what the user actually wanted 😄
There was a problem hiding this comment.
We've done a bit of both with these conflicts, I think. #16802 is one example, but maybe that's different 🙂
There was a problem hiding this comment.
Ok. I will check it.
|
Thanks for working on this. I'll close this PR due to inactivity. Feel free to resubmit the changes with the feedback addressed. |
## Summary Fixes #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 ("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 by `conflicting_import_settings()`. The error message explains the conflict and suggests two resolutions: alias the required import as `AbstractSet`, or disable PYI025. ### Prior art PR #21115 took a different approach (modifying `add_required_imports.rs` and `imports.rs` to 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 - 3 unit tests: conflicting config → error, aliased as `AbstractSet` → ok, PYI025 not enabled → ok - Reproduction case: `ruff check --config ruff.toml --unsafe-fixes --fix` now emits a clear configuration error instead of entering the infinite loop - `cargo test -p ruff_workspace` — all 26 tests pass
Summary
Fixes #20891
Test Plan
Added
required_import_skips_pyi025.