Commit Graph

821 Commits

Author SHA1 Message Date
Brent Westbrook 98d20a8219
Preserve quotes in generated byte strings (#15778)
## Summary

This is a very closely related follow-up to #15726, adding the same
quote-preserving behavior to bytestrings. Only one rule (UP018) was
affected this time, and it was easy to mirror the plain string changes.

## Test Plan

Existing tests
2025-01-28 08:19:40 -05:00
Alex Waygood 9c938442e5
[minor] Simplify some `ExprStringLiteral` creation logic (#15775) 2025-01-27 18:51:13 +00:00
Brent Westbrook 9bf138c45a
Preserve quote style in generated code (#15726)
## Summary

This is a first step toward fixing #7799 by using the quoting style
stored in the `flags` field on `ast::StringLiteral`s to select a quoting
style. This PR does not include support for f-strings or byte strings.

Several rules also needed small updates to pass along existing quoting
styles instead of using `StringLiteralFlags::default()`. The remaining
snapshot changes are intentional and should preserve the quotes from the
input strings.

## Test Plan

Existing tests with some accepted updates, plus a few new RUF055 tests
for raw strings.

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
2025-01-27 13:41:03 -05:00
Douglas Creager ef85c682bd
Remove customizable reference enum names (#15647)
The AST generator creates a reference enum for each syntax group — an
enum where each variant contains a reference to the relevant syntax
node. Previously you could customize the name of the reference enum for
a group — primarily because there was an existing `ExpressionRef` type
that wouldn't have lined up with the auto-derived name `ExprRef`. This
follow-up PR is a simple search/replace to switch over to the
auto-derived name, so that we can remove this customization point.
2025-01-21 13:46:31 -05:00
Calum Young 023c52d82b
Standardise ruff config (#15558) 2025-01-21 12:09:11 +01:00
Douglas Creager 98ef564170
Remove `AstNode` and `AnyNode` (#15479)
While looking into potential AST optimizations, I noticed the `AstNode`
trait and `AnyNode` type aren't used anywhere in Ruff or Red Knot. It
looks like they might be historical artifacts of previous ways of
consuming AST nodes?

- `AstNode::cast`, `AstNode::cast_ref`, and `AstNode::can_cast` are not
used anywhere.
- Since `cast_ref` isn't needed anymore, the `Ref` associated type isn't
either.

This is a pure refactoring, with no intended behavior changes.
2025-01-17 17:11:00 -05:00
Douglas Creager 8e3633f55a
Auto-generate AST boilerplate (#15544)
This PR replaces most of the hard-coded AST definitions with a
generation script, similar to what happens in `rust_python_formatter`.
I've replaced every "rote" definition that I could find, where the
content is entirely boilerplate and only depends on what syntax nodes
there are and which groups they belong to.

This is a pretty massive diff, but it's entirely a refactoring. It
should make absolutely no changes to the API or implementation. In
particular, this required adding some configuration knobs that let us
override default auto-generated names where they don't line up with
types that we created previously by hand.

## Test plan

There should be no changes outside of the `rust_python_ast` crate, which
verifies that there were no API changes as a result of the
auto-generation. Aggressive `cargo clippy` and `uvx pre-commit` runs
after each commit in the branch.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-01-17 14:23:02 -05:00
Micha Reiser 1ecb7ce645
Fix unstable f-string formatting for expressions containing a trailing comma (#15545) 2025-01-17 10:08:09 +01:00
Micha Reiser 9ed67ba33e
Fix bracket spacing for single-element tuples in f-string expressions (#15537) 2025-01-17 08:02:34 +00:00
Micha Reiser 420365811f
Fix joining of f-strings with different quotes when using quote style `Preserve` (#15524) 2025-01-16 12:01:42 +01:00
Micha Reiser 96c2d0996d
Fix curly bracket spacing around curly f-string expressions (#15471) 2025-01-15 09:22:47 +01:00
Micha Reiser c39ca8fe6d
Upgrade Rust toolchain to 1.84.0 (#15408) 2025-01-11 09:51:58 +01:00
Micha Reiser 2b28d566a4
Associate a trailing end-of-line comment in a parenthesized implicit concatenated string with the last literal (#15378) 2025-01-10 19:21:34 +01:00
Dhruv Manilawala f706c3fdf2 Add f-string formatting to the docs (#15367)
Revive https://github.com/astral-sh/ruff/pull/15341 as it got removed
from the latest rebase in https://github.com/astral-sh/ruff/pull/15238.
2025-01-09 10:20:06 +01:00
Micha Reiser 424b720c19 Ruff 2025 style guide (#13906)
Closes #13371
2025-01-09 10:20:06 +01:00
Micha Reiser 1218bc65ed
Preserve multiline implicit concatenated strings in docstring positions (#15126) 2025-01-03 10:27:14 +01:00
Micha Reiser 82faa9bb62
Add tests demonstrating f-strings with debug expressions in replacements that contain escaped characters (#14929) 2024-12-12 09:33:20 +00:00
Dimitri Papadopoulos Orfanos 68eb0a2511
Stop referring to early ruff versions (#14862)
## Summary

Referring to old versions has become more distracting than useful.

## Test Plan

—
2024-12-09 16:47:26 +01:00
Dimitri Papadopoulos Orfanos 59145098d6
Fix typos found by codespell (#14863)
## Summary

Just fix typos.

## Test Plan

CI tests.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2024-12-09 09:32:12 +00:00
Micha Reiser 1559c73fcd
Fix fstring formatting removing overlong implicit concatenated string in expression part (#14811)
## Summary

Fixes https://github.com/astral-sh/ruff/issues/14778


The formatter incorrectly removed the inner implicitly concatenated
string for following single-line f-string:

```py
f"{'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'a' if True else ""}"

# formatted
f"{ if True else ''}"
```

This happened because I changed the `RemoveSoftlinesBuffer` in
https://github.com/astral-sh/ruff/pull/14489 to remove any content
wrapped in `if_group_breaks`. After all, it emulates an *all flat*
layout. This works fine when `if_group_breaks` is only used to **add**
content if the gorup breaks. It doesn't work if the same content is
rendered differently depending on if the group fits using
`if_group_breaks` and `if_groups_fits` because the enclosing `group`
might still *break* if the entire content exceeds the line-length limit.

This PR fixes this by unwrapping any `if_group_fits` content by removing
the `if_group_fits` start and end tags.


## Test Plan

added test
2024-12-06 13:01:04 +01:00
renovate[bot] 5a67d3269b
Update pre-commit dependencies (#14719) 2024-12-02 06:02:56 +00:00
Micha Reiser b63c2e126b
Upgrade Rust toolchain to 1.83 (#14677) 2024-11-29 12:05:05 +00:00
Dhruv Manilawala f96fa6b0e2
Do not consider f-strings with escaped newlines as multiline (#14624)
## Summary

This PR fixes a bug in the f-string formatting to not consider the
escaped newlines for `is_multiline`. This is done by checking if the
f-string is triple-quoted or not similar to normal string literals.

This is not required to be gated behind preview because the logic change
for `is_multiline` was added in
https://github.com/astral-sh/ruff/pull/14454.

## Test Plan

Add a test case which formats differently on `main`:
https://play.ruff.rs/ea3c55c2-f0fe-474e-b6b8-e3365e0ede5e
2024-11-27 10:25:38 +00:00
Dhruv Manilawala 4cd2b9926e
Gate `is_multiline` change behind preview (#14630)
## Summary

Ref:
https://github.com/astral-sh/ruff/pull/14624#pullrequestreview-2464127254

## Test Plan

The test case in the follow-up PR showcases the difference between
preview and non-preview formatting:
https://github.com/astral-sh/ruff/pull/14624/files#diff-dc25bd4df280d9a9180598075b5bc2d0bac30af956767b373561029309c8f024
2024-11-27 15:50:28 +05:30
Dhruv Manilawala c84c690f1e
Avoid invalid syntax for format-spec with quotes for all Python versions (#14625)
## Summary

fixes: #14608

The logic that was only applied for 3.12+ target version needs to be
applied for other versions as well.

## Test Plan

I've moved the existing test cases for 3.12 only to `f_string.py` so
that it's tested against the default target version.

I think we should probably enabled testing for two target version (pre
3.12 and 3.12) but it won't highlight any issue because the parser
doesn't consider this. Maybe we should enable this once we have target
version specific syntax errors in place
(https://github.com/astral-sh/ruff/issues/6591).
2024-11-27 13:19:33 +05:30
Dhruv Manilawala f3dac27e9a
Fix f-string formatting in assignment statement (#14454)
## Summary

fixes: #13813

This PR fixes a bug in the formatting assignment statement when the
value is an f-string.

This is resolved by using custom best fit layouts if the f-string is (a)
not already a flat f-string (thus, cannot be multiline) and (b) is not a
multiline string (thus, cannot be flattened). So, it is used in cases
like the following:
```py
aaaaaaaaaaaaaaaaaa = f"testeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee{
    expression}moreeeeeeeeeeeeeeeee"
```
Which is (a) `FStringLayout::Multiline` and (b) not a multiline.

There are various other examples in the PR diff along with additional
explanation and context as code comments.

## Test Plan

Add multiple test cases for various scenarios.
2024-11-26 15:07:18 +05:30
Dhruv Manilawala efe54081d6
Remove `FormatFStringPart` (#14448)
## Summary

This is just a small refactor to remove the `FormatFStringPart` as it's
only used in the case when the f-string is not implicitly concatenated
in which case the only part is going to be `FString`. In implicitly
concatenated f-strings, we use `StringLike` instead.
2024-11-25 10:29:22 +05:30
Micha Reiser b80de52592
Consider quotes inside format-specs when choosing the quotes for an f-string (#14493) 2024-11-22 12:43:53 +00:00
Micha Reiser 302fe76c2b
Fix unnecessary space around power op in overlong f-string expressions (#14489) 2024-11-22 13:01:22 +01:00
yataka 1b180c8342 Change default for Python version from 3.8 to 3.9 (#13896)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-11-20 13:11:51 +01:00
Micha Reiser 1f07880d5c
Add tests for python version compatibility (#14430) 2024-11-18 12:26:55 +00:00
Micha Reiser c847cad389
Update insta snapshots (#14366) 2024-11-15 19:31:15 +01:00
Micha Reiser 443fd3b660
Disallow single-line implicit concatenated strings (#13928) 2024-11-03 11:49:26 +00:00
Micha Reiser cf0f5e1318
Fix formatting of single with-item with trailing comment (#14005) 2024-11-01 09:08:06 +01:00
Micha Reiser 9f3a38d408
Extract `LineIndex` independent methods from `Locator` (#13938) 2024-10-28 07:53:41 +00:00
Dhruv Manilawala 5af0966057
Remove unreferenced snapshots (#13958) 2024-10-28 07:16:05 +01:00
Micha Reiser 113ce840a6
Fix `normalize` arguments when `fstring_formatting` is disabled (#13910) 2024-10-24 13:07:18 +00:00
Micha Reiser 7272f83868
Fix preview style name in `can_omit_parentheses` to is_f_string_formatting_enabled (#13907) 2024-10-24 11:32:28 +00:00
Micha Reiser 73ee72b665
Join implicit concatenated strings when they fit on a line (#13663) 2024-10-24 11:52:22 +02:00
Micha Reiser 2f88f84972
Alternate quotes for strings inside f-strings in preview (#13860) 2024-10-23 07:57:53 +02:00
Micha Reiser e9dd92107c
formatter: Introduce `QuoteMetadata` (#13858) 2024-10-21 20:23:46 +01:00
Alex Waygood 72adb09bf3
Simplify iteration idioms (#13834)
Remove unnecessary uses of `.as_ref()`, `.iter()`, `&**` and similar, mostly in situations when iterating over variables. Many of these changes are only possible following #13826, when we bumped our MSRV to 1.80: several useful implementations on `&Box<[T]>` were only stabilised in Rust 1.80. Some of these changes we could have done earlier, however.
2024-10-20 22:25:27 +01:00
Micha Reiser 27c50bebec
Bump MSRV to Rust 1.80 (#13826) 2024-10-20 10:55:36 +02:00
Micha Reiser 2ff36530c3
Upgrade to Rust 1.82 (#13816) 2024-10-19 16:05:50 +02:00
Micha Reiser 6d7da7bdbe
Revert "Upgrade to Rust 1.82 toolchain" (#13810) 2024-10-18 12:18:26 +00:00
Micha Reiser ff72055558
Upgrade to Rust 1.82 toolchain (#13808) 2024-10-18 12:08:15 +00:00
Micha Reiser a94914dc35
Enable preview mode for 'unstable' black tests (#13776) 2024-10-16 12:25:34 +00:00
Micha Reiser 8f5b2aac9a
Refactor: Remove `StringPart` and `AnyStringPart` in favor of `StringLikePart` (#13772) 2024-10-16 12:52:06 +02:00
Micha Reiser b9827a4122
Remove layout values from `AnyStringPart` (#13681) 2024-10-09 07:25:40 +01:00
Micha Reiser fc661e193a
Normalize implicit concatenated f-string quotes per part (#13539) 2024-10-08 09:59:17 +00:00
Micha Reiser f3e464ea4c
refactor: Simplify quote selection logic (#13536) 2024-09-27 14:40:28 +02:00
Micha Reiser 253f5f269a
refactor: Rename `FormatStringContinuation` to `FormatImplicitConcatenatedString` (#13531) 2024-09-27 08:24:50 +00:00
Micha Reiser c046101b79
Fix codeblock dynamic line length calculation for indented examples (#13523) 2024-09-27 09:09:07 +02:00
Micha Reiser 9442cd8fae
Parenthesize `match..case` `if` guards (#13513) 2024-09-26 06:44:33 +00:00
Micha Reiser 8012707348
Align formatting of patterns in match-cases with expression formatting in clause headers (#13510) 2024-09-26 08:35:22 +02:00
Micha Reiser 531ebf6dff
Fix parentheses around return type annotations (#13381) 2024-09-20 09:23:53 +02:00
Hamir Mahal 8b3da1867e
refactor: remove unnecessary string hashes (#13250) 2024-09-18 19:08:59 +02:00
Micha Reiser 6ac61d7b89
Fix placement of inline parameter comments (#13379) 2024-09-18 08:26:06 +02:00
Micha Reiser d86e5ad031
Update Black tests (#13375) 2024-09-17 11:16:50 +02:00
Dhruv Manilawala 47f0b45be3
Implement `AstNode` for `Identifier` (#13207)
## Summary

Follow-up to #13147, this PR implements the `AstNode` for `Identifier`.
This makes it easier to create the `NodeKey` in red knot because it uses
a generic method to construct the key from `AnyNodeRef` and is important
for definitions that are created only on identifiers instead of
`ExprName`.

## Test Plan

`cargo test` and `cargo clippy`
2024-09-02 16:27:12 +05:30
Alex Waygood aa0db338d9
Implement `iter()`, `len()` and `is_empty()` for all display-literal AST nodes (#12807) 2024-08-12 10:39:28 +00:00
Micha Reiser 138e70bd5c
Upgrade to Rust 1.80 (#12586) 2024-07-30 19:18:08 +00:00
Micha Reiser e18b4e42d3
[red-knot] Upgrade to the *new* *new* salsa (#12406) 2024-07-29 07:21:24 +00:00
Micha Reiser ed238e0c76
Fix incorrect placement of leading function comment with type params (#12447) 2024-07-22 14:17:00 +02:00
konsti 9a817a2922
Insert empty line between suite and alternative branch after def/class (#12294)
When there is a function or class definition at the end of a suite
followed by the beginning of an alternative block, we have to insert a
single empty line between them.

In the if-else-statement example below, we insert an empty line after
the `foo` in the if-block, but none after the else-block `foo`, since in
the latter case the enclosing suite already adds empty lines.

```python
if sys.version_info >= (3, 10):
    def foo():
        return "new"
else:
    def foo():
        return "old"
class Bar:
    pass
```

To do so, we track whether the current suite is the last one in the
current statement with a new option on the suite kind.

Fixes #12199

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2024-07-15 12:59:33 +02:00
Micha Reiser bd01004a42
Use `space` separator before parenthesiszed expressions in comprehensions with leading comments. (#12282) 2024-07-11 22:38:12 +02:00
renovate[bot] 53a80a5c11
Update Rust crate rustc-hash to v2 (#12001) 2024-06-23 20:46:42 -04:00
Micha Reiser 1f654ee729
Upgrade to Rust 1.79 (#11875) 2024-06-17 07:15:10 +01:00
Dhruv Manilawala 549cc1e437
Build `CommentRanges` outside the parser (#11792)
## Summary

This PR updates the parser to remove building the `CommentRanges` and
instead it'll be built by the linter and the formatter when it's
required.

For the linter, it'll be built and owned by the `Indexer` while for the
formatter it'll be built from the `Tokens` struct and passed as an
argument.

## Test Plan

`cargo insta test`
2024-06-09 09:55:17 +00:00
Micha Reiser 32ca704956
Rename `PreorderVisitor` to `SourceOrderVisitor` (#11798)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-06-07 17:01:58 +00:00
Micha Reiser 5806bc915d
Fix formatter instability for lines only consisting of zero-width characters (#11748) 2024-06-05 17:55:14 +02:00
Dhruv Manilawala bf5b62edac
Maintain synchronicity between the lexer and the parser (#11457)
## Summary

This PR updates the entire parser stack in multiple ways:

### Make the lexer lazy

* https://github.com/astral-sh/ruff/pull/11244
* https://github.com/astral-sh/ruff/pull/11473

Previously, Ruff's lexer would act as an iterator. The parser would
collect all the tokens in a vector first and then process the tokens to
create the syntax tree.

The first task in this project is to update the entire parsing flow to
make the lexer lazy. This includes the `Lexer`, `TokenSource`, and
`Parser`. For context, the `TokenSource` is a wrapper around the `Lexer`
to filter out the trivia tokens[^1]. Now, the parser will ask the token
source to get the next token and only then the lexer will continue and
emit the token. This means that the lexer needs to be aware of the
"current" token. When the `next_token` is called, the current token will
be updated with the newly lexed token.

The main motivation to make the lexer lazy is to allow re-lexing a token
in a different context. This is going to be really useful to make the
parser error resilience. For example, currently the emitted tokens
remains the same even if the parser can recover from an unclosed
parenthesis. This is important because the lexer emits a
`NonLogicalNewline` in parenthesized context while a normal `Newline` in
non-parenthesized context. This different kinds of newline is also used
to emit the indentation tokens which is important for the parser as it's
used to determine the start and end of a block.

Additionally, this allows us to implement the following functionalities:
1. Checkpoint - rewind infrastructure: The idea here is to create a
checkpoint and continue lexing. At a later point, this checkpoint can be
used to rewind the lexer back to the provided checkpoint.
2. Remove the `SoftKeywordTransformer` and instead use lookahead or
speculative parsing to determine whether a soft keyword is a keyword or
an identifier
3. Remove the `Tok` enum. The `Tok` enum represents the tokens emitted
by the lexer but it contains owned data which makes it expensive to
clone. The new `TokenKind` enum just represents the type of token which
is very cheap.

This brings up a question as to how will the parser get the owned value
which was stored on `Tok`. This will be solved by introducing a new
`TokenValue` enum which only contains a subset of token kinds which has
the owned value. This is stored on the lexer and is requested by the
parser when it wants to process the data. For example:
8196720f80/crates/ruff_python_parser/src/parser/expression.rs (L1260-L1262)

[^1]: Trivia tokens are `NonLogicalNewline` and `Comment`

### Remove `SoftKeywordTransformer`

* https://github.com/astral-sh/ruff/pull/11441
* https://github.com/astral-sh/ruff/pull/11459
* https://github.com/astral-sh/ruff/pull/11442
* https://github.com/astral-sh/ruff/pull/11443
* https://github.com/astral-sh/ruff/pull/11474

For context,
https://github.com/RustPython/RustPython/pull/4519/files#diff-5de40045e78e794aa5ab0b8aacf531aa477daf826d31ca129467703855408220
added support for soft keywords in the parser which uses infinite
lookahead to classify a soft keyword as a keyword or an identifier. This
is a brilliant idea as it basically wraps the existing Lexer and works
on top of it which means that the logic for lexing and re-lexing a soft
keyword remains separate. The change here is to remove
`SoftKeywordTransformer` and let the parser determine this based on
context, lookahead and speculative parsing.

* **Context:** The transformer needs to know the position of the lexer
between it being at a statement position or a simple statement position.
This is because a `match` token starts a compound statement while a
`type` token starts a simple statement. **The parser already knows
this.**
* **Lookahead:** Now that the parser knows the context it can perform
lookahead of up to two tokens to classify the soft keyword. The logic
for this is mentioned in the PR implementing it for `type` and `match
soft keyword.
* **Speculative parsing:** This is where the checkpoint - rewind
infrastructure helps. For `match` soft keyword, there are certain cases
for which we can't classify based on lookahead. The idea here is to
create a checkpoint and keep parsing. Based on whether the parsing was
successful and what tokens are ahead we can classify the remaining
cases. Refer to #11443 for more details.

If the soft keyword is being parsed in an identifier context, it'll be
converted to an identifier and the emitted token will be updated as
well. Refer
8196720f80/crates/ruff_python_parser/src/parser/expression.rs (L487-L491).

The `case` soft keyword doesn't require any special handling because
it'll be a keyword only in the context of a match statement.

### Update the parser API

* https://github.com/astral-sh/ruff/pull/11494
* https://github.com/astral-sh/ruff/pull/11505

Now that the lexer is in sync with the parser, and the parser helps to
determine whether a soft keyword is a keyword or an identifier, the
lexer cannot be used on its own. The reason being that it's not
sensitive to the context (which is correct). This means that the parser
API needs to be updated to not allow any access to the lexer.

Previously, there were multiple ways to parse the source code:
1. Passing the source code itself
2. Or, passing the tokens

Now that the lexer and parser are working together, the API
corresponding to (2) cannot exists. The final API is mentioned in this
PR description: https://github.com/astral-sh/ruff/pull/11494.

### Refactor the downstream tools (linter and formatter)

* https://github.com/astral-sh/ruff/pull/11511
* https://github.com/astral-sh/ruff/pull/11515
* https://github.com/astral-sh/ruff/pull/11529
* https://github.com/astral-sh/ruff/pull/11562
* https://github.com/astral-sh/ruff/pull/11592

And, the final set of changes involves updating all references of the
lexer and `Tok` enum. This was done in two-parts:
1. Update all the references in a way that doesn't require any changes
from this PR i.e., it can be done independently
	* https://github.com/astral-sh/ruff/pull/11402
	* https://github.com/astral-sh/ruff/pull/11406
	* https://github.com/astral-sh/ruff/pull/11418
	* https://github.com/astral-sh/ruff/pull/11419
	* https://github.com/astral-sh/ruff/pull/11420
	* https://github.com/astral-sh/ruff/pull/11424
2. Update all the remaining references to use the changes made in this
PR

For (2), there were various strategies used:
1. Introduce a new `Tokens` struct which wraps the token vector and add
methods to query a certain subset of tokens. These includes:
	1. `up_to_first_unknown` which replaces the `tokenize` function
2. `in_range` and `after` which replaces the `lex_starts_at` function
where the former returns the tokens within the given range while the
latter returns all the tokens after the given offset
2. Introduce a new `TokenFlags` which is a set of flags to query certain
information from a token. Currently, this information is only limited to
any string type token but can be expanded to include other information
in the future as needed. https://github.com/astral-sh/ruff/pull/11578
3. Move the `CommentRanges` to the parsed output because this
information is common to both the linter and the formatter. This removes
the need for `tokens_and_ranges` function.

## Test Plan

- [x] Update and verify the test snapshots
- [x] Make sure the entire test suite is passing
- [x] Make sure there are no changes in the ecosystem checks
- [x] Run the fuzzer on the parser
- [x] Run this change on dozens of open-source projects

### Running this change on dozens of open-source projects

Refer to the PR description to get the list of open source projects used
for testing.

Now, the following tests were done between `main` and this branch:
1. Compare the output of `--select=E999` (syntax errors)
2. Compare the output of default rule selection
3. Compare the output of `--select=ALL`

**Conclusion: all output were same**

## What's next?

The next step is to introduce re-lexing logic and update the parser to
feed the recovery information to the lexer so that it can emit the
correct token. This moves us one step closer to having error resilience
in the parser and provides Ruff the possibility to lint even if the
source code contains syntax errors.
2024-06-03 18:23:50 +05:30
Micha Reiser 9b6d2ce1f2
Fix incorect placement of trailing stub function comments (#11632) 2024-05-31 12:06:17 +00:00
Alex Waygood 246a3388ee
Implement a common trait for the string flags (#11564) 2024-05-27 16:02:01 +01:00
Alex Waygood 6963f75a14
Move string-prefix enumerations to a separate submodule (#11425)
## Summary

This moves the string-prefix enumerations in `ruff_python_ast` to a
separate submodule. I think this helps clarify that these prefixes are
purely abstract: they only depend on each other, and do not depend on
any of the other code in `nodes.rs` in any way. Moreover, while various
AST nodes _use_ them, they're not really nodes themselves, so they feel
slightly out of place in `nodes.rs`.

I considered moving all of them to `str.rs`, but it felt like enough
code that it could be a separate submodule.

## Test Plan

`cargo test`
2024-05-15 07:40:27 -04:00
Charlie Marsh 6ed2482e27
Add Python 3.13 to list of allowed Python versions (#11411)
## Summary

I believe we're already "Python 3.13-ready"? The main Ruff-impacting
change I see in https://docs.python.org/3.13/whatsnew/3.13.html is [PEP
696](https://peps.python.org/pep-0696/) which Jelle added in
https://github.com/astral-sh/ruff/pull/11120.
2024-05-13 16:35:41 +00:00
Dhruv Manilawala 4b41e4de7f
Create a newtype wrapper around `Vec<FStringElement>` (#11400)
## Summary

This PR adds a newtype wrapper around `Vec<FStringElement>` that derefs
to a `&Vec<FStringElement>`.

Both f-string and format specifier are made up of `Vec<FStringElement>`.
By creating a newtype wrapper around it, we can share the methods for
both parent types.
2024-05-13 16:04:04 +00:00
Charlie Marsh af60d539ab
Move sub-crates to workspace dependencies (#11407)
## Summary

This matches the setup we use in `uv` and allows for consistency in the
`Cargo.toml` files.
2024-05-13 14:37:50 +00:00
Dimitri Papadopoulos Orfanos 3b0584449d
Fix a few typos found by codespell (#11404)
## Summary

Just fix typos.

## Test Plan

CI jobs.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-05-13 13:22:35 +00:00
Dhruv Manilawala 6ecb4776de
Rename `AnyStringKind` -> `AnyStringFlags` (#11405)
## Summary

This PR renames `AnyStringKind` to `AnyStringFlags` and `AnyStringFlags`
to `AnyStringFlagsInner`.

The main motivation is to have consistent usage of "kind" and "flags".
For each string kind, it's "flags" like `StringLiteralFlags`,
`BytesLiteralFlags`, and `FStringFlags` but it was `AnyStringKind` for
the "any" variant.
2024-05-13 13:18:07 +00:00
Charlie Marsh 6cec82fff8
Get `cargo shear` passing (#11392)
## Summary

Remove some unused dependencies, add a few ignores.
2024-05-13 01:56:24 +00:00
Alex Waygood 6774f27f4b
Refactor the `ExprDict` node (#11267)
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-05-07 11:46:10 +00:00
Micha Reiser 868bbd4de6
Fix 'MarkVerbatimCommentsAsFormattedVisitor' is unused warning in release builds (#11304) 2024-05-06 07:43:16 +00:00
Charlie Marsh d0f51c6434
Remove remaining `ruff_shrinking` references (#11272)
## Summary

This caused `rooster release` to fail.

Initially removed in https://github.com/astral-sh/ruff/pull/11242.
2024-05-03 20:22:08 +00:00
Micha Reiser 6a1e555537
Upgrade to Rust 1.78 (#11260) 2024-05-03 12:46:21 +00:00
Alex Waygood 87929ad5f1
Add convenience methods for iterating over all parameter nodes in a function (#11174) 2024-04-29 10:36:15 +00:00
Carl Meyer 845ba7cf5f
Make ImportFrom level just a u32 (#11170) 2024-04-26 20:38:35 -06:00
Dhruv Manilawala 77a72ecd38
Avoid multiline expression if format specifier is present (#11123)
## Summary

This PR fixes the bug where the formatter would format an f-string and
could potentially change the AST.

For a triple-quoted f-string, the element can't be formatted into
multiline if it has a format specifier because otherwise the newline
would be treated as part of the format specifier.

Given the following f-string:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f} ddddddddddddddd eeeeeeee"""
```

The formatter sees that the f-string is already multiline so it assumes
that it can contain line breaks i.e., broken into multiple lines. But,
in this specific case we can't format it as:

```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f
} ddddddddddddddd eeeeeeee"""
```
                     
Because the format specifier string would become ".3f\n", which is not
the original string (`.3f`).

If the original source code already contained a newline, they'll be
preserved. For example:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f
} ddddddddddddddd eeeeeeee"""
```

The above will be formatted as:
```py
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {variable:.3f
} ddddddddddddddd eeeeeeee"""
```

Note that the newline after `.3f` is part of the format specifier which
needs to be preserved.
The Python version is irrelevant in this case.

fixes: #10040 

## Test Plan

Add some test cases to verify this behavior.
2024-04-26 13:34:38 +00:00
Jelle Zijlstra cd3e319538
Add support for PEP 696 syntax (#11120) 2024-04-26 09:47:29 +02:00
Carl Meyer c80b9a4a90
Reduce size of Stmt from 144 to 120 bytes (#11051)
## Summary

I happened to notice that we box `TypeParams` on `StmtClassDef` but not
on `StmtFunctionDef` and wondered why, since `StmtFunctionDef` is bigger
and sets the size of `Stmt`.

@charliermarsh found that at the time we started boxing type params on
classes, classes were the largest statement type (see #6275), but that's
no longer true.

So boxing type-params also on functions reduces the overall size of
`Stmt`.

## Test Plan

The `<=` size tests are a bit irritating (since their failure doesn't
tell you the actual size), but I manually confirmed that the size is
actually 120 now.
2024-04-19 17:02:17 -06:00
Dhruv Manilawala 13ffb5bc19
Replace LALRPOP parser with hand-written parser (#10036)
(Supersedes #9152, authored by @LaBatata101)

## Summary

This PR replaces the current parser generated from LALRPOP to a
hand-written recursive descent parser.

It also updates the grammar for [PEP
646](https://peps.python.org/pep-0646/) so that the parser outputs the
correct AST. For example, in `data[*x]`, the index expression is now a
tuple with a single starred expression instead of just a starred
expression.

Beyond the performance improvements, the parser is also error resilient
and can provide better error messages. The behavior as seen by any
downstream tools isn't changed. That is, the linter and formatter can
still assume that the parser will _stop_ at the first syntax error. This
will be updated in the following months.

For more details about the change here, refer to the PR corresponding to
the individual commits and the release blog post.

## Test Plan

Write _lots_ and _lots_ of tests for both valid and invalid syntax and
verify the output.

## Acknowledgements

- @MichaReiser for reviewing 100+ parser PRs and continuously providing
guidance throughout the project
- @LaBatata101 for initiating the transition to a hand-written parser in
#9152
- @addisoncrump for implementing the fuzzer which helped
[catch](https://github.com/astral-sh/ruff/pull/10903)
[a](https://github.com/astral-sh/ruff/pull/10910)
[lot](https://github.com/astral-sh/ruff/pull/10966)
[of](https://github.com/astral-sh/ruff/pull/10896)
[bugs](https://github.com/astral-sh/ruff/pull/10877)

---------

Co-authored-by: Victor Hugo Gomes <labatata101@linuxmail.org>
Co-authored-by: Micha Reiser <micha@reiser.io>
2024-04-18 17:57:39 +05:30
Charlie Marsh 60fd98eb2f
Update Rust to v1.77 (#10510) 2024-03-21 12:10:33 -04:00
veryyet c5ea4209bb
chore: remove repetitive words (#10502) 2024-03-21 03:57:16 +00:00
Micha Reiser 9d705a4414
Fix subscript comment placement with parenthesized value (#10496)
## Summary

This is a follow up on https://github.com/astral-sh/ruff/pull/10492 

I incorrectly assumed that `subscript.value.end()` always points past
the value. However, this isn't the case for parenthesized values where
the end "ends" before the parentheses.

## Test Plan

I added new tests for the parenthesized case.
2024-03-20 20:30:22 +00:00
Micha Reiser 954a48b129
Fix instable formatting for trailing subscribt end-of-line comment (#10492)
## Summary

This PR fixes an instability where formatting a subscribt 
where the `slice` is not an `ExprSlice` and it has a trailing
end-of-line comment after its opening `[` required two formatting passes
to be stable.

The fix is to associate the trailing end-of-line comment as dangling
comment on `[` to preserve its position, similar to how Ruff does it for
other parenthesized expressions.
This also matches how trailing end-of-line subscript comments are
handled when the `slice` is an `ExprSlice`.

Fixes https://github.com/astral-sh/ruff/issues/10355

## Versioning

Shipping this as part of a patch release is fine because:

* It fixes a stability issue
* It doesn't impact already formatted code because Ruff would already
have moved to the comment to the end of the line (instead of preserving
it)

## Test Plan

Added tests
2024-03-20 18:12:10 +01:00
Alex Waygood 7caf0d064a
Simplify formatting of strings by using flags from the AST nodes (#10489) 2024-03-20 16:16:54 +00:00
Alex Waygood 92e6026446
Apply NFKC normalization to unicode identifiers in the lexer (#10412) 2024-03-18 11:56:56 +00:00
Micha Reiser 12486315fb
Move deviations from formatter README to documentation (#10444)
## Summary

#10151 documented the deviations between Ruff and Black with the new
2024 style guide in the `ruff-python-formatter/README.md`. However,
that's not the documentation shown
on the website when navigating to [intentional
deviations](https://docs.astral.sh/ruff/formatter/black/).

This PR streamlines the `ruff-python-formatter/README.md` and links to
the documentation on the website instead of repeating the same content.
The PR also makes the 2024 style guide deviations available on the
website documentation.

## Test Plan

I built the documentation locally and verified that the 2024 style guide
known deviations are now shown on the website.
2024-03-18 08:22:28 +00:00
Alex Waygood c2e15f38ee
Unify enums used for internal representation of quoting style (#10383) 2024-03-13 17:19:17 +00:00
Dhruv Manilawala 32d6f84e3d
Add methods to iter over f-string elements (#10309)
## Summary

This PR adds methods on `FString` to iterate over the two different kind
of elements it can have - literals and expressions. This is similar to
the methods we have on `ExprFString`.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-03-13 08:46:55 +00:00