plesty-sdk 0.3.5.dev1__tar.gz → 0.4.0__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_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/CHANGELOG.md +170 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/PKG-INFO +7 -3
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/README.md +6 -2
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/architecture.md +15 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/commands/check.md +1 -1
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/commands/init.md +32 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/getting-started.md +17 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/gl-secret-detection-report.json +7 -7
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/check/guidance.yaml +3 -1
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/docs-build-gitlab-ci.yml +6 -2
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/hub-theme/plesty-hub.css +2 -0
- plesty_sdk-0.4.0/plesty/sdk/assets/hub-theme/plesty-versions.css +49 -0
- plesty_sdk-0.4.0/plesty/sdk/assets/hub-theme/plesty-versions.js +110 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/init/next-steps.yaml +1 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/extras/device/device.py +6 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/README.md.jinja +12 -1
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/docs/index.md.jinja +16 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/plesty/{{module_name}}/{% if project_type in ['device', 'experiment'] %}__main__.py{% endif %}.jinja +93 -16
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/pyproject.toml.jinja +10 -1
- plesty_sdk-0.4.0/plesty/sdk/commands/docs/deploy.py +288 -0
- plesty_sdk-0.4.0/plesty/sdk/commands/docs/picker.py +141 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/docs/sphinx_builder.py +19 -3
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/field_test.py +5 -1
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/init.py +37 -1
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/pyproject.toml +11 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_docs_deploy.py +135 -32
- plesty_sdk-0.4.0/tests/test_docs_picker.py +148 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_field_test_scaffold.py +87 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_init.py +88 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_sphinx_builder.py +1 -1
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/uv.lock +189 -13
- plesty_sdk-0.3.5.dev1/plesty/sdk/commands/docs/deploy.py +0 -198
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/.coverage +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/.gitignore +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/.gitlab-ci.yml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/.mailmap +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/LICENSE +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/LICENSES/LGPL-3.0-or-later.txt +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/REUSE.toml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/commands/docs.md +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/commands/license.md +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/commands/manual.md +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/commands/update.md +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/index.md +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/docs/toc.yaml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/__init__.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/hub-theme/plesty-logo.svg +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/hub-theme/plesty-mark.svg +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/init/client-field-test.py.template +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/init/field-test-env.example +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/init/field-test-questions.yaml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/init/field-test.py.template +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/init/mock-test.py.template +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/manual/pdf-common.css +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/manual/pdf-page-landscape.css +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/manual/pdf-page-portrait.css +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/ruff.toml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/copier.yml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/extras/analyzer/analyzer.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/extras/device/base_device.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/extras/experiment/experiment.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/.gitignore +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/CHANGELOG.md.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/LICENSE +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/LICENSES/LGPL-3.0-or-later.txt +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/REUSE.toml.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/docs/toc.yaml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/plesty/{{module_name}}/__init__.py.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/plesty/{{module_name}}/config.yaml.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/tests/__init__.py.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/tests/test_{{module_name}}.py.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/{% if project_type == 'experiment' %}config{% endif %}/default.yaml +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/{% if project_type in ['device', 'experiment'] %}.env.example{% endif %}.jinja +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/authorship.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/cache.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/cli.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/__init__.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/check.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/docs/__init__.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/docs/generate.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/docs/serve.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/license.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/manual.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/mock_test.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/commands/update.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/context.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/report.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/semver.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/tui.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/__init__.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_authorship.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_cache.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_check.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_cli.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_context.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_docs_generate.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_docs_serve.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_license.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_manual.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_mock_test_scaffold.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_report.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_semver.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_tui.py +0 -0
- {plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/tests/test_update.py +0 -0
|
@@ -2,6 +2,176 @@
|
|
|
2
2
|
|
|
3
3
|
The format is based on [Keep a Changelog](https://keepachangelog.com).
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.4.0] — 2026-09-07
|
|
8
|
+
|
|
9
|
+
A scaffolded device can now be driven by hand. `plesty init device` generates a
|
|
10
|
+
`--gui` entry point that opens the module's control panel — every control built
|
|
11
|
+
from the device schema, nothing hand-written — as an alternative to serving the
|
|
12
|
+
instrument, so a new module is usable at the bench before anyone writes a client
|
|
13
|
+
for it. Qt rides in a `gui` extra, so a headless bench that only ever serves the
|
|
14
|
+
device pays nothing for the window it never opens. Generated projects pin
|
|
15
|
+
`plesty-lib>=0.4.0`, the release `plesty.lib.ui` begins at.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **A scaffolded device offers its control panel.** `plesty init device` now
|
|
19
|
+
generates `--gui` in the module's `__main__.py`: it opens plesty-lib's
|
|
20
|
+
`DevicePanel` over a `LocalHandle` on the instrument in this process, as an
|
|
21
|
+
alternative to serving it — both want the one session the instrument grants,
|
|
22
|
+
so `main()` does one or the other. Nothing about the window is hand-written;
|
|
23
|
+
the controls, their bounds, units and tooltips come from the device schema, so
|
|
24
|
+
a parameter added there appears in the panel.
|
|
25
|
+
|
|
26
|
+
The generated `open_panel()` calls `connect()` **before** the panel is built.
|
|
27
|
+
That ordering is the point of the entry point rather than an implementation
|
|
28
|
+
detail: what the instrument reports on connection narrows the schema's
|
|
29
|
+
device-wide envelope to the unit in front of the operator, and those are the
|
|
30
|
+
bounds worth typing into. On a PM100D the fitted head answers 400–1100 nm
|
|
31
|
+
against the 185–25000 nm the schema declares for every head.
|
|
32
|
+
|
|
33
|
+
Qt lands in a new `gui` extra (`plesty-lib[gui]`), not in `dependencies` — a
|
|
34
|
+
headless bench serves the device and never opens a window — and the
|
|
35
|
+
`plesty.lib.ui` import is local to `open_panel`, so serving pulls no toolkit.
|
|
36
|
+
Every module used to hand-add this entry point; `plesty-pm100d` was the last
|
|
37
|
+
to do it by hand.
|
|
38
|
+
|
|
39
|
+
- The device template's note on `kind` now says what declaring `lifecycle` does
|
|
40
|
+
beyond the field test: an operation whose effect outlives the call is kept off
|
|
41
|
+
a control panel — the local one and the one a remote client renders. The
|
|
42
|
+
schema is the only place either can learn it.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- `PLESTY_LIB_VERSION`, the `plesty-lib` floor a scaffold falls back to when
|
|
46
|
+
PyPI is unreachable, moves `0.3.6` → `0.4.0`. That is the release
|
|
47
|
+
`plesty.lib.ui` begins at, so it is the floor the generated `--gui` needs;
|
|
48
|
+
below it the panel path raises `ImportError`. The live PyPI lookup already
|
|
49
|
+
resolved 0.4.0 on any machine with a route out — this only changes the
|
|
50
|
+
offline case.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- **The pre-push hook no longer leaks git's hook variables into the gates.**
|
|
54
|
+
Git exports `GIT_DIR` and friends into every hook, and everything the hook
|
|
55
|
+
runs inherits them, so git work nested inside the gates resolves the pushing
|
|
56
|
+
repository instead of the one it is standing in. The hook now clears them
|
|
57
|
+
before running `plesty check`; nothing about what the gates check changes.
|
|
58
|
+
|
|
59
|
+
Two failures this had already caused. Gate 10 has pip clone each git-pinned
|
|
60
|
+
dependency into a temp directory, where versioningit read the outer
|
|
61
|
+
repository's tag and commit — on lightfield_spectrometer (2026-09-04) a
|
|
62
|
+
pinned `plesty-lib` came out as `0.1.0.dev65+<the module's sha>`, which
|
|
63
|
+
cannot satisfy the module's own floor, so the audit failed with a resolution
|
|
64
|
+
error unrelated to the code. That is enough to make anyone drop the pin
|
|
65
|
+
rather than debug it, and a dropped pin is a module quietly building against
|
|
66
|
+
the wrong dependency. Separately, a test suite that drives git could commit
|
|
67
|
+
into the real repository rather than its fixture, which is what made pushing
|
|
68
|
+
this repo from a worktree unsafe.
|
|
69
|
+
|
|
70
|
+
Existing modules keep the old hook until `plesty init` is re-run; the fix is
|
|
71
|
+
a one-line `unset` in `.git/hooks/pre-push` for anyone who does not want to.
|
|
72
|
+
|
|
73
|
+
## [0.3.6] — 2026-09-03
|
|
74
|
+
|
|
75
|
+
Everything the scaffolds generate now passes the gates the scaffolds ask for.
|
|
76
|
+
Two generated files failed a check the SDK itself enforces — a field-test
|
|
77
|
+
client with an import nothing used, and entry points on an event loop that
|
|
78
|
+
Python 3.16 will not give them — and the version picker no longer strands a
|
|
79
|
+
reader on a release it cannot leave. Generated projects pin `plesty-lib>=0.3.6`.
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
- Generated device and experiment entry points start through
|
|
83
|
+
`plesty.lib.service.run_server` instead of a bare `asyncio.run`. The bare
|
|
84
|
+
call worked on Windows only because importing `plesty.lib.service` installed
|
|
85
|
+
a global event-loop policy — deprecated in Python 3.14 (two warnings per
|
|
86
|
+
server start on benches already there) and removed in 3.16, where the entry
|
|
87
|
+
point would get a `ProactorEventLoop` and fail inside pyzmq for want of
|
|
88
|
+
`add_reader`. The `plesty-lib` pin floor moves to 0.3.6, the first release
|
|
89
|
+
carrying `run_server`. Existing modules keep working on 3.14 and 3.15 and
|
|
90
|
+
pick the swap up when they regenerate.
|
|
91
|
+
- `plesty init field-test` no longer writes a client whose imports fail the
|
|
92
|
+
module's own lint gate. A module reached through its `DocDevice` — or through
|
|
93
|
+
any construction taking no arguments — gets a bare factory, and the generated
|
|
94
|
+
`tests/field_test_client.py` imported `functools.partial` anyway: F401, so
|
|
95
|
+
`plesty check` could not pass on a module that had just been field-tested.
|
|
96
|
+
The import is now emitted only in the branch that calls `partial`. Both
|
|
97
|
+
branches are linted in the tests; neither was before, because every fixture
|
|
98
|
+
probed into the "no hardware-free construction" path.
|
|
99
|
+
Generating against released 0.3.3 has a worse form of the same block — it
|
|
100
|
+
emits the `partial` import but not the device import, leaving `SPAWN_FACTORY`
|
|
101
|
+
an undefined name (F821). Add the `from plesty.<module> import <factory>`
|
|
102
|
+
line by hand, or regenerate once this ships.
|
|
103
|
+
- The version picker no longer offers a version the reader cannot switch back
|
|
104
|
+
out of. A release built before the Read-the-Docs theme has no sidebar for the
|
|
105
|
+
picker to mount on and cannot be stamped, yet the manifest still listed it —
|
|
106
|
+
on the SDK's own docs, selecting 0.1 stranded the reader. The manifest now
|
|
107
|
+
advertises only releases that carry the picker; such a release stays
|
|
108
|
+
published and reachable at its own URL, and `/releases/` still redirects to
|
|
109
|
+
the newest one that exists. Stamping consequently runs before the manifest is
|
|
110
|
+
written, so the manifest sees the final state of every tree.
|
|
111
|
+
- A module with no releases rendered a dropdown holding a single entry. The
|
|
112
|
+
picker now appears only when there is something to pick between.
|
|
113
|
+
|
|
114
|
+
## [0.3.5] — 2026-08-24
|
|
115
|
+
|
|
116
|
+
Documentation gains a version picker, and the two things standing between it
|
|
117
|
+
and the published sites are fixed: the docs-deploy gate had been skipped since
|
|
118
|
+
2026-08-21 behind a failing test collection, and releases built before the
|
|
119
|
+
picker existed had no way back to the current docs.
|
|
120
|
+
|
|
121
|
+
### Added
|
|
122
|
+
- Every module's documentation carries a **version picker** in the sidebar.
|
|
123
|
+
Each module already deployed `latest/` from its default branch and
|
|
124
|
+
`releases/<major>.<minor>/` from each tag, but nothing linked them: a reader
|
|
125
|
+
on the release docs could not reach any other version. The picker is fed by
|
|
126
|
+
`versions.json`, fetched at page load rather than baked in — a page built
|
|
127
|
+
months ago cannot know which versions exist today. Switching versions keeps
|
|
128
|
+
the current page when the target has it, and falls back to that version's
|
|
129
|
+
index when it does not (pages come and go between releases). A deployment
|
|
130
|
+
without a manifest — a local `plesty docs serve` preview — renders no picker
|
|
131
|
+
at all.
|
|
132
|
+
|
|
133
|
+
### Fixed
|
|
134
|
+
- The version picker is no longer a one-way trip. Releases published before it
|
|
135
|
+
existed are never rebuilt, so switching to one landed the reader on pages
|
|
136
|
+
with no picker and no way back. Each deploy now stamps the picker's two
|
|
137
|
+
assets and the tags referencing them into any release tree that lacks them.
|
|
138
|
+
Only the `<head>` gains anything — the prose, the API reference and the
|
|
139
|
+
stylesheets a historical release was built with are untouched, which is why
|
|
140
|
+
the picker's styling moved out of `plesty-hub.css` into its own
|
|
141
|
+
`plesty-versions.css`. Idempotent, so re-running over a stamped tree does
|
|
142
|
+
nothing. A release predating the Read-the-Docs theme (plesty-sdk 0.1) has no
|
|
143
|
+
sidebar to mount on and is skipped.
|
|
144
|
+
- The test suite no longer fails to collect in CI. `plesty-lib` is declared in
|
|
145
|
+
a `dev` dependency group: `tests/test_mock_test_scaffold.py` drives the
|
|
146
|
+
mock-test scaffold against a real `plesty.lib.sim.demo_device.DemoDevice`,
|
|
147
|
+
which it subclasses and runs, but nothing installed the library on a runner —
|
|
148
|
+
so `hub-check` had been failing with `ModuleNotFoundError: No module named
|
|
149
|
+
'plesty.lib'`, which in turn skipped `hub-deploy-docs` and froze the
|
|
150
|
+
published documentation. It is a group rather than a runtime dependency:
|
|
151
|
+
installing plesty-sdk must not pull the library it scaffolds modules for.
|
|
152
|
+
- `versions.json` entries were origin-absolute (`"/0.3/"`), so they resolved
|
|
153
|
+
against the host rather than the module root, and the `releases/` redirect
|
|
154
|
+
stub built from them has been broken since it was written — on
|
|
155
|
+
docs.plesty.net it pointed at `docs.plesty.net/0.3/`. The manifest moves to
|
|
156
|
+
the module root, lists `latest` alongside the releases, and its URLs are
|
|
157
|
+
relative to that root, which is `/<slug>/` on docs.plesty.net and
|
|
158
|
+
`/<group>/<project>/` on GitLab Pages.
|
|
159
|
+
|
|
160
|
+
### Changed
|
|
161
|
+
- Both deploy modes rewrite the manifest, not only `--release`. This is what
|
|
162
|
+
gives a module that has never been tagged a picker, and what migrates
|
|
163
|
+
branches deployed by an older SDK — including their `.gitlab-ci.yml`, which
|
|
164
|
+
was previously written once at branch creation and never updated again.
|
|
165
|
+
- The Pages job publishes the whole `html/` tree instead of `html/latest`, so
|
|
166
|
+
the releases the picker lists are reachable there too, and `html/index.html`
|
|
167
|
+
redirects the Pages root to `latest/`. The layout now matches what
|
|
168
|
+
docs.plesty.net already serves, so one picker runs unchanged on both.
|
|
169
|
+
**Deep links to `plesty.gitlab.io/<group>/<project>/<page>.html` move under
|
|
170
|
+
`/latest/`**; docs.plesty.net URLs are unaffected. The reference link
|
|
171
|
+
`plesty check` prints on a failing gate followed that move, so it now points
|
|
172
|
+
at docs.plesty.net — the site readers are sent to, and the one whose path is
|
|
173
|
+
independent of how Pages lays the tree out.
|
|
174
|
+
|
|
5
175
|
## [0.3.5.dev1] — 2026-08-21
|
|
6
176
|
|
|
7
177
|
Development pre-release: the tutorial needs the pin option before 0.3.5 is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: plesty-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Command-line application for developing Python modules compliant with the Plesty standard.
|
|
5
5
|
Author: Plesty Development Team, Yunshuang Yuan, Christopher Borchers, fvrehlinger, Maximilian Heller, Michael Zopf
|
|
6
6
|
License-Expression: LGPL-3.0-or-later
|
|
@@ -55,10 +55,14 @@ plesty init device --author "Jane Doe" --email jane@example.com
|
|
|
55
55
|
|
|
56
56
|
# 2. Develop your module — the pre-push hook runs compliance checks automatically
|
|
57
57
|
|
|
58
|
-
# 3.
|
|
58
|
+
# 3. Drive the instrument from a control panel built out of your device schema
|
|
59
|
+
uv sync --extra gui
|
|
60
|
+
python -m plesty.power_meter --gui
|
|
61
|
+
|
|
62
|
+
# 4. Run the full [SDK] compliance check manually at any time
|
|
59
63
|
plesty check
|
|
60
64
|
|
|
61
|
-
#
|
|
65
|
+
# 5. Preview the documentation locally
|
|
62
66
|
plesty docs serve
|
|
63
67
|
```
|
|
64
68
|
|
|
@@ -23,10 +23,14 @@ plesty init device --author "Jane Doe" --email jane@example.com
|
|
|
23
23
|
|
|
24
24
|
# 2. Develop your module — the pre-push hook runs compliance checks automatically
|
|
25
25
|
|
|
26
|
-
# 3.
|
|
26
|
+
# 3. Drive the instrument from a control panel built out of your device schema
|
|
27
|
+
uv sync --extra gui
|
|
28
|
+
python -m plesty.power_meter --gui
|
|
29
|
+
|
|
30
|
+
# 4. Run the full [SDK] compliance check manually at any time
|
|
27
31
|
plesty check
|
|
28
32
|
|
|
29
|
-
#
|
|
33
|
+
# 5. Preview the documentation locally
|
|
30
34
|
plesty docs serve
|
|
31
35
|
```
|
|
32
36
|
|
|
@@ -187,6 +187,21 @@ have already diverged. The cost is a coupling to the component's ref and input c
|
|
|
187
187
|
a rename or ref change in plesty-ci breaks scaffolds (see technical debt below) — which we
|
|
188
188
|
accept because centralised evolution has proven far cheaper than fleet-wide file surgery.
|
|
189
189
|
|
|
190
|
+
**A generated device carries its own control panel, with Qt in an extra.** A device can be
|
|
191
|
+
reached two ways — served over TCP for a client to drive, or opened in a window on the
|
|
192
|
+
machine it is plugged into — and the scaffold generates the second as `--gui` on the module's
|
|
193
|
+
existing entry point rather than shipping a separate console or leaving each module to
|
|
194
|
+
hand-write one. The controls are derived from the device schema, so a module gets a usable
|
|
195
|
+
window the moment its schema is right, and it is the same serialized `describe` payload a
|
|
196
|
+
remote client renders: a hole in the payload surfaces at the bench instead of only across a
|
|
197
|
+
network. Operations are filtered by their declared `kind`, which makes the schema the single
|
|
198
|
+
place that decides what a panel offers, local or remote. Qt lives in a generated `gui` extra
|
|
199
|
+
rather than in the generated `dependencies` — a headless bench serves the device and never
|
|
200
|
+
opens a window — which is why `plesty.lib.ui` is imported inside the panel path and not at
|
|
201
|
+
module scope. The tradeoff is that the two modes are alternatives rather than layers: both
|
|
202
|
+
claim the single session most instruments grant, so a module cannot serve and show a local
|
|
203
|
+
panel at the same time.
|
|
204
|
+
|
|
190
205
|
**`plesty update --install-hook` for cloned projects.** Git hooks live in `.git/` and are
|
|
191
206
|
never cloned, so `plesty init`'s pre-push hook silently vanishes for every contributor
|
|
192
207
|
after the first. Rather than adopting a hook-manager dependency (pre-commit) or committing
|
|
@@ -146,7 +146,7 @@ failures and their guidance always print:
|
|
|
146
146
|
Error: [Coverage] total coverage 62% below threshold
|
|
147
147
|
This gate verifies: the pytest suite passes with at least 80% line coverage.
|
|
148
148
|
How to fix: Reproduce with 'uv run pytest --cov=plesty' and add tests ...
|
|
149
|
-
Reference: https://plesty.
|
|
149
|
+
Reference: https://docs.plesty.net/plesty-sdk/latest/commands/check.html
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
## Examples
|
|
@@ -184,6 +184,38 @@ python -m plesty.foo_bar --host 10.0.0.5 --tcp-port 6000 # CLI overrides env
|
|
|
184
184
|
variables, so one `.env` drives both the server and the tests. It is skipped unless
|
|
185
185
|
`DEVICE_HOST` is set.
|
|
186
186
|
|
|
187
|
+
## The control panel (device only)
|
|
188
|
+
|
|
189
|
+
The same entry point opens the device's control panel instead of serving it:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
uv sync --extra gui
|
|
193
|
+
python -m plesty.foo_bar --gui
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Serving and `--gui` are alternatives — both want the one session the instrument
|
|
197
|
+
grants, so `main()` does one or the other. The panel is
|
|
198
|
+
[`plesty.lib.ui.DevicePanel`](https://gitlab.com/plesty/core/plesty-lib) over a
|
|
199
|
+
`LocalHandle`, which builds every control from the device schema; a parameter
|
|
200
|
+
added to the schema appears in the window with no GUI code written. The
|
|
201
|
+
generated `open_panel()` calls `connect()` **before** the panel is built,
|
|
202
|
+
because it is what the instrument reports on connection — a fitted sensor head's
|
|
203
|
+
wavelength range, say — that narrows the schema's device-wide envelope to the
|
|
204
|
+
unit in front of the operator.
|
|
205
|
+
|
|
206
|
+
Operations are filtered by their `kind`: one whose effect outlives the call is
|
|
207
|
+
declared `@expose_to_api(kind="lifecycle")`, and that keeps it off this panel
|
|
208
|
+
*and* off the one a remote client renders, since the schema is the only place
|
|
209
|
+
either can learn it.
|
|
210
|
+
|
|
211
|
+
Qt goes in a `gui` extra rather than in `dependencies` — a headless bench serves
|
|
212
|
+
the device and never opens a window:
|
|
213
|
+
|
|
214
|
+
```toml
|
|
215
|
+
[project.optional-dependencies]
|
|
216
|
+
gui = ["plesty-lib[gui]>=0.4.0"]
|
|
217
|
+
```
|
|
218
|
+
|
|
187
219
|
## Rig start-up and the shared disk (experiment only)
|
|
188
220
|
|
|
189
221
|
The generated `__main__.py` does not open device clients itself. It declares
|
|
@@ -35,6 +35,23 @@ Use `--standard` to choose the compliance standard the generated CI pipeline enf
|
|
|
35
35
|
(default `pixel` — a fresh scaffold is a prototype; bump it alongside your releases), or
|
|
36
36
|
`--no-ci` to omit the CI file entirely.
|
|
37
37
|
|
|
38
|
+
### Running what you scaffolded
|
|
39
|
+
|
|
40
|
+
A device module's entry point does one of two things, and they are alternatives —
|
|
41
|
+
both want the one session the instrument grants:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
python -m plesty.power_meter --tcp-port 5555 # serve it for clients to drive
|
|
45
|
+
uv sync --extra gui
|
|
46
|
+
python -m plesty.power_meter --gui # drive it yourself, in a window
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The panel is built from the device schema, so the parameters and operations you
|
|
50
|
+
declare are the controls you get — there is no GUI code to write. Qt lives in the
|
|
51
|
+
`gui` extra, so a headless bench that only ever serves the device never installs
|
|
52
|
+
it. See [`plesty init`](commands/init.md) for how the panel picks up an
|
|
53
|
+
instrument's real limits, and which operations it leaves out.
|
|
54
|
+
|
|
38
55
|
## 2. Check compliance
|
|
39
56
|
|
|
40
57
|
Navigate into the project and run the compliance checker:
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"vendor": {
|
|
8
8
|
"name": "GitLab"
|
|
9
9
|
},
|
|
10
|
-
"version": "7.
|
|
10
|
+
"version": "7.39.0"
|
|
11
11
|
},
|
|
12
12
|
"scanner": {
|
|
13
13
|
"id": "gitleaks",
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
"version": "8.30.1"
|
|
20
20
|
},
|
|
21
21
|
"type": "secret_detection",
|
|
22
|
-
"start_time": "2026-
|
|
23
|
-
"end_time": "2026-
|
|
22
|
+
"start_time": "2026-09-07T14:07:04",
|
|
23
|
+
"end_time": "2026-09-07T14:07:04",
|
|
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.467099461,
|
|
30
30
|
"exit_code": 0,
|
|
31
31
|
"git_strategy": "FetchShallow",
|
|
32
|
-
"repo_size_kb":
|
|
32
|
+
"repo_size_kb": 500,
|
|
33
33
|
"commit_count": 1,
|
|
34
|
-
"bytes_scanned":
|
|
34
|
+
"bytes_scanned": 1215,
|
|
35
35
|
"pipeline_type": "Tag"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"passthrough_types": null,
|
|
41
41
|
"passthrough_count": 0,
|
|
42
42
|
"passthrough_auth_used": false,
|
|
43
|
-
"rules_version": "0.25.
|
|
43
|
+
"rules_version": "0.25.1"
|
|
44
44
|
}
|
|
45
45
|
]
|
|
46
46
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Per-gate failure guidance echoed by `plesty check` (issue sdk#26).
|
|
2
2
|
# Keys match the gate keys used in check_command; text is plain CLI prose.
|
|
3
|
-
|
|
3
|
+
# docs.plesty.net, not the Pages mirror: it is the site readers are sent to,
|
|
4
|
+
# and its /<slug>/latest/ path is unaffected by how Pages lays the tree out.
|
|
5
|
+
docs_url: https://docs.plesty.net/plesty-sdk/latest/commands/check.html
|
|
4
6
|
|
|
5
7
|
gates:
|
|
6
8
|
metadata:
|
|
@@ -4,7 +4,7 @@ pages:
|
|
|
4
4
|
stage: deploy
|
|
5
5
|
rules:
|
|
6
6
|
# The gate for creating the job, not a selector of what is published —
|
|
7
|
-
# `publish: html
|
|
7
|
+
# `publish: html` below uploads the whole directory. exists
|
|
8
8
|
# matches FILE globs: the bare directory path "html/latest/" stopped
|
|
9
9
|
# matching on gitlab.com between 2026-07-21 and 2026-08-10, every
|
|
10
10
|
# docs-build pipeline failed with "no jobs", and Pages froze while the
|
|
@@ -14,4 +14,8 @@ pages:
|
|
|
14
14
|
script:
|
|
15
15
|
- echo "Serving documentation on GitLab pages..."
|
|
16
16
|
pages:
|
|
17
|
-
|
|
17
|
+
# The whole tree, not just html/latest: the sidebar version picker needs
|
|
18
|
+
# versions.json and the releases/ it lists to be reachable from the same
|
|
19
|
+
# site. html/index.html forwards the Pages root to latest/, and the layout
|
|
20
|
+
# then matches docs.plesty.net, where the same picker runs unchanged.
|
|
21
|
+
publish: html
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Plesty Development Team
|
|
3
|
+
* SPDX-FileContributor: Yunshuang Yuan
|
|
4
|
+
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
5
|
+
*
|
|
6
|
+
* Styling for the sidebar version picker (plesty-versions.js).
|
|
7
|
+
*
|
|
8
|
+
* Separate from plesty-hub.css because it is also stamped into release docs
|
|
9
|
+
* built before the picker existed. Those trees carry their own copy of
|
|
10
|
+
* plesty-hub.css, and replacing it would change how a historical page looks
|
|
11
|
+
* beyond adding the dropdown; dropping one more file in beside it does not.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/* Sits at the foot of the sidebar header, under the search box. Added by the
|
|
15
|
+
* script, so a deployment without a versions.json shows no empty slot. */
|
|
16
|
+
.wy-side-nav-search .plesty-versions {
|
|
17
|
+
margin: 0.75rem 0 0;
|
|
18
|
+
text-align: left;
|
|
19
|
+
}
|
|
20
|
+
.wy-side-nav-search .plesty-versions label {
|
|
21
|
+
display: block;
|
|
22
|
+
margin-bottom: 0.3rem;
|
|
23
|
+
color: #d9d9d9;
|
|
24
|
+
font-size: 80%;
|
|
25
|
+
text-transform: uppercase;
|
|
26
|
+
letter-spacing: 0.06em;
|
|
27
|
+
}
|
|
28
|
+
.wy-side-nav-search .plesty-versions select {
|
|
29
|
+
width: 100%;
|
|
30
|
+
padding: 0.3rem 0.5rem;
|
|
31
|
+
border: 1px solid rgba(255, 255, 255, 0.25);
|
|
32
|
+
border-radius: 4px;
|
|
33
|
+
background: rgba(0, 0, 0, 0.2);
|
|
34
|
+
color: #fff;
|
|
35
|
+
font-size: 90%;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
.wy-side-nav-search .plesty-versions select:focus {
|
|
39
|
+
/* Plesty cyan, spelled out: the historical trees this file is stamped into
|
|
40
|
+
carry a plesty-hub.css from before the custom property existed. */
|
|
41
|
+
border-color: #0891b2;
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
44
|
+
/* The dropdown list itself renders in the OS palette, not the sidebar's —
|
|
45
|
+
without this the options are white-on-white on most platforms. */
|
|
46
|
+
.wy-side-nav-search .plesty-versions option {
|
|
47
|
+
color: #404040;
|
|
48
|
+
background: #fff;
|
|
49
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Plesty Development Team
|
|
3
|
+
* SPDX-FileContributor: Yunshuang Yuan
|
|
4
|
+
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
5
|
+
*
|
|
6
|
+
* Version picker for the Read-the-Docs sidebar.
|
|
7
|
+
*
|
|
8
|
+
* Every module is deployed as a tree of independently built docs — `latest/`
|
|
9
|
+
* from the default branch, `releases/<major>.<minor>/` from each tag — under
|
|
10
|
+
* one module root, and `versions.json` at that root lists them. A page built
|
|
11
|
+
* months ago cannot know which versions exist today, so the list is read at
|
|
12
|
+
* page load rather than baked in at build time.
|
|
13
|
+
*
|
|
14
|
+
* The module root is not derivable from the URL: docs.plesty.net serves the
|
|
15
|
+
* tree at /<slug>/ and GitLab Pages at /<group>/<project>/. It is derived
|
|
16
|
+
* from this script's own location instead — the file is always at
|
|
17
|
+
* <docs-root>/_static/plesty-versions.js, and `data-root-prefix` (set by
|
|
18
|
+
* sphinx_builder) is the hop from the docs root up to the module root.
|
|
19
|
+
*/
|
|
20
|
+
(() => {
|
|
21
|
+
// Read synchronously: document.currentScript is null once the DOM is ready.
|
|
22
|
+
const script = document.currentScript;
|
|
23
|
+
if (!script) return;
|
|
24
|
+
const rootPrefix = script.dataset.rootPrefix;
|
|
25
|
+
const current = script.dataset.version || "latest";
|
|
26
|
+
if (!rootPrefix) return;
|
|
27
|
+
|
|
28
|
+
const docsRoot = new URL("../", script.src);
|
|
29
|
+
const moduleRoot = new URL(rootPrefix, docsRoot);
|
|
30
|
+
// Page path within this version's docs, carried across when the target
|
|
31
|
+
// version has the same page.
|
|
32
|
+
const pagePath = decodeURIComponent(location.href.slice(docsRoot.href.length));
|
|
33
|
+
|
|
34
|
+
const label = (version) =>
|
|
35
|
+
version === "latest" ? "latest (development)" : version;
|
|
36
|
+
|
|
37
|
+
/* Navigate to `path` under `target`, falling back to the target's index
|
|
38
|
+
when the page does not exist there — pages come and go between versions,
|
|
39
|
+
and a picker that lands on a 404 is worse than one that lands on a
|
|
40
|
+
landing page. A HEAD request that cannot run at all (file:// origin)
|
|
41
|
+
falls back the same way. */
|
|
42
|
+
const goTo = async (target, path) => {
|
|
43
|
+
const home = new URL(target, moduleRoot);
|
|
44
|
+
if (!path) {
|
|
45
|
+
location.assign(home);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const exact = new URL(path, home);
|
|
49
|
+
try {
|
|
50
|
+
const response = await fetch(exact, { method: "HEAD" });
|
|
51
|
+
location.assign(response.ok ? exact : home);
|
|
52
|
+
} catch {
|
|
53
|
+
location.assign(home);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const render = (versions) => {
|
|
58
|
+
const container = document.querySelector(".wy-side-nav-search");
|
|
59
|
+
if (!container) return;
|
|
60
|
+
|
|
61
|
+
const picker = document.createElement("div");
|
|
62
|
+
picker.className = "plesty-versions";
|
|
63
|
+
|
|
64
|
+
const caption = document.createElement("label");
|
|
65
|
+
caption.textContent = "Version";
|
|
66
|
+
caption.htmlFor = "plesty-version-select";
|
|
67
|
+
picker.appendChild(caption);
|
|
68
|
+
|
|
69
|
+
const select = document.createElement("select");
|
|
70
|
+
select.id = "plesty-version-select";
|
|
71
|
+
for (const entry of versions) {
|
|
72
|
+
const option = document.createElement("option");
|
|
73
|
+
option.value = entry.url;
|
|
74
|
+
option.textContent = label(entry.version);
|
|
75
|
+
option.selected = entry.version === current;
|
|
76
|
+
select.appendChild(option);
|
|
77
|
+
}
|
|
78
|
+
// The running version is missing from versions.json when this build has
|
|
79
|
+
// not been indexed yet (a local preview, a tag mid-deploy). Show it so the
|
|
80
|
+
// picker never reads as if the reader were somewhere else.
|
|
81
|
+
if (!versions.some((entry) => entry.version === current)) {
|
|
82
|
+
const option = document.createElement("option");
|
|
83
|
+
option.textContent = label(current);
|
|
84
|
+
option.selected = true;
|
|
85
|
+
option.disabled = true;
|
|
86
|
+
select.insertBefore(option, select.firstChild);
|
|
87
|
+
}
|
|
88
|
+
select.addEventListener("change", () => goTo(select.value, pagePath));
|
|
89
|
+
picker.appendChild(select);
|
|
90
|
+
|
|
91
|
+
// Below the search box, so the picker does not push the search field out
|
|
92
|
+
// of its usual place under the logo.
|
|
93
|
+
container.appendChild(picker);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const ready = (run) =>
|
|
97
|
+
document.readyState === "loading"
|
|
98
|
+
? document.addEventListener("DOMContentLoaded", run)
|
|
99
|
+
: run();
|
|
100
|
+
|
|
101
|
+
fetch(new URL("versions.json", moduleRoot))
|
|
102
|
+
.then((response) => (response.ok ? response.json() : null))
|
|
103
|
+
.then((versions) => {
|
|
104
|
+
// Nothing to pick between — no manifest (a local `plesty docs serve`
|
|
105
|
+
// preview), or a module with no releases yet, whose manifest holds only
|
|
106
|
+
// `latest`. A dropdown with one entry is furniture, not navigation.
|
|
107
|
+
if (Array.isArray(versions) && versions.length > 1) ready(() => render(versions));
|
|
108
|
+
})
|
|
109
|
+
.catch(() => {});
|
|
110
|
+
})();
|
|
@@ -13,6 +13,7 @@ device:
|
|
|
13
13
|
- "Expose your custom operations with @expose_to_api and declare what each one does (kind=motion/acquire/lifecycle/control/configure) — the field test drives them by kind instead of asking you about every call."
|
|
14
14
|
- "Copy .env.example to .env and set DEVICE_HOST/DEVICE_PORT (never commit .env)."
|
|
15
15
|
- "Try it live: uv run python -m plesty.{module_name} --tcp-port 5555."
|
|
16
|
+
- "Or drive it by hand: uv sync --extra gui, then uv run python -m plesty.{module_name} --gui — the control panel is built from your schema, so every parameter and operation you declare shows up in it."
|
|
16
17
|
|
|
17
18
|
analyzer:
|
|
18
19
|
- "Declare your input/output schemas and implement analyze() in plesty/{module_name}/analyzer.py."
|
{plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/extras/device/device.py
RENAMED
|
@@ -58,3 +58,9 @@ class Device(BaseDevice):
|
|
|
58
58
|
## motion is driven one `step` out from what `position_key` reports and put
|
|
59
59
|
## back, a lifecycle operation runs once, a control operation once at rest
|
|
60
60
|
## after the motions, and a configure operation is never called.
|
|
61
|
+
##
|
|
62
|
+
## The field test is not the only reader. An operation whose effect
|
|
63
|
+
## outlives the call — homing, zeroing an offset, a reset — is declared
|
|
64
|
+
## `lifecycle`, and that is what keeps it off a control panel: the one
|
|
65
|
+
## `--gui` opens here, and the one a remote client renders over the wire.
|
|
66
|
+
## The schema is the only place either of them can learn it.
|
{plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/README.md.jinja
RENAMED
|
@@ -17,7 +17,18 @@ uv sync
|
|
|
17
17
|
Make sure the device is connected and powered on.
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
uv run python -m {{ module_name }} --tcp-port 5555
|
|
20
|
+
uv run python -m plesty.{{ module_name }} --tcp-port 5555
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Open The Control Panel
|
|
24
|
+
|
|
25
|
+
`--gui` drives the instrument from this process instead of serving it — the two
|
|
26
|
+
are alternatives, since one session is all the instrument grants. The controls
|
|
27
|
+
are built from the device schema, so nothing here is hand-written.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv sync --extra gui
|
|
31
|
+
uv run python -m plesty.{{ module_name }} --gui
|
|
21
32
|
```
|
|
22
33
|
{% elif project_type == 'experiment' %}
|
|
23
34
|
|
{plesty_sdk-0.3.5.dev1 → plesty_sdk-0.4.0}/plesty/sdk/assets/templates/template/docs/index.md.jinja
RENAMED
|
@@ -25,6 +25,22 @@ Make sure the device is connected and powered on, then:
|
|
|
25
25
|
```bash
|
|
26
26
|
uv run python -m plesty.{{ module_name }} --tcp-port 5555
|
|
27
27
|
```
|
|
28
|
+
|
|
29
|
+
## Opening the control panel
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
uv sync --extra gui
|
|
33
|
+
uv run python -m plesty.{{ module_name }} --gui
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`--gui` and serving are alternatives: both want the one session the instrument
|
|
37
|
+
grants, so the process does one or the other. The panel derives its controls —
|
|
38
|
+
the parameters, their bounds and units, the operations — from the device
|
|
39
|
+
schema, and it connects before it builds them, so the bounds shown are the ones
|
|
40
|
+
this unit reports rather than the envelope the schema carries for every unit.
|
|
41
|
+
|
|
42
|
+
An operation whose effect outlives the call belongs to `kind="lifecycle"`; that
|
|
43
|
+
is what keeps it off the panel here and off the one a remote client renders.
|
|
28
44
|
{% elif project_type == 'experiment' %}
|
|
29
45
|
|
|
30
46
|
## Running the experiment
|