Skip to content

Coalesce source slices when formatting attributes - #29841

Merged
charliermarsh merged 2 commits into
mainfrom
codex/formatter-coalesce-attribute-slices
Oct 30, 2026
Merged

charliermarsh merged 2 commits into
mainfrom
codex/formatter-coalesce-attribute-slices

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

Formatting and printing the top-level modules in CPython’s standard library took 3.9% less time in a local benchmark (125.7 ms to 120.8 ms), or 2.4% less with parsing included. CodSpeed reports a 5.1% efficiency improvement on the large/dataset.py formatter benchmark.

Today the formatter emits a source slice for a, a dot token, and a source slice for b just to print a.b. We now emit the whole expression as one slice when the dot touches both names, the first name is unparenthesized, and there are no comments or call-chain breaks to handle. Reading directly from the source also preserves Unicode spellings like 𝓪.𝓫.

For factory().attr, we still format the call and handle any line break before the dot, but we can emit .attr as one slice. This follows the approach in Oxc #28462.

@charliermarsh charliermarsh added formatter Related to the Ruff formatter performance Potential performance improvement labels Oct 30, 2026 — with ChatGPT Codex Connector
@astral-automations-bot

astral-automations-bot Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

ruff-ecosystem results

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

Formatter (stable) · Formatter (preview)


Results for 22b6453 · Workflow run

@codspeed

codspeed Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 5.33%

1 warning

⚠️ 1 benchmark with a significant change ran on different hardware

Its base and head results were measured on machines with a different CPU, core count or memory, so the change might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

⚡ 1 improved benchmark
✅ 59 untouched benchmarks
⏩ 238 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
⚡ CPU Simulation formatter[large/dataset.py] 14.1 ms 13.4 ms +5.33%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing codex/formatter-coalesce-attribute-slices (22b6453) with main (f93c0b1)

Open in CodSpeed

Footnotes

  1. 238 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@charliermarsh
charliermarsh marked this pull request as ready for review October 30, 2026 05:38

a = Namespace()

# Attribute slices preserve source spelling, including NFKC-normalized identifiers.

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.

The tests here feel excessive. They also test more than what was changed in this PR. Are they redundant?

if value.is_name_expr()
&& !call_chain_layout.is_fluent()
&& &f.context().source()[TextRange::new(value.end(), attr.start())] == "."
&& !f.context().is_expression_parenthesized(value.into())

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.

Is this check necessary? We test that the only text between value and attr is a .. Which means there's no closing parentheses between value and attr.

&& &f.context().source()[TextRange::new(value.end(), attr.start())] == "."
&& !f.context().is_expression_parenthesized(value.into())
&& !f.context().comments().has(value.as_ref())
&& !f.context().comments().has_dangling(item)

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.

Should we move the dangling declaration further up and use it here, to avoid resolving the item's dangling comments twice?

@charliermarsh
charliermarsh enabled auto-merge (squash) October 30, 2026 21:11
@charliermarsh
charliermarsh merged commit 08aac42 into main Oct 30, 2026
55 checks passed
@charliermarsh
charliermarsh deleted the codex/formatter-coalesce-attribute-slices branch October 30, 2026 21:16

This branch was previously deployed

1 inactive deployment
automations — 22b64531 Deployed Oct 30, 2026 by charliermarsh via security-review / security review #96376
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

formatter Related to the Ruff formatter performance Potential performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants