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

Format delete statement #5169

Merged
merged 21 commits into from
Jul 11, 2023
Merged

Format delete statement #5169

merged 21 commits into from
Jul 11, 2023

Conversation

cnpryer
Copy link
Contributor

@cnpryer cnpryer commented Jun 17, 2023

Summary

Format delete statement with Parenthesize::IfBreaks.

Test Plan

Add basic ruff fixture with comments.


TODO:

  • Naive first-pass
  • DeleteList Joiner
  • Testing snapshot(s)
  • Use join_comma_separated for many targets

@github-actions
Copy link
Contributor

github-actions bot commented Jun 18, 2023

PR Check Results

Ecosystem

✅ ecosystem check detected no changes.

Benchmark

Linux

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.01      7.9±0.01ms     5.1 MB/sec    1.00      7.9±0.02ms     5.2 MB/sec
formatter/numpy/ctypeslib.py               1.01   1761.5±2.73µs     9.5 MB/sec    1.00   1743.5±3.78µs     9.6 MB/sec
formatter/numpy/globals.py                 1.01    198.3±0.45µs    14.9 MB/sec    1.00    197.1±0.19µs    15.0 MB/sec
formatter/pydantic/types.py                1.02      3.9±0.02ms     6.6 MB/sec    1.00      3.8±0.01ms     6.7 MB/sec
linter/all-rules/large/dataset.py          1.00     13.4±0.03ms     3.0 MB/sec    1.00     13.4±0.02ms     3.0 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      3.4±0.00ms     4.9 MB/sec    1.01      3.4±0.00ms     4.9 MB/sec
linter/all-rules/numpy/globals.py          1.00    434.2±2.10µs     6.8 MB/sec    1.01    438.4±0.83µs     6.7 MB/sec
linter/all-rules/pydantic/types.py         1.00      5.9±0.01ms     4.3 MB/sec    1.00      5.9±0.02ms     4.3 MB/sec
linter/default-rules/large/dataset.py      1.00      6.7±0.01ms     6.1 MB/sec    1.00      6.7±0.02ms     6.1 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00   1470.4±2.49µs    11.3 MB/sec    1.00   1465.0±3.16µs    11.4 MB/sec
linter/default-rules/numpy/globals.py      1.00    169.2±0.61µs    17.4 MB/sec    1.01    171.4±2.57µs    17.2 MB/sec
linter/default-rules/pydantic/types.py     1.00      3.0±0.01ms     8.4 MB/sec    1.00      3.0±0.01ms     8.4 MB/sec

Windows

group                                      main                                   pr
-----                                      ----                                   --
formatter/large/dataset.py                 1.01      9.5±0.04ms     4.3 MB/sec    1.00      9.4±0.03ms     4.3 MB/sec
formatter/numpy/ctypeslib.py               1.01      2.0±0.02ms     8.3 MB/sec    1.00  1991.6±16.50µs     8.4 MB/sec
formatter/numpy/globals.py                 1.00    218.7±1.62µs    13.5 MB/sec    1.00    219.1±3.67µs    13.5 MB/sec
formatter/pydantic/types.py                1.01      4.6±0.02ms     5.6 MB/sec    1.00      4.5±0.02ms     5.6 MB/sec
linter/all-rules/large/dataset.py          1.00     15.5±0.08ms     2.6 MB/sec    1.00     15.4±0.05ms     2.6 MB/sec
linter/all-rules/numpy/ctypeslib.py        1.00      4.1±0.03ms     4.0 MB/sec    1.00      4.1±0.02ms     4.0 MB/sec
linter/all-rules/numpy/globals.py          1.00    423.0±5.11µs     7.0 MB/sec    1.01    428.6±8.56µs     6.9 MB/sec
linter/all-rules/pydantic/types.py         1.00      7.0±0.03ms     3.7 MB/sec    1.00      7.0±0.03ms     3.7 MB/sec
linter/default-rules/large/dataset.py      1.00      8.0±0.03ms     5.1 MB/sec    1.01      8.1±0.04ms     5.0 MB/sec
linter/default-rules/numpy/ctypeslib.py    1.00   1639.7±8.28µs    10.2 MB/sec    1.01  1662.8±14.87µs    10.0 MB/sec
linter/default-rules/numpy/globals.py      1.00    178.7±1.05µs    16.5 MB/sec    1.02    181.6±1.21µs    16.2 MB/sec
linter/default-rules/pydantic/types.py     1.00      3.6±0.03ms     7.1 MB/sec    1.00      3.6±0.02ms     7.1 MB/sec

crates/ruff_python_formatter/src/statement/stmt_delete.rs Outdated Show resolved Hide resolved

impl Format<PyFormatContext<'_>> for DeleteList<'_> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
write!(
Copy link
Member

Choose a reason for hiding this comment

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

you shouldn't need a write call here, the JoinBuilder writes internally (see ExprSequence)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

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 wanted to ask this earlier, so I apologize, but I spent some time actually reading Python's AST docs to see if I'm conflating concepts.

My brain wants to interpret del Expr* as del ExprSequence. If that's the case, would we want to just reuse your ExprSequence implementation here? Maybe I'm missing something.

Copy link
Contributor Author

@cnpryer cnpryer Jul 9, 2023

Choose a reason for hiding this comment

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

See b5fe6d5.

Initially I thought ExprSequence would be a nice fit and it felt more elegant, but IIUC I only need 71352fc here.

@konstin konstin added the formatter Related to the formatter label Jun 18, 2023
Comment on lines 110 to 192
# Completed
)
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 double-checked this. Could be another black bug.

