Skip to main content

braven (Python SDK)

The Braven experiment tracker's Python SDK. This package (packages/sdk-python, version 0.4.1) is the single source of truth.

The former external distribution (braven-lab/braven-python) was retired and folded in here: this package now carries the newer 0.4.0 object model (a Run from braven.init(), the removed-ambient __getattr__ guard, image-preview generation) plus this repo's Parquet dual-write path, which the external package never had.

The pipeline worker installs this package from source: apps/worker/Dockerfile builds from the repo root and runs pip install "/opt/sdk-python[parquet]", so the running pipeline tracks packages/sdk-python directly.

Install

pip install "braven"                 # requests only
pip install "braven[dataframe]"      # + pandas, for .as_dataframe() and table()
pip install "braven[plots]"          # + matplotlib/Pillow, for uploading a Figure
pip install "braven[parquet]"        # + pyarrow, for the Parquet dual-write
pip install ./packages/sdk-python    # install this repo's 0.4.1 from source

Releases are cut from this repo and published to PyPI (see Release). Until the first sdk-python-v0.4.1 tag is published, the PyPI braven artifact is still the retired external 0.4.0, so install from the checkout (pip install ./packages/sdk-python, or uv sync for development) to get 0.4.1.

Login

python -m braven login

Prompts for your backend URL and an SDK API key (bvn_api_..., from your Braven account's Settings → API keys) and saves them to ~/.braven/config.json. The key is sent as Authorization: Bearer bvn_api_... and authenticates as its owning user. A fresh, interactive first run of braven.init() with no saved credentials prompts for the key instead of failing (wandb-style).

For CI and test scripts, set BRAVEN_API_KEY in the environment instead (and BRAVEN_API_URL for a non-default backend): it supplies the credential without reading or writing ~/.braven/config.json. With neither an env key nor a saved config, a non-interactive run gets a clear instruction instead.

Object model

Every logging call goes through one Run, returned by braven.init(). The only thing that differs between a script you run yourself and a pipeline script is how the Experiment is identified — every method after that is identical.

import braven

run = braven.init(name="My Experiment", company="My Company", project="My Project")

run.config("radius_um", 55.0)
run.summary("q_factor", 18_400)
run.series("spectrum", [0.1, 0.4, 0.2])          # numeric series (JSON)
run.plot_series("snr_vs_temp", y=snr, x=temps, y_label="SNR")  # interactive plot
run.table("cycling_data", dataframe)             # named, columnar (pandas)
run.upload("spectrum.png")
run.finish()

flush=True (the default) sends each call immediately; pass flush=False to batch into one write at run.flush()/run.finish().

Pipeline scripts (run by the Braven worker) call braven.init() bare and adopt the Experiment the platform already created — no credentials or project. The same script run standalone falls back to local dry mode: every call prints [braven:local] would … instead of raising, and an uploaded Figure is saved under ./braven_local_output/ (ADR-0008).

In a pipeline, the first bare braven.init() returns the pipeline's own Experiment (the parent); every later braven.init() creates a child Experiment under it and returns it as its own Run. Re-running the pipeline replaces the children the previous run created.

Devices are a coordinate, not a suffix (ADR-0013): run.set_device(key) sets the device the experiment that run is on is about (parent or child; the last call wins, and None or a blank key raises ValueError). It creates nothing, so log each device on its own child. A child is one device's measurement (ADR-0022): logging on it before set_device() raises RuntimeError.

run = braven.init()               # the parent
run.set_device("WAFER-7")         # optional: the parent is about this device
for sensor_id, snr in results.items():
    sensor = braven.init()        # a new child Experiment
    sensor.set_device(sensor_id)
    sensor.summary("SNR", snr)

Parquet dual-write

Every data-bearing write — summary(), series(), table(), plot_series() and an uploaded matplotlib Figure — also posts its dataset as Parquet to /datasets, so analytics can query it instead of parsing JSON. Requires braven[parquet]; the JSON log is always written first and a dual-write failure is reported on stderr, never failing the logging call. Each dataset is posted to the Experiment the Run is on, so a child's datasets land on the child.

Notebooks

Write and run marimo notebooks on your own machine. One line keeps their folder synced to your Notebook Repo in a Project, where Braven shows each notebook with its latest outputs and any output can be sent to a Report, pinned to the exact version of the folder that made it:

braven.sync(project="My Project")   # the first time: writes braven.toml here
braven.sync()                       # after that

The folder is the nearest one up holding a braven.toml. Code and small text files sync (.gitignore is respected); large data doesn't, so read data from Braven: braven.experiment_picker() to choose Experiments, braven.collect() to read them. python -m braven sync does the same from a terminal, always on.

Optional dependencies

requests is the only hard dependency (plus tomli on Python 3.10). Everything else is optional and imported lazily:

Feature Install
.as_dataframe() on a downloaded file braven[dataframe]
Uploading a live matplotlib Figure (and its list thumbnail) braven[plots]
Parquet dual-write braven[parquet]
experiment_picker() in a marimo notebook braven[notebook]

Development

This package is managed by uv and type-checked by ty, both from the lock:

uv sync              # environment from uv.lock (incl. the dev group)
uv run pytest        # test suite
uv run ty check      # type check

ty check is wired into the repo gate: packages/sdk-python/package.json defines check-types: uv run ty check, so nub run -r check-types (part of nub run check) checks this package too.

Release

Publishing is owned by this repo; no external repository is involved.

  1. Bump [project].version in packages/sdk-python/pyproject.toml. It is the single version source — the module hard-codes no version.
  2. uv build (from packages/sdk-python) and confirm dist/ names the artifacts braven-<version>.
  3. Tag the commit sdk-python-v<version> and push the tag. A branch push does not publish; the tag does.
  4. Maintainer setup (once): add a PyPI API token for the braven project as the repository secret PYPI_TOKEN (Settings → Secrets and variables → Actions → New repository secret). The workflow passes it to uv publish as UV_PUBLISH_TOKEN.

.github/workflows/release-sdk-python.yml fails before building if the tag and [project].version disagree. PyPI refuses to overwrite an existing version, so bump the version rather than re-tagging.

License

MIT — see LICENSE.

Metadata

Release files for braven 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for braven 0.5.0
File Size Uploaded Provenance Actions
braven-0.5.0.tar.gz 49.8 kB Without provenance Details for braven-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for braven 0.5.0
File Interpreter ABI Platform Actions
braven-0.5.0-py3-none-any.whl Python 3 none any Details for braven-0.5.0-py3-none-any.whl

Total release size: 85.4 kB

Release files / braven-0.5.0.tar.gz

Download URL braven-0.5.0.tar.gz
Size 49.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e0c50eb028f6d949f1f620d4810700b8281647768ae74d8ee55692a90904a309
BLAKE2b-256 checksum
How to use checksums
649b8351d80a01b4091d5e61f8c8d49f0d6cbb3eb5dd1bc5d4e488a74142540f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / braven-0.5.0-py3-none-any.whl

Download URL braven-0.5.0-py3-none-any.whl
Size 35.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bd5ee2fe992f05c5e5d86dda39692734f3cb595311f82f7bd5b7d84bafaf9c2c
BLAKE2b-256 checksum
How to use checksums
3e445a1348f5b1162c759c5f9fc9ca0708d09906d4b439b8b28e82b55ef861ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for braven 0.5.0

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page