Skip to content

API reference

All public entry points live in klorpy (imports: from klorpy import ...).

klorpy.core

Roles and the special operators.

A, B, C              # predefined roles (Role singletons)
Role(name)           # create a new role; auto-registered under `name`
NOOP                 # sentinel result when a role has no value
UNHELD               # placeholder for tuple elements a role does not hold

A(x)                 # role call = lift(x, A)
lift(x, A | {A,B})   # lift an expression to a role / role set
copy(x, src, dst)    # communicate; result at loc(x) ∪ {dst}
narrow(x, roles)     # forget other locations
move(x, src, dst)    # narrow(copy(...), {dst})
pack(a, b, ...)      # build a tuple value
unpack([a, b], t)    # destructure a tuple (statement form)

All special operators are recognized statically; calling one outside a @choreography function raises ProjectionError.

Exceptions: ChoreographicError (base), ProjectionError (a choreography cannot be projected), and in klorpy.check: TypeCheckError (subclass of ProjectionError).

klorpy.projection

choreography(fn)     # decorator: analyze, type-check, project; returns Choreography

Choreography attributes/methods:

Member Meaning
name function name
roles tuple of projected role names
endpoints {role: async endpoint(state, transport)}
params tuple of parameter names
param_locs[param] location (frozenset / tuple) per parameter
retvar, retloc the return variable and its location
bind_param(role, param, value) erasure: map a global value to a role's state value (UNHELD = not bound)
role_holds_param(role, param) whether a role receives a parameter
collect_return(states) assemble the choreography's result

klorpy.check

typecheck(body, param_locs) — the static location type checker: branch-, loop- and return-consistency, run at definition time.

klorpy.runtime

simulate_chor(chor, init=None)   # run all roles in one process; return assembled result
play_role(config, chor, init)    # run one role; config = {role, send, recv, locators}
run_role(chor, role, tr, init)   # async; run one role on an arbitrary Transport

Transport                        # protocol: async send(src, dst, value) / recv(src, dst)
SimTransport(roles)              # in-memory queue transport for the simulator

play_role config keys:

  • role — role name;
  • send/recv — async fns (loc, value) and (loc);
  • locators{role: locator} (whatever your transport needs).

klorpy.sockets

TcpTransport(role, addr, peers)   # async send/recv over TCP (pickle framing)
    .start() / .close()           # also usable as an async context manager
    .port                         # bound port (meaningful after start())
    .peers[role]                  # peer addresses; mutable, wire up after bind

Values are pickle-serialized with a 4-byte length prefix. See Networking (TCP).

Internal pipeline (for contributors)

source
  -> Analyzer      (klorpy.projection: locations per variable)
  -> typecheck     (klorpy.check: branch/loop/return consistency)
  -> Projector     (klorpy.projection: per-role async step lists)
  -> endpoints     (async closures awaiting tr.send/tr.recv)
  -> transports    (SimTransport | TcpTransport | your own Transport)