API¶
This part of the documentation covers all the interfaces of bocpy.
- bocpy.__version__ = '0.9.0'¶
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’.
Behaviors¶
- class bocpy.Cown(value)¶
Lightweight wrapper around the underlying cown capsule.
- acquire()¶
Acquires the cown (required for reading and writing).
- 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.
The transpiler recognises module-level aliases for the decorator, so
from bocpy import when as boc_whenand@boc_when(...), as well asimport bocpy [as alias]followed by@bocpy.when(...)/@alias.when(...), are all supported. Aliases declared inside a function body are not tracked.
- bocpy.wait(timeout=None, *, stats=False, noticeboard=False)¶
Block until all behaviors complete, with optional timeout.
When
stats=True, captures the per-worker_core.scheduler_statssnapshot. Whennoticeboard=True, captures the noticeboard contents as a plaindictat the quiescence point (NOT after teardown — the two are equivalent in single-caller programs but the quiescence snapshot is the documented one). See the stub in__init__.pyifor the full contract.Return value:
neither flag:
None.stats=Trueonly:list[dict](or[]).noticeboard=Trueonly:dict[str, Any](or{}).both flags:
WaitResult.
Internally a thin wrapper around
quiesce()+Behaviors.stop; quiescence timeout warns rather than raising.
- class bocpy.WaitResult(stats: list[dict], noticeboard: dict[str, Any])¶
Bundle of optional artifacts returned by
wait().Only produced when both
stats=Trueandnoticeboard=Trueare passed (e.g.wait(stats=True, noticeboard=True)).- Variables:
stats – Per-worker scheduler-stats snapshot.
noticeboard – Final noticeboard contents as a plain
dict.
- bocpy.quiesce(timeout=None, *, stats=False, noticeboard=False)¶
Block until in-flight behaviors complete without tearing down the runtime.
- Parameters:
- Raises:
TimeoutError – If quiescence is not reached within
timeout.RuntimeError – If called from a non-primary interpreter while pinned cowns are live.
- bocpy.start(worker_count=None, module=None)¶
Start the behavior runtime: worker pool plus noticeboard thread.
Idempotent: bare
start()on a running runtime is a silent no-op; mismatchedworker_count/moduleraise.The runtime distributes scheduling (2PL link/release) across caller and worker threads; there is no central scheduler thread.
The runtime distributes scheduling (2PL link/release) across caller and worker threads; there is no central scheduler thread.
- Parameters:
- Raises:
RuntimeError – If called from a non-primary interpreter, or if the runtime is already up under a different
worker_count/modulethan the one supplied.
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:
Start — the first
@whencall (or an explicitstart()) spawns the worker sub-interpreters and the noticeboard thread.Schedule —
@when/whencall()schedules behaviors against cowns. Scheduling and release run on the caller and worker threads; there is no central scheduler thread.Wait —
wait()blocks until all scheduled behaviors complete, then tears down the runtime (joins workers, closes the noticeboard). For a non-tearing-down checkpoint (e.g. parallel-search inspection between rounds), usequiesce()instead — it blocks until the runtime is quiescent, returns optionalstats/noticeboardsnapshots, and leaves workers and the noticeboard thread running so further@whencalls work immediately.Re-start — after
wait()returns, the next@whencall spins up a fresh runtime. The noticeboard is cleared and worker statistics are reset; existingCownobjects 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¶
Pinned Cowns¶
See Pinned Cowns for the conceptual overview, the coarse-grained dispatch pattern, event-loop integration recipes, and the free-threaded support trajectory.
- class bocpy.PinnedCown(value)¶
A cown whose value never leaves the main interpreter.
Behaviors whose request set contains any PinnedCown run on the main interpreter, scheduled onto a pump queue that the runtime drains under
wait()and that hosts may drive explicitly viabocpy.pump().A regular
Cownstores its value as cross-interpreter data: every time a worker acquires the cown the value is unpickled into the worker’s interpreter, mutated, and re-pickled on release. That round-trip is the reason a cown can be acquired by any worker – but it also means the value must be picklable and that the same Python object is never observed twice in a worker.Many useful values cannot survive that round-trip: pyglet shapes, Tk widgets, open file handles, ctypes pointers into a library loaded by
__main__, an asyncio event loop, a GPU context. Their__reduce__either raises or silently reconstructs a broken object on the other side.A
PinnedCownholds its value as a plainPyObjectreference in the main interpreter. The value never goes throughXIData; the same Python object is observed on every acquire. The trade-off: every behavior whose request set contains a pinned cown runs on the main thread, drained bypump()(called from your event loop) or implicitly bywait().- Pattern: coarse-grained pinned dispatch
The pinned arm is single-consumer (the main thread). If you schedule a pinned behavior per item, those behaviors serialise on the main thread and you lose worker parallelism. Schedule pinned behaviors coarsely – one per logical frame or batch, not per item. Do per-item computation on workers against per-item
Cownslices, then dispatch one pinned@whenper frame that captures all of them together with the main-thread canvas / handle and performs the batched write-back.- Thread affinity
Pinned cowns may only be constructed from the main interpreter. Constructing one from a worker raises
RuntimeError; the value would have no home interpreter to live in.pump()likewise requires the main interpreter – any thread within it on classic CPython; on free-threaded builds (Py_GIL_DISABLED) a single thread at a time, enforced by a CAS on pump entry that raisesRuntimeErrorif a second thread tries to pump concurrently. The CAS is cleared on every exit path, includingBaseExceptionpropagation from a pinned body.- Mixed request sets
A behavior may freely combine pinned and unpinned cowns; the 2PL acquisition order is unchanged. As soon as the request set contains any pinned cown, the body runs on the main thread. Unpinned cowns in the set still travel through XIData into the main interpreter for the body’s duration.
- Exception model
Body exceptions follow the same rules as worker behaviors: captured on the result
Cownand surfaced throughcown.exception. The defaultpump()does not re-raise; passraise_on_error=Trueto opt into fail-fast propagation.- Nested pumping
Calling
pump()from inside a pinned-behavior body raisesRuntimeError(v1).- Handle vs. value
A
PinnedCownhandle (the Python wrapper object and its C capsule) is a normal cross-interpreter shareable. It travels via the same XIData mechanism as a regularCownand may be:shipped as a captured variable to a worker behavior,
embedded in any value graph stored in a regular
Cown(Cown(PinnedCown(x))is supported),placed in a noticeboard entry via
notice_write()ornotice_update().
What never crosses interpreter boundaries is the value
x. A worker that ends up holding a pinned-cown handle can do exactly one useful thing with it: schedule pinned behaviors against it (which the runtime auto-routes to the main pump queue). Any attempt to acquire the value from a worker is rejected by the C-level owner CAS – the value’s owner is permanently the main interpreter.- Restrictions
Constructible only on the main interpreter (see Thread affinity above).
The pinning interpreter is the main interpreter, by design. There is one pinned queue per process and one consumer of that queue (the main pumper); pinned cowns do not split across interpreters.
- bocpy.pump(deadline_ms=None, max_behaviors=None, raise_on_error=False)¶
Run pinned behaviors that are ready, then return.
Drains the main-thread queue of behaviors whose request sets contain at least one
PinnedCown. Each behavior runs to completion before the next starts. The pump is non-preemptive:deadline_msgates starting the next behavior, not interrupting one already running.Call
pump()from your event loop’s idle / on-tick hook. Script-mode programs need not call it explicitly –wait()pumps internally when anyPinnedCownexists in the process.- Bounding
deadline_ms: wall-clock budget.Nonedrains to empty; otherwise a positiveint.max_behaviors: hard count.Nonedrains to empty; otherwise a positiveint.
0is rejected for both bounds (useif budget:at the call site instead of relying on the pump to no-op).- Exception model
By default body exceptions land on the result cown; pump continues. With
raise_on_error=True, the first body exception re-raises on the pump thread after the queue finishes draining.BaseException(KeyboardInterrupt,SystemExit,GeneratorExit) propagates immediately after the offending behavior’s per-iteration cleanup completes; any behaviors still queued are left in place for the nextpump()call.- Thread affinity
pump()must run on the main interpreter. Calling from a worker interpreter raisesRuntimeErrorimmediately. On free-threaded builds (Py_GIL_DISABLED) only one thread may pump at a time: a concurrent call from a different thread raisesRuntimeError. Callingpump()when noPinnedCownexists is a no-op returningPumpResult(0, False, 0).- Reentrance
Not reentrant. Calling from inside a pinned-behavior body raises
RuntimeError(v1).
- Parameters:
deadline_ms (
Optional[int]) – Wall-clock budget in milliseconds.Nonefor unbounded; otherwise a positiveint. Must not bebool.max_behaviors (
Optional[int]) – Maximum behaviors to start this call.Nonefor unbounded; otherwise a positiveint. Must not bebool.raise_on_error (
bool) – Re-raise the first body exception after drain.
- Returns:
PumpResult(executed,deadline_reached,raised). OnBaseExceptionpropagation,pump()raises and noPumpResultis returned.- Return type:
- Raises:
TypeError – if
deadline_msormax_behaviorsis notNone, a positiveint, or isbool.RuntimeError – wrong interpreter, concurrent pump on free-threaded, nested pump, no live runtime (
start()has not been called), or watchdog raise threshold tripped.
- class bocpy.PumpResult(executed: int, deadline_reached: bool, raised: int)¶
Result of a
pump()call.- Variables:
executed – Pinned behaviors whose lifecycle ran to completion this call. Counts the iteration even if the body raised or the acquire failed (the MCS chain still drained).
deadline_reached –
Trueiff the loop exited becausedeadline_mstripped before the queue drained and beforemax_behaviorscapped.Falseon drain, onmax_behaviorscap, or whendeadline_msisNone.raised – Pinned behaviors whose body raised an
Exceptioncaptured to the result cown’s.exception. Cleanup-path failures (acquire, release, noticeboard cache-clear) do not count: they are logged viaPyErr_WriteUnraisableand the iteration is still counted inexecuted. OnBaseExceptionpropagation,pump()raises and noPumpResultis returned.
- bocpy.set_pump_watchdog(warn_ms=1000, on_starve=None)¶
Configure the pinned-queue starvation watchdog.
The watchdog is disabled until this function is called. No call means no warnings, regardless of how long the pinned queue has been non-empty.
warn_ms=1000is the kwarg default that applies if and when you opt in, not the runtime default.Warn-side sampling fires from
pump()on entry (sowait()’s auto-pump loop counts). The threshold gates on queue-non-empty time: a program that runs only unpinned work indefinitely never trips it.warn_ms(kwarg default 1000): logs a warning carrying the queue’s non-empty duration (ms) and current depth. PassNoneto disable. Must be a positive int when set.on_starve: optional callable(severity, message)to replace the default logger. Use this to escalate (for exampleon_starve=lambda s, m: pytest.fail(m)in tests, or a counter / alert hook in production).
- Parameters:
- Raises:
TypeError – if
warn_msis notNoneor a positiveint, oron_starveis not callable.OverflowError – if
warn_msexceeds the maximum representable nanosecond value.
- Return type:
- bocpy.set_wait_pump_poll(ms=50)¶
Set the poll cadence for
wait()’s auto-pump loop.Default cadence is 50 ms — the upper bound on how long the auto-pump loop will park between checks when no broadcast wakes it. The setting is process-global and may be changed at any time; the active
wait()loop picks up the new value on its next iteration.
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_writereturns 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/receivefor 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.
Values may embed
Cownreferences; the noticeboard keeps each embedded cown alive for as long as the entry remains in the noticeboard.
- 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.partialwith a module-level function or anoperatorfunction 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
REMOVEDsentinel, the entry is deleted from the noticeboard instead of being updated.The value returned by fn may embed
Cownreferences; the noticeboard retains them until the entry is overwritten or deleted, identical tonotice_write().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_noticeboardand audit callers ofnotice_update().
- 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_updatewith a function that returnsREMOVEDto conditionally delete an entry based on its current value.
- bocpy.noticeboard()¶
Return a cached snapshot of the noticeboard.
The noticeboard is a behavior-scope read surface. The supported use is from inside a
@whenbody: the first call captures all entries under mutex and caches them, and every subsequent call in the same behavior returns the same cached view.The returned mapping is read-only.
The only supported way to read the noticeboard from the main thread is to ask
wait()for it viawait(noticeboard=True)(orwait(stats=True, noticeboard=True)); that snapshot is taken on the main thread between joining the noticeboard mutator thread and clearing the C-side entries.Calling
noticeboard()ornotice_read()from any other main-thread context (outside a behavior, outsidewait(noticeboard=True)) is undefined behavior: the cached proxy is never re-anchored on a behavior boundary, so subsequent calls may observe either a stale snapshot or partially-applied writes.Seeding the noticeboard with
notice_write()from the main thread before scheduling behaviors is fine and is the recommended pattern for installing read-mostly configuration.
- bocpy.notice_read(key, default=None)¶
Read a single key from the noticeboard.
Convenience wrapper over
noticeboard()that takes a snapshot and returns one value. The same supported-usage contract applies: call from inside a@whenbehavior, or read the final state on main viawait(noticeboard=True). Callingnotice_read()from any other main-thread context is undefined behavior.
- bocpy.notice_sync(timeout=30.0)¶
Block until the caller’s prior noticeboard mutations are committed.
Because
notice_write(),notice_update(), andnotice_delete()are fire-and-forget, a behavior that wants read-your-writes ordering against a subsequent behavior must callnotice_sync()after its writes. The call posts a sentinel onto theboc_noticeboardtag (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.Nonewaits 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:
- 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(in_place=False)¶
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.
- angle(axis=None)¶
Polar angle (
atan2(y, x)) of every 2D vector. Returns a float for a single 2D vector, anMx1column matrix for anNx2row batch, or a1xNrow matrix for a2xNcolumn batch. On the ambiguous2x2shape the default is per-row; passaxis=0to force per-column.- Return type:
Union[float, Matrix]
- ceil(in_place=False)¶
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
- cross(other, /, axis=None)¶
2D (scalar z-component) or 3D cross product against another vector or batch. 1x2 / 2x1 inputs return a float; 1x3 / 3x1 return a Matrix preserving self’s orientation. Nx2 / 2xN row/column batches return per-vector scalars (Mx1 / 1xN); Nx3 / 3xN return same-shape batches. Batch operands accept either a same-shape other or a single 2D/3D vector (1xK / Kx1) broadcast against every per-vector slot —
selfmust be the batch (cross is anticommutative).axisdisambiguates the 2x2 / 3x3 squares (default rows,axis=0for columns).- Return type:
Union[float, Matrix]
- floor(in_place=False)¶
Element-wise floor.
- Return type:
Matrix
- length¶
Frobenius (L2) magnitude of the matrix as a read-only property.
Equivalent to
magnitude()called with no axis argument:sqrt(sum(x**2 for x in m))over all elements. Exposed as a@propertyso that vector-like code reads naturally (direction.length,velocity.length) without the extra parentheses of a method call.Note: this is not the element count. For
rows * columnsusesize(orlen(), which returnsrows).
- magnitude_squared(axis=None)¶
Sum of squared elements (Euclidean magnitude without the sqrt).
- Return type:
Union[float, Matrix]
- negate(in_place=False)¶
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]
- normalize(axis=None, in_place=False)¶
Divide elements by their magnitude.
axis=Nonedivides by the matrix’s total magnitude;axis=0divides each column by its own magnitude;axis=1divides each row by its own magnitude. Rows or columns whose magnitude is zero are left as the all-zero vector. Sub-normal magnitudes may overflow during division; threshold with magnitude_squared() if safety matters. Whenin_place=True, mutatesselfand returns it.- Return type:
Matrix
- classmethod ones(size, /)¶
Create a matrix of ones.
- perpendicular(axis=None, in_place=False)¶
Rotate every 2D vector 90 degrees counter-clockwise:
(x, y) -> (-y, x). Accepts a single 2D vector (1x2or2x1), a row batch (Nx2), or a column batch (2xN). On the ambiguous2x2shape the default is per-row; passaxis=0to force per-column. Whenin_place=True, mutatesselfand returns it.- Return type:
Matrix
- round(in_place=False)¶
Element-wise rounding (banker’s; IEEE round-half-to-even).
- 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.
- size¶
The total element count of the matrix (
rows * columns).
- transpose(in_place=False)¶
Return a transposed copy, or transpose
selfin place whenin_place=True(in which caseselfis returned).- Return type:
Matrix
- classmethod uniform(minval=0.0, maxval=1.0, /, size=None)¶
Sample from a uniform distribution.
- Return type:
Union[float, Matrix]
- vecdot(other, /, axis=None)¶
Axis-aware inner product: sum of element-wise products. Equivalent to numpy.linalg.vecdot for 1-D inputs with axis=None; not equivalent to numpy.dot.
- 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_dirsentry on a downstreamsetuptools.Extensionso its translation units can#include <bocpy/bocpy.h>. The directory contains a singlebocpy/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 containingbocpy.handxidata.h).- Return type:
- 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’ssources=list.- Return type: