Skip to content

Latest commit

 

History

History
211 lines (180 loc) · 14.8 KB

File metadata and controls

211 lines (180 loc) · 14.8 KB

Python coverage

What the Lean model of Python runs, measured. Everything outside the modelled tier is refused loudly (Res.unsupported, with a message naming the construct); it is never answered with a wrong value. The pass rate and the grammar table come from runs against the pinned CPython oracle; the builtin lists are the interpreter's own name tables. CI fails if this page goes stale (harness/coverage_page.py --check).

Differential pass rate

harness/diff_test.py runs every row of harness/cases.json through the model and through CPython 3.9 and compares the outcome (value, or exception class) exactly.

rows agree with CPython disagree recorded refusals
1335 1219 0 116

Of the 1219 rows the model decides, 1219 agree with CPython (100.0%). A recorded refusal is a row kept in the suite to pin a known gap: the model must refuse it, and the suite fails if it ever answers instead.

What the theorems can see

The rows above run through the runner's interpreter (LeanModels/Python/Monadic/). Theorems are stated about a second definition, LeanModels/Python/Semantics.lean, whose tier is narrower (python-architecture.md). diff_test.py --proof-interpreter runs the same rows through it; a refusal there is allowed, a wrong answer is not.

rows agree with CPython disagree refused
1335 1151 0 184

Grammar

harness/refusal_census.py --grammar: one small witness program per production of CPython 3.9's ast grammar, plus edge rows. MATCH means the model ran the witness and agreed with CPython; it does not mean every use of the construct is in tier (2 * 3 runs, "ab" * 3 may refuse). REFUSE shows the model's refusal message.

138 witnesses: 107 MATCH, 31 REFUSE.

stmt

