|
|
""" |
|
|
Python Executor - Persistent Python execution environment. |
|
|
Similar to Jupyter kernel or smolagents LocalPythonExecutor. |
|
|
""" |
|
|
|
|
|
import io |
|
|
import sys |
|
|
from typing import Any, Dict |
|
|
|
|
|
__all__ = ["PythonExecutor"] |
|
|
|
|
|
|
|
|
class PythonExecutor: |
|
|
""" |
|
|
Python execution environment similar to smolagents LocalPythonExecutor. |
|
|
Maintains persistent state and tool namespace across executions. |
|
|
""" |
|
|
|
|
|
def __init__(self): |
|
|
self.namespace = {} |
|
|
self.reset_environment() |
|
|
|
|
|
def reset_environment(self): |
|
|
"""Reset the execution environment.""" |
|
|
|
|
|
self.namespace = { |
|
|
"__builtins__": __builtins__, |
|
|
} |
|
|
|
|
|
self.namespace["_print_outputs"] = [] |
|
|
|
|
|
|
|
|
def captured_print(*args, **kwargs): |
|
|
output = " ".join(str(arg) for arg in args) |
|
|
self.namespace["_print_outputs"].append(output) |
|
|
print(*args, **kwargs) |
|
|
|
|
|
self.namespace["print"] = captured_print |
|
|
|
|
|
|
|
|
try: |
|
|
import pandas as pd |
|
|
import numpy as np |
|
|
import os |
|
|
from pathlib import Path |
|
|
self.namespace["pd"] = pd |
|
|
self.namespace["np"] = np |
|
|
self.namespace["os"] = os |
|
|
self.namespace["Path"] = Path |
|
|
|
|
|
|
|
|
def write_text_file(filepath, content): |
|
|
"""Write text content to a file.""" |
|
|
with open(filepath, 'w') as f: |
|
|
f.write(content) |
|
|
return f"File written to {filepath}" |
|
|
|
|
|
def write_dataframe_to_csv(df, filepath, **kwargs): |
|
|
"""Write pandas DataFrame to CSV file.""" |
|
|
df.to_csv(filepath, **kwargs) |
|
|
return f"DataFrame written to {filepath}" |
|
|
|
|
|
def write_dataframe_to_tsv(df, filepath, **kwargs): |
|
|
"""Write pandas DataFrame to TSV file.""" |
|
|
df.to_csv(filepath, sep='\t', **kwargs) |
|
|
return f"DataFrame written to {filepath}" |
|
|
|
|
|
def create_directory(dirpath): |
|
|
"""Create directory if it doesn't exist.""" |
|
|
Path(dirpath).mkdir(parents=True, exist_ok=True) |
|
|
return f"Directory created: {dirpath}" |
|
|
|
|
|
self.namespace["write_text_file"] = write_text_file |
|
|
self.namespace["write_dataframe_to_csv"] = write_dataframe_to_csv |
|
|
self.namespace["write_dataframe_to_tsv"] = write_dataframe_to_tsv |
|
|
self.namespace["create_directory"] = create_directory |
|
|
|
|
|
except ImportError as e: |
|
|
print(f"Warning: Could not import library: {e}") |
|
|
|
|
|
def send_functions(self, functions: Dict[str, Any]): |
|
|
"""Inject functions into the execution namespace.""" |
|
|
for func_name, func in functions.items(): |
|
|
self.namespace[func_name] = func |
|
|
|
|
|
def send_tools(self, tools: Dict[str, Any]): |
|
|
"""Legacy method for backward compatibility - redirects to send_functions.""" |
|
|
self.send_functions(tools) |
|
|
|
|
|
def send_variables(self, variables: Dict[str, Any]): |
|
|
"""Inject variables into the execution namespace.""" |
|
|
if variables: |
|
|
print(f"π Injecting {len(variables)} variables into Python executor...") |
|
|
self.namespace.update(variables) |
|
|
|
|
|
def __call__(self, code: str) -> Any: |
|
|
"""Execute code in the persistent namespace.""" |
|
|
return self.execute(code) |
|
|
|
|
|
def execute(self, code: str) -> Any: |
|
|
""" |
|
|
Execute Python code in the persistent environment. |
|
|
Similar to smolagents python execution. |
|
|
""" |
|
|
try: |
|
|
|
|
|
self.namespace["_print_outputs"] = [] |
|
|
|
|
|
|
|
|
old_stdout = sys.stdout |
|
|
sys.stdout = captured_output = io.StringIO() |
|
|
|
|
|
try: |
|
|
|
|
|
exec(code, self.namespace) |
|
|
|
|
|
|
|
|
stdout_output = captured_output.getvalue() |
|
|
|
|
|
|
|
|
print_outputs = self.namespace.get("_print_outputs", []) |
|
|
|
|
|
|
|
|
all_outputs = [] |
|
|
if stdout_output.strip(): |
|
|
all_outputs.append(stdout_output.strip()) |
|
|
if print_outputs: |
|
|
all_outputs.extend(print_outputs) |
|
|
|
|
|
result = "\n".join(all_outputs) if all_outputs else "Code executed successfully" |
|
|
|
|
|
return result |
|
|
|
|
|
finally: |
|
|
sys.stdout = old_stdout |
|
|
|
|
|
except Exception as e: |
|
|
return f"Error: {str(e)}" |