herolib_python/_archive/lib/web/mdserver/macro_sl.py
2025-08-05 15:15:36 +02:00

70 lines
2.1 KiB
Python

import re
import streamlit as st
import pandas as pd
import numpy as np
from io import StringIO
import sys
from typing import TYPE_CHECKING
from mdcollections.base_types import MDPage
# if TYPE_CHECKING:
# from .markdown_server import MDServer
def execute_streamlit_code(code_block):
"""
Execute a streamlit code block and capture its output.
The code block should be valid Python code that uses streamlit.
"""
# Create string buffer to capture any print outputs
old_stdout = sys.stdout
redirected_output = StringIO()
sys.stdout = redirected_output
try:
# Execute the code block
# The code block can use st, pd, np which are already imported
exec(code_block, {
'st': st,
'pd': pd,
'np': np
})
# Get any printed output
printed_output = redirected_output.getvalue()
return True, printed_output
except Exception as e:
return False, f"Error: {str(e)}\n\nFailed code:\n{code_block}"
finally:
# Restore stdout
sys.stdout = old_stdout
def process_streamlit_blocks(page: MDPage) -> MDPage:
"""
Find and process ```py sl code blocks in markdown content.
Returns the modified content with executed streamlit code blocks replaced by their output.
"""
if not isinstance(page, MDPage):
raise TypeError("page must be a MDPage")
# if not hasattr(md_server, 'collections_manager'):
# raise TypeError("md_server must be an instance of MDServer")
def replace_code_block(match):
code = match.group(1).strip()
success, result = execute_streamlit_code(code)
if not success:
# If execution failed, return the error message
return f"```\n{result}\n```"
# If successful, return empty string - the streamlit components
# will be rendered but the code block itself won't be shown
return ""
# Process the code block
processed_content = re.sub(r"```py\s+sl\n(.*?)\n```", replace_code_block, page.content, flags=re.DOTALL)
page.content_ = processed_content
return page