limitations/exceptions.md
Monty implements a fixed set of exception classes, listed below. Sandboxed
code cannot define new exception classes: the class statement exists
(see classes.md) but classes cannot inherit, so there is no way
to subclass BaseException/Exception. raise must therefore use one of
these built-ins — raise MyClass() on a plain user class raises
TypeError: exceptions must derive from BaseException, as in CPython.
BaseException, Exception, SystemExit, KeyboardInterrupt,
ArithmeticError, OverflowError, ZeroDivisionError, LookupError,
IndexError, KeyError, RuntimeError, NotImplementedError,
RecursionError, AttributeError, FrozenInstanceError, NameError,
UnboundLocalError, ValueError, UnicodeDecodeError, UnicodeEncodeError,
ImportError, ModuleNotFoundError, OSError, FileNotFoundError, FileExistsError,
IsADirectoryError, NotADirectoryError, PermissionError,
AssertionError, MemoryError, StopIteration, SyntaxError,
TimeoutError, TypeError.
Module-specific: json.JSONDecodeError (subclass of ValueError),
re.PatternError / re.error, io.UnsupportedOperation (catchable as
both OSError and ValueError, matching CPython's dual parentage).
Warning and all its subclasses (DeprecationWarning, etc.),
BufferError, EOFError, FloatingPointError, GeneratorExit,
ConnectionError and subclasses (ConnectionAbortedError,
ConnectionRefusedError, ConnectionResetError,
BrokenPipeError), BlockingIOError, ChildProcessError,
InterruptedError, ProcessLookupError, ReferenceError,
StopAsyncIteration, SystemError, TabError, IndentationError,
UnicodeError (parent), UnicodeTranslateError,
EncodingWarning, EnvironmentError / IOError aliases,
ExceptionGroup / BaseExceptionGroup (see language.md).
All exception constructors accept zero or one string argument only.
Multi-argument forms used in CPython (e.g. OSError(errno, strerror, filename), UnicodeDecodeError(encoding, obj, start, end, reason)) are
not supported — passing more than one argument raises an internal error.
exc.args — a tuple with 0 or 1 elements. Always a tuple, even when
empty.str(exc) — returns the single message string, or "" if none.repr(exc) — ClassName('message') matching CPython, except
UnicodeDecodeError/UnicodeEncodeError: CPython reprs these from their
real 5-field constructor (UnicodeDecodeError('ascii', b'\xff', 0, 1, 'ordinal not in range(128)')), which Monty doesn't track — Monty's
repr() uses the generic single-message form instead.Not implemented: __cause__, __context__, __suppress_context__,
__traceback__, __notes__, add_note(). The raise X from Y syntax
parses, but the from Y cause is silently dropped — chained
tracebacks are not preserved across raise from.
User class definitions are supported, but classes cannot inherit
(class Foo(Exception): raises NotImplementedError: ... class inheritance and metaclasses), so there is no way to create a new exception class inside
the sandbox. Raising a plain user class instance (raise MyClass()) fails
with TypeError: exceptions must derive from BaseException. Define custom
exception types on the host side if needed, or use the built-in subclass
that best fits.
finallybreak/continue/return inside a finally block follows CPython
semantics (the finally body runs exactly once and a return/break/
continue that exits it discards any in-flight exception), but Monty does
not emit CPython 3.14's PEP 765 SyntaxWarning for such statements — Monty
has no warnings machinery.
Tracebacks are formatted to match CPython, including the
File "...", line N, in <function> lines and ~ caret markers (Monty
uses ~ where CPython uses ^; the test harness normalizes between
them). Frame names use <module> for top-level code.
Known caret divergences:
name = f(...) assignment or return f(...) statement (a noise
heuristic in traceback._should_show_carets); Monty always draws carets for
the frame's range.class statement), Monty renders the CPython-style source
block — all lines when the range covers at most three, otherwise
...<N lines>... elision — but never draws caret markers under it, where
CPython draws multi-line carets for partial-line ranges (e.g. a multi-line
binary expression).Monty never emits CPython's Did you mean: '...'? suggestions on
NameError/AttributeError. Note this divergence is invisible to the test
suite: scripts/run_traceback.py strips the suggestions from CPython's output
before comparison, so traceback tests cannot catch it.
An exception raised inside a Python callable that native code invokes
synchronously — the key=/predicate/function argument of map, filter,
sorted/min/max, and a user-defined
__iter__/__next__/__contains__/__repr__/__str__ — omits the calling
frame from its traceback; the callee frame is present.
CPython shows both. This is a limitation of the re-entrant call path
(evaluate_function), which does not splice the host call site into the
traceback. The exception type and message are unaffected.