2016-02-03 39 views
4

我有一個腳本,可以重新編寫一個Python模塊,以便所有出現的func(a)轉換爲func2(a is None)。我現在想要支持func(a, msg)變成func2(a is None, msg),但我找不到這樣做的模式。這下面顯示了我的嘗試:模式匹配lib2to3的1或2-arg函數調用

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() 

對於在test_script字符串中找到每個func,我應該可以看到一個「發現」,所以一共3,但我只看到2個印,暗示func(a)不由模式匹配器發現。我基於lib2to3.fixes中提供的固定器上的圖案,但我必須忽略一個微妙之處。任何人都知道誰來修復PATTERN_ONE_OR_TWO_ARGS,以便找到所有3個函數?

我知道我可以創建一個單獨的修復程序實例,但使用該模式會使我無法編寫大量的代碼(我有幾個修復程序,總數將會是24!)。

回答

1

發現:

PATTERN_ONE_OR_TWO_ARGS = """ 
    power< 'func' trailer< '(' 
     (not(arglist | argument<any '=' any>) obj1=any 
     | arglist< obj1=any ',' obj2=any >) 
    ')' > > 
    """ 

如果變換()爲:

def transform(self, node, results): 
    if 'obj2' in results: 
     print("found 2", results['obj1'], results['obj2']) 
    else: 
     print("found 1", results['obj1']) 
    return node 

然後

test_script = """ 
    log.print("hi") 
    func(a, "12345") 
    func(a, msg="12345") 
    func(a) 
    func(k=a) 
    """ 

輸出是

found 2 a "12345" 
found 2 a msg="12345" 
found 1 a 

我也發現http://python3porting.com/fixers.html#fixers-chapter這表明我可以重寫match()方法而不是使用模式。四種感興趣的模式是:

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 >    ')' > >"""