Copy link
Member

Choose a reason for hiding this comment

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

if you filed black bugs link them in comments, it's really helpful to be able to read up later why certain decisions were made

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some differences with black but stable
Comment on lines 38 to 43
for element in self.delete_list {
join.entry(&format_with(|f| {
write!(f, [element.format().with_options(Parenthesize::IfBreaks)])
}));
}
join.finish()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

f.join_with(...)
    .entries(self.delete_list.iter().formatted())
    // ...

I don't think is what I'm looking for, but I'll look into it more.

Copy link
Member

Choose a reason for hiding this comment

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

formatted may not work for you because it doesn't allow you to pass any options (at least not to my knowledge)

Comment on lines 119 to 121
# Delete something
del x, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, b, c, d # Delete these
# Ready to delete
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Next on my list

Copy link
Contributor Author

@cnpryer cnpryer Jun 24, 2023

Choose a reason for hiding this comment

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

Set to fail in d103b07

Comment on lines 34 to 35
let separator =
format_with(|f| group(&format_args![text(","), soft_line_break_or_space(),]).fmt(f));
Copy link
Member

Choose a reason for hiding this comment

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

Nit

Suggested change
let separator =
format_with(|f| group(&format_args![text(","), soft_line_break_or_space(),]).fmt(f));
let separator = group(&format_args![text(","), soft_line_break_or_space()]);

Copy link
Member

Choose a reason for hiding this comment

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

You probably want to wrap the whole list in a group rather than each separator so that all soft_line_breaks become hard_line_breaks when a single element doesn't fit on the line. Or you may not need the group at all. But that depends on the expected formatting.

Copy link
Contributor Author

@cnpryer cnpryer Jun 22, 2023

Choose a reason for hiding this comment

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

let separator = group(&format_args![text(","), soft_line_break_or_space()]);

Hmm. I think I tried this but had temporary value issues. I'll check it out.

You probably want to wrap the whole list in a group rather than each separator

I'll play around with it. Thanks!

Copy link
Contributor Author

@cnpryer cnpryer Jul 9, 2023

Choose a reason for hiding this comment

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

I think #5169 (comment) might resolve this as well

@MichaReiser MichaReiser linked an issue Jun 22, 2023 that may be closed by this pull request
Set output to target
@cnpryer
Copy link
Contributor Author

cnpryer commented Jun 26, 2023

I'm going on a trip this week, so I apologize for the less than productive PRs.

FWIW even having to chip away at this stuff, I do find myself grasping more and more of ruff_python_formatter. Between the readme and some of the already implemented expressions and statements, it's a pretty straightforward process.

I find playing with --print-comments and --print-ir to be really useful as well.

Hopefully I'll have these wrapped up this or next week. Sorry for the wait! Feel free to supersede me if needed -- I get it.

@MichaReiser
Copy link
Member

MichaReiser commented Jun 28, 2023

@cnpryer nothing to worry about. Thanks for working on delete statements` and enjoy your trip!

@cnpryer
Copy link
Contributor Author

cnpryer commented Jul 9, 2023

So depending on how robust we want this to be in this pass, 14b80b6 could be reverted and added after #5630 is addressed. Note that this specific test case will fail regardless if it's for del, tuple, dict, etc.

IIRC ruff doesn't intend to handle comments exactly how black would.

@@ -146,6 +151,8 @@ del (
a,
) # Trailing

del a, a
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Huh. Actually black will format this as

del (x, x)

Copy link
Contributor Author

@cnpryer cnpryer Jul 9, 2023

Choose a reason for hiding this comment

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

Maybe this is because it could be interpreted as del tuple(x, x) instead of del obj, obj?

A more reasonable example would be

a, b, c = 1, 2, 3
del (
    a, 
    b, 
    c
)

But I'd guess that's not actually performing a delete of a, b, and c but instead a new object of tuple(a, b, c)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense

>>> print(ast.dump(ast.parse('del (a, b, c)'), indent=4))
Module(
    body=[
        Delete(
            targets=[
                Tuple(
                    elts=[
                        Name(id='a', ctx=Del()),
                        Name(id='b', ctx=Del()),
                        Name(id='c', ctx=Del())],
                    ctx=Del())])],
    type_ignores=[])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cnpryer
Copy link
Contributor Author

cnpryer commented Jul 9, 2023

I want to think about this more before I request a review.

@cnpryer
Copy link
Contributor Author

cnpryer commented Jul 10, 2023

So this looks stable and doesn't seem to introduce syntax errors with what fixtures already exist. I think I could throw test cases at this for days, so instead of going down that hole I'll mark this as ready for a review.

At this stage I'd like to play more with my assert PR, since I think learning how to manage comment placement would be a nice knowledge gap to fill.

One thing I noticed I have trouble grasping so far is when a comment is "dangling" vs just "trailing". IIUC it has to do with Node assignment?

@cnpryer cnpryer marked this pull request as ready for review July 10, 2023 16:20
@cnpryer
Copy link
Contributor Author

cnpryer commented Jul 10, 2023

I can loop around to check this out #5595 (comment)

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

So many comment test cases, nice!. Thank you

@MichaReiser MichaReiser merged commit 15c7b6b into astral-sh:main Jul 11, 2023
@cnpryer cnpryer deleted the stmt-delete branch July 11, 2023 13:47
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: Delete
3 participants