Skip to content

Inspect source without running it

Use apizr inspect to inspect one Python file or notebook before deciding how to expose its functions. Inspection reads declarations and reports the static evidence for an interface contract. It does not generate an API or run the source.

apizr inspect example.py
apizr inspect examples/pricing.ipynb

The default report shows logical source identity, source and IR digests, each capability's readiness, execution form, input/return limitations, unknown effects, and stable reason codes. Ordinary syntax or file errors appear on stderr.

Watch: Inspect a project and understand readiness · 4:11

Follow doctor, scan and inspect on the Requests project, then understand why a function can be refused.

English · Open on YouTube · Alien6 Studio. Use the written steps for the current release; a recording may show an earlier version.

Read the result

State What it means
ready Enough static contract evidence to describe an ordinary JSON/value interface
conditional Binding, initialization, dependencies or input semantics remain uncertain
unsupported A contract needs an adapter this policy does not define, such as streaming or Callable inputs
ambiguous Static evidence cannot select one coherent callable contract

can_generate_interface is true only for a ready IR capability. It is not permission to execute code. Effects remain unknown, return values are not enforced, and runtime failure remains possible. The REST generator consumes this readiness report. The historical generation workflow remains independent.

For example, an async function with integer inputs can be ready. A decorator or later reassignment makes its binding conditional. A generator needs a streaming adapter and is unsupported. Missing annotations are explicitly unconstrained; arbitrary application classes and forward references remain uncertain.

Structured model inputs with TypedDict

Describe a model payload with an ordinary Python TypedDict. Your prediction or calculation function can stay independent of a web framework:

from typing import TypedDict, Required, NotRequired


class Features(TypedDict):
    age: int
    score: float


class PredictionInput(TypedDict, total=False):
    customer_id: Required[str]
    features: Required[Features]
    note: NotRequired[str]


def predict(payload: PredictionInput) -> float:
    return payload["features"]["age"] * payload["features"]["score"]

Save this as prediction.py. Inspect once and generate either interface:

apizr inspect prediction.py --format json
apizr generate rest prediction.py --output-dir .output/typed-rest
apizr generate mcp prediction.py --output-dir .output/typed-mcp

Both interfaces accept {"payload":{"customer_id":"c","features":{"age":2,"score":3}}} and return 6.0. The function receives plain Python dictionaries. Missing required fields, wrong field types and extra fields are rejected at every object level. REST returns HTTP 422; MCP returns a tool error. Optional fields are omitted rather than filled with defaults. A return annotation describes the result; it does not enforce its runtime type.

Supported declarations are module-level class forms using an earlier, unambiguous from typing import TypedDict or import typing import (including aliases). Fields use the shared JSON type vocabulary and may refer to an earlier supported TypedDict in the same module. total=True is the default; total=False, Required[T] and NotRequired[T] determine field presence. Qualified and aliased stdlib wrappers work too. Explicit Any and bare containers retain their existing unconstrained JSON semantics. Private class field names follow Python's name mangling: __value in Input becomes the JSON key _Input__value; prefer ordinary public field names for API payloads.

The class body may contain a docstring, annotated fields and pass. Inheritance, functional declarations, typing_extensions, quoted or recursive/forward references, generic TypedDicts, annotation calls, field values, methods, decorators, metaclasses and nonliteral total are unsupported. Nesting is bounded to 32 levels and 4096 expanded type nodes. Duplicate fields and rebound or mutated typing names are refused. Ordinary classes, dataclasses, Pydantic models and framework response types do not acquire this exemption. APIZR-READY-019 and readiness.structured_types[].problem explain an unsupported declaration; unsafe class initialization still retains APIZR-READY-004.

The retained readiness.structured_types evidence records the logical name, source span and typed fields, bound to the inspected source digest. It contains shape only, without captured values. Analysis never imports or constructs the declared class.

Machine output and identity

apizr inspect example.py --format json
apizr inspect example.py --ir
apizr inspect examples/pricing.ipynb --module-name project.pricing --format json

JSON mode emits an apizr.inspection/v1 envelope containing capability_ir, ir_digest, readiness and readiness_digest. --ir emits only the canonical Capability IR bytes. These selectors are mutually exclusive; neither writes files unless you redirect stdout.

The logical module defaults to the filename stem. Use --module-name for a stable identity or filenames that are not valid module names. Moving a file while keeping the same bytes and logical identity preserves machine output. Renaming it without an override changes identity. Notebook input is exported statically; magics and shell commands are rejected, and notebook outputs are never executed.

Exit codes are identical for text, JSON and IR output:

  • 0: inspection completed with only ready/conditional assessments (or no capabilities).
  • 1: inspection completed with unsupported/ambiguous assessments or IR errors.
  • 2: operational/input error, including invalid syntax or unsupported file type.

A zero exit code does not mean every capability is eligible or safe to run. Inspection does not import the target, evaluate decorators/defaults/annotations, access the network or launch subprocesses. Starting a generated application does execute its source module and requires trusted input.

See Static readiness v1 for the precise bounded policy, reason codes, typed Python API and digest contracts.