Open pelson opened 5 months ago
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
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.
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
With the following transformer, and libcst
1.4.0
:The resulting code looks like:
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?