Skip to content

Comments

Simplify Program configuration for GitHub output#20420

Merged
ntBre merged 4 commits intobrent/ty-githubfrom
brent/refactor-diagnostic-config
Sep 17, 2025
Merged

Simplify Program configuration for GitHub output#20420
ntBre merged 4 commits intobrent/ty-githubfrom
brent/refactor-diagnostic-config

Conversation

@ntBre
Copy link
Contributor

@ntBre ntBre commented Sep 15, 2025

Summary

This is a follow-up to #20358 to avoid adding a new DisplayDiagnosticConfig option (with a surprising default value) just to print the program name for GitHub diagnostics.

Initially I expected this to be a larger refactor including making the various Renderer::render methods take a std::io::Write instead of a std::fmt::Formatter to make them easier to call directly in Ruff. However, this was a bit more painful than expected because we use the Display implementation of DisplayDiagnostics for more than writing directly to stdout. Implementing Display on the individual renderers seemed like a smaller step in this direction.

At this point it might make sense just to merge this into #20358. Alternatively, I could apply the same transformation to the other affected renderers. For example, the JSON and JSON-lines formats only use their config fields for the preview setting. Or we could update all of the renderers and call them directly in Ruff instead of assembling a config at all. I just wanted to make sure this approach looked reasonable before applying it to everything.

Test Plan

Existing tests

My initial idea here was to make each `render` method take a `&mut dyn
std::io::Write` instead, but there are a few places where we use the
`DisplayDiagnostic` `Display` implementation outside of rendering to stdout.
This seemed like a decent way to preserve the `Display` functionality but also
enable writing directly to an `io::Write` as well.

revert non-github rendering changes
@ntBre ntBre added the internal An internal refactor or improvement label Sep 15, 2025
@codspeed-hq
Copy link

codspeed-hq bot commented Sep 15, 2025

CodSpeed Instrumentation Performance Report

Merging #20420 will degrade performances by 12.28%

Comparing brent/refactor-diagnostic-config (c287764) with brent/ty-github (1db7531)

Summary

❌ 1 regression
✅ 42 untouched

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
DateType 224 ms 255.4 ms -12.28%

@github-actions
Copy link
Contributor

github-actions bot commented Sep 15, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+0 -6 violations, +0 -0 fixes in 4 projects; 51 projects unchanged)

apache/superset (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview --select ALL

- superset/commands/database/tables.py:143:34: SIM910 [*] Use `extra_dict_by_name.get(table.table)` instead of `extra_dict_by_name.get(table.table, None)`

binary-husky/gpt_academic (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview

- request_llms/bridge_all.py:1304:31: SIM910 [*] Use `dict.get()` without default value

zulip/zulip (+0 -2 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview --select ALL

- zerver/models/users.py:736:28: SIM910 [*] Use `user_data.get(field.id)` instead of `user_data.get(field.id, None)`
- zerver/tornado/event_queue.py:1231:49: SIM910 [*] Use `extra_user_data.get(client.user_profile_id)` instead of `extra_user_data.get(client.user_profile_id, None)`

astropy/astropy (+0 -2 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview

- astropy/table/mixins/registry.py:66:16: SIM910 [*] Use `dict.get()` without default value
- astropy/wcs/wcsapi/fitswcs.py:287:34: SIM910 [*] Use `CTYPE_TO_UCD1.get(ctype_name.upper())` instead of `CTYPE_TO_UCD1.get(ctype_name.upper(), None)`

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
SIM910 6 0 6 0 0

@ntBre
Copy link
Contributor Author

ntBre commented Sep 15, 2025

I'm pretty sure the ecosystem and benchmark results are just a quirk of the base branch, but I'll keep an eye on that for sure.

@ntBre ntBre marked this pull request as ready for review September 15, 2025 17:20
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
for diagnostic in diagnostics {
impl std::fmt::Display for GithubRenderer<'_> {
Copy link
Member

Choose a reason for hiding this comment

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

It wasn't clear to me from the summary what the motivation was for implementing Display for Renderer but, after playing with the code, the issue seems to be that ty uses an std::fmt::Write whereas Ruff uses an std::io::Write.

I do find it odd that a Renderer can be displayed, especially because its display implementation shows the diagnostic and not the renderer.

  1. Introduce a Renderer trait that has a single render method that takes a std::fmt::Formatter and a &[Diagnostic] and create a new DisplayDiagnostics<R: Renderer> that implements Display by forwarding to the wrapped renderer. The main challenge with this is that we already have a DisplayDiagnostics type in ruff_db. My opinion is still that we should delete the old DisplayDiagnostics type and move DiagnosticFormat out of ruff_db, as which formats are supported is a concern of ty/ruff. But this is a bit a larger refactor (but I think it would be worth it because it also helps clarify which program supports which DiagnosticFormats).
  2. Rename GithubRenderer to GithubDiagnostics. That's obviously a much simpler change but it's a bit more awkward because it no longer fits into the render module.

For this PR, I think what I'd do is to do a mix of 1 and 2 by:

  • Restore the render method on GithubRenderer
  • Introduce a new DisplayGithubDiagnostics type which takes a renderer and diagnostics as input and implements Display. We can use this type in places where we need to write to a std::io::Write

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah, sorry that wasn't clear. Yes, Ruff's Emitters take a &mut dyn std::io::Write, but DisplayDiagnostics and the Renderers in ty operate via std::fmt::Display and std::fmt::Formatters. As I mentioned on #20358, I thought the best fix was moving DisplayDiagnostics and the renderers to use std::io::Write too, but there were a few places where this wasn't an easy switch. These are two of the less important cases since they're in tests:

pub(super) fn render(&self, diag: &Diagnostic) -> String {
diag.display(&self.db, &self.config).to_string()
}
/// Render the given diagnostics into a `String`.
///
/// See `render` for rendering a single diagnostic.
///
/// (This will set the "printed" flag on `Diagnostic`.)
pub(super) fn render_diagnostics(&self, diagnostics: &[Diagnostic]) -> String {
DisplayDiagnostics::new(&self.db, &self.config, diagnostics).to_string()
}

This seemed like the more painful case that made me rethink the approach and try implementing Display for each renderer:

write!(
f,
"{}",
self.error
.diagnostic
.to_diagnostic()
.display(&self.db, &display_config)
)

I just tried fixing that one and more keep popping up, so I think your suggestions sound very helpful. Thank you!

@ntBre ntBre merged commit be3b649 into brent/ty-github Sep 17, 2025
34 of 35 checks passed
@ntBre ntBre deleted the brent/refactor-diagnostic-config branch September 17, 2025 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal An internal refactor or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants