Skip to content

optype.infer

Experimental

The optype.infer module is experimental and its API may change without notice.

The optype.infer module works out which optype protocols a function requires of its parameters. It runs the function against recording proxies that trace every operation, then renders the result as a PEP 695 signature.

This page documents the Python API. The same inference is available from the command line as optype infer; see Type Inference for a full tour of the behavior, with worked examples of overloads, intersections, branches, variadics, and more.

infer

def infer(
    func,
    /,
    *params: str | int,
    strict: bool = False,
    backend: Literal["terse", "compat"] = "terse",
) -> str: ...

Infer the optype protocol(s) required of func's parameters, returned as the inferred PEP 695 signature string:

>>> from optype.infer import infer
>>> infer(lambda x: x + 1)
'[R](x: CanAdd[Literal[1], R]) -> R'

Pass parameter names or positions to report only those parameters:

>>> infer(lambda x, y: x[y], "x")
'[T, R](x: CanGetitem[T, R]) -> R'

Raises InferError when func is not supported. When exploration is incomplete it emits an InferWarning and still returns a provisional signature; pass strict=True to raise an InferError instead.

Set backend to control how the signature is rendered: the default "terse" emits the compact form shown above, or "compat" for valid, type-checkable Python.

"compat"

backend="compat" (or --format compat on the command line) renders the result as a .pyi-style stub for the supported subset: imports, any synthesized helper Protocols, and @overload-decorated defs. This experimental exporter prioritizes contract preservation over additional Python coverage.

$ optype infer --format compat "lambda x: x + 1"
from typing import Literal
from optype import CanAdd

def f[R](x: CanAdd[Literal[1], R]) -> R: ...

Intersections and Has[...] become helper protocols. Parameter kinds are preserved.

Typevar-referencing bounds, intersections with type variables, complements, generic or callable class attributes, and reordered parameter kinds raise InferError; use backend="terse" instead. Some types remain inexpressible, and the exploration limitations still apply.

InferError

A subclass of NotImplementedError, raised when infer does not support the given function, such as a non-callable, an operation without a matching protocol, or a parameter that requires a value no placeholder can provide. It also reports a function that crashes the interpreter or blocks for longer than one minute.

InferWarning

A subclass of RuntimeWarning, emitted when infer could not explore the function exhaustively, such as when the branch or run budget runs out. The message categorizes each coverage gap and names the affected call form, and the returned signature then only covers the explored paths. The optype infer command prints the warning to standard error, leaving the signature alone on standard output. Pass strict=True to infer to raise an InferError instead.