Исходный код raito.utils.helpers.code_evaluator

from __future__ import annotations

import ast
import sys
import traceback
from collections.abc import Awaitable, Callable, Generator
from contextlib import contextmanager, redirect_stdout
from dataclasses import dataclass
from io import StringIO
from typing import Any


[документация] @dataclass class EvaluationData: """Stores the result of evaluated python code. :param stdout: Captured standard output (e.g. from ``print()``) :param result: The final returned result. :param error: Traceback string if an exception occurred. """ stdout: str | None = None result: str | None = None error: str | None = None
[документация] class CodeEvaluator: """Async code evaluator with stdout capture and error handling.""" @contextmanager def _capture_output(self) -> Generator[StringIO, Any, None]: """Context manager that captures ``stdout`` into a buffer. :yield: A ``StringIO`` buffer with captured output. """ old_stdout = sys.stdout buf = StringIO() try: with redirect_stdout(buf): yield buf finally: sys.stdout = old_stdout def _wrap_code(self, code: str) -> ast.Module: """Wraps code into an async function, returning the last expression. :param code: python code to wrap. :return: A module with a single async def. """ module = ast.parse(code, mode="exec") body = module.body or [ast.Pass()] if isinstance(body[-1], ast.Expr): body[-1] = ast.Return(value=body[-1].value) func_def = ast.AsyncFunctionDef( name="__eval_func", args=ast.arguments( posonlyargs=[], args=[], defaults=[], kwonlyargs=[], kw_defaults=[], ), body=body, decorator_list=[], ) wrapped_module = ast.Module(body=[func_def], type_ignores=[]) ast.fix_missing_locations(wrapped_module) return wrapped_module
[документация] async def evaluate(self, code: str, context: dict[str, Any]) -> EvaluationData: """Evaluates the given async python code with the provided context. :param code: Python code to execute. :param context: Variables available during execution. :return: Result of the evaluation as ``EvaluationData`` """ try: wrapped_module = self._wrap_code(code) compiled_code = compile(wrapped_module, "<raito_eval>", "exec") exec_locals: dict[str, Any] = {} with self._capture_output() as output: exec(compiled_code, context, exec_locals) eval_func: Callable[[], Awaitable[Any]] = exec_locals["__eval_func"] result = await eval_func() return EvaluationData( stdout=output.getvalue(), result=str(result) if result is not None else None, ) except Exception: # noqa: BLE001 return EvaluationData(error=traceback.format_exc())