torch.compiler API reference#
Created On: Jun 02, 2023 | Last Updated On: Oct 15, 2026
For a quick overview of torch.compiler, see torch.compiler.
compile |
See |
reset |
Reset the in-process compiler state. |
nonstrict_trace |
Decorator to mark a function as nonstrict-traceable for dynamo. |
allow_in_graph |
Tells the compiler frontend (Dynamo) to skip symbolic introspection of the function and instead directly write it to the graph when encountered. |
substitute_in_graph |
Register a polyfill handler for a function, usually a C function from the C extension, to be used in place of the original function when inlining the original function in the graph. |
assume_constant_result |
This function is used to mark a function fn as having a constant result. |
list_backends |
Return valid strings that can be passed to torch.compile(..., backend="name"). |
disable |
This function provides a decorator to disable compilation on a function. |
set_default_backend |
Set the default backend for |
get_default_backend |
Return the current default backend for |
set_stance |
Set the current stance of the compiler. |
set_enable_guard_collectives |
Enables use of collectives during guard evaluation to synchronize behavior across ranks. |
cudagraph_mark_step_begin |
Indicates that a new iteration of inference or training is about to begin. |
cudagraph_mark_warmup_incomplete |
Request another warmup for the active CUDA Graph Trees function. |
is_compiling |
Indicates whether a graph is executed/traced as part of torch.compile() or torch.export(). |
is_dynamo_compiling |
Indicates whether a graph is traced via TorchDynamo. |
is_exporting |
Indicates whether we're under exporting. |
keep_portable_guards_unsafe |
A common function to only keep guards that can be used in both Python and non-Python environments. |
skip_guard_on_inbuilt_nn_modules_unsafe |
A common function to skip guards on the inbuilt nn modules like torch.nn.Linear. |
skip_guard_on_all_nn_modules_unsafe |
A common function to skip guards on all nn modules, both user defined as well inbuilt nn modules (like torch.nn.Linear). |
keep_tensor_guards_unsafe |
A common function to keep tensor guards on all tensors. |
skip_guard_on_globals_unsafe |
A common function to skip guards on all globals. |
skip_all_guards_unsafe |
A function for skipping all guards on a compiled function. |
nested_compile_region |
Tells ``torch.compile`` that the marked set of operations forms a nested compile region (which is often repeated in the full model) whose code can be compiled once and safely reused. |
load_cache_artifacts |
Hot loads cache artifacts that were previously serialized via save_cache_artifacts |
load_compiled_function |
Load an aot-compiled function from a file. |
save_cache_artifacts |
Serializes all the cache artifacts that were created during the compilation |
wrap_numpy |
Decorator that turns a function from |
torch.compiler.precompile#
Warning
torch.compiler.precompile and everything reached through it is a prototype API.
Signatures, error types and the artifact format may change between releases without a
deprecation cycle.
torch.compiler.precompile captures a whole computation – fn(model, x), with the
model(s) passed as arguments – ahead of time from the caller’s own calls, and lowers it to
a self-contained Python source artifact plus an acceleration cache that a fresh process
reloads. No weights are baked in, so the model is passed again at runtime:
# step is a module-level function: def step(model, x): return model(x)
with torch.compiler.precompile.capture(
step, artifact_path="m.py", cache_path="m.cache"
) as cap:
y1 = cap(model, x1)
y2 = cap(model, x2) # a recompile or graph break becomes another variant
f = torch.compiler.precompile.load("m.py", "m.cache") # in a fresh process
y = f(model, x1)
The default DynamoTracer records every frame Dynamo compiles while your calls run and
the artifact dispatches among them by their guards; MakeFxTracer is a single non-strict
trace under the contract of Note [precompile programming model] in torch/_precompile.py.
torch.compiler.precompile is distinct from torch._dynamo.config.caching_precompile
(a torch.compile caching mode).
- torch.compiler.precompile.capture(fn, /, *, artifact_path, cache_path, tracer=DynamoTracer(guard_filter_fn=None, recompile_limit=256, dynamic=None, require_complete=True, require_no_risky_drops=True), backend='inductor')[source]#
Capture
fnacross the calls YOUR loop makes, writing the artifact on exit.Warning
This is a prototype API. Its signature, error types and artifact format may change between releases without a deprecation cycle.
Capture is caller-driven: this returns a capture object rather than running anything. Enter it as a context manager, call it exactly as you would
fninside the block (aMakeFxTracercapture takes exactly one call) – each call runs for real, folds what it exercised into the capture, and returns that run’s result – and the(python_code, cache)artifact is written toartifact_path/cache_pathwhen the block exits:with torch.compiler.precompile.capture( fn, artifact_path="m.py", cache_path="m.cache" ) as cap: y = cap(model, x) f = torch.compiler.precompile.load("m.py", "m.cache")
Because the caller makes the calls, inputs flow through naturally and return values stay available, so the capture drops into an ordinary pipeline loop. To write the artifact before the block ends, call
cap.save()inside it. A block that raises writes nothing it has not already saved, and a block that made no call raisesPrecompileErroron exit. A capture is single-use: to capture again, callcapture()again. ADynamoTracercapture records the kernel-cache artifacts of everything compiled inside the block, so compile nothing else there, and do not overlap two such captures. Only what runs inside the block is carried: run every kernel the serving process needs there, since one compiled or launched only before the block is not in the cache. Each write also freezes the compiled kernels the serving process needs, and raisesPrecompileErrorfor one it cannot freeze. That includes kernels launched directly through@triton.jitand@triton.autotuneinside the block: Triton compiles into a fresh cache directory there, with its autotuning cache on, so aTRITON_CACHE_DIRyou set is not used inside the block, and a JIT kernel or autotuner already used before the block compiles and tunes again on its first launch inside it. That retune benchmarks on the block’s real inputs, and the config it picks, which is what ships and what the process keeps using afterwards, may differ from the one picked before the block. Compiled JIT kernel specializations and autotuning decisions the block does not produce again are kept afterwards. Triton does not cache the decision of an autotuner withpre_hookconfigs, so one that does not prune its configs keeps its earlier decision in the block and is benchmarked again on first use in the serving process. No other thread should launch Triton kernels while the block opens or closes: the in-memory caches are dropped and restored then without synchronizing with launches, so a concurrent autotuner launch can fail. Triton kernels another thread compiles or tunes while the block is open go into the block’s cache directory and ship with it.tracerpicks the capture front-end and carries its tracer-specific configuration.DynamoTracer(the default) is an execution-driven multi-graph capture: it analyzes the Python rather than tracing one path, records every graph-break continuation and guarded recompilation the calls exercise, takes as many calls as you make (keyword arguments included), and the artifact dispatches among the captured variants by their guards – a call no variant covers RAISES rather than silently serving, since there is no compiler behind a source artifact.MakeFxTraceris one non-strict ATen trace: the capture takes exactly ONE positional call, refuses a second, and specializes control flow and shapes to that call, with the contract of Note [precompile programming model] intorch/_precompile.py.fnis the whole computation, e.g. a module-leveldef step(model, x): return model(x)(only aMakeFxTracercapture also takes a lambda): thenn.Modulearguments have their params/buffers lifted to graph inputs (no weights are baked in) and the rest are the runtime inputs; the reloaded callable is invoked with the same argument structure, and the runtime model must match the captured model’s parameter/buffer structure.A Dynamo artifact is STANDALONE: it rebuilds the entry from its code object and installs nothing, so
fnmust be a module-level function of an importable module (not a closure, not defined in__main__). The exception is a capture that compiled a frame the entry cannot reach through a graph-break continuation – a graph break inside a child module’s forward: its artifact hasSERVING_MODE = "installed"and serves by installing the captured entries onto the live code objects when loaded. It is locked to the producing Python version and torch build. The guards that could not be serialized are reported in the capture’ssummary()rather than checked, and theDynamoTracerrequire_*gates refuse the risky ones by default.backendselects how the captured graph is realized:"inductor"(default) lowers through AOTAutograd + Inductor into one self-contained module, and the cache holds the bundle that primes the inductor kernel caches on load;"eager"keeps the captured ATen graph and runs it as-is (no kernels, so the cache carries no artifact). A make_fxfnthat runs a backward captures it: the trace runs with grad enabled, the resulting parameter gradients are scattered onto the runtime model exactly like eager.backward(), and the artifact returnsfn’s own result. A Dynamo capture runs every call in the caller’s own grad mode and lowers a backward whenever grad is enabled (a.backward()infngraph-breaks and re-runs at serve time through the live autograd engine, accumulating.gradlike eager); serve the artifact under the grad mode it was captured in.Note
torch.compiler.precompileis NOTtorch._dynamo.config.caching_precompile(atorch.compileguard-serialization caching mode); it capturesfnahead of time and lowers it to a self-contained Python source artifact.- Return type:
Capture[~_P, _R]
- torch.compiler.precompile.load(artifact_path, cache_path, *, allow_serve_time_compiles=False)[source]#
Reconstruct a runnable from the two files a precompile capture wrote.
Warning
This is a prototype API. Its signature, error types and artifact format may change between releases without a deprecation cycle.
Name the two files
capture()wrote – thepython_codeartifact and itscache. A readable, current-format cache loads only against thepython_codeit was emitted with (it carries a sha256 of exactly those bytes); an unreadable or other-format cache is ignored with a warning.The driver runs from
python_code– the single source of truth for the whole calling convention.loadreads the source’sBACKEND, checks the cache’sbackendtag against it, primes the inductor kernel caches when the cache carries a bundle so a warm reload loads precompiled kernels instead of JIT-compiling, and then exec’spython_code. With no usable cache aMakeFxTracerartifact degrades to JIT’ing frompython_code; aDynamoTracerartifact carries its compiled subgraphs insidepython_code, with their kernels under inductor’s default bundling, so it serves without JIT either way. Both files are trusted, EXECUTABLE input: load only artifacts you produced or otherwise trust.Call the result with the SAME argument structure
fntook – the model(s) in their original positions plus the runtime inputs (keyword arguments too, for aDynamoTracerartifact). The runtime model must match the captured model’s parameter/buffer structure. The result is atorch.compiler.precompile.PrecompiledRunnable; a Dynamo artifact is standalone, so entering and unloading it are no-ops, and it re-seeds the names Dynamo minted into the captured module. The exception is a capture that compiled a frame the entry reaches only by an ordinary call (a graph break inside a child module’s forward): its artifact hasSERVING_MODE = "installed"and serves by installing the captured entries onto the live code objects; its calls refuse to compile, as under thefail_on_recompilestance, without setting that process-wide stance, and keep refusing under every process-wide stance that would compile (force_backend,"eager_then_compile", …). Under"force_eager"every call runs eagerly, bypassing the installed entries; under"eager_on_recompile"the captured variants are served and any other call runs eagerly. An installed artifact refuses to load withtorch._dynamo.config.compiled_autogradenabled, which would compile backward graphs outside it, and with Dynamo disabled (TORCHDYNAMO_DISABLE=1or theenable_dynamokillswitch), which it serves through. A Dynamo artifact whose capture graph-broke cannot load beside the live compile that captured it (the continuation names collide), and an installed artifact is refused wherever any frame it installs onto already has live Dynamo cache entries: load it in a fresh process. That check runs only at load: compiling those frames after load adds live entries that serve the calls the installed ones miss.Frozen C++ kernels are keyed by their full build command, which includes the producer’s absolute PyTorch include and library paths, so they serve only a host whose PyTorch install and toolchain paths match the producer’s. Any other host rebuilds them, which needs a C++ compiler there:
no_compilation()does not gate C++ builds.allow_serve_time_compiles=Trueopts an installed artifact out of the refusal: a call no captured variant covers compiles with the artifact’s backend, astorch.compilewould, under the process-wide stance like any other compile. The captured variants are still served first and do not count towardtorch._dynamo.config.recompile_limit, so each frame gets that many serve-time compiles on top of them; a missed call past the limit runs eagerly instead of compiling. Serve-time compiles are recorded nowhere, but they are built under the process’s Dynamo config: withtorch._dynamo.config.caching_precompileon they drop identity guards (ID_MATCH,CLOSURE_MATCH, …) exactly as any other compile in that process does. The flag does not lift thecompiled_autogradrefusal above. A standalone artifact has no compiler behind it, and an installed artifact captured before the flag existed cannot honor it, so passing the flag for either raisesPrecompileError.Raises
PrecompileErrorif either file cannot be read, ifpython_codeis not atorch.compiler.precompileartifact, or if the cache’sbackend,tracerorcode_hashdoes not matchpython_code– the pair came from different captures – or if an installed artifact cannot install onto the serving process (for example, a captured source changed since capture). A cache whoseformat/versiondoes not match (a foreign or different-build envelope) is NOT fatal: the cache is acceleration only, soloaddegrades to JIT’ing frompython_coderather than crashing.- Return type:
- torch.compiler.precompile.no_compilation()[source]#
Forbid graph/kernel compilation and autotuning on every thread of this process.
Use it around a serving worker’s lifetime to prove that a loaded artifact and its kernel/autotune cache cover every execution: anything that would trace a graph, compile a kernel, benchmark or autotune raises
PrecompileErrorinstead of silently compiling:runnable = torch.compiler.precompile.load(artifact_path, cache_path) with torch.compiler.precompile.no_compilation(): serve(runnable) # raises rather than compiling on a cache miss
Only kernels already in the in-process kernel cache may run.
Unlike
precompile.serving(), which is thread-local, the policy is process-wide. Nested and overlapping uses are depth-counted, so it stays active until the last owner exits; callers must drain work they dispatched (e.g. to compile workers) before that exit. While active,TORCH_PRECOMPILE_NO_COMPILATION=1is exported so child processes inherit it, and setting exactly"1"before startup enables the policy for the whole process.- Return type:
AbstractContextManager[None]
- exception torch.compiler.PrecompileError#
The error type raised by
torch.compiler.precompileand its artifacts.Raised when capture, lowering,
load, or a runtime call violates the precompile contract – e.g. a tensor baked as a constant (invariant 1), an unsupported / effectful op, a nested example input, which capture does not support on either path (invariant 3), an UNBACKED capture attempted inside another trace (invariant 3), a non-tensor output the inductor backend cannot lower, or a runtime input whose shape or memory format differs from the example (invariants 3 and 6). See Note [precompile programming model] in this module for the full contract.
- class torch.compiler.precompile.DynamoTracer(guard_filter_fn=None, recompile_limit=256, dynamic=None, require_complete=True, require_no_risky_drops=True)#
The
dynamocapture front-end (the default), passed astracer=totorch.compiler.precompile.capture().An execution-driven multi-graph capture that analyzes the Python (bytecode) rather than tracing one path: it records graph-break continuations and every guarded recompilation the calls exercise, so a capture with this tracer takes as many calls as you make, keyword arguments included. Part of the prototype
torch.compiler.precompileAPI, so it may change without a deprecation cycle.guard_filter_fntakes theGuardFilterEntryrecords (guard_type,name, …) and returns one keep flag per entry. It filters the runtime guards during capture as well as the serialized ones (the default drops only what cannot be serialized), so a dropped guard never triggers a recompile during capture;recompile_limitcaps recompilations per frame, and a call past it runs eager and is absent from the artifact without any gate refusing it;dynamicforces dynamic shapes astorch.compile(dynamic=)does. Therequire_*gates refuse, at write time, an artifact with a coverage gap (require_complete: a bypassed or uncovered frame, a call that raised) or one whose dropped guards told captured variants apart or hang off a configuration-chosen slot (require_no_risky_drops). Other dropped guards, such as the identity guards every model drops because they cannot be serialized, are listed in the artifact rather than refused.
- class torch.compiler.precompile.MakeFxTracer(decompositions=None)#
The
make_fxcapture front-end, passed astracer=to a precompile capture.A NON-STRICT single make_fx trace: it records the ATen ops of ONE execution of
fn, so acapturewith this tracer takes exactly one call and refuses a second, and control flow and shapes are specialized to that call (the source of the programming-model contract). Part of the prototypetorch.compiler.precompileAPI, so it may change without a deprecation cycle.The contract in brief (Note [precompile programming model] in
torch/_precompile.pyhas the full list): every tensorfnreads is an argument or a registered parameter/buffer of annn.Moduleargument, and shapes are static unless a dim is marked withmark_unbacked(torch._dynamo.decorators, inductor backend only) before the call: a marked dim is captured as an unbacked symint, so one artifact serves any runtime size of it, and a graph that needs to guard on it fails at capture. Dims that must be equal at runtime must share ashape_id: marked independently they bake a silent equal-size assumption, and a mismatch at runtime is not caught. Each input’s dtype and device are specialized too (a runtime mismatch is rejected), the inductor backend additionally specializes on memory format, and a nested-tensor example input is refused.decompositionsis an optional decomposition table (a dict mapping eachOpOverloadto a decomposition function) forwarded tomake_fxas itsdecomposition_table; it is specific to this tracer (Dynamo lowers through the backend instead).
- class torch.compiler.precompile.Capture#
The caller-driven capture
torch.compiler.precompile.capturereturns.Part of the prototype
torch.compiler.precompileAPI, so it may change without a deprecation cycle. Enter it as a context manager to arm the capture, call it exactly as you wouldfninside the block – each call runs for real, is folded into the capture, and returns that run’s result – and the artifact is written to theartifact_path/cache_pathfiles when the block exits. How many calls a capture takes is the tracer’s:MakeFxTracertakes exactly one. Callsave()inside the block to write what has been captured so far to those same files without ending the capture. A block that raises writes nothing it has not already saved, and a block that made no call raisesPrecompileErroron exit rather than writing an empty artifact. A capture is single-use: once its block exits it cannot be entered again, so callcapture()again to retry. That includes a failed write at exit: the spent capture does not keep its pair, so fix the path and capture again.- save()[source]#
Write everything captured so far to the artifact files without ending the capture.
Each call re-renders and rewrites both files, so a job that dies between saves leaves the last checkpoint loadable. A refusal (such as a
DynamoTracerrequire_*gate) or a failed write raises but writes nothing partial, and the capture stays open. RaisesPrecompileErroroutside the capture’swithblock.
- class torch.compiler.precompile.PrecompiledRunnable#
What
torch.compiler.precompile.loadreturns.A callable with the captured
fn’s calling convention that can also be entered as a context manager and unloaded. A standalone artifact installs nothing, so for it__enter__/__exit__/unload()are no-ops. Removing an installed artifact’s entries is not implemented yet either, so they stay installed until the process exits: serve an installed artifact from a process you can throw away. Part of the prototypetorch.compiler.precompileAPI, so it may change without a deprecation cycle.- Variables:
installed (bool) – Whether loading this artifact installed onto the captured code objects (
SERVING_MODE = "installed");Falsefor a standalone artifact.
- class torch.compiler.precompile.PrecompileSummary(*, frames, resume_functions, guarded_codes, backend_graphs, bypassed=(), truncated=(), uncovered_frames=(), wont_generalize=(), dropped_guards=(), kept_guards=(), risky_dropped_guards=(), policy_dropped_guards=(), dropped_guard_code=(), capture_errors=())#
Coverage and guard information from an observed precompile capture.
str(summary)renders a one-line digest: the counts, the dropped guards tallied by type, the risky slots and frame lists cut to their first five entries (+N more), and the first non-empty line of the first capture error. Everything here describes the calls that ran, not every possible input or unexecuted branch, and oncetruncatedis non-empty every count and frame list is a lower bound: from a limit hit on, that frame and everything it called ran untraced, so a frame first reached there is in no list here.The guard fields hold
(guard_type, source)slots, the source spelled with the local scope stripped (L['self'].act->self.act;G['CFG'].widthunchanged). Each list holds a slot once, however many frames or variants carried it, sodropped_guard_typescounts distinct slots, not occurrences. The relations between the lists hold within one frame variant, where the producer applies them, and are stated here rather than checked:kept_guardsanddropped_guardsare disjoint: the filter gives a slot one verdict, keep or reject.risky_dropped_guardsis drawn fromdropped_guards.policy_dropped_guardsis disjoint from both: a policy drop is taken out of the serialized copy the filter kept, once the slot held identically across every captured variant, and is not checked either.dropped_guard_codedraws its slots fromdropped_guardsandpolicy_dropped_guards.every
wont_generalizesource is the source half of akept_guardsslot, the value-equality guard that pins it.
The lists aggregate every captured frame and a slot names no frame, so two frames’
self.actare one slot: a slot one frame kept and another dropped is in bothkept_guardsanddropped_guards(the digest’s(N kept)is the kept count beside the drops, not the other half of a total), and a slot one frame’s filter rejected and another frame’s invariance policy dropped is in both drop lists. Nothing is enforced, as for the frame lists below: a report that raised on its own bookkeeping would lose the coverage it exists to describe. The one exception to “every captured frame” is a frame the artifact runs as plain Python (seeframes): its guards are left out, so a slot only such frames kept, dropped or riskily dropped is not in that list.The frame lists differ in what an entry is.
bypassedanduncovered_frameshold one bareco_nameper frame, read off the package’s entries, so a name can repeat (everynn.Modulehas aforward:['forward', 'forward']is two frames, not a repeat) and their lengths count frames.truncatedholdsco_name (filename:firstlineno), recorded once per code object that hit the limit, so its entries do identify a frame. A bare name identifies none, so the two bare lists cannot be checked disjoint.- Variables:
frames (int) – Captured frames: every frame the package holds an entry for, the
bypassed,truncatedanduncovered_framesones included, so the digest’s frame clauses cut into this count rather than add to it. Also included are the frames the artifact deliberately runs as plain Python: a frame other than the entry that compiled no graph or graph-break continuation and either lost a guard to the filter or was bypassed. Running its original bytecode gives up no compiled code, so it is served that way rather than through a variant missing a guard, and it is listed in neitherbypassednoruncovered_frames.resume_functions (int) – Of those, the graph-break continuations.
guarded_codes (int) – Guarded code objects across all frames.
backend_graphs (int) – Compiled backend graphs.
bypassed (tuple[str, ...]) – The
co_nameof each frame the package holds nothing servable for: no compile of the frame recorded a guarded code and one was bypassed (its guards could not be serialized, or its graph held parameters by static address), or a backend artifact was missing when the package was saved. A graphless frame run as plain Python (seeframes) is not listed. Not an eager fallback: the frame ran compiled during capture, but the package kept no variant of it a load can serve, so a call that reaches it raises.truncated (tuple[str, ...]) –
co_name (filename:firstlineno)of each frame that hit the recompile limit. A lower bound, which is why the digest prints it as>=: from a limit hit on, that frame and the frames it calls run without tracing, so a limit hit that would follow it there is never recorded.uncovered_frames (tuple[str, ...]) – The
co_nameof each frame the capture ran that ended with no guarded code and was not bypassed, so the artifact cannot serve it: a thin wrapper whose graphs all landed in an inner frame, a frame Dynamo gave up on, or a frame whose compile raised (its message is incapture_errors, so one failure shows in both digest clauses). A different cause frombypassed, never the same frame; a frame that hit the recompile limit before it recorded a guarded code is intruncatedtoo. Not a remainder: which frames count as a gap is the producer’s decision, and a frame the package holds an entry for but never ran is not one, so this is notframesminusbypassedminus the frames that hold guarded code.wont_generalize (tuple[str, ...]) – Guard sources (not frame names) a kept value-equality guard on a bare argument name pins in some variant (
self.epsis not a bare name) while no other variant of the same frame guards the source without pinning it, so as captured no variant served another value. Observed, not proven: a variant that never guarded the source does not count as serving other values of it.dropped_guards (tuple[tuple[str, str], ...]) – Slots the serialized copy’s guard filter rejected; a variant that dropped a slot does not check it, so a load through that variant cannot notice whatever it checked. The default filter drops a guard when the serializer refuses its type or a type its check derives: the identity guards (
ID_MATCH,FUNCTION_MATCH,NN_MODULEand the like),WEAKREF_ALIVEand mostDICT_VERSIONguards, so a load cannot notice that the objects they checked were rebound, mutated or collected. Passing it does not make a guard serializable; a caller-supplied filter decides its own set. A slot is listed under the guard’s own type whatever the reason for the drop, so aTENSOR_MATCHrejected for what its check derives is a droppedTENSOR_MATCH.kept_guards (tuple[tuple[str, str], ...]) – Slots the serialized copy’s guard filter kept and the invariance policy left in place.
risky_dropped_guards (tuple[tuple[str, str], ...]) – The subset of
dropped_guardsobserved to tell captured variants apart, or flagged by the risky-drop lint as a configuration-chosen binding.policy_dropped_guards (tuple[tuple[str, str], ...]) – Slots the filter kept that the invariance policy then dropped because they held identically across every captured variant (only guard types from a fixed set are eligible). Reported apart from
dropped_guardsbecause the remedy differs, and reported at all because a capture that discards a precondition should not look like one that had none.dropped_guard_code (tuple[tuple[str, str, str], ...]) –
(guard_type, source, rendered_check), one per slot ofdropped_guardsorpolicy_dropped_guardswhose guard rendered a check (how a guard is installed does not predict whether it renders one, and a slot whose guard rendered none has no entry). One rendering however many variants dropped the slot: where the check embeds the guarded value (EQUALS_MATCHrendersL['n'] == 3) it is one variant’s, the producer’s pick rather than a merge, so it tells the form of the check and not the value; that the slot varied at all is whatrisky_dropped_guardsrecords. Carried because a slot alone can be ambiguous: a dropped('HASATTR', "counts['pixel']")is either the benign companion of a keptTENSOR_MATCHon the same source or the only guard on an optional attribute, and only the rendered check tells them apart. Kept beside the slot lists so the slots stay the identity the policy compares on; for programmatic consumers, not the digest.capture_errors (tuple[str, ...]) – One message per distinct exception a capture call raised (repeats of the same type and message collapse), the exception type first (
"RuntimeError: boom"), so the digest’s first line is never empty however the exception was raised.
- property complete: bool#
Whether the capture covers everything it exercised.
Coverage only: False if a frame was
bypassed, hit the recompile limit (truncated) or ended with no guarded code (uncovered_frames), if a capture call raised (capture_errors), or if nothing was compiled. Bothguarded_codesandbackend_graphsmust be non-zero for the last check, because a frame that compiled nothing can still count as one guarded code, soguarded_codesalone cannot tell a real capture from an empty one. The guard fields never enter:risky_dropped_guardsis a lint finding, not a proof, andwont_generalizefollows from any value the capture pinned, so both describe how far a complete capture generalizes and the digest reports them on their own.