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 format named expr comments #5705

Closed

Conversation

davidszotten
Copy link
Contributor

fixes #5695

let leading_value_comments = comments.leading_comments(value.as_ref());
let dangling_item_comments = comments.dangling_comments(item);

if trailing_target_comments.is_empty() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

i tried making a single write! call with these ifs inside, but that doesn't work since space() and soft_line_break have different types. is there some trick to make this work? (or do we prefer multiple write calls?

Copy link
Member

Choose a reason for hiding this comment

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

There's format_with but personally i like this style better, multiple write calls are fine here, if required we can still optimize later

@davidszotten davidszotten force-pushed the fix-format-named-expr-comments branch from e707349 to 982b712 Compare July 12, 2023 08:54
let leading_value_comments = comments.leading_comments(value.as_ref());
let dangling_item_comments = comments.dangling_comments(item);

if trailing_target_comments.is_empty() {
Copy link
Member

Choose a reason for hiding this comment

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

There's format_with but personally i like this style better, multiple write calls are fine here, if required we can still optimize later

if trailing_target_comments.is_empty() {
write!(f, [space()])?;
} else {
write!(f, [soft_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 the reason for this being a soft line break?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

as opposed to?

Copy link
Member

Choose a reason for hiding this comment

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

a hard_line_break, since as far as i can tell we always want to break after the comments if there are any. I realized it doesn't make a difference here because a trailing comment will expand the group, but it might be easier to read

write!(f, [text(":="), dangling_comments(dangling_item_comments)])?;

if leading_value_comments.is_empty() {
write!(f, [space()])?;
Copy link
Member

Choose a reason for hiding this comment

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

What happens when there are dangling_item_comments but no leading leading_value_comments? this would make a good test case

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch. definitely something not what i expected. will continue investigating

@@ -185,6 +185,10 @@ pub(crate) enum TokenKind {
/// `.`.
Dot,

/// `:=`.
/// TODO: name?
Copy link
Member

Choose a reason for hiding this comment

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

@konstin konstin requested a review from MichaReiser July 12, 2023 09:02
@github-actions
Copy link
Contributor

github-actions bot commented Jul 12, 2023

PR Check Results

Ecosystem

✅ ecosystem check detected no changes.

Benchmark

Linux

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.00      8.4±0.01ms     4.9 MB/sec    1.01      8.5±0.01ms     4.8 MB/sec
formatter/numpy/ctypeslib.py               1.00   1899.9±2.13µs     8.8 MB/sec    1.01   1917.8±4.14µs     8.7 MB/sec
formatter/numpy/globals.py                 1.00    204.7±0.37µs    14.4 MB/sec    1.01    207.1±0.27µs    14.2 MB/sec
formatter/pydantic/types.py                1.00      4.2±0.01ms     6.0 MB/sec    1.00      4.2±0.01ms     6.0 MB/sec
linter/all-rules/large/dataset.py          1.00     14.0±0.03ms     2.9 MB/sec    1.00     14.1±0.02ms     2.9 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      3.5±0.00ms     4.7 MB/sec    1.00      3.5±0.01ms     4.7 MB/sec
linter/all-rules/numpy/globals.py          1.00    364.2±1.05µs     8.1 MB/sec    1.00    364.0±1.13µs     8.1 MB/sec
linter/all-rules/pydantic/types.py         1.00      6.2±0.01ms     4.1 MB/sec    1.00      6.2±0.04ms     4.1 MB/sec
linter/default-rules/large/dataset.py      1.01      7.2±0.02ms     5.7 MB/sec    1.00      7.1±0.01ms     5.8 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.01   1465.7±2.64µs    11.4 MB/sec    1.00   1452.3±2.85µs    11.5 MB/sec
linter/default-rules/numpy/globals.py      1.01    156.4±0.23µs    18.9 MB/sec    1.00    155.4±0.66µs    19.0 MB/sec
linter/default-rules/pydantic/types.py     1.01      3.2±0.00ms     8.0 MB/sec    1.00      3.2±0.04ms     8.0 MB/sec

Windows

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.00     11.0±0.45ms     3.7 MB/sec    1.10     12.2±0.67ms     3.3 MB/sec
formatter/numpy/ctypeslib.py               1.00      2.5±0.13ms     6.8 MB/sec    1.09      2.7±0.13ms     6.2 MB/sec
formatter/numpy/globals.py                 1.00   289.3±16.98µs    10.2 MB/sec    1.01   291.9±24.53µs    10.1 MB/sec
formatter/pydantic/types.py                1.00      5.7±0.28ms     4.5 MB/sec    1.01      5.8±0.30ms     4.4 MB/sec
linter/all-rules/large/dataset.py          1.04     18.1±1.51ms     2.2 MB/sec    1.00     17.4±0.44ms     2.3 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      4.5±0.39ms     3.7 MB/sec    1.04      4.7±0.26ms     3.5 MB/sec
linter/all-rules/numpy/globals.py          1.00   509.4±19.13µs     5.8 MB/sec    1.17   596.6±40.30µs     4.9 MB/sec
linter/all-rules/pydantic/types.py         1.00      7.5±0.36ms     3.4 MB/sec    1.10      8.3±0.33ms     3.1 MB/sec
linter/default-rules/large/dataset.py      1.00      9.2±0.74ms     4.4 MB/sec    1.03      9.5±0.35ms     4.3 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.02  1969.2±76.88µs     8.5 MB/sec    1.00  1932.5±84.95µs     8.6 MB/sec
linter/default-rules/numpy/globals.py      1.01   233.4±14.19µs    12.6 MB/sec    1.00   230.1±13.11µs    12.8 MB/sec
linter/default-rules/pydantic/types.py     1.00      4.0±0.13ms     6.4 MB/sec    1.01      4.0±0.19ms     6.4 MB/sec

pass
...

# should not add brackets
Copy link
Member

Choose a reason for hiding this comment

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

Hey. Just wanted to let you know that I'm working on changing NeedsParentheses to pass through the parent node. This should make it straightforward to implement the correct parentheses logic for the walrus operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

atm i can't even figure out what's causing these parens to be added. parenthesize gets set to "ifbreaks" and nothing is breaking...

Copy link
Member

Choose a reason for hiding this comment

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

This PR ships the infrastructure: #5708

The parentheses are added because FormatExpr first calls into NeedsParentheses to determine if parentheses are necessary

let parentheses = item.needs_parentheses(self.parenthesize, f.context());

And the implementation of NamedExpr returns Always

match default_expression_needs_parentheses(self.into(), parenthesize, context) {
// Unlike tuples, named expression parentheses are not part of the range even when
// mandatory. See [PEP 572](https://peps.python.org/pep-0572/) for details.
Parentheses::Optional => Parentheses::Always,
parentheses => parentheses,
}

We should implement the same rules as in https://github.com/psf/black/blob/d1248ca9beaf0ba526d265f4108836d89cf551b7/src/black/linegen.py#L1381-L1395 (requires access to the parent node)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

aah. thanks

do i understand correctly that his is separate to (i.e. won't help with) parens for generator comprehensions (that we were discussing yesterday)?

Copy link
Member

Choose a reason for hiding this comment

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

That's correct. The problem is related but needs a separate fix (and I first need to figure out what even the expected output is... I have suspicion I know how it's supposed to behave but I haven't verified it yet)

@konstin konstin added the formatter Related to the formatter label Jul 16, 2023
@charliermarsh
Copy link
Member

I suspect this can now be closed as the originating issue is resolved.

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.

formatter: comment formatting instability in named expr (and dict, others)
4 participants