monty-type-checking
Type checking for Monty, powered by ty.
Monty supports full modern Python type hints. This crate embeds ty's semantic
analysis (Astral's ty_python_semantic engine — the same one behind the ty
type checker) and checks code against
monty-typeshed: a trimmed
typeshed describing the stdlib subset Monty actually implements. Code that
uses unsupported stdlib surface is therefore flagged before it runs rather
than failing at runtime.
It backs monty --type-check in the CLI and the type_check option on
sessions in the pydantic-monty
and @pydantic/monty
packages.
Usage
use ;
use TypeCheckingConfig;
let mut checker = default;
let source = new;
let diagnostics = checker.run.unwrap;
// `Some(...)` means typing errors were found; `None` means the code is clean
assert!;
The second argument is an optional stubs file declaring names the host will
provide at runtime (external functions, inputs). The stubs are written
alongside the source and a from <stubs> import * line is injected, so
checked code can reference host functions without defining them — diagnostic
line numbers are adjusted back to the original source.
run_with takes a TypeCheckContext with host module stubs and a session's committed imports.
Each ModuleStub becomes a .pyi module or package tree, resolved through imports rather than star-imported.
scan_imports collects committed imports into a prelude, injected before the stubs' star import so later snippets
can use earlier imports.
TypeCheckingConfig picks the output format (ty's full, concise, json,
github, ... renderings) and whether to use ANSI colour. It is passed to
run rather than applied to the result because TypeCheckingDiagnostics
borrows the checker — ty's diagnostics resolve their spans against the
database that produced them, so anything that outlives the checker (notably
anything crossing a process boundary) has to keep the rendered string.
Reusing a checker
A TypeChecker owns one in-memory salsa
database, so reusing it across checks avoids rebuilding typeshed-derived
semantic state every time — which is what makes per-feed checking in a REPL
session affordable. Files written by a previous run stay in the database
(rewritten in place when the path repeats), so call reset before checking an
unrelated session's code: it scrubs every file written so far, including the
directories they created. TypeChecker is not Sync; concurrent checks each
need their own.
Monty crates
monty— the core interpreter: Python parser, bytecode VM, and sandbox.monty-types— the shared boundary data types (values, exceptions, OS calls, resource limits) hosts use without linking the interpreter.monty-fs— host-side filesystem mounts: maps virtual sandbox paths to real host directories.monty-runtime— themontybinary: REPL, file runner, and subprocess worker mode.monty-pool— an elastic pool of crash-isolatedmontyworker subprocesses.monty-proto— the protobuf wire protocol spoken between pool parents and workers.monty-type-checking— type checking of sandboxed code, powered by ty. this cratemonty-typeshed— the trimmed typeshed stubs describing the stdlib subset Monty implements.monty-macros— the proc macros behindmonty's argument parsing.