Skip to content
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

Fix zulip unstable formatting with end-of-line comments #6386

Merged
merged 3 commits into from
Aug 8, 2023

Conversation

konstin
Copy link
Member

@konstin konstin commented Aug 7, 2023

Bug

Given

x = () - (#
)

the comment is a dangling comment of the empty tuple. This is an end-of-line comment so it may move after the expression. It still expands the parent, so the operator breaks:

x = (
    ()
    - ()  #
)

In the next formatting pass, the comment is not a trailing tuple but a trailing bin op comment, so the bin op doesn't break anymore. The comment again expands the parent, so we still add the superfluous parentheses

x = (
    () - ()  #
)

Fix

The new formatting is to keep the comment on the empty tuple. This is a log uglier and again has additional outer parentheses, but it's stable:

x = (
    ()
    - (  #
    )
)

Alternatives

Black formats all the examples above as

x = () - ()  #

which i find better.

I would be happy about any suggestions for better solutions than the current one. I'd mainly need a workaround for expand parent having an effect on the bin op instead of first moving the comment to the end and then applying expand parent to the assign statement.

@konstin
Copy link
Member Author

konstin commented Aug 7, 2023

Current dependencies on/for this PR:

This comment was auto-generated by Graphite.

@konstin konstin added the formatter Related to the formatter label Aug 7, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Aug 7, 2023

PR Check Results

Benchmark

Linux

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.00      8.1±0.02ms     5.0 MB/sec    1.04      8.5±0.07ms     4.8 MB/sec
formatter/numpy/ctypeslib.py               1.00   1612.1±9.05µs    10.3 MB/sec    1.04  1669.3±11.53µs    10.0 MB/sec
formatter/numpy/globals.py                 1.00    184.8±5.80µs    16.0 MB/sec    1.00    184.7±1.01µs    16.0 MB/sec
formatter/pydantic/types.py                1.00      3.4±0.04ms     7.4 MB/sec    1.04      3.6±0.05ms     7.1 MB/sec
linter/all-rules/large/dataset.py          1.00     10.2±0.25ms     4.0 MB/sec    1.01     10.2±0.37ms     4.0 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      2.7±0.06ms     6.2 MB/sec    1.00      2.7±0.00ms     6.2 MB/sec
linter/all-rules/numpy/globals.py          1.00    377.2±0.61µs     7.8 MB/sec    1.00    378.4±0.86µs     7.8 MB/sec
linter/all-rules/pydantic/types.py         1.00      4.6±0.01ms     5.5 MB/sec    1.00      4.6±0.04ms     5.5 MB/sec
linter/default-rules/large/dataset.py      1.00      5.2±0.02ms     7.8 MB/sec    1.00      5.3±0.02ms     7.7 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00   1129.1±6.93µs    14.7 MB/sec    1.01   1136.6±9.73µs    14.6 MB/sec
linter/default-rules/numpy/globals.py      1.00    127.8±0.88µs    23.1 MB/sec    1.00    128.2±0.31µs    23.0 MB/sec
linter/default-rules/pydantic/types.py     1.00      2.3±0.00ms    10.9 MB/sec    1.01      2.4±0.01ms    10.8 MB/sec

Windows

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.04     10.3±0.26ms     4.0 MB/sec    1.00      9.8±0.09ms     4.1 MB/sec
formatter/numpy/ctypeslib.py               1.00  1905.3±23.53µs     8.7 MB/sec    1.00  1897.2±30.10µs     8.8 MB/sec
formatter/numpy/globals.py                 1.00    210.8±4.89µs    14.0 MB/sec    1.00    209.8±7.93µs    14.1 MB/sec
formatter/pydantic/types.py                1.00      4.2±0.04ms     6.1 MB/sec    1.01      4.2±0.13ms     6.0 MB/sec
linter/all-rules/large/dataset.py          1.03     12.8±0.43ms     3.2 MB/sec    1.00     12.5±0.13ms     3.3 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      3.4±0.03ms     4.8 MB/sec    1.01      3.5±0.09ms     4.8 MB/sec
linter/all-rules/numpy/globals.py          1.00    422.0±5.58µs     7.0 MB/sec    1.00    423.3±8.92µs     7.0 MB/sec
linter/all-rules/pydantic/types.py         1.00      5.8±0.08ms     4.4 MB/sec    1.01      5.9±0.21ms     4.3 MB/sec
linter/default-rules/large/dataset.py      1.00      6.8±0.07ms     6.0 MB/sec    1.00      6.7±0.07ms     6.0 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00  1380.4±10.52µs    12.1 MB/sec    1.01  1387.9±21.57µs    12.0 MB/sec
linter/default-rules/numpy/globals.py      1.01    159.4±3.49µs    18.5 MB/sec    1.00    158.0±2.54µs    18.7 MB/sec
linter/default-rules/pydantic/types.py     1.00      3.0±0.04ms     8.5 MB/sec    1.00      3.0±0.04ms     8.5 MB/sec

