Skip to content

Vendor latest annotate-snippets - #27033

Merged
epage merged 34 commits into
astral-sh:mainfrom
epage:update-annotate
Jul 28, 2026
Merged

Vendor latest annotate-snippets#27033
epage merged 34 commits into
astral-sh:mainfrom
epage:update-annotate

Conversation

@epage

@epage epage commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a first step towards #20411. After this, we would work to either upstream changes or adjust things within Ruff.

Performance improvements have already been upstreamed (rust-lang/annotate-snippets-rs#437, rust-lang/annotate-snippets-rs#440)

Re-implemented the following from the fork:

Additional hacks to minimize behavior change include

All of the above represents work that needs to be resolved to address #20411.

lib.name hack is used to simplify maintenance with the assumption that we'll continue working towards #20411.

Behavior changes that were included

  • Tweak when implicit padding lines are present
  • Fix Origin's line/column is now derived from the primary annotation
  • Make consistent the rendering of primary/context annotations
  • Fix snippets to show up for empty source (but may degrade ruff format --check outputs wrong line line/column numbers on syntax errors #24528)
  • Fix handling of term width
  • Fix rendering of annotations between newline and first character (granted, maybe the caller is wrong)
  • Tweak multiline annotation markers

New or upcoming features annotate-snippets features that we will be able to leverage by moving this forward

  • AnnotationKind::Visible to improve the quality of built-in code-folding if Ruff were to switch to it
  • DecorStyle::Unicode
  • (upcoming) No-graphiscs mode for screen readers (may also be useful for AIs)

Deferred:

  • Moving related Groups into the same Report
  • Using secondary_title for any Group after the first in a Report
  • Using a Snippet, instead of titles, for "virtual code" like Vendor latest annotate-snippets #27033 (comment)
  • Switching hidden snippets to Origin

Test Plan

Within cpython, I ran

$ hyperfine -i "../../ruff/target-baseline/release/ruff check" "../../ruff/target-update/release/ruff check" -N -m20 --output=null
Benchmark 1: ../../ruff/target-baseline/release/ruff check
  Time (mean ± σ):      27.5 ms ±   1.1 ms    [User: 33.0 ms, System: 108.4 ms]
  Range (min … max):    25.0 ms …  31.7 ms    94 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: ../../ruff/target-update/release/ruff check
  Time (mean ± σ):      28.1 ms ±   2.0 ms    [User: 33.4 ms, System: 105.7 ms]
  Range (min … max):    24.8 ms …  38.9 ms    102 runs

  Warning: Ignoring non-zero exit code.
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use t
he '--warmup' or '--prepare' options.

Summary
  ../../ruff/target-baseline/release/ruff check ran
    1.03 ± 0.08 times faster than ../../ruff/target-update/release/ruff check

Before:
image

After:
image

@epage
epage requested review from a team, BurntSushi, MichaReiser and dhruvmanila as code owners July 20, 2026 20:49
@epage
epage marked this pull request as draft July 20, 2026 20:49
@astral-sh-bot

astral-sh-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 96.84%. The percentage of expected errors that received a diagnostic held steady at 92.11%. The number of fully passing files held steady at 99/133.

@astral-sh-bot

astral-sh-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

Memory usage report

Memory usage unchanged ✅

@epage
epage force-pushed the update-annotate branch from 5fa50a5 to 7a252c7 Compare July 20, 2026 20:54
@astral-sh-bot

astral-sh-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

@epage
epage force-pushed the update-annotate branch from 7a252c7 to 18f44d1 Compare July 20, 2026 21:09
@astral-sh-bot

astral-sh-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@epage
epage force-pushed the update-annotate branch 2 times, most recently from 5bfbeb6 to ddbb335 Compare July 20, 2026 21:31
----- stdout -----
unformatted: File would be reformatted
--> CRATE_ROOT/resources/test/fixtures/unformatted.ipynb:cell 1:1:1
--> CRATE_ROOT/resources/test/fixtures/unformatted.ipynb:cell 1:2:1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntBre is this the format check bugfix that you wanted to look into?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. The root cause of #24528 is failing to attach spans to syntax error diagnostics, not a rendering issue.

6 | class FormFeedIndent:
7 | def __init__(self, a=[]):
| ^^
7 | def __init__(self, a=[]):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

Comment on lines -216 to 220
--> has_syntax_error.py:1:1
--> has_syntax_error.py:2:1
|
2 |
| ^

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While more correct, this may degrade #24528

Comment on lines 99 to 103
3 | elf:
4 | pass
| ^ Syntax Error: Expected a statement
5 | else:
| ^ Syntax Error: Expected a statement
6 | pass

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The span is between the \n and e, so this is the more correct placement but unsure what the intended placement is

@MichaReiser

MichaReiser commented Jul 21, 2026

Copy link
Copy Markdown
Member

I'm a bit confused by the changes in Bless added pipes and Bless removed pipes. It's not clear what's different between the pipes that were removed/added.

Overall, it might be helpful to give a short explanation for each of those blessed commits. E.g. why did the locations in Bless origin location changes. Were they incorrect, why? Same for added/removed pipes. Why were they removed/added? Were they incorrect?

info: This violates the Liskov Substitution Principle
help: It is recommended for `__eq__` to work with arbitrary objects, for example:
help
help:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now renders with a trailing whitespace. Any chance we can avoid printing the whitespace if not followed by a text?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to keep this as-is and instead open a follow up issue to switch this to using a Snippet to render it. If it is important enough to this PR, I could instead make that change before hand.

@epage

epage commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

I'm a bit confused by the changes in Bless added pipes and Bless removed pipes. It's not clear what's different between the pipes that were removed/added.

Overall, it might be helpful to give a short explanation for each of those blessed commits. E.g. why did the locations in Bless origin location changes. Were they incorrect, why? Same for added/removed pipes. Why were they removed/added? Were they incorrect?

Looking at it closer, it appears that the "added" commit just undoes some of the "removed" commit. I've squashed them.

--> lib/module.py:1:1
--> lib/module.py:1:1
|
1 |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think this is some special casing that @ntBre introduced to prevent this. I don't remember why we did that. Is there another way of disabling rendering of the snippet (at a diagnostic level)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we should call hide_snippet in places where we don't want to show an empty span.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked through each case

  • One is that the annotated line is empty
  • The rest are when a snippet is being shown for context but the source for that snippet is empty

In each case, I think this PR is doing the right thing in showing these snippets.

Two potential improvements that I think are reasonable to defer are

  • Showing an ␃ for empty spans at the end of a file
  • Showing a line of context before an error on an empty line

If there is a reason we should special case to hide empty lines, I would appreciate better understanding it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think this is some special casing that @ntBre introduced to prevent this. I don't remember why we did that.

Also, I dug through the history and changes, and didn't see what this was referring to.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you might mean the file-level stuff.

And looking closer, some of those look like they should be file level (go-to-definition for a module takes you to the module)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah, these file-level snippets are for an internal-only render to visualize IDE actions so it doesn't really matter.

@epage
epage force-pushed the update-annotate branch from ddbb335 to 5d641f1 Compare July 21, 2026 13:55
7 |
| ^ Syntax Error: Expected a statement
8 | a = 10
| ^ Syntax Error: Expected a statement

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd have to take a look at the parser but this certainly is confusing now. Because this is the start of a statement.

@MichaReiser MichaReiser Jul 21, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems accurate for what span the parser picks. I'd be nice if we can use a more meaningful range (or omit this error all together, if it always follow another error). If you're interested, feel free to take a look at it. I otherwise suggest that we open a follow up issue for this.

We could also consider slihgtly changing the wording, if that helps

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, #27170 removed all but one of these

@MichaReiser

MichaReiser commented Jul 21, 2026

Copy link
Copy Markdown
Member

Codex explained to me that the line changes were cases where the diagnostic incorrectly used the range of a secondary annotation. Whoops. Nice catch.

Yes. The old Ruff-vendored annotate-snippets renderer used the first annotation in the snippet, irrespective of whether it was primary:

@MichaReiser

Copy link
Copy Markdown
Member

This looks great overall. Thank you

epage added 25 commits July 28, 2026 11:19
78e5fe0 implemented support for hiding
severities from upstream annotate-snippets.
Likely, this was just an implementation oversight upstream but the exact
details of what it should look like upstream are TBD.
I believe the new rendered is collapsing the trailing padding line with
the annotation line.
The origin line and column is now determined by the primary annotation.
Reasons
- Primary now has precedence over context when overlapping
- The primary now always has the same symbol, independent of level
The old renderer allowed the snipper to go past the term width.
The annotation is between the newline and the first character,
so this is the more correct place to render it.
When to go past the end-of-line to represent the newline has changed.
The two renderers diverged in their newline behavior and I tried to
restore the old behavior as much as possible and I hit my timebox for
getting this exactly right since this didn't seem the most important to
get perfectly the same.
@epage
epage force-pushed the update-annotate branch from 9395226 to 5eec5d3 Compare July 28, 2026 16:26
@epage

epage commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

I'm going to go ahead and merge and continue to iterate as this is conflict heavy. If someone has a concern with this, we can revert.

@epage
epage merged commit 958efb1 into astral-sh:main Jul 28, 2026
63 checks passed
@epage
epage deleted the update-annotate branch July 28, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants