通过lib2to3以编程方式转换python代码

通过lib2to3以编程方式转换python代码,python,abstract-syntax-tree,Python,Abstract Syntax Tree,我想通过Python的标准库lib2to3将Python模块中出现的所有“some_func(a,b)”转换为“assert a==b”。我编写了一个脚本,将源代码作为输入: # convert.py # convert assert_equal(a, b) to assert a == b from lib2to3 import refactor refac = refactor.RefactoringTool(['fix_assert_equal']) result = refac.refa

我想通过Python的标准库lib2to3将Python模块中出现的所有“some_func(a,b)”转换为“assert a==b”。我编写了一个脚本,将源代码作为输入:

# convert.py
# convert assert_equal(a, b) to assert a == b
from lib2to3 import refactor
refac = refactor.RefactoringTool(['fix_assert_equal'])
result = refac.refactor_string('assert_equal(123, 456)\n', 'assert equal')
print(result)
以及单独模块中的实际定影器:

# fix_assert_equal.py, in same folder as convert.py
from lib2to3 import fixer_base, pygram, pytree, pgen2
import ast
import logging

grammar = pygram.python_grammar
logger = logging.getLogger("RefactoringTool")
driver = pgen2.driver.Driver(grammar, convert=pytree.convert, logger=logger)
dest_tree = driver.parse_string('assert a == b\n')


class FixAssertEqual(fixer_base.BaseFix):
    BM_compatible = True

    PATTERN = """
    power< 'assert_equal'
        trailer<
            '('
            arglist<
                obj1=any ','
                obj2=any
            >
            ')'
        >
    >
    """

    def transform(self, node, results):
        assert results
        obj1 = results["obj1"]
        obj1 = obj1.clone()
        obj1.prefix = ""
        obj2 = results["obj2"]
        obj2 = obj2.clone()
        obj2.prefix = ""
        prefix = node.prefix

        dest_tree2 = dest_tree.clone()
        node = dest_tree2.children[0].children[0].children[1]
        node.children[0] = obj1
        node.children[2] = obj2
        dest_tree2.prefix = prefix

        return dest_tree2
#fix_assert_equal.py,与convert.py位于同一文件夹中
来自lib2to3导入固定器_base、pygram、pytree、pgen2
导入ast
导入日志记录
语法=pygram.python\u语法
logger=logging.getLogger(“重构工具”)
driver=pgen2.driver.driver(语法,convert=pytree.convert,logger=logger)
dest_tree=driver.parse_字符串('assert a==b\n'))
类FixAssertEqual(fixer\u base.BaseFix):
BM_兼容=真
PATTERN=”“”
权力<'assert_equal'
拖车<
'('
arglist<
obj1=任何','
obj2=任何
>
')'
>
>
"""
def变换(自身、节点、结果):
断言结果
obj1=结果[“obj1”]
obj1=obj1.clone()
obj1.prefix=“”
obj2=结果[“obj2”]
obj2=obj2.clone()
obj2.prefix=“”
prefix=node.prefix
dest_tree2=dest_tree.clone()
node=dest_tree2.children[0]。children[0]。children[1]
node.children[0]=obj1
node.children[2]=obj2
dest_tree2.prefix=前缀
返回目的地树2

但是,这将生成输出
assert123==456
,而不是
assert 123==456
。知道如何解决这个问题吗?

我找到了解决方案:obj2.prefix不应该设置为“”,这会删除对象之前的空格

我找到了解决方案:obj2.prefix不应设置为“”,这将删除对象前面的空格

你在这里的最终目标是什么?您是否确实在尝试转换源代码(例如,为了不同的目的重新编写)?还是只想进行一些运行时交换?如果是后者,为什么不将函数
assert_equal
替换为一个断言参数相等的函数呢?我想删除对某个函数的依赖关系,在这个特殊的例子中,通过重写内置的断言,它恰好是邪恶的。无论我如何看待这个问题,这感觉像是一个黑客——但为什么不只是monkey patch
一些函数
,而另一个函数只是调用
assert
?@mgilson不是一个选项(编码标准)。@mgilson我支持你是运行时的monkey patch,但这不是运行时:它将在一个脚本中运行,该脚本将在所有源文件上运行一次,对不起,我没有说清楚。您的最终目标是什么?您是否确实在尝试转换源代码(例如,为了不同的目的重新编写)?还是只想进行一些运行时交换?如果是后者,为什么不将函数
assert_equal
替换为一个断言参数相等的函数呢?我想删除对某个函数的依赖关系,在这个特殊的例子中,通过重写内置的断言,它恰好是邪恶的。无论我如何看待这个问题,这感觉像是一个黑客——但为什么不只是monkey patch
一些函数
,而另一个函数只是调用
assert
?@mgilson不是一个选项(编码标准)。@mgilson我支持你是运行时的monkey patch,但这不是运行时:它将在一个脚本中运行,该脚本将在所有源文件上运行一次,很抱歉我没有说清楚。