Skip to content

Monty API — Dart

Sandboxed Python interpreter for Dart and Flutter. Pure Dart, no Flutter required.

MontyRuntime is the high-level API for stateful Python execution with tools, extensions, and OS-level interception.

final session = MontyRuntime(
  extensions: [JinjaTemplateExtension()],
  osHandlers: {'Path.': memoryFsHandler()},
);

// Variables persist natively across calls
await session.execute('x = 42').result;
final r = await session.execute('x + 1').result;
print(r.value); // 43

await session.dispose();

Execution Modes

  • Shared Mode (default): One interpreter persists across all calls. Variables and functions survive in the Rust heap.
  • Sandbox Mode (sandbox: true): Each call creates and disposes a fresh interpreter. Safe for async I/O host functions.

Monty (Low-level)

Monty from dart_monty_core is the low-level execution surface. It has three shapes:

// One-shot, stateless.
final result = await Monty.exec('2 + 2');

// Compiled-program holder — re-run with different inputs.
final program = Monty('x * 2');
final r1 = await program.run(inputs: {'x': 21});
final r2 = await program.run(inputs: {'x': 100});

// Stateful REPL — variables, functions, classes persist across calls.
final repl = MontyRepl();
await repl.feedRun('x = 42');
final r3 = await repl.feedRun('x + 1');
await repl.dispose();

Each Monty(code).run(...) call runs in a fresh interpreter — state from earlier calls does not persist. Use MontyRepl when you need accumulated state.

Static type checking

Monty.typeCheck analyses code without executing it:

final errors = await Monty.typeCheck('x: int = "not an int"');
for (final e in errors) {
  print('${e.path}:${e.line}:${e.column} ${e.code}: ${e.message}');
}

prefixCode lets you declare input or external-function shapes so the checker knows their types:

final errors = await Monty.typeCheck(
  'result: str = fetch("https://example.com")',
  prefixCode: 'def fetch(url: str) -> str: ...',
);

Per-call inputs

MontyRuntime.execute(code, inputs: {…}) injects Python variables before user code runs:

await runtime
    .execute('f"{greeting}, {name}!"', inputs: {
      'greeting': 'hello',
      'name': 'Alice',
    })
    .result;

Convertible types: bool, int, double, String, List, Map, and MontyNone(). Dart null throws MontyInternalError (use MontyNone() for Python None); unsupported types throw ArgumentError. Both are synchronous — the script never starts.

Host Functions

Expose Dart code to Python:

HostFunction(
  schema: const HostFunctionSchema(
    name: 'fetch',
    description: 'Fetch URL content.',
    params: [HostParam(name: 'url', type: HostParamType.string)],
  ),
  handler: (args, ctx) async => http.read(Uri.parse(args.str('url'))),
)

ctx (HostContext) exposes:

Field Purpose
emit / emitText Push BridgeEvents mid-call (progress, custom events)
executionId Per-call ID for event correlation
cancelToken Cooperative cancellation for long-running work
os Active OsCallHandler, for direct OS-primitive calls
parent: HostParentRef? Narrow view of the owning runtime — emitChildEvent, schemas. No execute() (would deadlock).
subExecute Run a sub-script in a fresh interpreter. See buildRunScriptFunction and the tutorial.

buildRunScriptFunction

Convenience builder for a run_script host function — Python calls run_script('foo.py', inputs={…}) and gets back the sub-script's last-expression value:

runtime.register(buildRunScriptFunction((path) async {
  return await File(path).readAsString();
}));

See the Inputs, run_script, and Sub-Execution tutorial for the full story.

Extensions

Group related tools into namespaced units.

Extension Description
JinjaTemplateExtension Jinja2 template rendering
MessageBusExtension In-memory message channels
SandboxExtension Recursive child interpreters
EventLoopExtension Long-running coroutine exchange

OS Call Handlers

Intercept Python pathlib, os, and datetime calls.

Handler Description
fsHandler(FileSystem) Generic Path.* handler
memoryFsHandler() Ephemeral in-memory VFS
sandboxedFsHandler(root) Restricted native FS
readOnlyHandler(child) Blocks write operations
overlayFsHandler() Copy-on-write overlay
composeOsHandlers({}) Prefix-based dispatch

Core Types

  • MontyResult: .value, .error, .usage, .printOutput
  • MontyException: .message, .excType, .traceback
  • MontyValue: Sealed hierarchy representing Python objects (Int, String, List, Map, etc.)
  • BridgeEvent: Sealed hierarchy for execution observability.