Commit Graph

484 Commits

Author SHA1 Message Date
Charlie Marsh dea65536e9
Fix placement for comments within f-strings concatenations (#7047)
## Summary

Restores the dangling comment handling for f-strings, which broke with
the parenthesized expression code.

Closes https://github.com/astral-sh/ruff/issues/6898.

## Test Plan

`cargo test`

No change in any of the similarity indexes or changed file counts:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99957 | 2760 | 67 |
| transformers | 0.99927 | 2587 | 468 |
| twine | 0.99982 | 33 | 1 |
| typeshed | 0.99978 | 3496 | 2173 |
| warehouse | 0.99818 | 648 | 24 |
| zulip | 0.99942 | 1437 | 32 |
2023-09-01 16:27:32 +00:00
Chris Pryer 0489bbc54c
Match Black's formatting of trailing comments containing NBSP (#7030) 2023-09-01 14:52:59 +02:00
Chris Pryer 17a44c0078
Exclude pragma comments from measured line width (#7008)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-09-01 06:34:51 +00:00
Charlie Marsh 376d3caf47
Treat empty-line separated comments as trailing statement comments (#6999)
## Summary

This PR modifies our between-statement comment handling such that
comments that are not separated by a statement by any newlines continue
to be treated as leading comments on the statement, but comments that
_are_ separated are instead formatted as trailing comments on the
preceding statement.

See, e.g., the originating snippet:

```python
DEFAULT_TEMPLATE = "flatpages/default.html"

# This view is called from FlatpageFallbackMiddleware.process_response
# when a 404 is raised, which often means CsrfViewMiddleware.process_view
# has not been called even if CsrfViewMiddleware is installed. So we need
# to use @csrf_protect, in case the template needs {% csrf_token %}.
# However, we can't just wrap this view; if no matching flatpage exists,
# or a redirect is required for authentication, the 404 needs to be returned
# without any CSRF checks. Therefore, we only
# CSRF protect the internal implementation.


def flatpage(request, url):
    pass
```

Here, we need to ensure that the `def flatpage` is precede by two empty
lines. However, we want those two empty lines to be enforced from the
_end_ of the comment block, _unless_ the comments are directly atop the
`def flatpage`.

I played with this a bit, and I think the simplest conceptual model and
implementation is to instead treat those as trailing comments on the
preceding node. The main difficulty with this approach is that, in order
to be fully compatible with Black, we'd sometimes need to insert
newlines _between_ the preceding node and its trailing comments. See,
e.g.:

```python
def func():
    ...
# comment

x = 1
```

In this case, we'd need to insert two blank lines between `def func():
...` and `# comment`, but `# comment` is trailing comment on `def
func(): ...`. So, we'd need to take this case into account in the
various nodes that _require_ newlines after them: functions, classes,
and imports. After some discussion, we've opted _not_ to support this,
and just treat these as trailing comments -- so we won't insert newlines
there. This means our handling is still identical to Black's on
Black-formatted code, but avoids moving such trailing comments on
unformatted code.

I dislike that the empty handling is so complex, and that it's split
between so many different nodes, but this is really tricky. Continuing
to treat these as leading comments is very difficult too, since we'd
need to do similar tricks for the leading comment handling in those
nodes, and influencing leading comments is even harder, since they're
all formatted _before_ the node itself.

Closes https://github.com/astral-sh/ruff/issues/6761.

## Test Plan

`cargo test`

Surprisingly, it doesn't change the similarity at all (apart from a
0.00001 change in CPython), but I manually confirmed that it did fix the
originating issue in Django.

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.76082          |
| django       | 0.99921          |
| transformers | 0.99854          |
| twine        | 0.99982          |
| typeshed     | 0.99953          |
| warehouse    | 0.99648          |
| zulip        | 0.99928          |


After:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.76081          |
| django       | 0.99921          |
| transformers | 0.99854          |
| twine        | 0.99982          |
| typeshed     | 0.99953          |
| warehouse    | 0.99648          |
| zulip        | 0.99928          |
2023-08-31 20:55:05 +00:00
magic-akari f4ba0ea144
Allow `tab_width` to be configable (#7016) 2023-08-31 07:40:03 +00:00
Micha Reiser 92143afeee
Group binary operators with same precedence only (#7010) 2023-08-31 09:19:45 +02:00
Micha Reiser eb552da8a9
Avoid parenthesizing multiline strings in binary expressions (#6973) 2023-08-30 16:03:17 +02:00
Charlie Marsh e2b2b1759f
Handle keyword comments between = and value (#6883)
## Summary

This PR adds comment handling for comments between the `=` and the
`value` for keywords, as in the following cases:

```python
func(
    x  # dangling
    =  # dangling
    # dangling
    1,
    **  # dangling
    y
)
```

(Comments after the `**` were already handled in some cases, but I've
unified the handling with the `=` handling.)

Note that, previously, comments between the `**` and its value were
rendered as trailing comments on the value (so they'd appear after `y`).
This struck me as odd since it effectively re-ordered the comment with
respect to its closest AST node (the value). I've made them leading
comments, though I don't know that that's a significant improvement. I
could also imagine us leaving them where they are.
2023-08-30 09:52:51 -04:00
Chris Pryer a3f4d7745a
Use reserved width to include line suffix measurement (#6901)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-08-30 08:07:11 +00:00
Charlie Marsh eb2b226142
Unset `after_class_docstring` state on every iteration (#7001) 2023-08-30 08:20:28 +02:00
Victor Hugo Gomes 31947af6a3
Don't "flatten" nested if expressions when formatting (#6996) 2023-08-30 04:11:58 +00:00
Charlie Marsh b404e54f33
Remove unnecessary `Comment#slice` calls (#6997) 2023-08-30 00:44:11 +00:00
Micha Reiser 715d86dae9
Remove Comprehension priority (#6947) 2023-08-29 08:30:15 +02:00
Micha Reiser adb48692d6
Use optional parentheses for tuples in return statements (#6875) 2023-08-29 08:30:05 +02:00
Charlie Marsh aea7500c1e
Allow `Locator#slice` to take `Ranged` (#6922)
## Summary

As a small quality-of-life improvement, the locator can now slice like
`locator.slice(stmt)` instead of requiring
`locator.slice(stmt.range())`.

## Test Plan

`cargo test`
2023-08-28 11:08:39 -04:00
Micha Reiser 60097bebcd
Handle implicit strings in `can_omit_parentheses (#6940) 2023-08-28 12:20:29 +00:00
Victor Hugo Gomes 99f4c6886e
Format `PatternMatchOr` (#6905) 2023-08-28 08:09:17 +00:00
Chris Pryer fa25dabf17
Add comments option to playground (#6911)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-08-28 07:26:23 +00:00
konsti e615870659
Unify line size settings between ruff and the formatter (#6873) 2023-08-28 06:44:56 +00:00
Chris Pryer 039694aaed
Add `LineSuffix` reserved width (#6830)
Thanks for working on this.
2023-08-28 07:46:54 +02:00
konsti c2413dcd2c
Add prototype of `ruff format` for projects (#6871)
**Summary** Add recursive formatting based on `ruff check` file
discovery for `ruff format`, as a prototype for the formatter alpha.
This allows e.g. `format ../projects/django/`. It's still lacking
support for any settings except line length.

Note just like the existing `ruff format` this will become part of the
production build, i.e. you'll be able to use it - hidden by default and
with a prominent warning - with `ruff format .` after the next release.

Error handling works in my manual tests (the colors do also work):

```
$  target/debug/ruff format scripts/
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended for internal use only.
```
(the above changes `add_rule.py` where we have the wrong bin op
breaking)

```
$ target/debug/ruff format ../projects/django/
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended for internal use only.
Failed to format /home/konsti/projects/django/tests/test_runner_apps/tagged/tests_syntax_error.py: source contains syntax errors: ParseError { error: UnrecognizedToken(Name { name: "syntax_error" }, None), offset: 131, source_path: "<filename>" }
```

```
$ target/debug/ruff format a
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended for internal use only.
Failed to read /home/konsti/ruff/a/d.py: Permission denied (os error 13)
```

**Test Plan** Missing! I'm not sure if it's worth building tests at this
stage or how they should look like.
2023-08-27 19:12:18 +00:00
Charlie Marsh 059757a8c8
Implement `Ranged` on more structs (#6921)
Now that it's in `ruff_text_size`, we can use it in a few places that we
couldn't before.
2023-08-27 19:03:08 +00:00
Charlie Marsh fc89976c24
Move `Ranged` into `ruff_text_size` (#6919)
## Summary

The motivation here is that this enables us to implement `Ranged` in
crates that don't depend on `ruff_python_ast`.

Largely a mechanical refactor with a lot of regex, Clippy help, and
manual fixups.

## Test Plan

`cargo test`
2023-08-27 14:12:51 -04:00
Micha Reiser eae59cf088
Optional source map generation (#6894) 2023-08-26 18:00:43 +02:00
Charlie Marsh 15b73bdb8a
Introduce AST nodes for `PatternMatchClass` arguments (#6881)
## Summary

This PR introduces two new AST nodes to improve the representation of
`PatternMatchClass`. As a reminder, `PatternMatchClass` looks like this:

```python
case Point2D(0, 0, x=1, y=2):
  ...
```

Historically, this was represented as a vector of patterns (for the `0,
0` portion) and parallel vectors of keyword names (for `x` and `y`) and
values (for `1` and `2`). This introduces a bunch of challenges for the
formatter, but importantly, it's also really different from how we
represent similar nodes, like arguments (`func(0, 0, x=1, y=2)`) or
parameters (`def func(x, y)`).

So, firstly, we now use a single node (`PatternArguments`) for the
entire parenthesized region, making it much more consistent with our
other nodes. So, above, `PatternArguments` would be `(0, 0, x=1, y=2)`.

Secondly, we now have a `PatternKeyword` node for `x=1` and `y=2`. This
is much more similar to the how `Keyword` is represented within
`Arguments` for call expressions.

Closes https://github.com/astral-sh/ruff/issues/6866.

Closes https://github.com/astral-sh/ruff/issues/6880.
2023-08-26 14:45:44 +00:00
Micha Reiser 9d77552e18
Add tab width option (#6848) 2023-08-26 12:29:58 +02:00
konsti 0e79074c31
Update to Rust 1.72 (#6874)
Update to [Rust
1.72](https://blog.rust-lang.org/2023/08/24/Rust-1.72.0.html), fixed the
failing lints.
2023-08-25 17:42:03 -04:00
Charlie Marsh edb9b0c62a
Use the formatter prelude in more files (#6882)
Removes a bunch of imports that are made redundant by the prelude.
2023-08-25 16:51:07 -04:00
Victor Hugo Gomes 91a780c771
Format `PatternMatchClass` (#6860) 2023-08-25 19:03:37 +00:00
Micha Reiser 29a0c1003b
Use `BestFit` layout even for attributes with a short name (#6872) 2023-08-25 17:47:02 +02:00
David Szotten 1c66bb80b7
fix is_raw_string for multiple prefixes (#6865)
fix `is_raw_string` in the presence of other prefixes (like `rb"foo"`)

fixes #6864
2023-08-25 09:58:26 +02:00
Micha Reiser 61b2ffa8e8
Add assert test cases (#6855) 2023-08-25 07:51:55 +02:00
Charlie Marsh 1044d66c1c
Add support for PatternMatchMapping formatting (#6836)
<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Adds support for `PatternMatchMapping` -- i.e., cases like:

```python
match foo:
    case {"a": 1, "b": 2, **rest}:
        pass
```

Unfortunately, this node has _three_ kinds of dangling comments:

```python
{  # "open parenthesis comment"
   key: pattern,
   **  # end-of-line "double star comment"
   # own-line "double star comment"
   rest  # end-of-line "after rest comment"
   # own-line "after rest comment"
}
```

Some of the complexity comes from the fact that in `**rest`, `rest` is
an _identifier_, not a node, so we have to handle comments _after_ it as
dangling on the enclosing node, rather than trailing on `**rest`. (We
could change the AST to use `PatternMatchAs` there, which would be more
permissive than the grammar but not totally crazy -- `PatternMatchAs` is
used elsewhere to mean "a single identifier".)

Closes https://github.com/astral-sh/ruff/issues/6644.

## Test Plan

`cargo test`
2023-08-25 04:33:34 +00:00
Charlie Marsh 813d7da7ec
Respect own-line leading comments before parenthesized nodes (#6820)
## Summary

This PR ensures that if an expression has an own-line leading comment
_before_ its open parentheses, we render it as such.

For example, given:

```python
[ # foo
    # bar
    ( # baz
        1
    )
]
```

On `main`, we format as:

```python
[  # foo
    (
        # bar
        # baz
        1
    )
]
```

As of this PR, we format as:

```python
[  # foo
    # bar
    (  # baz
        1
    )
]
```

## Test Plan

`cargo test`
2023-08-25 00:18:05 -04:00
Charlie Marsh 59e70896c0
Fix formatting of comments between function and arguments (#6826)
## Summary

We now format comments between a function and its arguments as dangling.
Like with other strange placements, I've biased towards preserving the
existing formatting, rather than attempting to reorder the comments.

Closes https://github.com/astral-sh/ruff/issues/6818.

## Test Plan

`cargo test`

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.76050          |
| django       | 0.99820          |
| transformers | 0.99800          |
| twine        | 0.99876          |
| typeshed     | 0.99953          |
| warehouse    | 0.99615          |
| zulip        | 0.99729          |

After:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.76050          |
| django       | 0.99820          |
| transformers | 0.99800          |
| twine        | 0.99876          |
| typeshed     | 0.99953          |
| warehouse    | 0.99615          |
| zulip        | 0.99729          |
2023-08-25 04:06:56 +00:00
Charlie Marsh f754ad5898
Handle bracketed comments on sequence patterns (#6801)
## Summary

This PR ensures that we handle bracketed comments on sequences, like `#
comment` here:

```python
match x:
    case [ # comment
        1, 2
    ]:
        pass
```

The handling is very similar to other, similar nodes, except that we do
need some special logic to determine whether the sequence is
parenthesized, similar to our logic for tuples.

## Test Plan

`cargo test`
2023-08-25 04:03:27 +00:00
Charlie Marsh 474e8fbcd4
Format all attribute dot comments manually (#6825)
## Summary

This PR modifies our formatting of comments around the `.` in an
attribute. Specifically, the goal here is to avoid _reordering_
comments, and the net effect is that we generally leave comments
where-they-are when dealing with comments between around the dot (which
you can also think of as comments between attributes).

All comments around the dot are now treated as dangling and formatted
manually, with the exception of end-of-line or parenthesized comments on
the value, like those marked as trailing here, which remain trailing:

```python
(
    (
        a # trailing end-of-line
        # trailing own-line
    ) # dangling before dot end-of-line
    .b # trailing end-of-line
)
```

Closes https://github.com/astral-sh/ruff/issues/6823.

## Test Plan

`cargo test`

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.76050          |
| django       | 0.99820          |
| transformers | 0.99800          |
| twine        | 0.99876          |
| typeshed     | 0.99953          |
| warehouse    | 0.99615          |
| zulip        | 0.99729          |

After:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.76050          |
| django       | 0.99820   |
| transformers | 0.99800          |
| twine        | 0.99876          |
| typeshed     | 0.99953          |
| warehouse    | 0.99615          |
| zulip        | 0.99729          |
2023-08-25 03:50:56 +00:00
Charlie Marsh 6f23469e00
Handle pattern parentheses in `FormatPattern` (#6800)
## Summary

This PR fixes the duplicate-parenthesis problem that's visible in the
tests from https://github.com/astral-sh/ruff/pull/6799. The issue is
that we might have parentheses around the entire match-case pattern,
like in `(1)` here:

```python
match foo:
    case (1):
        y = 0
```

In this case, the inner expression (`1`) will _think_ it's
parenthesized, but we'll _also_ detect the parentheses at the case level
-- so they get rendered by the case, then again by the expression.
Instead, if we detect parentheses at the case level, we can force-off
the parentheses for the pattern using a design similar to the way we
handle parentheses on expressions.

Closes https://github.com/astral-sh/ruff/issues/6753.

## Test Plan

`cargo test`
2023-08-25 03:45:49 +00:00
Micha Reiser 8b46b71038
Fix parenthesizing of implicit strings (#6852) 2023-08-24 12:31:02 +00:00
Micha Reiser 1cd7790a8a
Use BestFits for non-fluent attribute chains (#6817) 2023-08-24 14:09:25 +02:00
konsti d376cb4c2a
Improve formatter contributor docs (#6776)
The docs were out of date, and the new version incorporates some
feedback.

I tried to keep the language concise and the information ordered by how
early you need it, so people can get the relevant information quickly
before jumping into the code.

I did some minor format_dev changes for consistency in the docs.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2023-08-24 10:45:08 +00:00
Micha Reiser 04a9a8dd03
Maybe parenthesize long constants and names (#6816) 2023-08-24 09:47:57 +00:00
Harutaka Kawamura 205d234856
Format `PatternMatchStar` (#6653) 2023-08-24 01:58:05 +00:00
Charlie Marsh 71c25e4f9d
Implement `FormatPatternMatchValue` (#6799)
## Summary

This is effectively #6608, but with additional tests.

We aren't properly handling parenthesized patterns, but that needs to be
dealt with separately as it's somewhat involved.

Closes #6555
2023-08-23 14:01:14 +00:00
Micha Reiser 4bdd99f882
Fix: Re-add missing node start positions (#6780) 2023-08-23 09:59:36 +02:00
Charlie Marsh 1e6d1182bf
Improve comment handling around `PatternMatchAs` (#6797)
## Summary

Follows up on
https://github.com/astral-sh/ruff/pull/6652#discussion_r1300871033 with
some modifications to the `PatternMatchAs` comment handling.
Specifically, any comments between the `as` and the end are now
formatted as dangling, and we now insert some newlines in the
appropriate places.

## Test Plan

`cargo test`
2023-08-23 04:48:20 +00:00
Charlie Marsh 4bc5eddf91
Handle open-parenthesis comments on match case (#6798)
## Summary

Ensures that we retain the open-parenthesis comment in cases like:
```python
match pattern_comments:
    case (  # leading
        only_leading
    ):
        ...
```

Previously, this was treated as a leading comment on `only_leading`.

## Test Plan

`cargo test`
2023-08-23 00:40:18 -04:00
Harutaka Kawamura 94f5f18ddb
Format `PatternMatchSequence` (#6676) 2023-08-23 00:44:33 +00:00
Luc Khai Hai c34a342ab4
Format `PatternMatchAs` (#6652)
## Summary

Add formatting for `PatternMatchAs`.

This closes #6641.

## Test Plan

Add tests for comments.
2023-08-22 23:58:15 +00:00
Charlie Marsh cc278c24e2
Allow up to two empty lines after top-level imports (#6777)
## Summary

For imports, we enforce that there's _at least_ one empty line after an
import (assuming the next statement is _not_ an import), but allow up to
two at the module level.

Closes https://github.com/astral-sh/ruff/issues/6760.

## Test Plan

`cargo test`
2023-08-22 12:27:40 -04:00
Micha Reiser ccac9681e1
Preserve yield parentheses (#6766) 2023-08-22 10:27:20 +00:00
Micha Reiser b52cc84df6
Omit tuple parentheses in for statements except when absolutely necessary (#6765) 2023-08-22 12:18:59 +02:00
Micha Reiser fec6fc2fab
Preserve empty lines between try clause headers (#6759) 2023-08-22 11:50:28 +02:00
Victor Hugo Gomes 0f9ccfcad9
Format `PatternMatchSingleton` (#6741) 2023-08-22 08:23:47 +02:00
konsti b182368008
Simplify suite formatting (#6722)
Avoid the nesting in a macro by using the new `WithNodeLevel` to
`PyFormatter` deref. No changes otherwise.

I wanted to follow this up with quickly fixing the typeshed empty line
rules but they turned out a lot more complex than i had anticipated.
2023-08-21 21:01:51 +02:00
Micha Reiser 17a26e6ff3
Fix `fmt:skip` for function with return type (#6733) 2023-08-21 17:45:23 +02:00
Charlie Marsh 2405536d03
Remove unnecessary LibCST usage in key-in-dict (#6727)
## Summary

We're using LibCST to ensure that we return the full parenthesized range
of an expression, for display purposes. We can just use
`parenthesized_range` which is more efficient and removes one LibCST
dependency.

## Test Plan

`cargo test`
2023-08-21 10:32:09 -04:00
Micha Reiser f017555d53
Parenthesize NamedExpr if target breaks (#6714) 2023-08-21 16:29:26 +02:00
Micha Reiser 8b347cdaa9
Simplify IfRequired needs parentheses condition (#6678) 2023-08-21 07:11:31 +00:00
Tom Kuson 2a8d24dd4b
Format function and class definitions into a single line if its body is an ellipsis (#6592) 2023-08-21 09:02:23 +02:00
Victor Hugo Gomes 59e533047a
Fix typo in `ruff_python_formatter` documentation (#6687)
## Summary

In the documentation was written `Javascript` but we are working with
`Python` here :)

## Test Plan

n/a
2023-08-18 19:16:09 -04:00
Charlie Marsh 6a5acde226
Make `Parameters` an optional field on `ExprLambda` (#6669)
## Summary

If a lambda doesn't contain any parameters, or any parameter _tokens_
(like `*`), we can use `None` for the parameters. This feels like a
better representation to me, since, e.g., what should the `TextRange` be
for a non-existent set of parameters? It also allows us to remove
several sites where we check if the `Parameters` is empty by seeing if
it contains any arguments, so semantically, we're already trying to
detect and model around this elsewhere.

Changing this also fixes a number of issues with dangling comments in
parameter-less lambdas, since those comments are now automatically
marked as dangling on the lambda. (As-is, we were also doing something
not-great whereby the lambda was responsible for formatting dangling
comments on the parameters, which has been removed.)

Closes https://github.com/astral-sh/ruff/issues/6646.

Closes https://github.com/astral-sh/ruff/issues/6647.

## Test Plan

`cargo test`
2023-08-18 15:34:54 +00:00
Micha Reiser 0cea4975fc
Rename Comments methods (#6649) 2023-08-18 06:37:01 +00:00
Charlie Marsh 3ceb6fbeb0
Remove some unnecessary ampersands in the formatter (#6667) 2023-08-18 04:18:26 +00:00
Charlie Marsh 8e18f8018f
Remove some trailing commas in write calls (#6666) 2023-08-18 00:14:44 -04:00
Charlie Marsh 8228429a70
Convert comment to rustdoc in placement.rs (#6665) 2023-08-18 04:11:38 +00:00
Charlie Marsh 1811312722
Improve `with` statement comment handling and expression breaking (#6621)
## Summary

The motivating code here was:

```python
with test as (
    # test
foo):
    pass
```

Which we were formatting as:

```python
with test as
# test
(foo):
    pass
```

`with` statements are oddly difficult. This PR makes a bunch of subtle
modifications and adds a more extensive test suite. For example, we now
only preserve parentheses if there's more than one `WithItem` _or_ a
trailing comma; before, we always preserved.

Our formatting is_not_ the same as Black, but here's a diff of our
formatted code vs. Black's for the `with.py` test suite. The primary
difference is that we tend to break parentheses when they contain
comments rather than move them to the end of the life (this is a
consistent difference that we make across the codebase):

```diff
diff --git a/crates/ruff_python_formatter/foo.py b/crates/ruff_python_formatter/foo.py
index 85e761080..31625c876 100644
--- a/crates/ruff_python_formatter/foo.py
+++ b/crates/ruff_python_formatter/foo.py
@@ -1,6 +1,4 @@
-with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-), aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
+with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
     ...
     # trailing
 
@@ -16,28 +14,33 @@ with (
     # trailing
 
 
-with a, b:  # a  # comma  # c  # colon
+with (
+    a,  # a  # comma
+    b,  # c
+):  # colon
     ...
 
 
 with (
-    a as  # a  # as
-    # own line
-    b,  # b  # comma
+    a as (  # a  # as
+        # own line
+        b
+    ),  # b  # comma
     c,  # c
 ):  # colon
     ...  # body
     # body trailing own
 
-with (
-    a as  # a  # as
+with a as (  # a  # as
     # own line
-    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb  # b
-):
+    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+):  # b
     pass
 
 
-with (a,):  # magic trailing comma
+with (
+    a,
+):  # magic trailing comma
     ...
 
 
@@ -47,6 +50,7 @@ with a:  # should remove brackets
 with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as c:
     ...
 
+
 with (
     # leading comment
     a
@@ -74,8 +78,7 @@ with (
 with (
     a  # trailing same line comment
     # trailing own line comment
-    as b
-):
+) as b:
     ...
 
 with (
@@ -87,7 +90,9 @@ with (
 with (
     a
     # trailing own line comment
-) as b:  # trailing as same line comment  # trailing b same line comment
+) as (  # trailing as same line comment
+    b
+):  # trailing b same line comment
     ...
 
 with (
@@ -124,18 +129,24 @@ with (  # comment
     ...
 
 with (  # outer comment
-    CtxManager1() as example1,  # inner comment
+    (  # inner comment
+        CtxManager1()
+    ) as example1,
     CtxManager2() as example2,
     CtxManager3() as example3,
 ):
     ...
 
-with CtxManager() as example:  # outer comment
+with (  # outer comment
+    CtxManager()
+) as example:
     ...
 
 with (  # outer comment
     CtxManager()
-) as example, CtxManager2() as example2:  # inner comment
+) as example, (  # inner comment
+    CtxManager2()
+) as example2:
     ...
 
 with (  # outer comment
@@ -145,7 +156,9 @@ with (  # outer comment
     ...
 
 with (  # outer comment
-    (CtxManager1()),  # inner comment
+    (  # inner comment
+        CtxManager1()
+    ),
     CtxManager2(),
 ) as example:
     ...
@@ -179,7 +192,9 @@ with (
 ):
     pass
 
-with a as (b):  # foo
+with a as (  # foo
+    b
+):
     pass
 
 with f(
@@ -209,17 +224,13 @@ with f(
 ) as b, c as d:
     pass
 
-with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-) as b:
+with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
     pass
 
 with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
     pass
 
-with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-) as b, c as d:
+with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b, c as d:
     pass
 
 with (
@@ -230,6 +241,8 @@ with (
     pass
 
 with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-) as b, c as d:
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b,
+    c as d,
+):
     pass
```

Closes https://github.com/astral-sh/ruff/issues/6600.
## Test Plan

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75473          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74292          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

After:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75473          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74292          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

`cargo test`
2023-08-18 03:30:38 +00:00
Charlie Marsh 26bba11be6
Manually format comments around `:=` in named expressions (#6634)
## Summary

Attaches comments around the `:=` operator in a named expression as
dangling, and formats them manually in the `named_expr.rs` formatter.

Closes https://github.com/astral-sh/ruff/issues/5695.

## Test Plan

`cargo test`
2023-08-18 03:10:45 +00:00
Charlie Marsh db1c556508
Implement `Ranged` on more structs (#6639)
## Summary

I noticed some inconsistencies around uses of `.range.start()`, structs
that have a `TextRange` field but don't implement `Ranged`, etc.

## Test Plan

`cargo test`
2023-08-17 11:22:39 -04:00
Charlie Marsh 1334232168
Introduce `ExpressionRef` (#6637)
## Summary

This PR revives the `ExpressionRef` concept introduced in
https://github.com/astral-sh/ruff/pull/5644, motivated by the change we
want to make in https://github.com/astral-sh/ruff/pull/6575 to narrow
the type of the expression that can be passed to `parenthesized_range`.

## Test Plan

`cargo test`
2023-08-17 10:07:16 -04:00
Micha Reiser fa7442da2f
Support `fmt: skip` on compound statements (#6593) 2023-08-17 06:05:41 +00:00
Micha Reiser 4dc32a00d0
Support `fmt: skip` for simple-statements and decorators (#6561) 2023-08-17 05:58:19 +00:00
Charlie Marsh d0b8e4f701
Update Black tests (#6618)
## Summary

Pulls in some tests that we previously couldn't support

## Test Plan

`cargo test`
2023-08-16 15:05:51 +00:00
Charlie Marsh 12f3c4c931
Fix comment formatting for yielded tuples (#6603)
## Summary
Closes https://github.com/astral-sh/ruff/issues/6384, although I think
the issue was fixed already on main, for the most part.

The linked issue is around formatting expressions like:

```python
def test():
    (
        yield 
        #comment 1
        * # comment 2
        # comment 3
        test # comment 4
    )

```

On main, prior to this PR, we now format like:

```python
def test():
    (
        yield (
            # comment 1
            # comment 2
            # comment 3
            *test
        )  # comment 4
    )
```

Which strikes me as reasonable. (We can't test this, since it's a syntax
error after for our parser, despite being a syntax error in both cases
from CPython's perspective.)

Meanwhile, Black does:

```python
def test():
    (
        yield
        # comment 1
        *  # comment 2
        # comment 3
        test  # comment 4
    )
```

So our formatting differs in that we move comments between the star and
the expression above the star.

As of this PR, we also support formatting this input, which is valid:

```python
def test():
    (
        yield 
        #comment 1
        * # comment 2
        # comment 3
        test, # comment 4
        1
    )
```

Like:

```python
def test():
    (
        yield (
            # comment 1
            (
                # comment 2
                # comment 3
                *test,  # comment 4
                1,
            )
        )
    )
```

There were two fixes here: (1) marking starred comments as dangling and
formatting them properly; and (2) supporting parenthesized comments for
tuples that don't contain their own parentheses, as is often the case
for yielded tuples (previously, we hit a debug assert).

Note that this diff

## Test Plan
cargo test
2023-08-16 13:41:07 +00:00
Charlie Marsh 95f78821ad
Fix parenthesized detection for tuples (#6599)
## Summary

This PR fixes our code for detecting whether a tuple has its own
parentheses, which is necessary when attempting to preserve parentheses.
As-is, we were getting some cases wrong, like `(a := 1), (b := 3))` --
the detection code inferred that this _was_ parenthesized, and so
wrapped the entire thing in an unnecessary set of parentheses.

## Test Plan

`cargo test`

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75472          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74288          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

After:
| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75473          |
| django       | 0.99804 |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74288          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |
2023-08-16 13:20:48 +00:00
Micha Reiser daac31d2b9
Make `Buffer::write_element` non-failable (#6613) 2023-08-16 15:13:07 +02:00
Charlie Marsh 86ccdcc9d9
Add support for multi-character operator tokens to `SimpleTokenizer` (#6563)
## Summary

Allows for proper lexing of tokens like `->`.

The main challenge is to ensure that our forward and backwards
representations are the same for cases like `===`. Specifically, we want
that to lex as `==` followed by `=` regardless of whether it's a
forwards or backwards lex. To do so, we identify the range of the
sequential characters (the full span of `===`), lex it forwards, then
return the last token.

## Test Plan

`cargo test`
2023-08-16 09:09:19 -04:00
Micha Reiser e28858bb29
Fast path for ASCII only identifiers start (#6609) 2023-08-16 10:22:44 +02:00
Micha Reiser 897cce83b3
Call pattern formatting (#6594) 2023-08-16 08:31:25 +05:30
Charlie Marsh a3d4f08f29
Add general support for parenthesized comments on expressions (#6485)
## Summary

This PR adds support for parenthesized comments. A parenthesized comment
is a comment that appears within a parenthesis, but not within the range
of the expression enclosed by the parenthesis. For example, the comment
here is a parenthesized comment:

```python
if (
    # comment
    True
):
    ...
```

The parentheses enclose the `True`, but the range of `True` doesn’t
include the `# comment`.

There are at least two problems associated with parenthesized comments:
(1) associating the comment with the correct (i.e., enclosed) node; and
(2) formatting the comment correctly, once it has been associated with
the enclosed node.

The solution proposed here for (1) is to search for parentheses between
preceding and following node, and use open and close parentheses to
break ties, rather than always assigning to the preceding node.

For (2), we handle these special parenthesized comments in `FormatExpr`.
The biggest risk with this approach is that we forget some codepath that
force-disables parenthesization (by passing in `Parentheses::Never`).
I've audited all usages of that enum and added additional handling +
test coverage for such cases.

Closes https://github.com/astral-sh/ruff/issues/6390.

## Test Plan

`cargo test` with new cases.

Before:

| project      | similarity index |
|--------------|------------------|
| build        | 0.75623          |
| cpython      | 0.75472          |
| django       | 0.99804          |
| transformers | 0.99618          |
| typeshed     | 0.74233          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

After:

| project      | similarity index |
|--------------|------------------|
| build        | 0.75623          |
| cpython      | 0.75472          |
| django       | 0.99804          |
| transformers | 0.99618          |
| typeshed     | 0.74237          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |
2023-08-15 18:59:18 +00:00
Micha Reiser 29c0b9f91c
Use single lookup for leading, dangling, and trailing comments (#6589) 2023-08-15 17:39:45 +02:00
Charlie Marsh b1c4c7be69
Add trailing comma for single-element import-from groups (#6583)
## Summary

Unlike other statements, Black always adds a trailing comma if an
import-from statement breaks with a single import member. I believe this
is for compatibility with isort -- see
09f5ee3a19,
https://github.com/psf/black/issues/127, or
66648c528a/src/black/linegen.py (L1452)
for the current version.

## Test Plan

`cargo test`, notice that a big chunk of the compatibility suite is
removed.

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75472          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74233          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

After:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75472          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74260          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |
2023-08-15 07:15:33 -04:00
Tom Kuson 84d178a219
Use one line between top-level items if formatting a stub file (#6501)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-08-15 09:33:57 +02:00
Micha Reiser 455db84a59
Replace `inline(always)` with `inline` (#6590) 2023-08-15 08:58:11 +02:00
Micha Reiser 232b44a8ca
Indent statements in suppressed ranges (#6507) 2023-08-15 08:00:35 +02:00
Charlie Marsh 96d310fbab
Remove `Stmt::TryStar` (#6566)
## Summary

Instead, we set an `is_star` flag on `Stmt::Try`. This is similar to the
pattern we've migrated towards for `Stmt::For` (removing
`Stmt::AsyncFor`) and friends. While these are significant differences
for an interpreter, we tend to handle these cases identically or nearly
identically.

## Test Plan

`cargo test`
2023-08-14 13:39:44 -04:00
Micha Reiser 09c8b17661
`fmt: off..on` suppression comments (#6477) 2023-08-14 15:57:36 +00:00
qdegraaf 278a4f6e14
Formatter: Fix posonlyargs for `expr_lambda` (#6562) 2023-08-14 17:38:56 +02:00
Charlie Marsh c3a9151eb5
Handle comments on open parentheses in with statements (#6515)
## Summary

This PR adds handling for comments on open parentheses in parenthesized
context managers. For example, given:

```python
with (  # comment
    CtxManager1() as example1,
    CtxManager2() as example2,
    CtxManager3() as example3,
):
    ...
```

We want to preserve that formatting. (Black does the same.) On `main`,
we format as:

```python
with (
    # comment
    CtxManager1() as example1,
    CtxManager2() as example2,
    CtxManager3() as example3,
):
    ...
```

It's very similar to how `StmtImportFrom` is handled.

Note that this case _isn't_ covered by the "parenthesized comment"
proposal, since this is a common on the statement that would typically
be attached to the first `WithItem`, and the `WithItem` _itself_ can
have parenthesized comments, like:

```python
with (  # comment
    (
        CtxManager1()  # comment
    ) as example1,
    CtxManager2() as example2,
    CtxManager3() as example3,
):
    ...
```

## Test Plan

`cargo test`

Confirmed no change in similarity score.
2023-08-14 15:11:03 +00:00
Charlie Marsh a7cf8f0b77
Replace dynamic implicit concatenation detection with parser flag (#6513)
## Summary

In https://github.com/astral-sh/ruff/pull/6512, we added a flag to the
AST to mark implicitly-concatenated string expressions. This PR makes
use of that flag to remove the `is_implicit_concatenation` method.

## Test Plan

`cargo test`
2023-08-14 10:27:17 -04:00
Charlie Marsh 40407dcce5
Avoid marking inner-parenthesized comments as dangling bracket comments (#6517)
## Summary

The bracketed-end-of-line comment rule is meant to assign comments like
this as "immediately following the bracket":

```python
f(  # comment
    1
)
```

However, the logic was such that we treated this equivalently:

```python
f(
    (  # comment
        1
    )
)
```

This PR modifies the placement logic to ensure that we only skip the
opening bracket, and not any nested brackets. The above is now formatted
as:

```python
f(
    (
        # comment
        1
    )
)
```

(But will be corrected once we handle parenthesized comments properly.)

## Test Plan

`cargo test`

Confirmed no change in similarity score.
2023-08-14 09:52:19 -04:00
Micha Reiser fc0c9507d0
Override fmt_dangling_comments for frequent nodes (#6551) 2023-08-14 15:29:05 +02:00
konsti 01eceaf0dc
Format docstrings (#6452)
**Summary** Implement docstring formatting

**Test Plan** Matches black's `docstring.py` fixture exactly, added some
new cases for what is hard to debug with black and with what black
doesn't cover.

similarity index:

main:
zulip: 0.99702
django: 0.99784
warehouse: 0.99585
build: 0.75623
transformers: 0.99469
cpython: 0.75989
typeshed: 0.74853

this branch:

zulip: 0.99702
django: 0.99784
warehouse: 0.99585
build: 0.75623
transformers: 0.99464
cpython: 0.75517
typeshed: 0.74853

The regression in transformers is actually an improvement in a file they
don't format with black (they run `black examples tests src utils
setup.py conftest.py`, the difference is in hubconf.py). cpython doesn't
use black.

Closes #6196
2023-08-14 12:28:58 +00:00
Charlie Marsh e91caea490
Add test case for walrus operators in return types (#6438)
## Summary

Closes https://github.com/astral-sh/ruff/issues/6437.

## Test Plan

`cargo test`
2023-08-11 18:28:48 +00:00
Charlie Marsh 53246b725e
Allow return type annotations to use their own parentheses (#6436)
## Summary

This PR modifies our logic for wrapping return type annotations.
Previously, we _always_ wrapped the annotation in parentheses if it
expanded; however, Black only exhibits this behavior when the function
parameters is empty (i.e., it doesn't and can't break). In other cases,
it uses the normal parenthesization rules, allowing nodes to bring their
own parentheses.

For example, given:

```python
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
]:
    ...

def xxxxxxxxxxxxxxxxxxxxxxxxxxxx(x) -> Set[
    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
]:
    ...
```

Black will format as:

```python
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> (
    Set[
        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ]
):
    ...


def xxxxxxxxxxxxxxxxxxxxxxxxxxxx(
    x,
) -> Set[
    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
]:
    ...
```

Whereas, prior to this PR, Ruff would format as:

```python
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> (
    Set[
        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ]
):
    ...


def xxxxxxxxxxxxxxxxxxxxxxxxxxxx(
    x,
) -> (
    Set[
        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ]
):
    ...
```

Closes https://github.com/astral-sh/ruff/issues/6431.

## Test Plan

Before:

- `zulip`: 0.99702
- `django`: 0.99784
- `warehouse`: 0.99585
- `build`: 0.75623
- `transformers`: 0.99470
- `cpython`: 0.75988
- `typeshed`: 0.74853

After:

- `zulip`: 0.99724
- `django`: 0.99791
- `warehouse`: 0.99586
- `build`: 0.75623
- `transformers`: 0.99474
- `cpython`: 0.75956
- `typeshed`: 0.74857
2023-08-11 18:19:21 +00:00
Charlie Marsh d616c9b870
Avoid omitting optional parentheses for argument-less parentheses (#6484)
## Summary

This PR fixes some misformattings around optional parentheses for
expressions.

I first noticed that we were misformatting this:

```python
return (
    unicodedata.normalize("NFKC", s1).casefold()
    == unicodedata.normalize("NFKC", s2).casefold()
)
```

The above is stable Black formatting, but we were doing:
```python
return unicodedata.normalize("NFKC", s1).casefold() == unicodedata.normalize(
    "NFKC", s2
).casefold()
```

Above, the "last" expression is a function call, so our
`can_omit_optional_parentheses` was returning `true`...

However, it turns out that Black treats function calls differently
depending on whether or not they have arguments -- presumedly because
they'll never split empty parentheses, and so they're functionally
non-useful. On further investigation, I believe this applies to all
parenthesized expressions. If Black can't split on the parentheses, it
doesn't leverage them when removing optional parentheses.

## Test Plan

Nice increase in similarity scores.

Before:

- `zulip`: 0.99702
- `django`: 0.99784
- `warehouse`: 0.99585
- `build`: 0.75623
- `transformers`: 0.99470
- `cpython`: 0.75989
- `typeshed`: 0.74853

After:

- `zulip`: 0.99705
- `django`: 0.99795
- `warehouse`: 0.99600
- `build`: 0.75623
- `transformers`: 0.99471
- `cpython`: 0.75989
- `typeshed`: 0.74853
2023-08-11 17:58:42 +00:00
Dhruv Manilawala c434bdd2bd
Add formatting for `MatchCase` (#6360)
## Summary

This PR adds formatting support for `MatchCase` node with subs for the
`Pattern`
nodes.

## Test Plan

Added test cases for case node handling with comments, newlines.

resolves: #6299
2023-08-11 19:20:25 +05:30
Charlie Marsh f2939c678b
Avoid breaking call chains unnecessarily (#6488)
## Summary

This PR attempts to fix the formatting of the following expression:

```python
max_message_id = (
    Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id
)
```

Specifically, Black preserves _that_ formatting, while we do:

```python
max_message_id = (
    Message.objects.filter(recipient=recipient)
    .order_by("id")
    .reverse()[0]
    .id
)
```

The fix here is to add a group around the entire call chain.

## Test Plan

Before:

- `zulip`: 0.99702
- `django`: 0.99784
- `warehouse`: 0.99585
- `build`: 0.75623
- `transformers`: 0.99470
- `cpython`: 0.75989
- `typeshed`: 0.74853

After:

- `zulip`: 0.99703
- `django`: 0.99791
- `warehouse`: 0.99586
- `build`: 0.75623
- `transformers`: 0.99470
- `cpython`: 0.75989
- `typeshed`: 0.74853
2023-08-11 13:33:15 +00:00
Victor Hugo Gomes b05574babd
Fix formatter instability with half-indented comment (#6460)
## Summary
The bug was happening in this
[loop](75f402eb82/crates/ruff_python_formatter/src/comments/placement.rs (L545)).

Basically, In the first iteration of the loop, the `comment_indentation`
is bigger than `child_indentation` (`comment_indentation` is 7 and
`child_indentation` is 4) making the `Ordering::Greater` branch execute.
Inside the `Ordering::Greater` branch, the `if` block gets executed,
resulting in the update of these variables.
```rust
parent_body = current_body;                    
current_body = Some(last_child_in_current_body);
last_child_in_current_body = nested_child;
```
In the second iteration of the loop, `comment_indentation` is smaller
than `child_indentation` (`comment_indentation` is 7 and
`child_indentation` is 8) making the `Ordering::Less` branch execute.
Inside the `Ordering::Less` branch, the `if` block gets executed, this
is where the bug was happening. At this point `parent_body` should be a
`StmtFunctionDef` but it was a `StmtClassDef`. Causing the comment to be
incorrectly formatted.

That happened for the following code:
```python
class A:
    def f():
        pass
       # strangely indented comment

print()
```

There is only one problem that I couldn't figure it out a solution, the
variable `current_body` in this
[line](75f402eb82/crates/ruff_python_formatter/src/comments/placement.rs (L542C5-L542C49))
now gives this warning _"value assigned to `current_body` is never read
maybe it is overwritten before being read?"_
Any tips on how to solve that?

Closes #5337

## Test Plan

Add new test case.

---------

Co-authored-by: konstin <konstin@mailbox.org>
2023-08-11 11:21:16 +00:00
konsti 0ef6af807b
Implement DerefMut for WithNodeLevel (#6443)
**Summary** Implement `DerefMut` for `WithNodeLevel` so it can be used
in the same way as `PyFormatter`. I want this for my WIP upstack branch
to enable `.fmt(f)` on `WithNodeLevel` context. We could extend this to
remove the other two method from `WithNodeLevel`.
2023-08-11 10:41:48 +00:00