Documentation Index
Fetch the complete documentation index at: https://mintlify.com/pydantic/monty/llms.txt
Use this file to discover all available pages before exploring further.
The Monty class is the main interface for creating and running a sandboxed Python interpreter. It parses Python code on initialization and can execute it multiple times with different inputs, separating parsing cost from execution.
Constructor
Monty(
code: str,
*,
script_name: str = 'main.py',
inputs: list[str] | None = None,
type_check: bool = False,
type_check_stubs: str | None = None,
dataclass_registry: list[type] | None = None,
) -> Monty
Create a new Monty interpreter by parsing the given code.
Name used in tracebacks and error messages
List of input variable names available in the code
Whether to perform type checking on the code
Optional code to prepend before type checking, e.g. with input variable declarations or external function signatures
Optional list of dataclass types to register for proper isinstance() support on output
Raises:
MontySyntaxError: If the code cannot be parsed
MontyTypingError: If type_check is True and type errors are found
Example
import pydantic_monty
# Simple code with no inputs
m = pydantic_monty.Monty('1 + 2')
print(m.run())
# Output: 3
# Code with input variables
m = pydantic_monty.Monty('x * y', inputs=['x', 'y'])
print(m.run(inputs={'x': 2, 'y': 3}))
# Output: 6
Methods
run()
def run(
self,
*,
inputs: dict[str, Any] | None = None,
limits: ResourceLimits | None = None,
external_functions: dict[str, Callable[..., Any]] | None = None,
print_callback: Callable[[Literal['stdout'], str], None] | None = None,
os: Callable[[OsFunction, tuple[Any, ...]], Any] | None = None,
) -> Any
Execute the code and return the result. The GIL is released allowing parallel execution.
Dict of input variable values (must match names from constructor)
Optional resource limits configuration
external_functions
dict[str, Callable[..., Any]] | None
Dict of external function callbacks
print_callback
Callable[[Literal['stdout'], str], None] | None
Optional callback for print output
os
Callable[[OsFunction, tuple[Any, ...]], Any] | None
Optional callback for OS calls. Called with (function_name, args) where function_name is like 'Path.exists' and args is a tuple of arguments. Must return the appropriate value for the OS function (e.g., bool for exists(), stat_result for stat()).
The result of the last expression in the code
Raises:
MontyRuntimeError: If the code raises an exception during execution
Example with External Functions
import pydantic_monty
# Code that calls an external function
m = pydantic_monty.Monty('double(x)', inputs=['x'])
# Provide the external function implementation
result = m.run(
inputs={'x': 5},
external_functions={'double': lambda x: x * 2}
)
print(result)
# Output: 10
Example with Resource Limits
import pydantic_monty
m = pydantic_monty.Monty('x + y', inputs=['x', 'y'])
limits = pydantic_monty.ResourceLimits(max_duration_secs=1.0)
result = m.run(inputs={'x': 1, 'y': 2}, limits=limits)
print(result)
# Output: 3
start()
def start(
self,
*,
inputs: dict[str, Any] | None = None,
limits: ResourceLimits | None = None,
print_callback: Callable[[Literal['stdout'], str], None] | None = None,
) -> FunctionSnapshot | NameLookupSnapshot | FutureSnapshot | MontyComplete
Start the code execution and return a progress object, or completion. This allows you to iteratively run code and pause/resume whenever an external function is called. The GIL is released allowing parallel execution.
Dict of input variable values (must match names from constructor)
Optional resource limits configuration
print_callback
Callable[[Literal['stdout'], str], None] | None
Optional callback for print output
FunctionSnapshot if an external function call is pending
NameLookupSnapshot if more futures need to be resolved
FutureSnapshot if futures need to be resolved
MontyComplete if execution finished without external calls
Raises:
MontyRuntimeError: If the code raises an exception during execution
Example with Iterative Execution
import pydantic_monty
code = """
data = fetch(url)
len(data)
"""
m = pydantic_monty.Monty(code, inputs=['url'])
# Start execution - pauses when fetch() is called
result = m.start(inputs={'url': 'https://example.com'})
print(type(result))
# Output: <class 'pydantic_monty.FunctionSnapshot'>
print(result.function_name)
# Output: fetch
print(result.args)
# Output: ('https://example.com',)
# Perform the actual fetch, then resume with the result
result = result.resume(return_value='hello world')
print(type(result))
# Output: <class 'pydantic_monty.MontyComplete'>
print(result.output)
# Output: 11
type_check()
def type_check(self, prefix_code: str | None = None) -> None
Perform static type checking on the code. Analyzes the code for type errors without executing it. This uses a subset of Python’s type system supported by Monty.
Optional code to prepend before type checking, e.g. with input variable declarations or external function signatures
Raises:
MontyTypingError: If type errors are found. Use .display(format, color) on the exception to render the diagnostics in different formats.
RuntimeError: If the type checking infrastructure fails internally.
dump()
Serialize the Monty instance to a binary format. The serialized data can be stored and later restored with Monty.load(). This allows caching parsed code to avoid re-parsing on subsequent runs.
Bytes containing the serialized Monty instance
Raises:
ValueError: If serialization fails
Example
import pydantic_monty
# Serialize parsed code to avoid re-parsing
m = pydantic_monty.Monty('x + 1', inputs=['x'])
data = m.dump()
# Later, restore and run
m2 = pydantic_monty.Monty.load(data)
print(m2.run(inputs={'x': 41}))
# Output: 42
load() (static method)
@staticmethod
def load(
data: bytes,
*,
dataclass_registry: list[type] | None = None,
) -> Monty
Deserialize a Monty instance from binary format.
The serialized Monty data from dump()
Optional list of dataclass types to register for proper isinstance() support on output
Raises:
ValueError: If deserialization fails
register_dataclass()
def register_dataclass(self, cls: type) -> None
Register a dataclass type for proper isinstance() support on output.
When a dataclass passes through Monty and is returned, it normally becomes an UnknownDataclass. By registering the original type, we can use it to instantiate a real instance of that dataclass.
The dataclass type to register
Raises:
TypeError: If the argument is not a dataclass type
Async Helper Function
run_monty_async()
async def run_monty_async(
monty_runner: Monty,
*,
inputs: dict[str, Any] | None = None,
external_functions: dict[str, Callable[..., Any]] | None = None,
limits: ResourceLimits | None = None,
print_callback: Callable[[Literal['stdout'], str], None] | None = None,
os: AbstractOS | None = None,
) -> Any
Run a Monty script with async external functions and optional OS access. This function provides a convenient way to run Monty code that uses both async external functions and filesystem operations.
The Monty instance to execute
Dictionary of input variable values
external_functions
dict[str, Callable[..., Any]] | None
Dictionary of external functions (can be sync or async)
Optional resource limits configuration
print_callback
Callable[[Literal['stdout'], str], None] | None
Optional callback for print output
Optional OS access handler for filesystem operations (e.g., OSAccess instance)
The output of the Monty script
Example
import asyncio
import pydantic_monty
async def async_fetch(url):
# Simulated async operation
await asyncio.sleep(0.1)
return f"Data from {url}"
async def main():
code = "result = fetch('https://example.com')"
m = pydantic_monty.Monty(code)
output = await pydantic_monty.run_monty_async(
m,
external_functions={'fetch': async_fetch}
)
print(output)
asyncio.run(main())
MontyRepl
The MontyRepl class provides an incremental, no-replay REPL (Read-Eval-Print Loop) session. Each feed() call compiles and executes only the provided snippet against preserved heap/global state, unlike traditional REPLs that replay all history.
create() (static method)
@staticmethod
def create(
code: str,
*,
script_name: str = 'main.py',
inputs: list[str] | None = None,
start_inputs: dict[str, Any] | None = None,
limits: ResourceLimits | None = None,
print_callback: Callable[[Literal['stdout'], str], None] | None = None,
dataclass_registry: list[type] | None = None,
) -> tuple[MontyRepl, Any]
Create a REPL session directly from source code. Returns a tuple of (repl, output) where output is the initial execution result.
Initial Python code to execute
Name used in tracebacks and error messages
List of input variable names available in the code
Initial input values for the session
Optional resource limits configuration
print_callback
Callable[[Literal['stdout'], str], None] | None
Optional callback for print output
Optional list of dataclass types to register
A tuple containing the REPL session and the initial execution result
Raises:
MontySyntaxError: If the code cannot be parsed
MontyRuntimeError: If the code raises an exception during execution
script_name (property)
@property
def script_name(self) -> str
Returns the name of the script being executed.
feed()
def feed(
self,
code: str,
*,
print_callback: Callable[[Literal['stdout'], str], None] | None = None,
) -> Any
Execute one incremental snippet and return its output. The snippet is compiled and executed against the current session state without replaying previous code.
Python code snippet to execute
print_callback
Callable[[Literal['stdout'], str], None] | None
Optional callback for print output
The result of the code snippet
Raises:
MontyRuntimeError: If the code raises an exception during execution
Example
import pydantic_monty
# Create REPL with initial state
repl, initial = pydantic_monty.MontyRepl.create("x = 1")
print(initial)
# Output: None (assignment has no return value)
# Feed additional snippets
result = repl.feed("x + 10")
print(result)
# Output: 11
# State is preserved
result = repl.feed("x = x * 2; x")
print(result)
# Output: 2
dump()
Serialize the REPL session to bytes. The serialized data can be stored and later restored with MontyRepl.load().
Bytes containing the serialized REPL session
load() (static method)
@staticmethod
def load(
data: bytes,
*,
print_callback: Callable[[Literal['stdout'], str], None] | None = None,
dataclass_registry: list[type] | None = None,
) -> MontyRepl
Restore a REPL session from bytes.
The serialized REPL data from dump()
print_callback
Callable[[Literal['stdout'], str], None] | None
Optional callback for print output
Optional list of dataclass types to register
Raises:
ValueError: If deserialization fails