如何从 ast.Call 对象获取函数结果?
How to get the function result from ast.Call object?
我需要在没有 运行 文件的情况下测试 python 模块中的 python 字典。所以我决定用 ast.parse
解析它。我几乎弄清楚了如何构建原始字典,只是我找不到让函数值起作用的方法。
config.py
...
config = {
# theese None, booleans and strings I got parsed
user_info: None,
debug: False,
cert_pass: "test",
# the function values I have problem with
project_directory: os.path.join(__file__, 'project')
}
...
test.py
...
# Skiping the AST parsing part, going straight to parsing config dict
def parse_ast_dict(ast_dict):
#ast_dict is instance of ast.Dict
result_dict = {}
# iterating over keys and values
for item in zip(ast_dict.keys, ast_dict.values):
if isinstance(item[1], ast.NameConstant):
result_dict[item[0].s] = item[1].value
elif isinstance(item[1], ast.Str):
result_dict[item[0].s] = item[1].s
elif isinstance(item[1], ast.Num):
result_dict[item[0].s] = item[1].n
# I got stuck here parsing the ast.Call which in my case is os.path.join calls
elif isinstance(item[0].s, ast.Call):
pass
return result_dict
我无法将配置对象移动到不同的文件,以便我可以单独测试它,因为它是供应商提供的代码片段,也无法将其导入测试,因为它包含大量库导入所以我坚持 ast
.
要评估一个函数调用,您需要实际执行它(除非您想自己实现一个 Python 解释器)。
但是,为了避免执行整个 config.py
,您应该专注于从 AST 中提取所需的字典节点以进行独立评估。
为此,首先找到赋值目标为 'config'
的赋值节点(因为这是接收字典的变量的名称)。然后,提取赋值节点的值,在本例中就是你想要的字典。从值构建一个 Expression
节点,用 ast.fix_missing_locations
调整行号和代码偏移量,以 'eval'
模式编译它,最后用 eval
评估编译后的代码对象它将 return 您要查找的词典。请记住向 eval
传递一个全局字典,其中包含 os
和 __file__
等必要名称的适当值,以便可以正确调用其中的函数。
import ast
import os
config_path = 'config.py'
with open(config_path) as config_file:
for node in ast.walk(ast.parse(config_file.read())):
if isinstance(node, ast.Assign) and node.targets[0].id == 'config':
expr = ast.Expression(body=node.value)
ast.fix_missing_locations(expr)
config = eval(
compile(expr, '', 'eval'),
{'os': os, '__file__': os.path.realpath(config_path)}
)
break
print(config)
我需要在没有 运行 文件的情况下测试 python 模块中的 python 字典。所以我决定用 ast.parse
解析它。我几乎弄清楚了如何构建原始字典,只是我找不到让函数值起作用的方法。
config.py
...
config = {
# theese None, booleans and strings I got parsed
user_info: None,
debug: False,
cert_pass: "test",
# the function values I have problem with
project_directory: os.path.join(__file__, 'project')
}
...
test.py
...
# Skiping the AST parsing part, going straight to parsing config dict
def parse_ast_dict(ast_dict):
#ast_dict is instance of ast.Dict
result_dict = {}
# iterating over keys and values
for item in zip(ast_dict.keys, ast_dict.values):
if isinstance(item[1], ast.NameConstant):
result_dict[item[0].s] = item[1].value
elif isinstance(item[1], ast.Str):
result_dict[item[0].s] = item[1].s
elif isinstance(item[1], ast.Num):
result_dict[item[0].s] = item[1].n
# I got stuck here parsing the ast.Call which in my case is os.path.join calls
elif isinstance(item[0].s, ast.Call):
pass
return result_dict
我无法将配置对象移动到不同的文件,以便我可以单独测试它,因为它是供应商提供的代码片段,也无法将其导入测试,因为它包含大量库导入所以我坚持 ast
.
要评估一个函数调用,您需要实际执行它(除非您想自己实现一个 Python 解释器)。
但是,为了避免执行整个 config.py
,您应该专注于从 AST 中提取所需的字典节点以进行独立评估。
为此,首先找到赋值目标为 'config'
的赋值节点(因为这是接收字典的变量的名称)。然后,提取赋值节点的值,在本例中就是你想要的字典。从值构建一个 Expression
节点,用 ast.fix_missing_locations
调整行号和代码偏移量,以 'eval'
模式编译它,最后用 eval
评估编译后的代码对象它将 return 您要查找的词典。请记住向 eval
传递一个全局字典,其中包含 os
和 __file__
等必要名称的适当值,以便可以正确调用其中的函数。
import ast
import os
config_path = 'config.py'
with open(config_path) as config_file:
for node in ast.walk(ast.parse(config_file.read())):
if isinstance(node, ast.Assign) and node.targets[0].id == 'config':
expr = ast.Expression(body=node.value)
ast.fix_missing_locations(expr)
config = eval(
compile(expr, '', 'eval'),
{'os': os, '__file__': os.path.realpath(config_path)}
)
break
print(config)