from __future__ import annotations import contextlib import functools import io from types import NoneType from typing import Any, Protocol, TYPE_CHECKING from libclinic import unspecified from libclinic.block_parser import Block from libclinic.converter import CConverter, converters from libclinic.converters import buffer, robuffer, rwbuffer from libclinic.return_converters import CReturnConverter, return_converters if TYPE_CHECKING: from libclinic.app import Clinic class Parser(Protocol): def __init__(self, clinic: Clinic) -> None: ... def parse(self, block: Block) -> None: ... @functools.cache def _create_parser_base_namespace() -> dict[str, Any]: ns = dict( CConverter=CConverter, CReturnConverter=CReturnConverter, buffer=buffer, robuffer=robuffer, rwbuffer=rwbuffer, unspecified=unspecified, NoneType=NoneType, ) for name, converter in converters.items(): ns[f'{name}_converter'] = converter for name, return_converter in return_converters.items(): ns[f'{name}_return_converter'] = return_converter return ns def create_parser_namespace() -> dict[str, Any]: base_namespace = _create_parser_base_namespace() return base_namespace.copy() class PythonParser: def __init__(self, clinic: Clinic) -> None: pass def parse(self, block: Block) -> None: namespace = create_parser_namespace() with contextlib.redirect_stdout(io.StringIO()) as s: exec(block.input, namespace) block.output = s.getvalue()