ruff/crates
Dylan 04a3ec3689
Adjust own-line comment placement between branches (#21185)
This PR attempts to improve the placement of own-line comments between
branches in the setting where the comment is more indented than the
preceding node.

There are two main changes.

### First change: Preceding node has leading content

If the preceding node has leading content, we now regard the comment as
automatically _less_ indented than the preceding node, and format
accordingly.

For example, 

```python
if True: preceding_node
# leading on `else`, not trailing on `preceding_node`
else: ...
```

This is more compatible with `black`, although there is a (presumably
very uncommon) edge case:

```python
if True:
    this;that
    # leading on `else`, but trailing in `black`
else: ...
```

I'm sort of okay with this - presumably if one wanted a comment for
those semi-colon separated statements, one should have put it _above_
them, and one wanted a comment only for `that` then it ought to have
been on the same line?

### Second change: searching for last child in body

While searching for the (recursively) last child in the body of the
preceding _branch_, we implicitly assumed that the preceding node had to
have a body to begin the recursion. But actually, in the base case, the
preceding node _is_ the last child in the body of the preceding branch.
So, for example:

```python
if True:
    something
    last_child_but_no_body
    # leading on else for `main` but trailing in this PR
else: ...
```

### More examples

The table below is an attempt to summarize the changes in behavior. The
rows alternate between an example snippet with `while` and the same
example with `if` - in the former case we do _not_ have an `else` node
and in the latter we do.

Notice that:

1. On `main` our handling of `if` vs. `while` is not consistent, whereas
it is consistent in the present PR
2. We disagree with `black` in all cases except that last example on
`main`, but agree in all cases for the present PR (though see above for
a wonky edge case where we disagree).

<table>
<tr>
<th>Original
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>

<th><code>main</code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
<th>This
PR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>

<th><code>black</code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
</tr>
<tr>
<td>

<pre lang="python">
while True: 
    pass
        # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
else:
    # comment
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
    # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
    # comment
else:
    pass
</pre>

</td>
</tr>
<tr>
<td>

<pre lang="python">
if True:
    pass
        # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
    # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
    # comment
else:
    pass
</pre>

</td>
</tr>
<tr>
<td>

<pre lang="python">
while True: pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
    # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
# comment
else:
    pass
</pre>

</td>
</tr>
<tr>
<td>

<pre lang="python">
if True: pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
    # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
# comment
else:
    pass
</pre>

</td>
</tr>
<tr>
<td>

<pre lang="python">
while True: pass
    # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
else:
    # comment
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
while True:
    pass
# comment
else:
    pass
</pre>

</td>
</tr>
<tr>
<td>

<pre lang="python">
if True: pass
    # comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
# comment
else:
    pass
</pre>

</td>
<td>

<pre lang="python">
if True:
    pass
# comment
else:
    pass
</pre>

</td>
</tr>
</table>
2025-11-17 07:30:34 -06:00
..
ruff Fix analyze graph tests on windows (#21481) 2025-11-16 18:27:07 +00:00
ruff_annotate_snippets
ruff_benchmark [ty] Faster subscript assignment checks for (unions of) TypedDicts (#21378) 2025-11-12 20:16:38 +01:00
ruff_cache
ruff_db [ty] Support for notebooks in VS Code (#21175) 2025-11-13 13:23:19 +01:00
ruff_dev Update Rust toolchain to 1.91 (#21179) 2025-11-01 01:50:58 +00:00
ruff_diagnostics
ruff_formatter [ty] Use "cannot" consistently over "can not" (#21255) 2025-11-03 10:38:20 -05:00
ruff_graph analyze: Add option to skip over imports in TYPE_CHECKING blocks (#21472) 2025-11-16 12:30:24 +00:00
ruff_index
ruff_linter [refurb] Fix FURB103 autofix (#21454) 2025-11-16 09:32:41 +01:00
ruff_macros Document when a rule was added (#21035) 2025-10-23 14:48:41 -04:00
ruff_memory_usage
ruff_notebook [ty] Respect notebook cell boundaries when adding an auto import (#21322) 2025-11-13 18:58:08 +01:00
ruff_options_metadata
ruff_python_ast [ruff] Ignore str() when not used for simple conversion (RUF065) (#21330) 2025-11-10 18:04:41 -05:00
ruff_python_ast_integration_tests
ruff_python_codegen Configurable "unparse mode" for ruff_python_codegen::Generator (#21041) 2025-10-24 15:44:48 +00:00
ruff_python_formatter Adjust own-line comment placement between branches (#21185) 2025-11-17 07:30:34 -06:00
ruff_python_importer [ty] Respect notebook cell boundaries when adding an auto import (#21322) 2025-11-13 18:58:08 +01:00
ruff_python_index
ruff_python_literal
ruff_python_parser [ty] name is parameter and global is a syntax error (#21312) 2025-11-14 18:15:34 +00:00
ruff_python_semantic [pyflakes] Revert to stable behavior if imports for module lie in alternate branches for F401 (#20878) 2025-10-27 10:23:36 -05:00
ruff_python_stdlib
ruff_python_trivia
ruff_python_trivia_integration_tests
ruff_server Fix missing diagnostics for notebooks (#21156) 2025-10-31 01:16:43 +00:00
ruff_source_file
ruff_text_size
ruff_wasm Bump 0.14.5 (#21435) 2025-11-13 14:37:31 -05:00
ruff_workspace analyze: Add option to skip over imports in TYPE_CHECKING blocks (#21472) 2025-11-16 12:30:24 +00:00
ty [ty] Improve diagnostic range for non-subscriptable diagnostics (#21461) 2025-11-14 21:15:14 +00:00
ty_combine
ty_completion_eval [ty] Sync vendored typeshed stubs (#21466) 2025-11-15 17:12:32 +00:00
ty_ide [ty] Inlay hint call argument location (#20349) 2025-11-17 11:33:09 +01:00
ty_project [ty] Fix --exclude and src.exclude merging (#21341) 2025-11-10 12:52:45 +01:00
ty_python_semantic [ty] Subscript assignment diagnostics follow-up (#21452) 2025-11-17 11:14:58 +00:00
ty_server [ty] Inlay hint call argument location (#20349) 2025-11-17 11:33:09 +01:00
ty_static
ty_test [ty] Provide proper error on dangling revealed (#21416) 2025-11-16 08:34:54 +00:00
ty_vendored [ty] Sync vendored typeshed stubs (#21466) 2025-11-15 17:12:32 +00:00
ty_wasm [ty] Inlay hint call argument location (#20349) 2025-11-17 11:33:09 +01:00