leds
An event viewer for the LEGEND experiment: a Panel dashboard with event display, waveforms, spectra, dataset-metadata and validation views over a legend-dataflow production cycle.
Running
pip install legend-leds # or: uv pip install .
leds app /path/to/production_cycle # local single-user browser tab
leds app --desktop /path/to/cycle # native window (needs leds[desktop])
leds serve /path/to/cycle --port 5006 # hosted multi-user server
The production-cycle path (a directory containing dataflow-config.yaml, or a
directory of such cycles) can also come from $LEDS_BASE_PATH; several paths
may be listed separated by :.
Deployment (NERSC Spin)
The Dockerfile builds a slim two-stage image by cloning this repository:
docker build -t registry.nersc.gov/<project>/leds:latest \
--build-arg LEDS_REPO=https://github.com/legend-exp/leds.git \
--build-arg LEDS_REF=main .
docker push registry.nersc.gov/<project>/leds:latest
(Point LEDS_REPO at a fork while changes are not upstream yet.) The container
listens on port 5006 and runs under an arbitrary non-root UID, as Spin requires.
Service environment
| Variable | Required | Meaning |
|---|---|---|
LEDS_BASE_PATH |
yes | production cycle(s) on the mounted filesystem (e.g. CFS) |
BOKEH_ALLOW_WS_ORIGIN |
yes | public hostname (host[:port]) allowed to open the websocket, i.e. the Spin ingress name |
NUM_PROCS |
no (default 2) | Panel worker processes; sessions in one process share its caches (and its HDF5 lock, see Threads) |
NUM_THREADS |
no (default 4) | thread pool per worker that callbacks run on, so one session's slow read does not freeze the others; 0 disables it (see Threads) |
LEDS_PREWARM |
no (default on) | scan cycles and build the newest channelmap before forking workers, so the first session of each is warm; delays the listening socket; 0 disables |
LEDS_CACHE_TTL |
no (default 3600) | seconds a metadata-derived entry (channelmaps, statuses, calibration pars) is reused before being re-read |
LEDS_SCAN_TTL |
no (default 300) | seconds a directory scan is reused; bounds how long a newly-written run stays invisible |
LEDS_MAX_CACHED_RUN_SPECTRA |
no (default 4) | whole runs of per-hit energies held per worker; the dominant memory line |
LEDS_MAX_CACHED_CAL_PARS |
no (default 4) | parsed par_hit calibration files held per worker; MB-scale each |
Sessions in one worker share the read-only data they have in common —
channelmaps, detector statuses, directory scans, per-run reductions — so a
second user on the same cycle starts nearly instantly and does not duplicate
that memory. All the bounds above are per worker process, so multiply by
NUM_PROCS when sizing the Spin memory limit.
Because that sharing includes the parsed metadata, an updated metadata checkout
is picked up within LEDS_CACHE_TTL rather than immediately. Lower it if the
deployment updates metadata often; restarting the service always picks it up at
once.
Threads
NUM_THREADS (passed by the image to leds serve --num-threads, like
NUM_PROCS to --num-procs) runs callbacks on a thread pool instead of the
worker's single event loop. Without it, one session's slow operation — a first
visit to the Validation tab, a raw read stalling on CFS — freezes the UI of
every other session in that worker until it finishes. With it those sessions
keep responding, and work that is not HDF5 (parsing a channelmap, evaluating
cuts, building Bokeh models) runs in parallel.
What it does not buy: h5py serialises every HDF5 call behind one process-wide
lock, so two sessions' raw reads still take turns within a worker. NUM_PROCS
is the lever for that; the two combine.
Per-session state — the viewer's caches and open HDF5 handles, the spectrum accumulator, the tab bookkeeping — is guarded by one lock per session, so a session's own callbacks never overlap even though they run on the pool. Open HDF5 handles are per session and never shared across sessions or forked workers. A playback tick that arrives while the previous frame is still rendering is dropped rather than queued.
Login (Spin secrets)
Without any of the variables below the server is open. In all authenticated
setups set a fixed LEDS_COOKIE_SECRET — with an ephemeral one, logins
break on every restart and across the NUM_PROCS workers.
Option A — shared password / user list: set LEDS_BASIC_AUTH to either a
single shared password or a path to a mounted JSON file of
{"username": "password"}.
Option B — LDAP (takes precedence over LEDS_BASIC_AUTH): users sign in
with their directory credentials. Fill the values in from the LEGEND LDAP
administrators:
| Variable | Required | Meaning |
|---|---|---|
LEDS_LDAP_SERVER |
yes (enables LDAP) | e.g. ldaps://ldap.legend.example:636 |
LEDS_LDAP_USER_DN_TEMPLATE |
direct-bind mode | e.g. uid={username},ou=people,dc=legend,dc=example |
LEDS_LDAP_BIND_DN / LEDS_LDAP_BIND_PASSWORD |
search-bind mode | read-only service account (as a Spin secret) |
LEDS_LDAP_SEARCH_BASE |
search-bind mode | subtree searched for the user entry |
LEDS_LDAP_USER_FILTER |
no (default (uid={username})) |
search filter template |
LEDS_LDAP_GROUP_DN |
no | if set, only members (member/uniqueMember/memberUid) of this group may log in |
LEDS_LDAP_STARTTLS |
no | 1 upgrades an ldap:// connection via StartTLS |
LEDS_LDAP_CA_FILE |
no | CA bundle path (mount as a secret); defaults to certifi's bundle |
Configure either LEDS_LDAP_USER_DN_TEMPLATE (direct bind) or the three
search-bind variables; if both are present, direct bind wins. Server
certificates are always verified. Bad credentials, unknown users and non-members
all get the same generic login error; infrastructure failures are reported as
"authentication service unavailable" with details in the container log only.
To try the LDAP flow locally against a throwaway directory:
docker run --rm -d -p 1389:1389 -e LDAP_ADMIN_PASSWORD=adminpw \
-e LDAP_USERS=alice -e LDAP_PASSWORDS=alicepw bitnamilegacy/openldap
LEDS_LDAP_SERVER=ldap://localhost:1389 \
LEDS_LDAP_USER_DN_TEMPLATE="cn={username},ou=users,dc=example,dc=org" \
LEDS_COOKIE_SECRET=devsecret leds serve /path/to/cycle
Metadata
Release files for legend-leds 0.0.3
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 |
|---|---|---|---|---|
| legend_leds-0.0.3.tar.gz | 135.1 kB | With provenance | Details for legend_leds-0.0.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| legend_leds-0.0.3-py3-none-any.whl | Python 3 | none | any | Details for legend_leds-0.0.3-py3-none-any.whl |
Total release size: 259.0 kB
Release files / legend_leds-0.0.3.tar.gz
| Download URL | legend_leds-0.0.3.tar.gz |
|---|---|
| Size | 135.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b657a8178887e5271aca9bc32bd5c79a526e0e4e8cd4dd35e1200079a6083ad4
|
|
BLAKE2b-256 checksum How to use checksums |
cded14d43372b6c630bf53914a4c7502b0073c1cccaa0df271c7a0638dbe6dd3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logRelease files / legend_leds-0.0.3-py3-none-any.whl
| Download URL | legend_leds-0.0.3-py3-none-any.whl |
|---|---|
| Size | 124.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4e0a69e5463eeb7f03fc78d12f1129e3ff77be31dc15eeb3d94f473d666547fa
|
|
BLAKE2b-256 checksum How to use checksums |
f2be0dd86b9b0f7cf7933caca9d899d914329d983f8f9498ba82c786393eb208
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logSecurity for legend-leds 0.0.3
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for legend_leds-0.0.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.
Transparency logA 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.