Evaluate an abstract syntax tree using the content of the variables stored in a state and only evaluating a given set of functions. This function will recurse through the nodes of the tree provided. Args: expression (`ast.AST`): The code to evaluate, as an abst
(
expression: ast.AST,
state: dict[str, Any],
static_tools: dict[str, Callable],
custom_tools: dict[str, Callable],
authorized_imports: list[str] = BASE_BUILTIN_MODULES,
)
| 1415 | |
| 1416 | @safer_eval |
| 1417 | def evaluate_ast( |
| 1418 | expression: ast.AST, |
| 1419 | state: dict[str, Any], |
| 1420 | static_tools: dict[str, Callable], |
| 1421 | custom_tools: dict[str, Callable], |
| 1422 | authorized_imports: list[str] = BASE_BUILTIN_MODULES, |
| 1423 | ): |
| 1424 | """ |
| 1425 | Evaluate an abstract syntax tree using the content of the variables stored in a state and only evaluating a given |
| 1426 | set of functions. |
| 1427 | |
| 1428 | This function will recurse through the nodes of the tree provided. |
| 1429 | |
| 1430 | Args: |
| 1431 | expression (`ast.AST`): |
| 1432 | The code to evaluate, as an abstract syntax tree. |
| 1433 | state (`Dict[str, Any]`): |
| 1434 | A dictionary mapping variable names to values. The `state` is updated if need be when the evaluation |
| 1435 | encounters assignments. |
| 1436 | static_tools (`Dict[str, Callable]`): |
| 1437 | Functions that may be called during the evaluation. Trying to change one of these static_tools will raise an error. |
| 1438 | custom_tools (`Dict[str, Callable]`): |
| 1439 | Functions that may be called during the evaluation. These custom_tools can be overwritten. |
| 1440 | authorized_imports (`List[str]`): |
| 1441 | The list of modules that can be imported by the code. By default, only a few safe modules are allowed. |
| 1442 | If it contains "*", it will authorize any import. Use this at your own risk! |
| 1443 | """ |
| 1444 | if state.setdefault("_operations_count", {"counter": 0})["counter"] >= MAX_OPERATIONS: |
| 1445 | raise InterpreterError( |
| 1446 | f"Reached the max number of operations of {MAX_OPERATIONS}. Maybe there is an infinite loop somewhere in the code, or you're just asking too many calculations." |
| 1447 | ) |
| 1448 | state["_operations_count"]["counter"] += 1 |
| 1449 | common_params = (state, static_tools, custom_tools, authorized_imports) |
| 1450 | if isinstance(expression, ast.Assign): |
| 1451 | # Assignment -> we evaluate the assignment which should update the state |
| 1452 | # We return the variable assigned as it may be used to determine the final result. |
| 1453 | return evaluate_assign(expression, *common_params) |
| 1454 | elif isinstance(expression, ast.AnnAssign): |
| 1455 | return evaluate_annassign(expression, *common_params) |
| 1456 | elif isinstance(expression, ast.AugAssign): |
| 1457 | return evaluate_augassign(expression, *common_params) |
| 1458 | elif isinstance(expression, ast.Call): |
| 1459 | # Function call -> we return the value of the function call |
| 1460 | return evaluate_call(expression, *common_params) |
| 1461 | elif isinstance(expression, ast.Constant): |
| 1462 | # Constant -> just return the value |
| 1463 | return expression.value |
| 1464 | elif isinstance(expression, ast.Tuple): |
| 1465 | return tuple((evaluate_ast(elt, *common_params) for elt in expression.elts)) |
| 1466 | elif isinstance(expression, ast.GeneratorExp): |
| 1467 | return evaluate_generatorexp(expression, *common_params) |
| 1468 | elif isinstance(expression, ast.ListComp): |
| 1469 | return evaluate_listcomp(expression, *common_params) |
| 1470 | elif isinstance(expression, ast.DictComp): |
| 1471 | return evaluate_dictcomp(expression, *common_params) |
| 1472 | elif isinstance(expression, ast.SetComp): |
| 1473 | return evaluate_setcomp(expression, *common_params) |
| 1474 | elif isinstance(expression, ast.UnaryOp): |
no test coverage detected
searching dependent graphs…