refactor
refactor copied to clipboard
Multiline strings get indented
This refactoring, similar to what I actually used:
import ast
import refactor
class WrapF(refactor.Rule):
def match(self, node: ast.AST) -> refactor.BaseAction:
assert isinstance(node, ast.Constant)
# Prevent wrapping F-strings that are already wrapped in F()
# Otherwise you get infinite F(F(F(F(...))))
parent = self.context.ancestry.get_parent(node)
assert not (isinstance(parent, ast.Call) and isinstance(parent.func, ast.Name) and parent.func.id == 'F')
return refactor.Replace(node, ast.Call(func=ast.Name(id="F"), args=[node], keywords=[]))
refactor.run(rules=[WrapF])
produces this:
def f():
- return """
-a
-"""
+ return F("""
+ a
+ """)
This changes the value of the string.
Possibly related is https://github.com/isidentical/refactor/issues/12, but I couldn't reproduce an equivalent problem with just ast.unparse:
import ast
source = '''
def f():
return """
a
"""
'''
tree = ast.parse(source)
node = tree.body[0].body[0].value
call = ast.Call(func=ast.Name(id="F"), args=[node], keywords=[])
ast.copy_location(call, node)
ast.fix_missing_locations(call)
print(ast.unparse(node)) # '\na\n'
print(ast.unparse(call)) # F('\na\n')
Interesting and not thought about in: https://github.com/isidentical/refactor/pull/66, which partially solves the issue with a line, but because it is f-string'd with parenthesis, still applies the indent for """ line, due to """ not matching """) - Looking into a workaround to improve the PR, maybe:
- Detecting that the difference with source is only ')' and allow a match (meaning, no indent)
- Detecting that the new line and old line first matching chars are in
''', """and allow a match