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

Indentation wart when removing an Arg from a Call - is whitespace being represented in the right place? #1157

Open
pelson opened this issue Jun 7, 2024 · 3 comments
Labels
enhancement New feature or request parsing Converting source code into CST nodes

Comments

@pelson
Copy link

pelson commented Jun 7, 2024

With the following transformer, and libcst 1.4.0:

example = """\
foo(
    arg1=None,
)
"""

import libcst as cst


class DropArg(cst.CSTTransformer):
    def leave_Arg(self, node: cst.Arg, update_node: cst.Arg):
        return cst.RemoveFromParent()


result = cst.parse_module(example).visit(DropArg())
print(result.code)

The resulting code looks like:

foo(
    )

Is this a symptom of the whitespace/indentation being in the wrong place for Arg objects? Is there a good pattern to remove the whitespace above?

@zsol
Copy link
Member

zsol commented Jun 7, 2024

Yes, this is because the whitespace between ( and arg1 is owned by the function call node. You can see this yourself if you go to https://libcst.me/, paste your example:

foo(
    arg1=None,
)

and move the cursor after (. You should see the corresponding CST Node highlighted on the right.

I don't think this is the wrong place, though. Consider two examples:

foo(
    arg1=None,
    arg2=None,
)

You'd want the removal of arg1 to keep the indentation for arg2, and the removal of arg2 to keep the closing ) unindented.

Example 2:

foo(  # very important comment
   arg1=None,
)

You'd want to preserve that comment even if arg1 is dropped.

Is there a good pattern to remove the whitespace above?

I'd add a leave_Call function that checks for the case where there aren't any args left on updated_node and reset whitespace_before_args.last_line

@pelson
Copy link
Author

pelson commented Jun 7, 2024

Thanks for the quick response.

You'd want to preserve that comment even if arg1 is dropped.

Yes, ideally, but if there is no distinction between inline and block comments, I'm not 100% convinced that this is the most important behaviour. In PEP-8, there is a general discouragement from inline comments in favour of block comments (https://peps.python.org/pep-0008/#inline-comments). From a defaults perspective, treating something as a block comment would be reasonable, given the above, IMO. (of course, even better if we can distinguish block from inline comments)

If we extend my example to cover this:

example = """\
foo(  # A really important call comment
    # A really important arg1 comment
    arg1=None,
    # A really important arg2 comment
    arg2=None,
)
"""

import libcst as cst


class DropArg(cst.CSTTransformer):
    def __init__(self, names_to_drop=()):
        self._names_to_drop = names_to_drop

    def leave_Arg(self, node: cst.Arg, update_node: cst.Arg):
        if node.keyword.value in self._names_to_drop:
            return cst.RemoveFromParent()
        else:
            return update_node

m = cst.parse_module(example)

print('# dropping arg1')
print(m.visit(DropArg(names_to_drop=['arg1'])).code)
print('-' *  80)
print('# dropping arg2')
print(m.visit(DropArg(names_to_drop=['arg2'])).code)
print('-' *  80)
print('# dropping arg1 & arg2')
print(m.visit(DropArg(names_to_drop=['arg1', 'arg2'])).code)

Results in:

# dropping arg1
foo(  # A really important call comment
    # A really important arg1 comment
    arg2=None,
)

--------------------------------------------------------------------------------
# dropping arg2
foo(  # A really important call comment
    # A really important arg1 comment
    arg1=None,
    # A really important arg2 comment
    )

--------------------------------------------------------------------------------
# dropping arg1 & arg2
foo(  # A really important call comment
    # A really important arg1 comment
    )

I don't think any of these behaviours would be what the user actually wanted.

@cassieyu1
Copy link

I ran into the same issue and I struggled to find a way to fix the indentation. Like what Phil said above, this doesn't seem to be the desired behavior. It adds an extra indentation whenever we remove the last argument of a call, even when there's still at least one argument. Does anyone know how to fix this? Any help is greatly appreciated

@zsol zsol added enhancement New feature or request parsing Converting source code into CST nodes labels Jul 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request parsing Converting source code into CST nodes
Projects
None yet
Development

No branches or pull requests

3 participants