Comment on lines +256 to +265
// Avoid unstable formatting with
// ```python
// x = () - (#
// )
// ```
// Without this the comment would go after the empty tuple first, but still expand
// the bin op. In the second formatting pass they are trailing bin op comments
// so the bin op collapse. Suboptimally we keep parentheses around the bin op in
// either case.
(!self.comments[..end_of_line_split].is_empty()).then_some(hard_line_break()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's our motivation to keep the trailing end of line comments on the same line as the opening parentheses?

I prefer

x = () - (
	# comment
)

over

x = () - ( # comment
)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turning an end-of-line comment into an own line comment leads to unstable formatting by the two spaces we insert after the line, so we need turn one comment kind into the other atm.

From a style perspective i prefer black with () # comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turning an end-of-line comment into an own line comment leads to unstable formatting by the two spaces we insert after the line,

We shouldn't insert the two empty spaces in that case. We just format them as own line comments.

@MichaReiser
Copy link
Member

I would be happy about any suggestions for better solutions than the current one. I'd mainly need a workaround for expand parent having an effect on the bin op instead of first moving the comment to the end and then applying expand parent to the assign statement.

This isn't possible without moving the comment inside of placement.rs. I personally prefer if the formatter doesn't move my comments out of the parenthesis, because it does change the semantics of the comment:

a = call([ 	# empty because of x
], b) + []

I prefer:

a = call(
	[ 	
		# empty because of x
	], 
	b
) 	+ []

Over

a = call([], b) + [] # empty because of x

Because it is now unclear what the comment refers to

@charliermarsh
Copy link
Member

I haven’t reviewed yet but just want to confirm - is this still necessary after my two PRs that get the stability checks passing?

@konstin
Copy link
Member Author

konstin commented Aug 7, 2023

I think so, this is a slightly different case (empty tuple vs. empty function) that the minimizer stumbled into because you can get to it by removing the function. I'll rebase and check again once the other PRs are merged

@charliermarsh
Copy link
Member

Okay, should be all-clear to rebase.

## Bug

Given
```python
x = () - (#
)
```
the comment is a dangling comment of the empty tuple. This is an end-of-line comment so it may move after the expression. It still expands the parent, so the operator breaks:
```python
x = (
    ()
    - ()  #
)
```
In the next formatting pass, the comment is not a trailing tuple but a trailing bin op comment, so the bin op doesn't break anymore. The comment again expands the parent, so we still add the superfluous parentheses
```python
x = (
    () - ()  #
)
```

## Fix

The new formatting is to keep the comment on the empty tuple. This is a log uglier and again has additional outer parentheses, but it's stable:
```python
x = (
    ()
    - (  #
    )
)
```

## Alternatives

Black formats all the examples above as
```python
x = () - ()  #
```
which i find better.

I would be happy about any suggestions for better solutions than the current one. I'd mainly need a workaround for expand parent having an effect on the bin op instead of first moving the comment to the end and then applying expand parent to the assign statement.
@konstin konstin force-pushed the fix_zulip_unstable_formatting branch from d5547e9 to 58a33f4 Compare August 8, 2023 09:07
@konstin konstin enabled auto-merge (squash) August 8, 2023 09:08
@konstin konstin merged commit 90ba40c into main Aug 8, 2023
16 checks passed
@konstin konstin deleted the fix_zulip_unstable_formatting branch August 8, 2023 09:15
konstin added a commit that referenced this pull request Aug 10, 2023
**Summary** I collected all examples of end-of-line comments after
opening parentheses that i could think of so we get a comprehensive view
at the state of their formatting (#6390).

This PR intentionally only adds tests cases without any changes in
formatting. We need to decide which exact formatting we want, ideally in
terms of these test files, and implement this in follow-up PRs.

~~One stability check is still deactivated pending
#6386
durumu pushed a commit to durumu/ruff that referenced this pull request Aug 12, 2023
## Bug

Given
```python
x = () - (#
)
```
the comment is a dangling comment of the empty tuple. This is an
end-of-line comment so it may move after the expression. It still
expands the parent, so the operator breaks:
```python
x = (
    ()
    - ()  #
)
```
In the next formatting pass, the comment is not a trailing tuple but a
trailing bin op comment, so the bin op doesn't break anymore. The
comment again expands the parent, so we still add the superfluous
parentheses
```python
x = (
    () - ()  #
)
```

## Fix

The new formatting is to keep the comment on the empty tuple. This is a
log uglier and again has additional outer parentheses, but it's stable:
```python
x = (
    ()
    - (  #
    )
)
```

## Alternatives

Black formats all the examples above as
```python
x = () - ()  #
```
which i find better. 

I would be happy about any suggestions for better solutions than the
current one. I'd mainly need a workaround for expand parent having an
effect on the bin op instead of first moving the comment to the end and
then applying expand parent to the assign statement.
durumu pushed a commit to durumu/ruff that referenced this pull request Aug 12, 2023
…ral-sh#6420)

**Summary** I collected all examples of end-of-line comments after
opening parentheses that i could think of so we get a comprehensive view
at the state of their formatting (astral-sh#6390).

This PR intentionally only adds tests cases without any changes in
formatting. We need to decide which exact formatting we want, ideally in
terms of these test files, and implement this in follow-up PRs.

~~One stability check is still deactivated pending
astral-sh#6386
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
formatter Related to the formatter
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants