Qimchi Connect
qimchi-connect publishes real-time xarray.Dataset snapshots to Qimchi without
requiring a specific measurement framework or storage format.
To publish a measurement, provide a callback that returns the current
xarray.Dataset. Built-in providers support QCoDeS, qcutils, and Quantify.
Installation
Install the latest release from PyPI:
pip install qimchi-connect
For a project managed with uv:
uv add qimchi-connect
To install the latest development version from the main branch:
pip install "qimchi-connect @ git+https://gitlab.com/squad-lab/qimchi-connect.git@main"
For a project managed with uv:
uv add "qimchi-connect @ git+https://gitlab.com/squad-lab/qimchi-connect.git@main"
Qimchi Connect requires Python 3.13 or later. Python 3.13 is recommended, and CI also tests Python 3.14.
Optional extras are listed below. For example, install the Quantify extra with
pip install "qimchi-connect[quantify]".
| Extra | Adds | For |
|---|---|---|
examples |
qcodes |
QCoDeSSnapshotProvider and examples/qcodes_measurement.py |
quantify |
quantify-core |
QuantifySnapshotProvider and examples/quantify_measurement.py |
dev |
pre-commit, ruff, pytest | Development |
test |
pytest, pytest-cov | Tests |
Publishing a measurement
The snapshot callback is evaluated when a client requests data. It should return a consistent view of the measurement and use the producer's own lock when the underlying data can change concurrently.
from qimchi_connect import live_measurement
with live_measurement(
measurement_id="experiment-42",
snapshot=lambda: current_dataset.copy(deep=True),
disk_path="data/experiment-42.nc",
):
perform_measurement()
Supported frameworks
Pass a framework provider to live_measurement instead of a callback. A
provider can prepare the first snapshot, set source_package, and derive the
measurement ID and disk path.
The WebSocket server runs on a background thread. A framework handle may not be
safe to read from that thread. For example, QCoDeS uses a thread-bound SQLite
connection and batches writes. Direct calls to
datasaver.dataset.to_xarray_dataset() from the server thread can raise
sqlite3.ProgrammingError, and reads may not include the latest result.
QCoDeSSnapshotProvider manages the cache, locking, write flushing, and refresh
rate:
# QCoDeS
from qimchi_connect import QCoDeSSnapshotProvider, live_measurement
with meas.run() as datasaver:
live = QCoDeSSnapshotProvider(datasaver)
with live_measurement(f"qcodes-{datasaver.dataset.captured_run_id}", live):
for voltage in voltages:
dac.ch1.set(voltage)
live.add_result((dac.ch1, voltage), (dmm.v1, dmm.v1.get()))
The provider prepares a snapshot before registration and sets the run's
source_package. See examples/qcodes_measurement.py for a complete example.
QCUtilsSnapshotProvider reads the in-memory Zarr store used by a qcutils
sweep:
# qcutils
from qimchi_connect import QCUtilsSnapshotProvider, register_live_measurement
register_live_measurement(measurement_id, QCUtilsSnapshotProvider(memory_store))
QuantifySnapshotProvider derives the measurement ID and disk path from a
tuid. It retries when dataset.hdf5 is not yet readable at the start of a run.
Install it with pip install "qimchi-connect[quantify]".
# Quantify
from qimchi_connect import QuantifySnapshotProvider, live_measurement
live = QuantifySnapshotProvider(tuid)
with live_measurement(live.measurement_id, live, disk_path=live.disk_path):
MC.run(experiment_name)
See Adding a framework to support another framework.
Runnable examples
The examples do not require hardware. All three call
qimchi_connect.live_measurement; only the snapshot argument differs.
examples/qcodes_measurement.pyusesQCoDeSSnapshotProviderwith a standard QCoDeSMeasurementanddatasaver. The provider manages the snapshot cache, locking, write flushing, and refresh rate. Install its dependency withpip install qimchi-connect[examples].examples/quantify_measurement.pyusesQuantifySnapshotProviderwith a two-dimensional QuantifyMeasurementControlsweep. A discovery thread publishes the TUID that Quantify creates insiderun(). Install its dependency withpip install "qimchi-connect[quantify]".examples/generic_producer.pyuses an acquisition loop that updates a locked NumPy array and exposes it as anxarray.Dataset. Use this pattern for frameworks without a provider.
tests/test_examples.py runs all three scripts. When adding an example, add a
test for it in that file. test_every_example_is_covered_by_a_test checks this
requirement.
There is no separate qcutils script in this directory because qcutils already
includes higher-level examples based on qcutils.measure.run and Sweep.
Repairing discovery records
Registration checks records marked as live. It marks a record as ended when the endpoint remains unavailable after retries or no longer advertises the recorded dataset. It then deletes ended records older than seven days.
Run the same maintenance manually with:
qimchi-connect cleanup --retention-days 7
The discovery database is stored at ~/.qcutils/live_measurements.db for
compatibility with existing qcutils and Qimchi installations.
Runtime behavior
One server per process. The WebSocket server is process-wide. The first
live_measurement call starts it. Later calls use the same server. The host
and port arguments apply only to the call that starts the server. Each
registration advertises the active server.
Snapshots are read-only. Numeric and boolean variables are transferred as
raw bytes and received as read-only NumPy arrays. Call .copy() before
modifying a variable.
The callback runs on the server thread. It runs when a client requests data.
Use a lock and return a copy instead of a live buffer. See
examples/generic_producer.py. Use QCoDeSSnapshotProvider for QCoDeS.
Development
uv sync --extra dev --extra test --extra examples
uv run pre-commit install # once per clone
uv run pytest
ruff is pinned to the same version in pyproject.toml,
.pre-commit-config.yaml and the CI lint job. Bump all three together.
See CONTRIBUTING.md for branch and release rules and for instructions on adding framework support.
License
AGPL-3.0-or-later. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qimchi_connect-0.1.0.tar.gz.
File metadata
- Download URL: qimchi_connect-0.1.0.tar.gz
- Upload date:
- Size: 236.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6790f45700c7e0a8797c7fdf1fa2ed4472052a710b5241d9042b08ded7fe4fd8
|
|
| MD5 |
a7abb83ec4c50347fb56fc343d069460
|
|
| BLAKE2b-256 |
313b2738e62c81e493e41818580f89d58907f35e14ee9e17f3d0cfc685bc3c5c
|
File details
Details for the file qimchi_connect-0.1.0-py3-none-any.whl.
File metadata
- Download URL: qimchi_connect-0.1.0-py3-none-any.whl
- Upload date:
- Size: 42.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7da2ef2b2e12ce46f7e079ec255f5c6ef6e82d25d4442230900fb6b95065732e
|
|
| MD5 |
b26bb9cba58ef6f74d39f1db703605ca
|
|
| BLAKE2b-256 |
d7aa711ab113a1c23ae37de29046f2d5f46dd8111ee5d408e2f97928aefaf4dc
|