匹配装饰器的Python EBNF语法

2 人关注

我有一个非常大的项目,我需要把一些模块从 bar 移到 foo.bar ,并随后更新所有函数调用以反映新的位置。

这对函数调用很有效,但我在建立一个模式来匹配装饰器方面遇到了问题。

我喜欢匹配的代码是:。

  from unittest.mock import patch
  @patch('bar')
  def func(self, patcher):

我想把上面的补丁变成@patch('foo.bar')

我目前的模式在patch是一个函数调用时与之匹配,但在作为一个装饰器时却不匹配:。

class FixRenameMockPatch(fixer_base.BaseFix):
    PATTERN = """
    power<
        'patch' args=trailer< '(' [any] ')' >
    def transform(self, node, results):

我真的很难受,因为我不知道该怎么去理解 "我 "的语法。https://docs.python.org/3.8/reference/grammar.html所以我的修复器主要是基于lib2to3的源代码。

我怎么写上面的模式来匹配patch的所有使用,包括一个装饰器和一个上下文管理器? 还有一个完整的补丁的使用,比如mock.patchunittest.mock.patch

python
ebnf
lib2to3
Meitham
Meitham
发布于 2020-12-14
1 个回答
fbessho
fbessho
发布于 2020-12-15
已采纳
0 人赞同

你可以试试这个

PATTERN = "decorator< '@' 'patch' '(' [any] ')' any* >"
PATTERN = """
    decorator< '@' 'patch' '(' [any] ')' any* >
    | decorator< '@' dotted_name< 'mock' '.' 'patch' > '(' [any] ')' any* >

如果你想与@mock.patch也相匹配。

There is 脚本 (written in Python2, Py3 version here)来解析你的文件,并显示解析后的模式,我觉得这很有用。例如,你创建test.py

from unittest.mock import patch
@patch('bar')
def func(self, patcher):
    print('foo')

然后运行find_pattern.py,点击回车,直到显示你想解析的行,然后输入一些字符(下面的例子是y),点击回车显示解析结果。

$ python find_pattern.py -f test.py
' unittest.mock'
'from unittest.mock import patch'
'from unittest.mock import patch\n'