将Python调用AST节点替换为Try节点

6g8kf2rb  于 2023-03-20  发布在  Python
关注(0)|答案(1)|浏览(165)

我使用的系统允许用户将Python布尔表达式指定为字符串(在配置文件中),系统获取字符串,将其转换为Python AST对象,然后基于输入数据计算表达式。
在某些情况下,布尔表达式可能会导致错误条件(例如输入数据的条目数不正确)。要求是如果用户将布尔表达式 Package 在fail_on_error(...)中,则会捕获异常并转换为False(例如):

assert test('fail_on_error(True)') == True
assert test('fail_on_error(False)') == False
assert test('fail_on_error(list()[0])') == False # index out of range

这可以使用正则表达式来完成,解析表达式字符串,但是我更愿意用Python的ast模块来“正确地”完成,不幸的是我遇到了问题。

密码

class ReplaceWithTry(ast.NodeTransformer):
    def visit_Call(self, node):
        if node.func.id != 'fail_on_error':
            return node

        # Get (first) argument to 'fail_on_error' and return its evaluated expression
        return_expr = ast.Return(value=node.args[0])
        except_handler = ast.ExceptHandler(type=None,
                                           name=None,
                                           body=ast.Return(value=ast.NameConstant(value=False))])
        return ast.Try(body=[return_expr],
                       handlers=[except_handler],
                       orelse=[],
                       finalbody=[])

def test(expr_str):
    syntax_tree = ast.parse(expr_str, '<string>', 'eval')
    new_tree = ast.fix_missing_locations(ReplaceWithTry().visit(syntax_tree))
    ast_obj = compile(new_tree, '<string>', 'eval')
    return eval(ast_obj)

错误

我收到以下错误:

knoepfel$ python replace_with_try.py 
Traceback (most recent call last):
  File "replace_with_try.py", line 24, in <module>
    assert test('fail_on_error(True)')
  File "replace_with_try.py", line 21, in test
    ast_obj = compile(new_tree, '<string>', 'eval')
TypeError: expected some sort of expr, but got <ast.Try object at 0x103da33a0>

显然我漏掉了什么。有什么想法吗?

lmyy7pcs

lmyy7pcs1#

这是一个很老的问题,但我想这是可行的

class ReplaceWithTry(ast.NodeTransformer):
    def visit_Call(self, node):
        if node.func.id != 'fail_on_error':
            return node

        new_node = ast.parse("""try: ...""") # your statement in python code
        return new_node

以及

def test(expr_str):
    syntax_tree = ast.parse(expr_str)
    new_tree = ast.fix_missing_locations(ReplaceWithTry().visit(syntax_tree))
    ast_obj = compile(ast.unparse(new_tree), '<ast>', 'eval')
    return eval(ast_obj)

相关问题