I have a script that can re-write a Python module so that all occurrences of func(a)
are transfored to func2(a is None)
. I now want to support also func(a, msg)
becoming func2(a is None, msg)
, but I can't find the pattern that will do this. This following shows my attempt:
from lib2to3 import refactor, fixer_base
from textwrap import dedent
PATTERN_ONE_ARG = """power< 'func' trailer< '(' arglist< obj1=any > ')' > >"""
PATTERN_ONE_OR_TWO_ARGS = """power< 'func' trailer< '(' arglist< obj1=any [',' obj2=any] > ')' > >"""
class TestFixer(fixer_base.BaseFix):
def __init__(self, options, fixer_log):
# self.PATTERN = PATTERN_ONE_ARG
self.PATTERN = PATTERN_ONE_OR_TWO_ARGS
super().__init__(options, fixer_log)
def transform(self, node, results):
print("found it")
return node
class TestRefactoringTool(refactor.MultiprocessRefactoringTool):
def get_fixers(self):
fixer = TestFixer(self.options, self.fixer_log)
return [fixer], []
def test():
test_script = """
log.print("hi")
func(a, "12345")
func(a, msg="12345")
func(a)
"""
refac.refactor_string(dedent(test_script), 'script')
flags = dict(print_function=True)
refac = TestRefactoringTool([], flags)
test()
For each func
found in the test_script
string, I should see one "found it", so a total of 3, but I only see 2 printed, implying that the func(a)
is not found by the pattern matcher. I'm basing the pattern on the fixers available in lib2to3.fixes
, but I must be missing a subtlety. Anyone know who to fix PATTERN_ONE_OR_TWO_ARGS so that all 3 functions will be found?
I know that I could create a separate fixer instance, but using the pattern would save me from writing a lot of code (I have a couple dozen of those fixers, total would then be 24!).
Found it:
PATTERN_ONE_OR_TWO_ARGS = """
power< 'func' trailer< '('
( not(arglist | argument<any '=' any>) obj1=any
| arglist< obj1=any ',' obj2=any > )
')' > >
"""
If transform() is:
def transform(self, node, results):
if 'obj2' in results:
print("found 2", results['obj1'], results['obj2'])
else:
print("found 1", results['obj1'])
return node
then for
test_script = """
log.print("hi")
func(a, "12345")
func(a, msg="12345")
func(a)
func(k=a)
"""
the output is
found 2 a "12345"
found 2 a msg="12345"
found 1 a
I also found http://python3porting.com/fixers.html#fixers-chapter which shows that I could just override the match() method instead of using a pattern. The four patterns of interest are:
PATTERN_ONE_ARG_OR_KWARG = """power< 'func' trailer< '(' not(arglist) obj1=any ')' > >"""
PATTERN_ONE_ARG = """power< 'func' trailer< '(' not(arglist | argument<any '=' any>) obj1=any ')' > >"""
PATTERN_ONE_KWARG = """power< 'func' trailer< '(' obj1=argument< any '=' any > ')' > >"""
PATTERN_TWO_ARGS_OR_KWARGS = """power< 'func' trailer< '(' arglist< obj1=any ',' obj2=any > ')' > >"""
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With