dart_monty

dart_monty

CI Pages codecov

Live Demo | Documentation | GitHub

Sandboxed Python interpreter for Dart and Flutter. Run Python from native, web, and mobile — one package, every platform.

Quick Start

Install

dart pub add dart_monty

The low-level bindings (dart_monty_core) are pulled in transitively.

On Flutter, add the asset stanza so the bundler includes dart_monty_core's WASM/JS bridge files (plain-Dart consumers can skip this):

flutter:
  assets:
    - package: dart_monty_core

For local development against a worktree, override with path: deps:

dependencies:
  dart_monty:
    path: /path/to/dart_monty
  dart_monty_core:
    path: /path/to/dart_monty_core

Then import the package:

import 'package:dart_monty/dart_monty.dart';

On Flutter Web, initialise the bridge before first use:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await DartMonty.ensureInitialized(); // loads bridge on web; no-op native
  runApp(const MyApp());
}

No <script> tag in web/index.html is required — DartMonty.ensureInitialized() injects the bridge dynamically.

Now you can use dart_monty in three ways:

1. One-shot execution

For simple, stateless execution, use the static Monty.exec() method:

Future<void> main() async {
  final result = await Monty.exec('2 + 2');
  print(result.value); // 4
}

2. Stateful REPL

For interactive, stateful sessions, use a MontyRepl:

Future<void> main() async {
  final repl = MontyRepl();
  await repl.feedRun('x = 42');
  await repl.feedRun('def double(n): return n * 2');
  final result = await repl.feedRun('double(x)');
  print(result.value); // MontyInt(84)
  await repl.dispose();
}

3. Runtime with extensions

For more advanced use cases, create a MontyRuntime to manage extensions and sessions:

Future<void> main() async {
  final runtime = MontyRuntime(
    extensions: [JinjaTemplateExtension(), MessageBusExtension()],
  );
  final result = await runtime.execute(
    "tmpl_render(template='Hello {{ name }}!', context={'name': 'World'})",
  ).result;
  print(result.value); // 'Hello World!'
  await runtime.dispose();
}

Examples

Runnable end-to-end demos, all platform-agnostic (FFI on the VM, WASM in Chrome — Monty dispatches to the same Rust ABI on every backend):

File What it shows
example/example.dart Minimal Monty.exec one-shots, including error handling.
example/type_check_demo.dart Monty.typeCheck for static type analysis — clean code, type errors, prefixCode for declaring external function shapes.
example/dataclass_demo.dart Stateful dataclass round-trip across MontyRuntime.execute calls — produce, attribute-access, return, and re-bind a @dataclass, hydrating into a typed Dart User on the way back.

Run any of them with dart run example/<file>.dart from the repo root. For the native and web runners (with built Rust library and a COOP/COEP server), see example/native/run.sh and example/web/run.sh.

Documentation

License

MIT License. See LICENSE.

Libraries

dart_monty
Pure Dart bindings for the Monty sandboxed Python interpreter.
dart_monty_bridge
High-level bridge layer for dart_monty.
dart_monty_testing
Testing utilities for dart_monty.
monty_backend_spi
Backward-compatibility re-export for test files that previously imported the platform SPI from the old multi-package layout.