witness verdict refusal message / note
FunctionDef MATCH plain positional def
AsyncFunctionDef REFUSE unsupported statement 'AsyncFunctionDef'
ClassDef MATCH H3 class tier, default protocol only
Return MATCH
Delete MATCH bare-name del at module scope
Assign MATCH
AugAssign MATCH
AnnAssign REFUSE unsupported statement 'AnnAssign:module-scope'
AnnAssign-local MATCH FUNCTION scope: PEP 526 never evaluates the annotation, so this is an ordinary assign — was REFUSE, landed by…
AnnAssign-novalue REFUSE unsupported statement 'AnnAssign:no-value'
For MATCH
AsyncFor REFUSE unsupported statement 'AsyncFunctionDef'
While MATCH
If MATCH
With REFUSE unsupported statement 'With'
AsyncWith REFUSE unsupported statement 'AsyncFunctionDef'
Raise REFUSE 'raise ' (anything but an admitted exception class name) is outside the tier (docs/memory-model.m…
Try MATCH FLIPPED by §except-builtin: ValueError is now an admitted handler class. WHAT THIS ROW PROVES AND DOES NOT:…
Assert MATCH assert is in tier; AssertionError is not catchable
Import REFUSE unsupported statement 'Import'
ImportFrom REFUSE unsupported statement 'ImportFrom'
Global REFUSE unsupported statement 'Global'
Nonlocal REFUSE unsupported statement 'NestedDef'
Expr MATCH
Pass MATCH
Break MATCH
Continue MATCH

expr

witness verdict refusal message / note
BoolOp MATCH
NamedExpr MATCH §L14's walrus, general expression position
BinOp MATCH
UnaryOp MATCH
Lambda MATCH module-scope single-target lambda only
IfExp MATCH
Dict MATCH
Set REFUSE unsupported expression 'Set'
ListComp MATCH desugared to list(genexp) at ingestion
SetComp REFUSE unsupported expression 'SetComp'
DictComp REFUSE unsupported expression 'DictComp'
GeneratorExp MATCH lowered to a synthesized generator function
Await REFUSE unsupported statement 'AsyncFunctionDef'
Yield MATCH statement position only
YieldFrom MATCH inlined at ingestion
Compare MATCH
Call MATCH
JoinedStr MATCH bare replacement fields only
FormattedValue MATCH same node; the conversion/spec slots are the gap
Constant MATCH the int/str/bool/None inventory
Attribute MATCH
Subscript MATCH
Starred MATCH display position only
Name MATCH
List MATCH
Tuple MATCH
Slice MATCH str receivers; list/tuple slices allocate and refuse

dict

witness verdict refusal message / note
for MATCH the live cursor — inch 3a. Was REFUSE/mono=MATCH while there were two interpreters; there is one now, so the …
list MATCH a DRAINING consumer: no mutation window — landed by §L53 rung 3b
tuple MATCH landed by §L53 rung 3b
sorted MATCH landed by §L53 rung 3b
sum MATCH landed by §L53 rung 3b
max MATCH landed by §L53 rung 3b
star MATCH landed by §L53 rung 3b
for-in-function MATCH the cursor at FUNCTION scope — execGen's arm, and it exercises break and continue through the new frame (…
for-keys MATCH for k in d.keys() at function scope — inch 3c-i-a
for-values MATCH for v in d.values() — the VALUES view, whose element is the value, not the key
values MATCH the VALUES view, consumed immediately — inch 3c-i-b
items-consumed MATCH the ITEMS view, consumed immediately — inch 3c-i-b
view-escapes REFUSE method call '.keys' on a dict is outside the tier (dict '.get'/'.clear' only; docs/memory-model.md)
values-identity-eq REFUSE method call '.values' on a dict is outside the tier (dict '.get'/'.clear' only; docs/memory-model.md)
keys-set-algebra REFUSE method call '.keys' on a dict is outside the tier (dict '.get'/'.clear' only; docs/memory-model.md)
enumerate MATCH the key cursor with an index — inch 3c-i-c
enumerate-start MATCH the START is an int, not a Nat: CPython counts from a negative start as readily as a positive one — inch …
enumerate-escapes MATCH THE RULED DELTA (2026-08-23-pycomplete-13 (c)): binding an enumerate and then GROWING the dict is SILENT in C…
enumerate-resize MATCH the same two statements as dict.enumerate-escapes with a different THIRD line, and that pairing is the poin…
enumerate-of-items REFUSE method call '.items' on a dict is outside the tier (dict '.get'/'.clear' only; docs/memory-model.md)
iter-next MATCH the flagship's key expression, minimal: CPython answers 2 — the FIRST key in INSERTION order, which is what m…
iter-steps MATCH ONE cursor, stepped twice. next already implemented both its forms, so the inch bought the stepping for fre…
iter-empty MATCH the 2-argument next on an EXHAUSTED-at-birth cursor: CPython answers the default, and the 1-argument form o…
iter-escapes MATCH dict.enumerate-escapes again, at a different builtin: binding an iterator and then GROWING the dict is SILE…
iter-resize MATCH the same two statements with a different THIRD line, and that pairing is the point: stepping after the growth…
iter-exhausted MATCH THE EXHAUSTION BOUNDARY, measured: an iterator STEPPED PAST the end is DEAD (CPython clears its di_dict), s…
iter-for MATCH THE WITNESS FOR THE ALLOCATOR CENSUS. iter is the THIRD expression that can allocate an Obj.generator wit…
iter-churn REFUSE the dict's KEY SET changed during iteration without changing its size — CPython's answer depends on its entri…
iter-of-list MATCH THE RECEIVER BOUNDARY, now ANSWERED. list_iterator is a PLAIN INDEX cursor — it_index against the CURRENT…
genexp-next MATCH the flagship's key expression: CPython answers 1 -- the first key in INSERTION order that passes the filter. …
genexp-nomatch MATCH no key passes the filter, so the 1-argument next is the faithful StopIteration -- and dict.genexp-default…
genexp-default MATCH the 2-argument form on the same empty filter
genexp-drain MATCH the same filter under a DRAINING consumer, which is a different lowering admission path (list is in drainin…
genexp-bound-is-loud MATCH PEP 289 calls iter() on the outermost iterable when the genexp OBJECT is made, so the cursor's size guard p…
genfun-mutate-after-create MATCH THE NEGATIVE HALF, and it is why the fix is genexp-only: calling a generator FUNCTION runs no code, so CPytho…
keys MATCH a view method in CONSUMING position — landed by inch 3c-i-b's ingestion rewrite, on a dict LITERAL receiver, …
items MATCH MEASURED CORRECTION — the live cursor is already BUILT at MODULE scope (the script executor's .items() shel…
items-in-function MATCH the SAME loop inside a function — 3a gave the bare-key form a cursor at every scope; 3c-i-a gives the VIEW fo…
items-grow MATCH MEASURED: the module-scope shell already raises CPython's RuntimeError VERBATIM ('dictionary changed size dur…
items-update MATCH the admissible regime, already exact at module scope
update-value-during-iter MATCH MEASURED admissible: updating an EXISTING key's value during iteration is fine in CPython — the regime inch 3…
grow-during-iter MATCH MEASURED: CPython raises RuntimeError('dictionary changed size during iteration') at the NEXT step — inch 3a …
churn-during-iter REFUSE the dict's KEY SET changed during iteration without changing its size — CPython's answer depends on its entri…

del

witness verdict refusal message / note
dict-key MATCH dict item deletion — the ingestion rewrite to <dictdel>(d, k)
dict-missing MATCH CPython raises KeyError(9) and the tier reproduces it
dict-reinsert-order MATCH deletion does NOT hold the slot: reinsertion APPENDS, so the entries array stays exactly the insertion sequen…
dict-churn REFUSE the dict's KEY SET changed during iteration without changing its size — CPython's answer depends on its entri…
non-dict-receiver REFUSE 'del o[k]' on a non-dict receiver is outside the tier (dict item deletion only; docs/memory-model.md §the del…
dict-next-iter MATCH THE FLAGSHIP LINE (sunfish.py:541 del self.tp_score[next(iter(self.tp_score))]), whole. Inch (1) landed the…

const

witness verdict refusal message / note
float REFUSE unsupported expression 'Constant:float'
bytes REFUSE unsupported expression 'Constant:bytes'
complex REFUSE unsupported expression 'Constant:complex'
ellipsis REFUSE unsupported expression 'Constant:ellipsis'

op

witness verdict refusal message / note
Add MATCH
Sub MATCH
Mult MATCH int only; str/list repetition refuses
Div REFUSE unsupported expression 'BinOp:Div'
FloorDiv MATCH Int.fdiv
Mod MATCH Int.fmod; str % args is a second tier
Pow MATCH MEASURED CORRECTION: ** is in tier; only the float-valued negative exponent refuses (op.Pow-negative)
Pow-negative REFUSE '**' with a negative exponent (float result) is outside the v0 tier
LShift MATCH budget-capped shift width
RShift MATCH was REFUSE; §L39 rung 1 landed it (op.RShift-budget is its edge)
RShift-budget REFUSE a right shift beyond shiftBudget is outside the tier (docs/memory-model.md §left shift and bitwise or)
BitOr MATCH
BitXor MATCH was REFUSE — the one witness that found the whole rung; §L39 landed it
BitAnd MATCH
MatMult REFUSE unsupported expression 'BinOp:MatMult'
UAdd MATCH was REFUSE; §L39 rung 1
USub MATCH
Not MATCH
Invert MATCH was REFUSE; §L39 rung 1
Eq MATCH
NotEq MATCH
Lt MATCH
LtE MATCH
Gt MATCH
GtE MATCH
Is MATCH refs by address; two immediates refuse
IsNot MATCH
In MATCH
NotIn MATCH
And MATCH
Or MATCH

Builtins

Read from LeanModels/Python/Ast.lean. A modelled name may still refuse some argument shapes (see the grammar and the differential suite); a refused name always refuses, and never raises a fabricated NameError.

Modelled functions (22 of 73): abs, all, any, chr, dict, enumerate, input, int, iter, len, list, max, min, next, ord, print, range, set, sorted, str, sum, tuple

Refused functions (51): ascii, bin, bool, breakpoint, bytearray, bytes, callable, classmethod, compile, complex, copyright, credits, delattr, dir, divmod, eval, exec, exit, filter, float, format, frozenset, getattr, globals, hasattr, hash, help, hex, id, isinstance, issubclass, license, locals, map, memoryview, object, oct, open, pow, property, quit, repr, reversed, round, setattr, slice, staticmethod, super, type, vars, zip

Also modelled: count (from from itertools import count).

Exception classes except can name (12): AssertionError, AttributeError, Exception, IndexError, KeyError, NameError, RecursionError, RuntimeError, StopIteration, TypeError, ValueError, ZeroDivisionError. Other exception names refuse, including ancestors such as LookupError; user classes class E(Exception): pass are admitted.

Other CPython builtin names (56), refused when used: ArithmeticError, BaseException, BlockingIOError, BrokenPipeError, BufferError, BytesWarning, ChildProcessError, ConnectionAbortedError, ConnectionError, ConnectionRefusedError, ConnectionResetError, DeprecationWarning, EOFError, Ellipsis, EnvironmentError, FileExistsError, FileNotFoundError, FloatingPointError, FutureWarning, GeneratorExit, IOError, ImportError, ImportWarning, IndentationError, InterruptedError, IsADirectoryError, KeyboardInterrupt, LookupError, MemoryError, ModuleNotFoundError, NotADirectoryError, NotImplemented, NotImplementedError, OSError, OverflowError, PendingDeprecationWarning, PermissionError, ProcessLookupError, ReferenceError, ResourceWarning, RuntimeWarning, StopAsyncIteration, SyntaxError, SyntaxWarning, SystemError, SystemExit, TabError, TimeoutError, UnboundLocalError, UnicodeDecodeError, UnicodeEncodeError, UnicodeError, UnicodeTranslateError, UnicodeWarning, UserWarning, Warning.