plesty-lib 0.3.5.dev1__tar.gz → 0.3.5.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/CHANGELOG.md +61 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/PKG-INFO +1 -1
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/composite_device.md +51 -1
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/experiment.md +47 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/gl-secret-detection-report.json +5 -5
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/composite_device.py +400 -26
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/experiment/__init__.py +3 -0
- plesty_lib-0.3.5.dev2/plesty/lib/experiment/assets/preflight.yaml +20 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/experiment/base_experiment.py +43 -3
- plesty_lib-0.3.5.dev2/plesty/lib/experiment/preflight.py +168 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/service/tcp_ip_client.py +25 -4
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/logger.py +54 -20
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_composite_config.py +280 -4
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_base.py +4 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_experiment.py +30 -0
- plesty_lib-0.3.5.dev2/tests/test_experiment_preflight.py +114 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_utils.py +36 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/.gitignore +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/.gitlab-ci.yml +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/LICENSE +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/LICENSES/LGPL-3.0-or-later.txt +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/README.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/REUSE.toml +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/analyzer.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/api_reference.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/architecture.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/contributing.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/data_schemas.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/base_device.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/cmd_solver.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/error_handling.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/func_system.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/index.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/logging_system.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/param_system.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/test_helper.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/device/traffic_manager.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/imgs/device_layers.svg +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/imgs/device_standard.svg +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/imgs/plesty_framework.svg +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/index.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/monitor.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/quickstart.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/toc.yaml +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/docs/ui.md +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/analyzer/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/analyzer/base_analyzer.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/array.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/ctype_manager.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/io.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/table.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/types.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/data/units.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/async_wrapper.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/base_apt_device.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/base_device_sync.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/base_tcp_scpi_device.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/base_visa_scpi_device.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/device_utils.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/doc.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/funcs.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/params.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/device/telemetry.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/experiment/journal.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/experiment/runs.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/experiment/schedule.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/monitor/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/monitor/assets/viz.yaml +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/monitor/base_monitor.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/monitor/sources.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/monitor/viz.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/service/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/service/resource_manager.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/service/tcp_ip_server.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/sim/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/sim/apt.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/sim/data_generator.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/sim/demo_device.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/solver/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/solver/iceblock.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/solver/scpi.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/analyzer_pipeline.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/client_field_test.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/device_func_system.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/device_param_system.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/device_pipeline.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/experiment_pipeline.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/field_test.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/field_test_concurrency.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/grouped_param_keys.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/report_artifact.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/resource_allocation.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/schema_params.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/test/schema_refresh.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/apt.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/apt_protocol.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/serial.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/tcp_ip.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/usb_utils.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/utils.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/traffic/visa.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/assets/palette.json +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/assets/shell.qss +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/monitor_panel.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/panel.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/qt/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/qt/app.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/qt/plot.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/qt/recorder.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/qt/shell.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/ui/theme.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/__init__.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/config.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/dll_utils.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/error_utils.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/registry.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/plesty/lib/utils/settings.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/pyproject.toml +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_analyzer.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_analyzer_pipeline.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_async_wrapper_threading.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_client_field_test.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_config.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_data_array.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_data_io_hdf5.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_data_types.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_demo_device.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_apt.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_data_path.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_funcs.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_params.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_pipeline.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_scpi.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_device_telemetry.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_experiment_pipeline.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_experiment_runs.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_field_test.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_misc.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_monitor.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_report_artifact.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_schema_params.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_schema_refresh.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_service_manager.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_settings.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_shipped_imports.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_sim.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_solver.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_tcp_ip_resources.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_traffic_drivers.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_traffic_orphan.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_traffic_utils.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_ui.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_visa_discovery.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/tests/test_viz.py +0 -0
- {plesty_lib-0.3.5.dev1 → plesty_lib-0.3.5.dev2}/uv.lock +0 -0
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.5.dev2 — 2026-08-17
|
|
4
|
+
|
|
5
|
+
Development pre-release for field-testing the rig start-up (#36, #37):
|
|
6
|
+
bounded, visible connects, the preflight, and default logging. Same line as
|
|
7
|
+
0.3.5.dev1 — the final release is 0.4.0.
|
|
8
|
+
|
|
9
|
+
- **A run starts only on a rig that is really there** (pol-pl field
|
|
10
|
+
finding: a sweep went on with the powermeter server absent).
|
|
11
|
+
`CompositeDevice.preflight()` checks that every remote sub-device exposes
|
|
12
|
+
the methods listed under the new `requires` config key and answers
|
|
13
|
+
`identity()`; `Experiment.setup()` runs it and raises `RigNotReadyError`
|
|
14
|
+
on any problem. `plesty.lib.experiment.connect_rig(build, optional=…)`
|
|
15
|
+
is the start-up for every experiment's `__main__`: build, preflight, and
|
|
16
|
+
on a failure print which device, at which address, from which variable,
|
|
17
|
+
then ask `[r]etry / [a]bort / [s]kip` (skip only for optional
|
|
18
|
+
sub-devices, returned as `skipped`); non-interactive processes get the
|
|
19
|
+
diagnosis logged and `RigNotReadyError`. Text in
|
|
20
|
+
`experiment/assets/preflight.yaml`.
|
|
21
|
+
- **A composite that is given up closes its clients.** New
|
|
22
|
+
`CompositeDevice.release()` closes every remote client on its owning
|
|
23
|
+
thread (server-side disconnect with a 1 s window, linger 0) and stops the
|
|
24
|
+
threads; `disconnect_all()` does the same for remote clients, and a first
|
|
25
|
+
connect that fails closes the clients that did connect. A client left to
|
|
26
|
+
the garbage collector blocked the interpreter in its ZMQ context's
|
|
27
|
+
`__del__` — seen mid-run after `connect_rig` rebuilt a rig without the
|
|
28
|
+
powermeter. `connect_rig` releases a rig it gives up.
|
|
29
|
+
- **A first connect to a dead server now returns.** The client's connect
|
|
30
|
+
failure path closed its DEALER socket with the default infinite LINGER,
|
|
31
|
+
so `ctx.term()` blocked forever on the undelivered handshake — a rig built
|
|
32
|
+
against one absent server hung with no output, and no attempt ladder or
|
|
33
|
+
deadline could bound it. `_DeviceTCPIPClient` now drops undelivered
|
|
34
|
+
messages (linger 0) when a connect fails and on `close()`.
|
|
35
|
+
`CompositeDevice` also resolves every address before starting any connect
|
|
36
|
+
(a half-configured `.env` raises `ValueError` without touching a server)
|
|
37
|
+
and stops its worker threads when a first connect fails.
|
|
38
|
+
- **`CompositeDevice` signals sub-device connection state and bounds the first
|
|
39
|
+
connect** (#36). Each sub-device carries a `ConnectionState`
|
|
40
|
+
(`CONNECTING → CONNECTED → DEGRADED → DISCONNECTED`), read with
|
|
41
|
+
`status()` / `status(dev)` and observed with `on_status_change(callback)`;
|
|
42
|
+
every transition is logged (WARNING for `DEGRADED` / `DISCONNECTED`).
|
|
43
|
+
New config key `connect_deadline_s` (default 10 s): a server that does not
|
|
44
|
+
answer within it raises `DeviceUnreachableError(dev, address, elapsed_s)`
|
|
45
|
+
from the constructor instead of running attempts × timeout × backoff
|
|
46
|
+
(~40 s per dead server before). Under thread affinity the first connects
|
|
47
|
+
run in parallel on the sub-devices' own threads. `reconnect()` reuses the
|
|
48
|
+
sub-device's configured `timeout_ms` / `attempts` / `backoff_s` instead of
|
|
49
|
+
the 50 s defaults; a call timeout marks the sub-device `DEGRADED` before
|
|
50
|
+
the rebuild. `_DeviceTCPIPClient.set_default_timeout(ms)` added.
|
|
51
|
+
- **Default logging for experiments and composites** (#37): nothing is
|
|
52
|
+
silent anymore without module code. `Experiment` logs
|
|
53
|
+
`Run <id>: N step(s) (k already completed), run dir …`, `Setup: …`,
|
|
54
|
+
`Step i/N <id> (<op>)` / `Step i/N done in x s`, `Teardown: …`, and
|
|
55
|
+
`Run … completed (N steps) in x s`. `CompositeDevice` logs
|
|
56
|
+
`Connecting <dev> @ <addr>` / `Connected <dev> @ <addr> in x s`, each failed
|
|
57
|
+
attempt with the retry delay, `Reconnecting <dev> @ <addr>`, and the timeout
|
|
58
|
+
a retried call ran under. New `plesty.lib.utils.logger.ensure_logging()`
|
|
59
|
+
(root level + one console sink, idempotent) is called by both constructors;
|
|
60
|
+
`setup_logging(app)` builds on it and adds the per-process log file — the
|
|
61
|
+
first `app` names the file, so a rig built before its experiment no longer
|
|
62
|
+
steals the file name.
|
|
63
|
+
|
|
3
64
|
## 0.3.5.dev1 — 2026-08-17
|
|
4
65
|
|
|
5
66
|
Development pre-release for field-testing the run convention (#34); the
|
|
@@ -60,7 +60,9 @@ composite = CompositeDevice(
|
|
|
60
60
|
|---|---|
|
|
61
61
|
| `address` | Explicit ZMQ address, skipping the environment |
|
|
62
62
|
| `env` | Environment variable to read, overriding the derived name |
|
|
63
|
-
| `timeout_ms`, `attempts`, `backoff_s` | Forwarded to `connect_client` |
|
|
63
|
+
| `timeout_ms`, `attempts`, `backoff_s` | Forwarded to `connect_client` (first connect and every reconnect) |
|
|
64
|
+
| `connect_deadline_s` | Budget for the *first* connect (default 10 s); past it the constructor raises `DeviceUnreachableError` |
|
|
65
|
+
| `requires` | Remote methods the server must expose; checked by `preflight()` (a wrong address connects fine but is not this device) |
|
|
64
66
|
|
|
65
67
|
The address comes from `address` if given, else the environment; an unset
|
|
66
68
|
variable raises a `ValueError` naming the variable to set.
|
|
@@ -106,10 +108,48 @@ explicitly.
|
|
|
106
108
|
`connect_client(address)` is the module-level builder used for the rebuilds:
|
|
107
109
|
`build_client` plus a connection-handshake retry with linear backoff, which
|
|
108
110
|
matters when several clients open back-to-back against the same server.
|
|
111
|
+
`reconnect(dev)` rebuilds with the sub-device's own `timeout_ms` /
|
|
112
|
+
`attempts` / `backoff_s`, not the defaults.
|
|
109
113
|
|
|
110
114
|
Every multi-device composite gets this robustness for free instead of
|
|
111
115
|
re-implementing it per module.
|
|
112
116
|
|
|
117
|
+
## Connection state and a bounded first connect
|
|
118
|
+
|
|
119
|
+
The composite is never silent about its servers. Constructing it logs one
|
|
120
|
+
line per sub-device (`Connecting hwp @ tcp://… (timeout 5000 ms) …`,
|
|
121
|
+
`Connected hwp @ tcp://… in 0.4 s`, or `Connect to tcp://… failed, attempt
|
|
122
|
+
1/4: … ; retrying in 2 s`) and a summary (`PolPlRig ready in 1.2 s:
|
|
123
|
+
hwp=tcp://…, spec=tcp://…`) — the console sink is switched on by the
|
|
124
|
+
composite itself (`ensure_logging()`), so this shows even when the composite
|
|
125
|
+
is built before the experiment that would configure logging.
|
|
126
|
+
|
|
127
|
+
The **first connect is bounded**: each configured sub-device gets
|
|
128
|
+
`connect_deadline_s` (default 10 s); a server that does not answer within it
|
|
129
|
+
raises `DeviceUnreachableError(dev, address, elapsed_s)` from the constructor
|
|
130
|
+
instead of grinding through attempts × timeout × backoff. Under thread
|
|
131
|
+
affinity the first connects run in parallel on the sub-devices' own threads,
|
|
132
|
+
so three dead servers cost one deadline, not three. Reconnects during a run
|
|
133
|
+
keep the attempt ladder — a server busy finishing a long move must be waited
|
|
134
|
+
for, not declared dead.
|
|
135
|
+
|
|
136
|
+
Each sub-device carries a `ConnectionState` — `CONNECTING → CONNECTED →
|
|
137
|
+
DEGRADED` (a call timed out, the client is being rebuilt) `→ DISCONNECTED`
|
|
138
|
+
(connect/reconnect failed, or `disconnect_all()`):
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
composite.status() # {"hwp": ConnectionState.CONNECTED, "spec": ...}
|
|
142
|
+
composite.status("hwp") # ConnectionState.CONNECTED
|
|
143
|
+
|
|
144
|
+
@composite.on_status_change
|
|
145
|
+
def _show(dev, old, new, detail):
|
|
146
|
+
ui.set_led(dev, new) # runs on the thread that changed the state
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Every transition is logged (INFO, or WARNING for `DEGRADED` /
|
|
150
|
+
`DISCONNECTED`) whether or not anyone subscribes; a subscriber that raises
|
|
151
|
+
is logged and ignored — a broken UI hook must not break the rig.
|
|
152
|
+
|
|
113
153
|
## One thread per sub-device
|
|
114
154
|
|
|
115
155
|
ZMQ sockets are not thread-safe, and even migrating one between threads is
|
|
@@ -161,6 +201,16 @@ for a data directory either fails or means nothing:
|
|
|
161
201
|
composite.set_data_path(frames_dir, devices=["spec"])
|
|
162
202
|
```
|
|
163
203
|
|
|
204
|
+
## Preflight
|
|
205
|
+
|
|
206
|
+
`preflight()` proves each sub-device is the device it is supposed to be and
|
|
207
|
+
answers: a remote sub-device must expose every method in its `requires`
|
|
208
|
+
list and its `identity()` must reply; a local one must have the required
|
|
209
|
+
attributes. It returns `{name: problem}` for the failures (empty when the
|
|
210
|
+
rig is ready) and logs one line per sub-device either way. `Experiment`
|
|
211
|
+
runs it in `setup()`; `plesty.lib.experiment.connect_rig` runs it at
|
|
212
|
+
start-up and asks the operator what to do (see the experiment guide).
|
|
213
|
+
|
|
164
214
|
## Interplay with experiments
|
|
165
215
|
|
|
166
216
|
`Experiment` accepts a `CompositeDevice` at construction; its default
|
|
@@ -84,6 +84,53 @@ Step methods may be sync or async; results are awaited automatically. Each
|
|
|
84
84
|
step is retried (`max_retries`, `retry_sleep` constructor arguments) before
|
|
85
85
|
the run aborts.
|
|
86
86
|
|
|
87
|
+
## Starting on a rig that is really there
|
|
88
|
+
|
|
89
|
+
An experiment's `__main__` builds the rig with `connect_rig` — the same
|
|
90
|
+
start for every experiment: connect the servers, run the composite's
|
|
91
|
+
`preflight()` (each sub-device exposes the methods its configuration
|
|
92
|
+
`requires` and answers `identity()`), and if anything is missing, tell the
|
|
93
|
+
operator which device, at which address, from which variable — and ask:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from plesty.lib.experiment import connect_rig
|
|
97
|
+
|
|
98
|
+
rig, skipped = connect_rig(
|
|
99
|
+
lambda skip: PolPlRig(with_powermeter="pm" not in skip),
|
|
100
|
+
optional={"pm"}, # the experiment can run without it
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
The rig is not ready — 1 device(s) failed the preflight:
|
|
106
|
+
- pm: no answer from tcp://127.0.0.1:5557: TimeoutError('Server did not respond in time')
|
|
107
|
+
address tcp://127.0.0.1:5557 (from PM_ADDRESS in .env / the environment)
|
|
108
|
+
Check that the pm server(s) are running and that PM_ADDRESS point at them
|
|
109
|
+
(a wrong port connects fine but is not the expected device).
|
|
110
|
+
[r] retry (after fixing .env or starting the server) [a] abort [s] continue without pm
|
|
111
|
+
>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`r` rebuilds the rig (an edited `.env` or a freshly started server is picked
|
|
115
|
+
up), `a` raises `RigNotReadyError`, `s` — offered only when every failing
|
|
116
|
+
sub-device is in `optional` — returns the rig without them and names them in
|
|
117
|
+
`skipped`, so the experiment can drop the matching part of its plan. Without
|
|
118
|
+
a terminal on stdin nothing waits: the diagnosis is logged and
|
|
119
|
+
`RigNotReadyError` raised.
|
|
120
|
+
|
|
121
|
+
The check also runs inside `Experiment.setup()`: a run never starts on a
|
|
122
|
+
composite whose `preflight()` reports a problem, whether or not `connect_rig`
|
|
123
|
+
was used. Declare what each sub-device must be able to do in its
|
|
124
|
+
configuration — that is what turns "the port answers" into "it is the
|
|
125
|
+
stage":
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
devices:
|
|
129
|
+
hwp: {timeout_ms: 5000, requires: [home_stage, move_absolute, get_position]}
|
|
130
|
+
spec: {timeout_ms: 5000, requires: [acquire, get_recent_file, write, query]}
|
|
131
|
+
pm: {timeout_ms: 5000, requires: [measure_power, write]}
|
|
132
|
+
```
|
|
133
|
+
|
|
87
134
|
## Data on a shared disk
|
|
88
135
|
|
|
89
136
|
Blobs a device writes itself (spectrometer frames, camera images) never
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
"version": "8.30.1"
|
|
20
20
|
},
|
|
21
21
|
"type": "secret_detection",
|
|
22
|
-
"start_time": "2026-08-
|
|
23
|
-
"end_time": "2026-08-
|
|
22
|
+
"start_time": "2026-08-17T15:29:32",
|
|
23
|
+
"end_time": "2026-08-17T15:29:32",
|
|
24
24
|
"status": "success",
|
|
25
25
|
"observability": {
|
|
26
26
|
"events": [
|
|
27
27
|
{
|
|
28
28
|
"event": "collect_secrets_analyzer_scan_metrics_from_pipeline",
|
|
29
|
-
"time_s": 0.
|
|
29
|
+
"time_s": 0.45769703,
|
|
30
30
|
"exit_code": 0,
|
|
31
31
|
"git_strategy": "FetchShallow",
|
|
32
|
-
"repo_size_kb":
|
|
32
|
+
"repo_size_kb": 708,
|
|
33
33
|
"commit_count": 1,
|
|
34
|
-
"bytes_scanned":
|
|
34
|
+
"bytes_scanned": 220,
|
|
35
35
|
"pipeline_type": "Tag"
|
|
36
36
|
},
|
|
37
37
|
{
|