boti-dask
Dask runtime/session/resilience utilities for the Boti ecosystem.
API sections
- Session:
docs/api/session.md - Resilience:
docs/api/resilience.md - Diagnostics:
docs/api/diagnostics.md
Phase-1 scope
This initial bootstrap provides:
DaskSessionanddask_session(...)helpersDaskSessionSettingsanddask_session_from_env_prefix(...)helpers- shared-session lifecycle support
- recommended Dask config profile helpers
- resilient execution wrappers:
safe_compute,safe_persist,safe_wait,safe_head,safe_gather- async counterparts
- diagnostics helpers:
inspect_graph,describe_frame,diagnostics_logger
- Dask emptiness and unique-value helpers:
dask_is_probably_empty,dask_is_empty,UniqueValuesExtractor
Quick start
from boti_dask import dask_session, inspect_graph, safe_compute
import dask
with dask_session(cluster_kwargs={"n_workers": 1, "threads_per_worker": 1, "processes": False, "dashboard_address": ":0"}) as client:
value = dask.delayed(lambda: 6 * 7)()
print(safe_compute(value, dask_client=client))
print(inspect_graph(value))
If dashboard_address is omitted for local managed sessions, boti-dask defaults it to ":0".
Load session defaults from prefixed environment variables:
from boti_dask import DaskSessionSettings, dask_session_from_env_prefix
settings = DaskSessionSettings.from_env_prefix("BOTI_DASK_", env_file=".env")
session = dask_session_from_env_prefix("BOTI_DASK_", env_file=".env", verify_connectivity=True)
Distributed computing scenarios
Multi-worker cluster with grouped aggregation
Launch a 4-worker cluster, distribute a DataFrame across 8 partitions, and run a grouped sum that executes in parallel across all workers:
from boti_dask import dask_session, describe_client, safe_persist, safe_compute
import dask.dataframe as dd, pandas as pd
with dask_session(
cluster_kwargs={"n_workers": 4, "threads_per_worker": 2, "processes": False, "dashboard_address": ":0"},
) as client:
print(describe_client(client)) # "workers": 4, "threads": 8
ddf = dd.from_pandas(pd.DataFrame({"v": range(10_000), "g": ["X","Y","Z"] * 3334}), npartitions=8)
persisted = safe_persist(ddf, dask_client=client)
grouped = safe_compute(persisted.groupby("g")["v"].sum(), dask_client=client)
print(grouped) # {"X": 16665000, "Y": 16665000, "Z": 16665000}
Shared session with nested contexts
Multiple with blocks share the same Dask client via reference counting.
The client stays alive until the last holder exits:
from boti_dask import dask_session
kwargs = {"n_workers": 2, "threads_per_worker": 1, "processes": False, "dashboard_address": ":0"}
with dask_session(cluster_kwargs=kwargs, shared=True, shared_key="my-cluster") as outer:
with dask_session(shared=True, shared_key="my-cluster") as inner:
print(outer is inner) # True
# outer still alive here
Async distributed pipeline
Persist, wait, head, compute, and gather — all through async-safe wrappers:
import asyncio
from boti_dask import dask_session, async_safe_persist, async_safe_head, async_safe_gather
import dask.dataframe as dd, pandas as pd, dask
async def pipeline():
ddf = dd.from_pandas(pd.DataFrame({"id": range(100)}), npartitions=4)
with dask_session(cluster_kwargs={"n_workers": 2, "processes": False, "dashboard_address": ":0"}) as client:
p = await async_safe_persist(ddf, dask_client=client)
preview = await async_safe_head(p, n=3, dask_client=client)
gathered = await async_safe_gather([dask.delayed(lambda: 42)()], dask_client=client)
return preview["id"].tolist(), gathered
asyncio.run(pipeline())
Orphaned graph detection
When a Dask collection outlives the session that created it, operations fail with a clear error instead of a cryptic Dask traceback:
with dask_session(cluster_kwargs={...}) as client:
persisted = safe_persist(ddf, dask_client=client)
# session closed — persisted is now orphaned
safe_head(persisted) # RuntimeError: orphaned from its original client/worker state
Pass an external Dask Client to keep the client alive across session boundaries:
from dask.distributed import LocalCluster, Client
cluster = LocalCluster(...)
external = Client(cluster)
with dask_session(client=external) as session_client:
result = safe_compute(dask.delayed(lambda: 42)(), dask_client=session_client)
# external.close() # manual lifecycle
Development
uv sync --dev
uv run pytest -q
Examples
uv run python examples/data_facade_dask_resilience.py
uv run python examples/smoke_all_examples.py
See examples/README.md for details.
Metadata
Release files for boti-dask 1.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| boti_dask-1.0.7.tar.gz | 19.1 kB | Without provenance | Details for boti_dask-1.0.7.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| boti_dask-1.0.7-py3-none-any.whl | Python 3 | none | any | Details for boti_dask-1.0.7-py3-none-any.whl |
Total release size: 40.5 kB
Release files / boti_dask-1.0.7.tar.gz
| Download URL | boti_dask-1.0.7.tar.gz |
|---|---|
| Size | 19.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2508276f207c7b6639d9a4dde639779b5d0e7796c3752225fcd7cfc1992a2a10
|
|
BLAKE2b-256 checksum How to use checksums |
de79486b3a257b1431cb81e6b4d7df28fb2b4193bb3b945f4b45bd38fb9ec047
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / boti_dask-1.0.7-py3-none-any.whl
| Download URL | boti_dask-1.0.7-py3-none-any.whl |
|---|---|
| Size | 21.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cb8186d683a191b8ba54cfa6d79291c3d2916136f50a37c13bee28d9a2a107e8
|
|
BLAKE2b-256 checksum How to use checksums |
30fdb1f51fda6c8446f53e709618a40d9c1c9a1b6621b27df1649e384e8cbb91
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for boti-dask 1.0.7
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.