Python Types Supported in Monty: A Complete Guide to the Pydantic Sandbox Runtime
Monty supports a comprehensive subset of Python's data model including primitives (None, bool, int, float), containers (list, dict, set, tuple), callables (functions, builtins), and standard library types like pathlib.Path, all implemented through the Type and Value enums in the Rust source.
Monty is a secure Python interpreter from Pydantic that executes untrusted code in a sandboxed environment. Understanding which Python types are supported in Monty is essential for developers building safe code execution pipelines. This guide examines the complete type system implemented in the Monty Rust codebase, mapping every supported Python type to its underlying enum variants and source file locations.
Primitive and Singleton Types in Monty
Monty implements Python's fundamental singletons and numeric types through dedicated enum variants in crates/monty/src/types/type.rs and crates/monty/src/value.rs.
None, bool, and Numeric Types
The basic building blocks include:
None– Represented asType::NoneTypeandValue::None(type.rs L32-L33)bool–Type::BoolwithValue::Bool(bool)storage (type.rs L33-L34)int– Supports both small integers viaValue::Int(i64)and arbitrarily large integers throughValue::InternLongInt(LongIntId)(type.rs L34-L35)float–Type::FloatwithValue::Float(f64)for IEEE 754 double-precision storage (type.rs L35-L36)
Ellipsis and Type Objects
Monty also supports Python's special singletons:
Ellipsis(...) –Type::EllipsisandValue::Ellipsis(type.rs L30-L31)typeobjects –Type::Typefor metaclass operations andisinstancechecks (type.rs L31-L32)
Container and Collection Types Supported by Monty
Monty implements Python's core data structures with full mutability semantics and iterator support. Each container type resides in its own module (e.g., list.rs, dict.rs) and stores data on the heap via Value::Ref to keep the enum size small.
Mutable Sequences and Mappings
list–Type::Listwith heap-allocatedHeapData::Liststorage (type.rs L39-L41)dict–Type::DictwithHeapData::Dictfor key-value mappings (type.rs L43-L44)set–Type::SetwithHeapData::Setfor unordered unique collections (type.rs L44-L45)
Immutable Collections and Sequences
tuple–Type::TuplewithHeapData::Tuplefor immutable sequences (type.rs L40-L42)frozenset–Type::FrozenSetwithHeapData::FrozenSetfor immutable sets (type.rs L45-L46)range–Type::RangewithHeapData::Rangefor lazy integer sequences (type.rs L36-L37)slice–Type::SlicewithHeapData::Slicefor indexing operations (type.rs L38-L39)
Text and Binary Data
str–Type::StrwithHeapData::Strfor Unicode strings (type.rs L38-L39)bytes–Type::ByteswithHeapData::Bytesfor immutable byte sequences (type.rs L39-L40)
Callable and Iterator Types in Monty
Monty supports Python's callable objects and asynchronous primitives, enabling function definitions, built-in method calls, and async/await patterns.
User-Defined Functions and Builtins
function(user-defined) –Type::FunctionwithValue::DefFunction(FunctionId)referencing the function definition table (type.rs L48-L50)builtin_function_or_method–Type::BuiltinFunctionwithValue::Builtin(Builtins)for sandbox-safe built-in operations likelen()orprint()(type.rs L49-L51)
Iterators, Coroutines, and Modules
iterator–Type::IteratorwithHeapData::Iterfor objects returned byiter()(type.rs L52-L53)coroutine/external_future–Type::CoroutinewithValue::ExternalFuture(CallId)for async/await patterns and external async calls (type.rs L54-L56)module–Type::ModulewithValue::Ref→HeapData::Modulefor imported namespace objects (type.rs L55-L56)
Standard Library Types in the Monty Sandbox
Beyond core built-ins, Monty includes carefully selected standard library types that maintain sandbox safety while providing essential functionality.
pathlib.Path and Dataclasses
pathlib.Path(POSIX) –Type::PathwithHeapData::Pathfor filesystem path manipulation without unsafe operations (type.rs L63-L65)dataclass–Type::DataclasswithHeapData::Dataclassfor the runtime representation of data classes (type.rs L46-L47)
Descriptors, Typing, and I/O
propertydescriptor –Type::PropertywithValue::Property(Property)for managed attributes (type.rs L66-L68)typing._SpecialForm(e.g.,Any,Union) –Type::SpecialFormfor generic type hints (type.rs L60-L62)io.TextIOWrapper(stdout/stderr) –Type::TextIOWrapperwithValue::Marker(Marker)for stream handling (type.rs L57-L59)
Exception Types
- Exception classes (e.g.,
ValueError) –Type::Exception(ExcType)for the exception hierarchy, though notably disabled fromEnumStringparsing since exceptions cannot be constructed from plain string tokens (type.rs L47-L48)
How Monty Implements Python Type Checking
Monty's type system relies on a dual-enum architecture that separates static type metadata from runtime object representation.
The Type Enum vs Value Enum Architecture
The Type enum in crates/monty/src/types/type.rs defines the static type system used for isinstance checks, type() calls, and constructor dispatch. The Value enum in crates/monty/src/value.rs represents every Python object that can exist at runtime, with small values stored inline and larger containers allocated on the heap via Value::Ref.
This separation allows Monty to perform fast type comparisons using the Type enum while maintaining rich runtime semantics through Value variants like Value::Int(i64) for small integers or Value::Ref pointing to HeapData::List for mutable sequences.
Constructor Dispatch and isinstance Checks
When the parser encounters a literal such as 'hello', 123, or [1, 2], it creates the appropriate Value variant directly. For constructor calls like list(x), int('42'), or str(b), the Type::call method (defined in type.rs lines 72-78) dispatches to the concrete type's init implementation—such as List::init, Str::init, or the Int conversion logic.
The isinstance builtin compares the object's runtime type tag against the Type enum variant, ensuring CPython-compatible behavior while maintaining sandbox safety.
Working with Monty Types: Code Examples
The following examples demonstrate that Monty's supported types behave identically to CPython, whether accessed through the Python bindings (pydantic_monty) or the Rust API.
Using Monty from Python
from pydantic_monty import Monty
code = """
# primitives
a = None
b = True
c = 42
d = 3.14
e = ...
# containers
lst = [1, 2, 3]
tpl = (4, 5)
dct = {'x': 1, 'y': 2}
st = {1, 2, 3}
frz = frozenset([4, 5])
rng = range(0, 10, 2)
slc = slice(1, 5, 2)
bts = b'abc'
txt = "hello"
# callable / iterator
it = iter(lst)
next(it)
# special objects
import pathlib
p = pathlib.Path('.')
p / 'subdir' / 'file.txt'
# show types
print(type(a), type(b), type(c), type(d), type(e))
print(type(lst), type(tpl), type(dct), type(st), type(frz), type(rng), type(slc))
print(type(bts), type(txt))
print(type(it), type(p))
"""
m = Monty(code)
result = m.run()
print(result)
Expected output (matching CPython):
<class 'NoneType'> <class 'bool'> <class 'int'> <class 'float'> <class 'ellipsis'>
<class 'list'> <class 'tuple'> <class 'dict'> <class 'set'> <class 'frozenset'> <class 'range'> <class 'slice'>
<class 'bytes'> <class 'str'>
<class 'range_iterator'> <class 'PosixPath'>
Creating a Monty Sandbox from Rust
For Rust developers embedding the interpreter directly:
use pydantic_monty::Monty;
let src = r#"
x = [1, 2, 3]
print(type(x)) # -> <class 'list'>
"#;
let mut interpreter = Monty::new(src);
interpreter.run().unwrap();
The output matches CPython because the Type enum implements fmt::Display to return the exact Python type names (see impl fmt::Display for Type in type.rs).
Summary
- Monty supports primitive types including
None,bool,int,float, andEllipsis, withinthandling both small values and arbitrarily large integers through separate variants. - Container types cover the full Python collection hierarchy: mutable (
list,dict,set), immutable (tuple,frozenset,range), and sequence helpers (slice,str,bytes), all heap-allocated viaValue::Ref. - Callable types include user-defined functions (
Type::Function), built-in methods (Type::BuiltinFunction), iterators, coroutines, and modules, enabling complete Python program execution. - Standard library extensions such as
pathlib.Path,dataclass,propertydescriptors, and exception types extend the sandbox with safe I/O and data structure capabilities. - The dual-enum architecture separates static type checking (
Typeintype.rs) from runtime object representation (Valueinvalue.rs), with constructor dispatch handled byType::callmethods.
Frequently Asked Questions
Does Monty support Python's arbitrary-precision integers?
Yes. Monty handles arbitrarily large integers through the Value::InternLongInt(LongIntId) variant for values exceeding i64 range, while small integers use the inline Value::Int(i64) representation. This matches CPython's transparent int/long unification.
How does Monty handle mutable versus immutable container types?
Mutable containers like list, dict, and set are stored on the heap via Value::Ref pointing to HeapData variants (e.g., HeapData::List), allowing reference-counted sharing and in-place modification. Immutable types like tuple and frozenset use the same heap storage but enforce immutability through their method implementations in tuple.rs and set.rs.
Can Monty execute Python code that uses type hints from the typing module?
Yes. Monty supports typing._SpecialForm objects including Any, Union, and other generic constructs through the Type::SpecialForm variant. However, these are currently treated as runtime objects rather than participating in static type checking within the sandbox.
What file paths contain the core type definitions in Monty?
The master type system lives in crates/monty/src/types/type.rs (the Type enum for isinstance and constructors) and crates/monty/src/value.rs (the Value enum for runtime object representation). Container implementations are modularized in crates/monty/src/types/list.rs, dict.rs, set.rs, and str.rs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →