dart_monty 0.17.1
dart_monty: ^0.17.1 copied to clipboard
Script your Dart/Flutter app with sandboxed Python — runtime extensions, Flutter glue, and FFI/WASM asset loading on top of dart_monty_core.
dart_monty #
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 host functions and extensions
MontyRuntime manages host functions, extensions, and long-lived sessions.
Register HostFunctions to expose Dart callbacks to Python:
Future<void> main() async {
final runtime = MontyRuntime()
..register(HostFunction(
schema: const HostFunctionSchema(
name: 'fetch',
params: [HostParam(name: 'url', type: HostParamType.string)],
),
// DispatchMode.future lets Python `await fetch(url)` directly.
// asyncio.gather over multiple calls runs them concurrently.
dispatch: DispatchMode.future,
handler: (args, _) async => httpClient.get(args['url']! as String),
));
final result = await runtime.execute(
'await fetch(base_url)',
inputs: {'base_url': 'https://example.com/api'},
).result;
print(result.value);
await runtime.dispose();
}
For plugin-style wiring, pass extensions:
final runtime = MontyRuntime(
extensions: [JinjaTemplateExtension(), MessageBusExtension()],
);
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 #
- Installation — Add to your project
- Overview — API summary and quick start
- Architecture — Module structure and internals
- REPL Guide — Stateful interactive execution
- Extensions — Template, MessageBus, Sandbox
- Contributing — Build, run tests, gate scripts, release process
- Contributor Setup — Toolchain install (Rust, Dart, Python)
Stability and versioning #
This package does not follow semantic versioning. Breaking changes can land in any release. The CHANGELOG is kept up-to-date with every breaking change, so pin to a specific version and read the changelog before upgrading.
We expect to stabilise the API and adopt semver when the package goes into production — roughly 1–3 months from now. If you are planning to depend on this package, please open an issue so we can factor your use-case into the stabilisation work.
License #
MIT License. See LICENSE.