[pyupgrade] Gated behind a preview of separate diagnostics (UP010)#20020
[pyupgrade] Gated behind a preview of separate diagnostics (UP010)#20020IDrokin117 wants to merge 4 commits intoastral-sh:mainfrom
pyupgrade] Gated behind a preview of separate diagnostics (UP010)#20020Conversation
|
CodSpeed Performance ReportMerging #20020 will not alter performanceComparing Summary
Footnotes
|
d94ab32 to
6b2d9f7
Compare
6b2d9f7 to
f0419d2
Compare
|
@ntBre Could you please review PR? |
|
Yes, sorry for the delay! We've been preparing for the 0.13 release this past week. I'll be catching up on reviews once that goes out. |
|
What's the motivation for splitting the diagnostics? This seems unnecessarily verbose to me. Could we instead use the new sub-diagnostics to highlight the individual ranges? |
|
What I liked about the split diagnostics in #19769 (review) was mostly just underlining the affected imports instead of the whole import statement, which I think could also be handled by sub-diagnostics. As one supporting example, we also emit one diagnostic per import for unused-import (F401). Although we could revisit that as well now that we have sub-diagnostics. I don't feel too strongly either way, though. |
|
@ntBre What should I do here? It seems diagnostics work per import as for F401, doesn't it? Should I use sub-diagnostics instead? What piece of code can I take as a "sub-diagnostic" example? |
|
I think we just need to reach agreement on how many diagnostics to emit. If you want to try sub-diagnostics to see how they look, here is a previous comment I used on another PR: The easiest way is with ruff/crates/ruff_linter/src/checkers/ast/mod.rs Lines 3309 to 3311 in 2245355 Here's the one use of it we've added so far: ruff/crates/ruff_linter/src/rules/pyflakes/rules/redefined_while_unused.rs Lines 195 to 198 in 2245355 And an example of the type of diagnostic it produces (the There are some other options if that doesn't look good, but that's the easiest place to start. That's not technically a sub-diagnostic, but we've only added a nice helper for secondary annotations rather than |
gated changes behind preview
544c1c5 to
846deed
Compare
846deed to
2f8a912
Compare
|
@ntBre @MichaReiser I've rewritten the diagnostic using secondary_annotation. Please check it and let me know how it looks now. |
| 1 | from __future__ import nested_scopes, generators | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^-------------^^---------- |
There was a problem hiding this comment.
I think if we do go this route, we should narrow the primary diagnostic range to just __future__ (or maybe from __future__ or from __future__ import) to keep the two ranges from overlapping:
| 1 | from __future__ import nested_scopes, generators | |
| | ^^^^^^^^^^^^^^^^^^^^^^^-------------^^---------- | |
| 1 | from __future__ import nested_scopes, generators | |
| | ^^^^^^^^^^ ------------- ---------- |
I think I'd still prefer either one diagnostic per import, or just leaving the diagnostic as it is on stable, over this, though. But I'm curious to hear what Micha thinks. Thank you for exploring this!
There was a problem hiding this comment.
I'd have to double-check but narrowing the range changes the places where suppression comments are allowed.
E.g, the following currently works but I suspect won't work if we narrow the range
from __future__ import (
nested_scopes, # noqa <RULE>
generators
)
There was a problem hiding this comment.
Hmm yeah, using multiple annotated ranges and highlighting the entire import statement doesn't help improve readability.
I only found this usage in cargo:
warning: methods `unused1` and `unused2` are never used
--> src/function/maybe_changed_after.rs:41:19
|
32 | impl VerifyResult {
| ----------------- methods in this implementation
...
41 | pub(crate) fn unused1(&self) {}
| ^^^^^^^
42 |
43 | pub(crate) fn unused2(&self) {}
| ^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
They use the unused1 as the primary range and mark the impl block as a secondary annotation. But doing the same in Ruff requires figuring out how to make our suppression system understand that this diagnostic represents two separate violations (the current assumption is that diagnostics only represent a single error.
There was a problem hiding this comment.
Ah, would narrowing the noqa range actually be a benefit of separate diagnostics here? Something like this doesn't currently work:
from __future__ import (
nested_scopes, # noqa: UP010
generators,
)
generatorsYou have to put the noqa here:
from __future__ import ( # noqa: UP010
nested_scopes,
generators,
)
generatorsat least that's the only place I found that works.
But yeah, I think secondary annotations are probably better for highlighting additional context that helps to explain the main diagnostic but likely falls outside the normal snippet context window, like in your Rust example.
There was a problem hiding this comment.
It appears that the previous implementation, which uses separate diagnostics, functions well for # noqa: UP010 per import object. Should I revert to that approach?
There was a problem hiding this comment.
I'm leaning towards leaving it as is. I don't think that any of the tried approaches greatly improve the rendered diagnostics to justify a breaking change. But maybe Brent thinks differently? I'd otherwise close this PR and suggest that we revisit the rendering once we have figured out how to better handle those cases with our diagnostic system. But thank you a lot for trying out all those different approaches. It was very helpful to drive the decision-making and show where there's some need to improve our diagnostic system.
There was a problem hiding this comment.
Yeah, I think I agree with Micha. Thank you for working on this, I also agree that it was very helpful to see the different options!
Summary
Second part of #19769
Separate diagnostic generation for each unused import and range updating accordingly. Gated behind a preview
Test Plan
Added preview snapshots