-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does the Ruff formatter validate the final AST in a similar manner to Black? #8184
Comments
We don't have this behavior, no. We could consider adding it based on interest. (Not strictly relevant to the question, but just so there's no confusion for any future readers: all benchmarks were compared against Black with |
Thanks for the info! |
No problem. For completeness: our test suite consists of a large set of fixtures (including Black's own test fixtures, plus a bunch of our own), and then we also run the formatter over a selection of open source projects on CI too ( For the fixtures, we validate output against checked-in snapshots. For the ecosystem projects, we're just diffing to assess similarity. But in both cases, we also error if:
|
(Will leave this open for now to see if other folks have additional feedback or questions.) |
We also have fuzzing (e.g. #7938) which covers a lot of strange edge cases. In recent runs i've only seen instabilities (the second formatting pass looks different than the first) but no syntax errors. |
Validating the final AST can still help against accidental formatting changes that would change runtime behaviour. A good example would be accidentally formatting |
FWIW I think it should be opt-in, behind a flag to enable it, and all tests (including ones that run ruff against open source projects) should run with that flag enabled, to catch such cases. |
That's true, but it requires that the used AST only captures runtime semantics, which isn't the case for Ruff. For example, ruff stores (or will soon) the parts of each implicit concatenated string as individual nodes because having access to each part is useful when doing static analysis (but irrelevant for an interpreter): "a" "b"
# joined
"ab"
The runtime value of both expressions is the same, but Ruff uses a different internal representation for each. I believe there are other examples around parenthesizing match cases which change the AST structure, but don't result in a semantical change. Because of that, I believe using the AST for asserting that the runtime semantics are unchanged isn't a good choice and it prevents Ruff from changing its internal AST structure to capture more information, slowing down the development. It would be nice to have another automatic means to validate that the formatter doesn't change program semantics (could be very useful during fuzzing). We could explore integrating and comparing Python's AST as part of fuzzing, but I prefer not to compare Ruff's ASTs as part of |
@MichaReiser That is indeed along the lines of what I'm suggesting. Having that option available to end users behind a CLI flag would be a nice to have, but using it for fuzzing during CI seems much more important to me. |
In fairness, we do have the |
Oh right. Although it will be interesting to see how we would support this (in a cheap way) if we change our AST structure more fundamentally. We're also considering integrating |
Consider having Since import sorting should be a flag that you can disable ( |
I've been working on introducing the ruff formatter at work but got this question when trying to introduce it as a formatting tool for my organization. The
Implementing a similar AST validation as an optional flag for the ruff formatter would be a great feature that would make switching over a no-brainer for the team - and speaking personally we would be more than willing to pay for the performance hit that it might cause. |
If you only want to add it to tests and fuzzing, one easy way to write an AST comparison test would be: def check_same_ast(path):
with temp_copy(path) as before:
with temp_copy(path) as after:
run_ruff(after)
run_black(before)
run_black(after)
assert run_sha256sum(before) == run_sha256sum(after) |
@SonOfLilit ruff outputs aren't identical to black though |
Indeed, they aren't. But black output is idempotent and does the check we
want, so two files will have the same output if and only if they contain
the same AST, so comparing before/after ruff is a cheap way to compare ASTs.
…On Fri, Nov 10, 2023, 11:38 Tushar Sadhwani ***@***.***> wrote:
@SonOfLilit <https://github.com/SonOfLilit> ruff outputs aren't identical
to black though
—
Reply to this email directly, view it on GitHub
<#8184 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAADU7OIFELZ34GIE6LCLE3YDXYX7AVCNFSM6AAAAAA6OJRBJWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMBVGM4DSOBXGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Ah right, i misread the code. Not a bad idea. |
## Summary This PR implements validation in the formatter tests to ensure that we don't modify the AST during formatting. Black has similar logic. In implementing this, I learned that Black actually _does_ modify the AST, and their test infrastructure normalizes the AST to wipe away those differences. Specifically, Black changes the indentation of docstrings, which _does_ modify the AST; and it also inserts parentheses in `del` statements, which changes the AST too. Ruff also does both these things, so we _also_ implement the same normalization using a new visitor that allows for modifying the AST. Closes #8184. ## Test Plan `cargo test`
We now perform this validation during tests. Interestingly, in implementing this validation, I learned that Black actually does modify the AST during formatting, and so Ruff does too :) Namely, Black modifies indentation within docstrings, which is reflected in the AST; and Black will also parenthesize long |
If I understand the above correctly, this check is only performed when running ruffs test suite at the moment. |
No, we don’t support running this check at runtime. |
We are looking to replace
black
with the Ruff formatter, but one question I had was does the Ruff formatter validate for an AST equivalent to the original? I know this can be disabled inblack
with the--fast
flag but was curious if this was built into the Ruff formatter by default.The text was updated successfully, but these errors were encountered: