API

This part of the documentation covers all the interfaces of bocpy.

Behaviors

class bocpy.Cown(value)

Lightweight wrapper around the underlying cown capsule.

acquire()

Acquires the cown (required for reading and writing).

property acquired: bool

Whether the cown is currently acquired.

property exception: bool

Whether the held value is the result of an unhandled exception.

release()

Releases the cown.

property value: T

Return the current stored value.

@bocpy.when

Decorator to schedule a function as a behavior using given cowns.

This decorator takes a list of zero or more cown objects, which will be passed in the order in which they were provided to the decorated function. The function itself is extracted and run as a behavior once all the cowns are available (i.e., not acquired by other behaviors). Behaviors are scheduled such that deadlock will not occur.

The function itself will be replaced by a Cown which will hold the result of executing the behavior. This Cown can be used for further coordination.

Note: the transpiler matches @when by literal name. Aliasing the import (from bocpy import when as boc_when) is not supported – the rewrite will not fire and the worker will fail.

bocpy.wait(timeout=None, *, stats=False)

Block until all behaviors complete, with optional timeout.

When stats=True, returns the per-worker _core.scheduler_stats() snapshot captured at shutdown (after all behaviors have run, before the per-worker array is freed). When stats=False (the default), returns None. Returns [] if the runtime was never started or the snapshot could not be captured.

bocpy.start(worker_count=None, module=None)

Start the behavior runtime: worker pool plus noticeboard thread.

The runtime distributes scheduling (2PL link/release) across caller and worker threads; there is no central scheduler thread.

Parameters:
  • worker_count (Optional[int]) – The number of worker interpreters to start. If None, defaults to the number of available cores minus one.

  • module (Optional[tuple[str, str]]) – A tuple of the target module name and file path to export for worker import. If None, the caller’s module will be used.

Cown Groups

In addition to passing individual cowns to @when, you can pass a list of cowns to acquire an entire group atomically. The list is delivered to the behavior parameter as a list[Cown]:

from bocpy import Cown, when, wait

items = [Cown(i) for i in range(5)]

@when(items)
def _(items):
    # `items` is a list[Cown] — all five acquired together
    total = sum(c.value for c in items)
    print("Sum:", total)

wait()

You can mix individual cowns and groups freely:

summary = Cown(0)
items = [Cown(i) for i in range(5)]

@when(summary, items)
def _(summary, items):
    summary.value = sum(c.value for c in items)

Each argument to @when becomes one parameter of the decorated function: a single Cown is passed directly, while a list is delivered as a list[Cown].

Runtime Lifecycle

The bocpy runtime follows a simple lifecycle:

  1. Start — the first @when call (or an explicit start()) spawns the worker sub-interpreters and the noticeboard thread.

  2. Schedule@when / whencall() schedules behaviors against cowns. Scheduling and release run on the caller and worker threads; there is no central scheduler thread.

  3. Waitwait() blocks until all scheduled behaviors complete, then tears down the runtime (joins workers, closes the noticeboard).

  4. Re-start — after wait() returns, the next @when call spins up a fresh runtime. The noticeboard is cleared and worker statistics are reset; existing Cown objects survive and can be scheduled against the new runtime.

bocpy.WORKER_COUNT = 3

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4

Advanced

bocpy.whencall(thunk, args, captures)

Invoke a behavior by name with cown args and captured values.

Return type:

Cown

Noticeboard

See the Noticeboard guide for a conceptual overview, consistency model, and worked examples.

bocpy.notice_write(key, value)

Write a value to the noticeboard.

The write is fire-and-forget: the value is serialized immediately and handed to a dedicated noticeboard thread, which applies it under mutex. notice_write returns as soon as the message is enqueued.

No ordering guarantee. A subsequent behavior — even one that chains directly off the writer through a shared cown — is not guaranteed to observe this write. The noticeboard mutator runs on its own thread and may not have processed the message by the time the next behavior reads. Treat the noticeboard as eventually consistent shared state, never as a synchronization channel between behaviors. Use cowns or send/receive for that.

The noticeboard supports up to 64 distinct keys. Writes beyond the limit are not applied; the noticeboard thread catches the resulting error and logs a warning. No exception propagates to the caller.

Parameters:
  • key (str) – The noticeboard key (max 63 UTF-8 bytes).

  • value (Any) – The value to store.

Return type:

None

bocpy.notice_update(key, fn, default=None)

Atomically update a noticeboard entry.

Reads the current value for key (or default if absent), applies fn to it, and writes the result back. The read-modify-write is atomic because the single-threaded noticeboard mutator performs all three steps without interleaving.

Like notice_write(), the call is fire-and-forget and carries no ordering guarantee with respect to other behaviors. The update is processed on the noticeboard thread; subsequent behaviors may or may not observe the result.

Both fn and default must be picklable — they are serialized and sent to the noticeboard thread via the message queue. Lambdas and closures are not picklable; use functools.partial with a module-level function or an operator function instead:

import operator
from functools import partial
notice_update("total", partial(operator.add, 5), default=0)
notice_update("best", partial(max, 42), default=float("-inf"))

If fn raises, the key retains its previous value and a warning is logged by the noticeboard thread.

Important: fn runs synchronously on the single-threaded noticeboard mutator. It must be fast, pure (no side effects), and must not call any bocpy API (notice_write, send, when, etc.). A blocking or expensive fn will stall every other noticeboard mutation.

If fn returns the REMOVED sentinel, the entry is deleted from the noticeboard instead of being updated.

Warning

fn and default are pickled and sent to the noticeboard thread for execution. Anyone with permission to call this function can therefore cause arbitrary Python code to run on the noticeboard thread, which holds the privileged noticeboard-mutator role. In the current threat model bocpy treats all code running in the runtime (primary and sub-interpreters) as equally trusted, so this is no worse than any other cross-interpreter message. If you need to run untrusted behavior code, restrict what can reach boc_noticeboard and audit callers of notice_update().

Parameters:
  • key (str) – The noticeboard key (max 63 UTF-8 bytes).

  • fn (Callable[[Any], Any]) – A picklable callable taking the current value, returning the new.

  • default (Any) – Value used when key does not yet exist.

Return type:

None

bocpy.notice_delete(key)

Delete a single noticeboard entry.

The deletion is fire-and-forget: the request is sent to the noticeboard thread, which removes the entry under mutex. If the key does not exist, the operation is a no-op. Like notice_write(), this carries no ordering guarantee with respect to other behaviors.

Alternatively, use notice_update with a function that returns REMOVED to conditionally delete an entry based on its current value.

Parameters:

key (str) – The noticeboard key to delete (max 63 UTF-8 bytes).

Return type:

None

bocpy.noticeboard()

Return a cached snapshot of the noticeboard.

Must be called from within a @when behavior. The first call within a behavior captures all entries under mutex and caches the data. Subsequent calls in the same behavior return a view of the same cached data.

The returned mapping is read-only.

Calling from outside a behavior (e.g. the main thread) will return a snapshot that is never refreshed for that thread.

Returns:

A read-only mapping of keys to their stored values.

Return type:

Mapping[str, Any]

bocpy.notice_read(key, default=None)

Read a single key from the noticeboard.

Must be called from within a @when behavior. Convenience wrapper that takes a snapshot and returns one value.

Calling from outside a behavior (e.g. the main thread) will return a snapshot that is never refreshed for that thread.

Parameters:
  • key (str) – The noticeboard key to read.

  • default (Any) – Value returned when key is absent.

Returns:

The stored value, or default if the key does not exist.

Return type:

Any

bocpy.notice_sync(timeout=30.0)

Block until the caller’s prior noticeboard mutations are committed.

Because notice_write(), notice_update(), and notice_delete() are fire-and-forget, a behavior that wants read-your-writes ordering against a subsequent behavior must call notice_sync() after its writes. The call posts a sentinel onto the boc_noticeboard tag (which is FIFO per producer) and blocks until the noticeboard thread has drained that sentinel. By the time this returns, every write/update/delete posted from the calling thread before the sentinel has been applied to the noticeboard.

The barrier carries no ordering guarantee with respect to writes posted from other threads or behaviors interleaved with the caller’s; it only flushes the caller’s own queued mutations.

Parameters:

timeout (Optional[float]) – Maximum seconds to wait. None waits forever. Defaults to 30 seconds.

Raises:
  • TimeoutError – If the noticeboard thread does not drain the caller’s sentinel within timeout seconds.

  • RuntimeError – If the runtime is not started.

Return type:

None

bocpy.REMOVED = REMOVED

Sentinel returned by notice_update fn to delete the entry.

Math

class bocpy.Matrix(rows, columns, values=None)

A dense 2-D matrix of double-precision floats.

T

Return a new matrix that is the transpose of this one.

__init__(*args, **kwargs)

Create a new rows x columns matrix.

Parameters:
  • rows – Number of rows (must be ≥ 1).

  • columns – Number of columns (must be ≥ 1).

  • values – Initial values. May be None (zero-filled), a scalar (broadcast to every element), or a flat sequence of rows x columns numbers in row-major order.

abs()

Element-wise absolute value.

Return type:

Matrix

acquired

Whether the matrix is currently acquired.

classmethod allclose(lhs, rhs, /, rtol=1e-05, atol=1e-08, equal_nan=False)

Check element-wise equality within tolerance.

ceil()

Element-wise ceiling.

Return type:

Matrix

clip(min_or_maxval, /, maxval=None)

Clip elements to a range.

Return type:

Matrix

columns

The number of columns in the matrix.

classmethod concat(values, /, axis=0)

Concatenate matrices along an axis.

Return type:

Matrix

copy()

Return a deep copy.

Return type:

Matrix

floor()

Element-wise floor.

Return type:

Matrix

magnitude(axis=None)

Euclidean magnitude.

Return type:

Union[float, Matrix]

max(axis=None)

Maximum of elements.

Return type:

Union[float, Matrix]

mean(axis=None)

Mean of elements.

Return type:

Union[float, Matrix]

min(axis=None)

Minimum of elements.

Return type:

Union[float, Matrix]

negate()

Element-wise negation.

Return type:

Matrix

classmethod normal(mean=0.0, stddev=1.0, /, size=None)

Sample from a normal distribution.

Return type:

Union[float, Matrix]

classmethod ones(size, /)

Create a matrix of ones.

round()

Element-wise rounding.

Return type:

Matrix

rows

The number of rows in the matrix.

select(indices, /, axis=0)

Select rows or columns by index.

shape

The (rows, columns) shape of the matrix.

sum(axis=None)

Sum of elements.

Return type:

Union[float, Matrix]

transpose()

Return a transposed copy.

Return type:

Matrix

transpose_in_place()

Transpose in place.

classmethod uniform(minval=0.0, maxval=1.0, /, size=None)

Sample from a uniform distribution.

Return type:

Union[float, Matrix]

classmethod vector(values, /, as_column=False)

Create a vector from a sequence.

Return type:

Matrix

w

Set the fourth vector component.

x

Set the first vector component.

y

Set the second vector component.

z

Set the third vector component.

classmethod zeros(size, /)

Create a zero-filled matrix.

Messaging

See the Messaging guide for a conceptual overview, the selective-receive pattern, timeouts, and a worked calculator example.

bocpy.send(tag, contents, /)

Sends a message.

bocpy.receive(tags, /, timeout=-1, after=None)

Receives a message.

bocpy.set_tags(tags, /)

Assigns tags to message queues.

bocpy.drain(tags, /)

Drains all messages for the given tags.

bocpy.TIMEOUT = '__timeout__'

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.

C ABI

See C ABI for the full usage contract for downstream C extensions that want to interoperate with bocpy at the C level.

bocpy.get_include()

Return the absolute path to the bocpy public C header root.

Use the returned path as an additional include_dirs entry on a downstream setuptools.Extension so its translation units can #include <bocpy/bocpy.h>. The directory contains a single bocpy/ subdirectory holding the public ABI surface; bocpy’s private headers are not exposed.

Returns:

Absolute filesystem path to the include root (the parent of the bocpy/ subdirectory containing bocpy.h and xidata.h).

Return type:

str

bocpy.get_sources()

Return platform-specific extra C sources for downstream extensions.

On Windows the returned list contains the absolute path to bocpy_msvc.c, which provides MSVC out-of-line bodies for the atomic ops declared in <bocpy/bocpy.h>. On non-Windows platforms the list is empty (<stdatomic.h> provides everything).

Returns:

A list of absolute paths to add to a downstream setuptools.Extension’s sources= list.

Return type:

list[str]