labcode 0.8.0__tar.gz → 0.10.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.
- {labcode-0.8.0 → labcode-0.10.0}/.github/workflows/ci.yml +15 -0
- labcode-0.10.0/CHANGELOG.md +107 -0
- {labcode-0.8.0 → labcode-0.10.0}/PKG-INFO +65 -20
- {labcode-0.8.0 → labcode-0.10.0}/README.md +55 -16
- {labcode-0.8.0 → labcode-0.10.0/docs}/SPECIFICATIONS.md +201 -56
- {labcode-0.8.0 → labcode-0.10.0}/examples/README.md +65 -15
- labcode-0.10.0/examples/lads_plate_cycle.env.yaml +288 -0
- labcode-0.10.0/examples/lads_seal.env.yaml +100 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/preflight_sila2_env.py +24 -9
- {labcode-0.8.0 → labcode-0.10.0}/examples/render_sila2_plate_cycle.py +3 -2
- labcode-0.10.0/examples/run_all_lads_examples.py +93 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/run_all_sila2_examples.py +1 -1
- {labcode-0.8.0 → labcode-0.10.0}/examples/run_sila2_plate_cycle.py +9 -5
- {labcode-0.8.0 → labcode-0.10.0}/examples/run_sila2_plate_cycle_no_atc.py +5 -5
- {labcode-0.8.0 → labcode-0.10.0}/examples/run_sila2_seal.py +4 -3
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_plate_cycle.boundary.yaml +1 -1
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_plate_cycle.wrapped.env.yaml +7 -7
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_plate_cycle_no_atc.boundary.yaml +1 -1
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_plate_cycle_no_atc.wrapped.env.yaml +7 -7
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_seal.boundary.yaml +1 -1
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_seal.env.yaml +2 -2
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_seal.wrapped.env.yaml +4 -4
- {labcode-0.8.0 → labcode-0.10.0}/labcode/_child.py +8 -9
- {labcode-0.8.0 → labcode-0.10.0}/labcode/backend.py +114 -54
- {labcode-0.8.0 → labcode-0.10.0}/labcode/cli.py +16 -1
- labcode-0.10.0/labcode/connections.py +257 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/dialect.py +98 -40
- {labcode-0.8.0 → labcode-0.10.0}/labcode/extension.py +44 -7
- labcode-0.10.0/labcode/lads.py +181 -0
- labcode-0.10.0/labcode/lads_commands.py +167 -0
- labcode-0.10.0/labcode/lads_unit.py +331 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/objectid.py +122 -33
- {labcode-0.8.0 → labcode-0.10.0}/labcode/probe.py +4 -4
- {labcode-0.8.0 → labcode-0.10.0}/labcode/run_cli.py +5 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/runner.py +20 -3
- labcode-0.10.0/labcode/sila2.py +154 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/sila2_commands.py +1 -1
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/PKG-INFO +65 -20
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/SOURCES.txt +13 -1
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/requires.txt +11 -3
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/scm_file_list.json +13 -1
- labcode-0.10.0/labcode.egg-info/scm_version.json +8 -0
- {labcode-0.8.0 → labcode-0.10.0}/pyproject.toml +34 -10
- labcode-0.10.0/tests/fixtures/dispense_read.workflow.yaml +81 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_backend.py +162 -5
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_cli.py +16 -1
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_dialect.py +135 -6
- labcode-0.10.0/tests/test_lads.py +184 -0
- labcode-0.10.0/tests/test_lads_unit.py +396 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_objectid.py +109 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_run_cli.py +32 -18
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_sila2.py +2 -2
- labcode-0.10.0/tests/test_structured_labcode.py +135 -0
- labcode-0.8.0/labcode/sila2.py +0 -280
- labcode-0.8.0/labcode.egg-info/scm_version.json +0 -8
- {labcode-0.8.0 → labcode-0.10.0}/.github/workflows/publish.yml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/.gitignore +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/LICENSE +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/MANIFEST.in +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/plate_line.boundary.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/plate_line.observation.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/plate_line.plan.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/plate_line.svg +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/shared_bench.boundary.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/shared_bench.observation.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/shared_bench.plan.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/shared_bench.svg +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/sila2_plate_cycle.boundary.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/sila2_plate_cycle.observation.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/sila2_plate_cycle.plan.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/outputs/sila2_plate_cycle.svg +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/plate_line.boundary.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/plate_line.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/plate_line.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/render_plate_line.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/render_shared_bench.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/shared_bench.afternoon.boundary.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/shared_bench.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/shared_bench.morning.boundary.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/shared_bench.run.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/shared_bench.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_plate_cycle.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_plate_cycle_no_atc.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/examples/sila2_seal.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/__init__.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/__main__.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/idgen.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/otel.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/otel_sila2.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/py.typed +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/record.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode/sila2_instrument.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/dependency_links.txt +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/entry_points.txt +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/labcode.egg-info/top_level.txt +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/setup.cfg +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/device_script.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/device_script.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/joint.run.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/replenishment.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/reroute_device.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/reroute_transporter.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/transport.env.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/fixtures/transport.workflow.yaml +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_joint.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_otel.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_otel_child.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_otel_grpc.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_otel_sila2.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_probe.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_record.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_recording.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_sila2_commands.py +0 -0
- {labcode-0.8.0 → labcode-0.10.0}/tests/test_sila2_instrument.py +0 -0
|
@@ -22,6 +22,21 @@ jobs:
|
|
|
22
22
|
- run: pip install -e ".[test]"
|
|
23
23
|
- run: pytest
|
|
24
24
|
|
|
25
|
+
test-export:
|
|
26
|
+
# `lc export` is the optional extra `labcode[export]`, so the matrix above runs
|
|
27
|
+
# without it and tests the "not installed" answer. This installs it the way a
|
|
28
|
+
# user would -- through the extra -- and tests that `lc export` reaches it.
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v7
|
|
32
|
+
- uses: actions/setup-python@v7
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.12"
|
|
35
|
+
cache: pip
|
|
36
|
+
- run: pip install -e ".[test,export]"
|
|
37
|
+
- run: python -c "import ofplang.export"
|
|
38
|
+
- run: pytest tests/test_cli.py
|
|
39
|
+
|
|
25
40
|
lint:
|
|
26
41
|
runs-on: ubuntu-latest
|
|
27
42
|
steps:
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
What changed in each release of labcode, for someone deciding whether to upgrade. The
|
|
4
|
+
specification the section numbers refer to is [`docs/SPECIFICATIONS.md`](docs/SPECIFICATIONS.md).
|
|
5
|
+
|
|
6
|
+
Releases before 0.9.0 are described in the messages of their `Release vX.Y.Z` commits
|
|
7
|
+
(`git log --grep '^Release v'`).
|
|
8
|
+
|
|
9
|
+
## 0.10.0 — 2026-10-05
|
|
10
|
+
|
|
11
|
+
labcode runs a protocol repeated over every plate (`map` / `fold`), and stops making up
|
|
12
|
+
a value a script did not compute.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`map` and `fold`** run, as ofplang-schedule 0.13 expands them and ofplang-run 0.13
|
|
17
|
+
executes the expansion. An **Array of Objects** at the run boundary is one Object per
|
|
18
|
+
element: its `view` is a list of views, one per spot, and each element gets its own
|
|
19
|
+
`_id`, keyed by the element (`plates[1]`, §4.3). An invocation's node path carries its
|
|
20
|
+
iteration index, and so do the keys of what it creates.
|
|
21
|
+
- **What a run made up, it says** (`lc run` prints each as `lc run: warning: ...`):
|
|
22
|
+
- `entry_input_defaulted` — a boundary view written in part, or not at all: the
|
|
23
|
+
declared fields it left out run on their type's default (§4.2). Once per Object.
|
|
24
|
+
- `output_view_defaulted` — a script that did not return an Object it created: the
|
|
25
|
+
view runs on its type's default (§1.2). Once per process and port.
|
|
26
|
+
- `_id` is never reported; minting it is labcode's identity, not a default.
|
|
27
|
+
|
|
28
|
+
### Changed — may need your attention
|
|
29
|
+
|
|
30
|
+
- **A script must return every Pure Data output it declares** (§1.2). Until now one left
|
|
31
|
+
out took its type's default — `return {}` from a `read` gave `od: 0.0`, a reading
|
|
32
|
+
nothing took. It now fails the operation (`script_output_names`), as v0 §22.2 does. An
|
|
33
|
+
Object output may still be left out: a mapped one is carried, a created one gets its
|
|
34
|
+
default view (reported).
|
|
35
|
+
- **A process with no script anywhere that declares a Pure Data output is refused** by
|
|
36
|
+
`lc run` before anything runs (§2): a no-op can compute nothing, so every run of it
|
|
37
|
+
would fail. One with only Object outputs still runs as a no-op, with the warning it
|
|
38
|
+
always had. A process with a script on some modes only fails if a mode without one is
|
|
39
|
+
chosen.
|
|
40
|
+
- **A boundary view that is not a mapping** (or, for an Array, not a list of them) is
|
|
41
|
+
refused. It used to be replaced by an empty view without a word.
|
|
42
|
+
- **An Object mapped from an input with no `_id`** fails the operation
|
|
43
|
+
(`missing_object_id`). No run can reach this; it is there to catch a broken invariant
|
|
44
|
+
early.
|
|
45
|
+
- A v0 §22 workflow script in a language other than Python fails the operation
|
|
46
|
+
(`script_language`) instead of running as a no-op.
|
|
47
|
+
- Requires ofplang-validate 0.3, ofplang-schedule 0.13 and ofplang-run 0.13
|
|
48
|
+
(specification revision 0.4).
|
|
49
|
+
|
|
50
|
+
`lc export` is unchanged; drawing a run that has `map` / `fold` invocations in it is not
|
|
51
|
+
yet supported there.
|
|
52
|
+
|
|
53
|
+
## 0.9.0 — 2026-09-28
|
|
54
|
+
|
|
55
|
+
labcode can now drive a lab over **LADS OPC UA** as well as SiLA2, and gains `lc export`.
|
|
56
|
+
Both are optional extras; nothing changes for an environment that uses neither.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **`flavor: lads`** — a script that is the commands alone, handed its LADS OPC UA clients
|
|
61
|
+
as a `sila2` script is handed SiLA2 ones (§1.10).
|
|
62
|
+
- A connection may say `kind: lads`, and may name the `device` and functional `unit` on the
|
|
63
|
+
server; left out, each is the only one there is (§1.5).
|
|
64
|
+
- The script sees `lads_clients` / `lads_client`: one functional unit per machine, with the
|
|
65
|
+
program runs, state-machine methods, cover movements and set-points LADS defines, each
|
|
66
|
+
waiting for what it starts, and `.raw` for the asyncua client itself.
|
|
67
|
+
- `labcode.lads_commands` holds the waits: a program run to its result, a state machine to
|
|
68
|
+
settle (§1.10.1). A timeout fails the operation and aborts nothing, as SiLA2's does.
|
|
69
|
+
- A script speaks one protocol. An operation may hold machines of both kinds, but a script
|
|
70
|
+
commands only its own flavor's; reaching for the other kind says why
|
|
71
|
+
(`lads_other_protocol` / `sila2_other_protocol`).
|
|
72
|
+
- The client library is the `lads` extra (`asyncua`). labcode imports it only when a `lads`
|
|
73
|
+
script connects.
|
|
74
|
+
- **`lc export`** — forwards to [ofplang-export](https://github.com/ofplang/export)'s CLI
|
|
75
|
+
unchanged, as `lc validate` and `lc schedule` do. `lc export view plan.yaml -o plan.html`
|
|
76
|
+
writes the workflow and its plan as one self-contained HTML file. It is the `export` extra;
|
|
77
|
+
without it `lc export` names the extra and exits 2.
|
|
78
|
+
- **LADS examples** — `lads_seal.env.yaml` and `lads_plate_cycle.env.yaml` run the
|
|
79
|
+
`sila2_seal` and `sila2_plate_cycle` workflows unchanged, with every machine reached over
|
|
80
|
+
LADS. `run_all_lads_examples.py` runs both against the reference lab,
|
|
81
|
+
[ofplang/mocklab](https://github.com/ofplang/mocklab).
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- `SPECIFICATIONS.md` moved to `docs/SPECIFICATIONS.md`.
|
|
86
|
+
- The `ofplang-schedule` cap is `<0.13`, admitting schedule 0.12. The floor is unchanged.
|
|
87
|
+
- The front door checks a connecting script's connection **per kind**. A `sila2` or `lads`
|
|
88
|
+
script needs a machine of its own kind. An endpoint of the other kind draws a warning, as
|
|
89
|
+
an endpoint with no connection does. Messages that named only `sila2` now name the flavor.
|
|
90
|
+
- What a connecting flavor needs (planning the clients, holding them for one operation,
|
|
91
|
+
generating the wrapper) moved from `labcode.sila2` into `labcode.connections`. The `sila2`
|
|
92
|
+
flavor's behaviour, messages and reason codes are unchanged.
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- `examples/preflight_sila2_env.py` treated every declared connection as SiLA2. An
|
|
97
|
+
environment with a LADS machine would have reported it as a failing SiLA2 server. It now
|
|
98
|
+
checks SiLA2 machines only and lists the others as not checked.
|
|
99
|
+
|
|
100
|
+
### Documentation
|
|
101
|
+
|
|
102
|
+
- The reference lab is named by its current name, ofplang/mocklab (formerly
|
|
103
|
+
ofplang-sila2-backend), and the examples record the commit they were last verified against.
|
|
104
|
+
- Section references written before probing took §1.6 pointed at the wrong sections and are
|
|
105
|
+
corrected. The `labcode.sila2_commands` section is numbered §1.7.1.
|
|
106
|
+
- The README lists the optional extras, lists every example, and links by absolute URL, so the
|
|
107
|
+
links also work on PyPI.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: labcode
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: labcode -- a dialect wrapper over the Object-Flow Programming Language toolchain
|
|
5
5
|
Author-email: Kazunari Kaizu <kwaizu@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,21 +20,27 @@ Classifier: Typing :: Typed
|
|
|
20
20
|
Requires-Python: >=3.10
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: ofplang-validate<0.
|
|
24
|
-
Requires-Dist: ofplang-schedule<0.
|
|
25
|
-
Requires-Dist: ofplang-run<0.
|
|
23
|
+
Requires-Dist: ofplang-validate<0.4,>=0.3
|
|
24
|
+
Requires-Dist: ofplang-schedule<0.14,>=0.13
|
|
25
|
+
Requires-Dist: ofplang-run<0.14,>=0.13
|
|
26
26
|
Provides-Extra: test
|
|
27
27
|
Requires-Dist: pytest>=7.0; extra == "test"
|
|
28
28
|
Requires-Dist: opentelemetry-sdk>=1.20; extra == "test"
|
|
29
29
|
Requires-Dist: opentelemetry-instrumentation-grpc[instruments]>=0.41b0; extra == "test"
|
|
30
|
+
Requires-Dist: asyncua>=2.0; extra == "test"
|
|
30
31
|
Provides-Extra: dev
|
|
31
32
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
32
33
|
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
33
34
|
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
34
35
|
Requires-Dist: opentelemetry-sdk>=1.20; extra == "dev"
|
|
35
36
|
Requires-Dist: opentelemetry-instrumentation-grpc[instruments]>=0.41b0; extra == "dev"
|
|
37
|
+
Requires-Dist: asyncua>=2.0; extra == "dev"
|
|
36
38
|
Provides-Extra: sila2
|
|
37
39
|
Requires-Dist: sila2>=0.14; extra == "sila2"
|
|
40
|
+
Provides-Extra: lads
|
|
41
|
+
Requires-Dist: asyncua>=2.0; extra == "lads"
|
|
42
|
+
Provides-Extra: export
|
|
43
|
+
Requires-Dist: ofplang-export<0.2,>=0.1; extra == "export"
|
|
38
44
|
Provides-Extra: otel
|
|
39
45
|
Requires-Dist: opentelemetry-api>=1.20; extra == "otel"
|
|
40
46
|
Requires-Dist: opentelemetry-sdk>=1.20; extra == "otel"
|
|
@@ -55,6 +61,7 @@ ofplang toolchain and exposes it under a single command:
|
|
|
55
61
|
lc validate ... # check a workflow is well-formed portable v0
|
|
56
62
|
lc schedule ... # compute a schedule for a workflow
|
|
57
63
|
lc run ... # execute a workflow on the labcode backend
|
|
64
|
+
lc export ... # write documents out for people to read (optional: labcode[export])
|
|
58
65
|
```
|
|
59
66
|
|
|
60
67
|
labcode is where a site-specific dialect and a custom runner (real lab hardware)
|
|
@@ -63,7 +70,7 @@ forward to the ofplang siblings unchanged; **`lc run` is the labcode dialect's o
|
|
|
63
70
|
runner**: it drives the workflow on the labcode backend, running each device
|
|
64
71
|
operation's script — supplied in the environment as an `x-labcode.script` extension
|
|
65
72
|
on a process mode — out-of-process on a wall clock, so a long-running real operation
|
|
66
|
-
never blocks the replan loop. See [`SPECIFICATIONS.md`](SPECIFICATIONS.md) for the
|
|
73
|
+
never blocks the replan loop. See [`docs/SPECIFICATIONS.md`](https://github.com/ofplang/labcode/blob/main/docs/SPECIFICATIONS.md) for the
|
|
67
74
|
`x-labcode` extension.
|
|
68
75
|
|
|
69
76
|
```yaml
|
|
@@ -94,7 +101,25 @@ sibling packages unchanged; `lc run` is this package's own runner, built on them
|
|
|
94
101
|
- [`ofplang-run`](https://github.com/ofplang/run) — the runner / simulator
|
|
95
102
|
|
|
96
103
|
The language is defined in the [ofplang/spec](https://github.com/ofplang/spec)
|
|
97
|
-
repository, and what labcode adds to it in [`SPECIFICATIONS.md`](SPECIFICATIONS.md).
|
|
104
|
+
repository, and what labcode adds to it in [`docs/SPECIFICATIONS.md`](https://github.com/ofplang/labcode/blob/main/docs/SPECIFICATIONS.md).
|
|
105
|
+
|
|
106
|
+
Talking to instruments, recording a run and exporting documents are optional, each an extra
|
|
107
|
+
installed into the interpreter that runs `lc` (labcode runs every script with that same
|
|
108
|
+
interpreter):
|
|
109
|
+
|
|
110
|
+
| extra | brings | needed for |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `sila2` | the `sila2` client library | `flavor: sila2` scripts (§1.7) |
|
|
113
|
+
| `lads` | `asyncua`, an OPC UA client | `flavor: lads` scripts (§1.10) |
|
|
114
|
+
| `otel` | the OpenTelemetry SDK and exporter | `lc run --trace` |
|
|
115
|
+
| `export` | [`ofplang-export`](https://github.com/ofplang/export) | `lc export view` — the workflow and its plan as one self-contained HTML file |
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
pip install 'labcode[sila2,lads]'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Without an extra, labcode still runs; only what needs it — a script of that flavor,
|
|
122
|
+
`--trace`, or `lc export` — fails, with a message naming the extra to install.
|
|
98
123
|
|
|
99
124
|
What `lc run` brings of its own, beyond dispatching:
|
|
100
125
|
|
|
@@ -114,12 +139,18 @@ What `lc run` brings of its own, beyond dispatching:
|
|
|
114
139
|
- **object identity** — the reserved `_id` view key is declared on Object types and minted
|
|
115
140
|
per object, so a physical thing can be followed through a run (§4).
|
|
116
141
|
- **`flavor: sila2`** — a script that speaks SiLA2 gets its clients opened around it
|
|
117
|
-
(§1.7). The client library
|
|
118
|
-
|
|
142
|
+
(§1.7). The client library is the `sila2` extra.
|
|
143
|
+
- **`flavor: lads`** — the same for LADS OPC UA: a script is handed one LADS functional
|
|
144
|
+
unit per machine, already connected, with the program runs, state-machine methods and
|
|
145
|
+
cover movements LADS defines and the waits each needs (§1.10). A connection may name the
|
|
146
|
+
`device` and `unit` on the server, or leave them to be found. A script speaks one protocol;
|
|
147
|
+
an operation holding machines of both kinds commands only its own flavor's. The client
|
|
148
|
+
library is the `lads` extra.
|
|
119
149
|
- **recording a run** — with `--trace`, what the run did is recorded as OpenTelemetry
|
|
120
150
|
traces: one trace per run, a span per operation, and — measured inside the process that
|
|
121
151
|
issued them — a span per SiLA2 connection, per command, and per gRPC call each of those
|
|
122
|
-
made. Off by default; the extra
|
|
152
|
+
made. Off by default; it needs the `otel` extra. A `lads` operation is
|
|
153
|
+
recorded as its span alone for now.
|
|
123
154
|
|
|
124
155
|
## Usage
|
|
125
156
|
|
|
@@ -133,9 +164,11 @@ lc --version
|
|
|
133
164
|
|
|
134
165
|
`lc` can also be run as a module: `python -m labcode <command> ...`.
|
|
135
166
|
|
|
136
|
-
`lc validate` and `lc
|
|
137
|
-
options are documented in those repositories
|
|
138
|
-
|
|
167
|
+
`lc validate`, `lc schedule` and `lc export` are the ofplang siblings' own CLIs unchanged,
|
|
168
|
+
so their options are documented in those repositories — `lc export view plan.yaml -o
|
|
169
|
+
plan.html`, for one, writes the workflow and its plan as a single HTML file
|
|
170
|
+
([ofplang/export](https://github.com/ofplang/export); needs `labcode[export]`). `lc run` is
|
|
171
|
+
this package's own, and is described below.
|
|
139
172
|
|
|
140
173
|
### `lc run`
|
|
141
174
|
|
|
@@ -267,9 +300,10 @@ duration and nothing is commanded. That is a real thing to write (an operator to
|
|
|
267
300
|
stock up while the schedule waits for them) and an easy one to write by accident, so it is
|
|
268
301
|
warned about.
|
|
269
302
|
|
|
270
|
-
`flavor: sila2`
|
|
271
|
-
and which machine's clients a refill should receive — the replenisher's,
|
|
272
|
-
transport may ask for — is not settled. Use `
|
|
303
|
+
`flavor: sila2` and `flavor: lads` are **refused on a refill route** for now: such a script
|
|
304
|
+
is handed clients, and which machine's clients a refill should receive — the replenisher's,
|
|
305
|
+
or both ends' as a transport may ask for — is not settled. Use `raw` (the default), which may
|
|
306
|
+
connect for itself.
|
|
273
307
|
|
|
274
308
|
A refill holds the device it fills *and* the replenisher filling it, so it never overlaps
|
|
275
309
|
the work it feeds. It is recorded (`--trace`) as a `replenishment` span naming both
|
|
@@ -332,11 +366,22 @@ OpenTelemetry's own export timeout allows: labcode sets no timeout of its own, s
|
|
|
332
366
|
|
|
333
367
|
## Examples
|
|
334
368
|
|
|
335
|
-
[`examples/`](examples/README.md) holds
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
369
|
+
[`examples/`](https://github.com/ofplang/labcode/blob/main/examples/README.md) holds worked runs of two kinds.
|
|
370
|
+
|
|
371
|
+
- **Runnable with nothing but Python** — `plate_line`, an Object-bearing line driven entirely
|
|
372
|
+
by environment scripts, and `shared_bench`, two jobs sharing one laboratory (`--jobs`).
|
|
373
|
+
- **Against real instrument servers** — `sila2_seal` (one instrument), `sila2_plate_cycle` (a
|
|
374
|
+
circuit through four instruments and an arm) and `sila2_plate_cycle_no_atc` (the same
|
|
375
|
+
circuit on a bench without a thermal cycler), over SiLA2; and `lads_seal` and
|
|
376
|
+
`lads_plate_cycle`, the first two workflows unchanged with every machine reached over LADS
|
|
377
|
+
OPC UA instead. `sila2_seal` also walks through what a run does when a machine stops
|
|
378
|
+
answering — before an operation, and in the middle of one.
|
|
379
|
+
|
|
380
|
+
The servers they are verified against are the reference lab,
|
|
381
|
+
[ofplang/mocklab](https://github.com/ofplang/mocklab): mock instruments serving SiLA2 or LADS
|
|
382
|
+
OPC UA by Docker Compose profile, over one simulated world. It is a reference, not a
|
|
383
|
+
requirement — the environments speak plain SiLA2 and LADS, so a bench is a change of hosts and
|
|
384
|
+
ports. `run_all_sila2_examples.py` and `run_all_lads_examples.py` run each set as a check.
|
|
340
385
|
|
|
341
386
|
## License
|
|
342
387
|
|
|
@@ -11,6 +11,7 @@ ofplang toolchain and exposes it under a single command:
|
|
|
11
11
|
lc validate ... # check a workflow is well-formed portable v0
|
|
12
12
|
lc schedule ... # compute a schedule for a workflow
|
|
13
13
|
lc run ... # execute a workflow on the labcode backend
|
|
14
|
+
lc export ... # write documents out for people to read (optional: labcode[export])
|
|
14
15
|
```
|
|
15
16
|
|
|
16
17
|
labcode is where a site-specific dialect and a custom runner (real lab hardware)
|
|
@@ -19,7 +20,7 @@ forward to the ofplang siblings unchanged; **`lc run` is the labcode dialect's o
|
|
|
19
20
|
runner**: it drives the workflow on the labcode backend, running each device
|
|
20
21
|
operation's script — supplied in the environment as an `x-labcode.script` extension
|
|
21
22
|
on a process mode — out-of-process on a wall clock, so a long-running real operation
|
|
22
|
-
never blocks the replan loop. See [`SPECIFICATIONS.md`](SPECIFICATIONS.md) for the
|
|
23
|
+
never blocks the replan loop. See [`docs/SPECIFICATIONS.md`](https://github.com/ofplang/labcode/blob/main/docs/SPECIFICATIONS.md) for the
|
|
23
24
|
`x-labcode` extension.
|
|
24
25
|
|
|
25
26
|
```yaml
|
|
@@ -50,7 +51,25 @@ sibling packages unchanged; `lc run` is this package's own runner, built on them
|
|
|
50
51
|
- [`ofplang-run`](https://github.com/ofplang/run) — the runner / simulator
|
|
51
52
|
|
|
52
53
|
The language is defined in the [ofplang/spec](https://github.com/ofplang/spec)
|
|
53
|
-
repository, and what labcode adds to it in [`SPECIFICATIONS.md`](SPECIFICATIONS.md).
|
|
54
|
+
repository, and what labcode adds to it in [`docs/SPECIFICATIONS.md`](https://github.com/ofplang/labcode/blob/main/docs/SPECIFICATIONS.md).
|
|
55
|
+
|
|
56
|
+
Talking to instruments, recording a run and exporting documents are optional, each an extra
|
|
57
|
+
installed into the interpreter that runs `lc` (labcode runs every script with that same
|
|
58
|
+
interpreter):
|
|
59
|
+
|
|
60
|
+
| extra | brings | needed for |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `sila2` | the `sila2` client library | `flavor: sila2` scripts (§1.7) |
|
|
63
|
+
| `lads` | `asyncua`, an OPC UA client | `flavor: lads` scripts (§1.10) |
|
|
64
|
+
| `otel` | the OpenTelemetry SDK and exporter | `lc run --trace` |
|
|
65
|
+
| `export` | [`ofplang-export`](https://github.com/ofplang/export) | `lc export view` — the workflow and its plan as one self-contained HTML file |
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
pip install 'labcode[sila2,lads]'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Without an extra, labcode still runs; only what needs it — a script of that flavor,
|
|
72
|
+
`--trace`, or `lc export` — fails, with a message naming the extra to install.
|
|
54
73
|
|
|
55
74
|
What `lc run` brings of its own, beyond dispatching:
|
|
56
75
|
|
|
@@ -70,12 +89,18 @@ What `lc run` brings of its own, beyond dispatching:
|
|
|
70
89
|
- **object identity** — the reserved `_id` view key is declared on Object types and minted
|
|
71
90
|
per object, so a physical thing can be followed through a run (§4).
|
|
72
91
|
- **`flavor: sila2`** — a script that speaks SiLA2 gets its clients opened around it
|
|
73
|
-
(§1.7). The client library
|
|
74
|
-
|
|
92
|
+
(§1.7). The client library is the `sila2` extra.
|
|
93
|
+
- **`flavor: lads`** — the same for LADS OPC UA: a script is handed one LADS functional
|
|
94
|
+
unit per machine, already connected, with the program runs, state-machine methods and
|
|
95
|
+
cover movements LADS defines and the waits each needs (§1.10). A connection may name the
|
|
96
|
+
`device` and `unit` on the server, or leave them to be found. A script speaks one protocol;
|
|
97
|
+
an operation holding machines of both kinds commands only its own flavor's. The client
|
|
98
|
+
library is the `lads` extra.
|
|
75
99
|
- **recording a run** — with `--trace`, what the run did is recorded as OpenTelemetry
|
|
76
100
|
traces: one trace per run, a span per operation, and — measured inside the process that
|
|
77
101
|
issued them — a span per SiLA2 connection, per command, and per gRPC call each of those
|
|
78
|
-
made. Off by default; the extra
|
|
102
|
+
made. Off by default; it needs the `otel` extra. A `lads` operation is
|
|
103
|
+
recorded as its span alone for now.
|
|
79
104
|
|
|
80
105
|
## Usage
|
|
81
106
|
|
|
@@ -89,9 +114,11 @@ lc --version
|
|
|
89
114
|
|
|
90
115
|
`lc` can also be run as a module: `python -m labcode <command> ...`.
|
|
91
116
|
|
|
92
|
-
`lc validate` and `lc
|
|
93
|
-
options are documented in those repositories
|
|
94
|
-
|
|
117
|
+
`lc validate`, `lc schedule` and `lc export` are the ofplang siblings' own CLIs unchanged,
|
|
118
|
+
so their options are documented in those repositories — `lc export view plan.yaml -o
|
|
119
|
+
plan.html`, for one, writes the workflow and its plan as a single HTML file
|
|
120
|
+
([ofplang/export](https://github.com/ofplang/export); needs `labcode[export]`). `lc run` is
|
|
121
|
+
this package's own, and is described below.
|
|
95
122
|
|
|
96
123
|
### `lc run`
|
|
97
124
|
|
|
@@ -223,9 +250,10 @@ duration and nothing is commanded. That is a real thing to write (an operator to
|
|
|
223
250
|
stock up while the schedule waits for them) and an easy one to write by accident, so it is
|
|
224
251
|
warned about.
|
|
225
252
|
|
|
226
|
-
`flavor: sila2`
|
|
227
|
-
and which machine's clients a refill should receive — the replenisher's,
|
|
228
|
-
transport may ask for — is not settled. Use `
|
|
253
|
+
`flavor: sila2` and `flavor: lads` are **refused on a refill route** for now: such a script
|
|
254
|
+
is handed clients, and which machine's clients a refill should receive — the replenisher's,
|
|
255
|
+
or both ends' as a transport may ask for — is not settled. Use `raw` (the default), which may
|
|
256
|
+
connect for itself.
|
|
229
257
|
|
|
230
258
|
A refill holds the device it fills *and* the replenisher filling it, so it never overlaps
|
|
231
259
|
the work it feeds. It is recorded (`--trace`) as a `replenishment` span naming both
|
|
@@ -288,11 +316,22 @@ OpenTelemetry's own export timeout allows: labcode sets no timeout of its own, s
|
|
|
288
316
|
|
|
289
317
|
## Examples
|
|
290
318
|
|
|
291
|
-
[`examples/`](examples/README.md) holds
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
319
|
+
[`examples/`](https://github.com/ofplang/labcode/blob/main/examples/README.md) holds worked runs of two kinds.
|
|
320
|
+
|
|
321
|
+
- **Runnable with nothing but Python** — `plate_line`, an Object-bearing line driven entirely
|
|
322
|
+
by environment scripts, and `shared_bench`, two jobs sharing one laboratory (`--jobs`).
|
|
323
|
+
- **Against real instrument servers** — `sila2_seal` (one instrument), `sila2_plate_cycle` (a
|
|
324
|
+
circuit through four instruments and an arm) and `sila2_plate_cycle_no_atc` (the same
|
|
325
|
+
circuit on a bench without a thermal cycler), over SiLA2; and `lads_seal` and
|
|
326
|
+
`lads_plate_cycle`, the first two workflows unchanged with every machine reached over LADS
|
|
327
|
+
OPC UA instead. `sila2_seal` also walks through what a run does when a machine stops
|
|
328
|
+
answering — before an operation, and in the middle of one.
|
|
329
|
+
|
|
330
|
+
The servers they are verified against are the reference lab,
|
|
331
|
+
[ofplang/mocklab](https://github.com/ofplang/mocklab): mock instruments serving SiLA2 or LADS
|
|
332
|
+
OPC UA by Docker Compose profile, over one simulated world. It is a reference, not a
|
|
333
|
+
requirement — the environments speak plain SiLA2 and LADS, so a bench is a change of hosts and
|
|
334
|
+
ports. `run_all_sila2_examples.py` and `run_all_lads_examples.py` run each set as a check.
|
|
296
335
|
|
|
297
336
|
## License
|
|
298
337
|
|