The language subset
This is Monty's subset, ported as-is. It is deliberately smaller than CPython, and the constructs it does not support are rejected at parse time rather than failing halfway through a run, which is the behaviour you want when a model wrote the code.
Supported
| Values | int, float, bool, str, bytes, list, tuple, dict, set, frozenset, None, slices, ranges |
| Statements | assignment (including augmented, chained and starred unpacking), if / elif / else, for, while, break, continue, try / except / else / finally, raise, with, assert, import, global, nonlocal, pass |
| Functions | positional, keyword, default, *args, **kwargs, keyword-only, nested functions, closures, lambda, recursion to the depth limit |
| Classes | simple classes: instance methods, __init__, __repr__, __str__, class variables |
| Decorators | on classes and on top-level or nested def / async def |
| Comprehensions | list, set, dict, and generator expressions |
| Strings | f-strings including nesting, format specs and =, plus str.format and % |
| Exceptions | the standard hierarchy, custom exception classes, raise … from … |
Not supported
Each of these raises at compile time, before any code runs:
- Class inheritance and metaclasses.
class Foo(Bar):is rejected; classes are simple. - Decorators on methods, which also rules out
@classmethod,@staticmethodand@property. yieldandyield from. There are no generator functions. Generator expressions parse, and currently materialise to a list rather than staying lazy.matchstatements.delstatements, in either form.async with,async forand async comprehensions.- Exception groups (
try*/except*). - PEP 695
typealiases. - Wildcard imports (
from m import *). - Complex numbers and t-strings.
Reject early, and say why
An unsupported construct raises a NotImplementedError naming what it was, at compile time.
A model handed that message can fix its own code; one that hit the same limitation halfway
through a run would have already left side effects behind.
One deliberate divergence
Upstream Monty recycles object slots on its own heap, so a temporary's id() can be handed to the
next object of the same shape. Object identity here is the host runtime's and an id is never
recycled. It is the single conformance fixture this port does not pass, and it is a difference you
would only notice by asserting on id().
Read next
- Standard library — the modules that ship.
- Host libraries — adding your own.