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.
- Bump
[project].versioninpackages/sdk-python/pyproject.toml. It is the single version source — the module hard-codes no version. uv build(frompackages/sdk-python) and confirmdist/names the artifactsbraven-<version>.- Tag the commit
sdk-python-v<version>and push the tag. A branch push does not publish; the tag does. - Maintainer setup (once): add a PyPI API token for the
bravenproject as the repository secretPYPI_TOKEN(Settings → Secrets and variables → Actions → New repository secret). The workflow passes it touv publishasUV_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.2
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 |
|---|---|---|---|---|
| braven-0.5.2.tar.gz | 51.3 kB | Without provenance | Details for braven-0.5.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| braven-0.5.2-py3-none-any.whl | Python 3 | none | any | Details for braven-0.5.2-py3-none-any.whl |
Total release size: 87.7 kB
Release files / braven-0.5.2.tar.gz
| Download URL | braven-0.5.2.tar.gz |
|---|---|
| Size | 51.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6764d58dcb4adbfcc9e64b3a4c71654e6aace1299bd06bba73488deaddc0c4e2
|
|
BLAKE2b-256 checksum How to use checksums |
de55faaef84833440b790d1052fb061dcca79d331ee8a860fef96de0eff7930b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","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.2-py3-none-any.whl
| Download URL | braven-0.5.2-py3-none-any.whl |
|---|---|
| Size | 36.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c0b2113d56af79b38083d2f3e6856423fe8f2ad182c627a5c731369a63dd761b
|
|
BLAKE2b-256 checksum How to use checksums |
59fa40edc49ce4a9374806402049fb47219cdfb8e7aa46c7812ed1ffa5eb178d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","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.2
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.