Skip to main content

Python API

The tomii Python package builds graphs, compiles plugins, and runs the Tomii binary. This page documents every public name the package exports. For a walkthrough, see your first graph; for graph-construction concepts, see nodes and vars.

import tomii as tm

app = tm.Graph()

buf_size = app.var("buf_size", 100)
num_nodes = app.var("num_nodes", 200)
fft_planner = app.var("fft_planner", func="fft_planner", args=[buf_size])

gen_vec = app.node("gen_vec", func="generate_vector", factor=num_nodes, args=[buf_size])
compute_fft = app.node("compute_fft", func="compute_fft", factor=num_nodes,
args=[fft_planner, gen_vec.out(0)])

app.build(func_path="src/lib.rs", plugin_manifest="Cargo.toml")
app.run(workers=4, slots=2, timing="timing.txt")

The snippet above is the usage example from the package docstring (tomii/__init__.py).

Exported names

NameKindPurpose
GraphclassTop-level graph container
exportdecoratorMark a Python function as a node body
procsdecorator factoryProcess-pool dispatch for pure-Python node bodies
list_knobsfunctionHuman-readable runtime knob list
knob_spacefunctionVersioned tuning search space
knobsmoduleKnob-space generator and domain helpers
NodeOutput, NodeDepclassesDependency handles (returned by node methods)
Loop, Condition, IndexFuncdataclassesNode loop, conditional execution, network index mapping
usizeComplex64, Vec, infer_typetype wrappersExplicitly typed argument values

Graph

Graph holds all variables, nodes, and configuration. Construct it with no arguments: app = tm.Graph().

Graph.var

def var(name, value=None, *, func=None, args=None, factor=None) -> Var

Defines an initialization variable. Exactly one of value or func must be given; passing both or neither raises ValueError.

ParameterTypeDefaultDescription
namestrrequiredUnique name within the graph
valueanyNoneLiteral value (type inferred, see infer_type)
funcstrNonePlugin function that computes the value at init time
argslistNoneArguments passed to func
factorint or VarNoneNumber of instances

The returned Var serializes as a $ref argument when passed to a node.

Graph.node

def node(name, *, func, args=None, factor=None, priority=None,
use_workers=None, group_size=None, loop=None, loop_args=None,
condition=None) -> Node

Defines a computation node.

ParameterTypeDefaultDescription
namestrrequiredUnique name within the graph
funcstrrequiredPlugin function name
argslistNoneNode arguments: Var, NodeOutput, NodeDep, barrier handles, or typed values
factorint or VarNoneNumber of parallel instances
prioritystrNoneScheduling priority: "high", "normal", or "low"
use_workersstrNoneWorker index range, e.g. "0-3" (inclusive)
group_sizeintNoneInstances grouped into one task
loopLoopNoneLoop configuration
loop_argslistNoneArguments for the loop
conditionConditionNoneConditional execution

Graph.post_node

def post_node(name, *, func, args=None, factor=None, priority=None,
use_workers=None, group_size=None, loop=None, loop_args=None,
condition=None) -> Node

Same parameters as node. Defines a post-computation node, serialized into the post_nodes section of the graph JSON.

Graph.py_node

def py_node(name, *, fn, args=None, factor=None, priority=None,
use_workers=None, group_size=None) -> Node

Defines a node whose body is a Python function decorated with @tomii.export. Analogous to node() but wires to the generic Python bridge plugin instead of a Rust/C dylib function. See Python plugins.

ParameterTypeDefaultDescription
fncallable or strrequiredDecorated Python callable, or a string "module.fn_name"
argslistNoneNode arguments (same semantics as node(args=...))

Barrier dependencies (predecessor.wait()) may appear in args; the bridge filters them out before calling the Python function. py_node raises ValueError if fn is not registered via @tomii.export.

Graph.network

def network(**config) -> None

Sets the network receiver configuration. Keys map to the network_config JSON block: socket_type, num_sockets, packet_length, frame_packets, buffer_depth (default 128), address, start_port, extract_packet_func, id_function, and index_function (an IndexFunc or dict; required). Values that are Var objects serialize as name references. See network sources.

Graph.build

def build(*, func_path=None, wrap_path=None, reg_path=None,
plugin_manifest=None, release=True, clean=False, env=None,
python_plugin=False, python_interpreter=None) -> BuildResult

Compiles tomii-core and the plugin library. Returns a BuildResult with the path to the compiled .so.

ParameterTypeDefaultDescription
func_pathstrNoneAnnotated Rust source; wrappers are auto-generated from #[tomii_export]
wrap_pathstrNonePre-written wrapper file (legacy path)
reg_pathstrNonePre-written registry file (legacy path)
plugin_manifeststrNonePlugin Cargo.toml
releaseboolTrueBuild with optimizations
cleanboolFalseClean before building
envdictNoneExtra build environment variables
python_pluginboolFalseCompile the bundled PyO3 bridge plugin instead
python_interpreterstrNoneInterpreter for the bridge, e.g. "python3.13t"; defaults to the current one

Graph.run

def run(*, dylib=None, env=None, **kwargs) -> subprocess.CompletedProcess

Writes the graph JSON to a temporary file and invokes the Tomii binary. If dylib is omitted and build() was called, the built dylib is used; otherwise RuntimeError is raised. **kwargs are runtime knobs (workers=4, slots=2, timing="timing.txt", …) that map one-to-one to binary flags — the full set is in the knob catalog.

For Python-bridge runs, run() also propagates the interpreter environment to the subprocess: it sets TOMII_PARENT_PYTHON, PYTHONPATH, PYTHONHOME, and (on Linux, for binaries built without --features embed-python) LD_PRELOAD for libpython.

Graph.build_and_run

def build_and_run(*, func_path=None, wrap_path=None, reg_path=None,
plugin_manifest=None, release=True, clean=False, env=None,
python_plugin=False, python_interpreter=None,
**run_kwargs) -> subprocess.CompletedProcess

Calls build() then run() in sequence.

Graph.to_json and Graph.save_json

def to_json(indent=4) -> str
def save_json(path) -> None

to_json serializes the graph to a JSON string in the graph format; save_json writes it to a file.

Graph.visualize

def visualize(mode="web", *, editable=False, save_path=None, port=None) -> None

Opens the graph in the browser visualizer (mode="web") or prints terminal box-drawing art (mode="ascii"). With editable=True the browser view can modify the graph; save_path sets where the edited graph is saved. The same functionality is available from the command line via python -m tomii --visualize.

Node handles

Graph.node, Graph.post_node, and Graph.py_node return Node objects. A Node produces dependency handles that you pass as arguments to downstream nodes. All three methods share the same signature:

def out(start=0, end=None, *, group_by=None) -> NodeOutput # $res
def dep(start=0, end=None, *, group_by=None) -> NodeDep # $dep
def wait(start=0, end=None, *, group_by=None) -> NodeBarrier # $barrier
ParameterTypeDescription
startint, str, or list[int]Relative instance offset, list of offsets, or a named reference
endint, str, or VarRange end; combined with start as "start-end"
group_byintGroup this many predecessor completions before firing

out is a data dependency: the successor consumes the predecessor's result. dep is an ordering-only dependency: the edge is tracked for scheduling but the result value is not fetched, and the runtime skips result storage for nodes whose only non-barrier successors are ordering-only deps. wait is a barrier: the successor waits for the selected predecessor instances to complete. See control flow for how these serialize.

NodeOutput and NodeDep are exported so you can type-annotate or construct them directly; NodeBarrier is returned by wait() but is not in the package's public exports.

export

def export(fn=None, *, variadic=False, name=None)

Marks a Python function as a Tomii-callable node body — the Python analogue of Rust's #[tomii_export]. The decorator returns the original function untouched; direct Python calls are unaffected.

ParameterTypeDefaultDescription
variadicboolFalseCollect all trailing result args into a Python list passed as the last positional argument
namestrNoneOverride the registry key; defaults to "{module}.{fn_name}"

Raises TomiiExportError if the function is defined in __main__: the embedded interpreter launched by the Tomii binary cannot import __main__, so the function must live in an importable .py module.

@tomii.export
def generate_vector(n: int) -> np.ndarray:
return np.random.randn(n).astype(np.complex64)

@tomii.export(variadic=True)
def write_to_file(path: str, mats: list) -> None:
np.savez(path, *mats)

procs

def procs(workers=None) -> decorator

Decorator factory that wraps a function with process-pool dispatch. The decorated function submits work to a shared ProcessPoolExecutor and blocks on future.result() with the GIL released, so multiple Tomii workers can dispatch simultaneously on stock CPython. workers sets the pool size and defaults to os.cpu_count(); all @tomii.procs()-wrapped functions share one pool.

Use it for pure-Python loops and custom algorithms without NumPy vectorization (per-call overhead is roughly 50–200 µs, break-even around 500 µs of compute per call). Skip it for NumPy/SciPy-heavy functions — those already release the GIL internally. Arguments cross the process boundary via pickle; for arrays beyond ~50 MB, use multiprocessing.shared_memory inside the function instead.

@tomii.export
@tomii.procs()
def heavy_pure_python(data: list) -> list:
return [x ** 2 for x in data]

Loop, Condition, IndexFunc

@dataclass
class Loop:
name: str
factor: Union[int, Var]

Loop configuration for a node: name is the loop key in JSON, factor the number of iterations.

@dataclass
class Condition:
operation: str # e.g. "Eq", "Neq"
value: Any
value_type: str # explicit Rust type string, e.g. "usize"
func: str # plugin function that returns the condition value
args: List[Any] = []

Node-level conditional execution: the node runs only if func(*args) <operation> value holds. See control flow.

@dataclass
class IndexFunc:
function: str
args: List[Any] = []

Index-mapping function for network nodes; required by Graph.network() as index_function.

Type wrappers

Node and var arguments carry explicit Rust types. Plain Python values are auto-inferred; wrappers give explicit control.

WrapperRust typeCall form
i8, i16, i32, i64, i128signed integerstm.i32(-5)
u8, u16, u32, u64, u128unsigned integerstm.u8(255)
usize, isizepointer-sized integerstm.usize(100)
f32, f64floatstm.f32(1.5)
StringStringtm.String("hello")
bool_booltm.bool_(True)
char_chartm.char_("x") (single character; else ValueError)
Complex32, Complex64complex numberstm.Complex64(3.5, 2.5)
VecVec<T>tm.Vec("usize", [1, 2, 3])

infer_type

def infer_type(value) -> TypedValue

Converts a plain Python value using the auto-inference rules: boolbool, intusize, floatf64. Any other type raises TypeError and requires an explicit wrapper. The full type list on the runtime side is in types.

Agent and tuning helpers

list_knobs

def list_knobs() -> str

Returns a human-readable list of all graph.run() options. The machine-readable form is python -m tomii --list-knobs-json; both are rendered in the knob catalog.

knob_space

def knob_space(graph=None, *, workload=None, include_graph_knobs=True) -> dict

Generates the versioned knob search space for a workload.

ParameterTypeDefaultDescription
graphGraph, dict, or pathNoneGraph to extract per-graph knobs from; omit for runtime knobs only
workloadstrNoneWorkload label recorded in the space
include_graph_knobsboolTrueSet False to restrict to runtime knobs even when a graph is given

Returns a dict with version, workload, knobs (each entry carries a kind of "cli" or "graph", a domain, and provenance fields), and forbidden — the invariants no optimizer may violate. Only knobs with role perf and a defined domain enter the space; receiver_threads is dropped for graphs without a network_config. See agent tuning.

knobs module

tomii.knobs is the module behind knob_space. It also exposes enumerate_domain(domain), which materializes a domain dict into its concrete search points (bool[False, True], choice → its values, int with pow2 scale → powers of two within [min, max]).