Skill Tracer
Skills › Scientific Agent Skills › omero-integration › scripts.md

scripts.md

307 lines · skills/omero-integration/references/scripts.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Bundled Helpers and OMERO.server Scripts
2
3The local files in this skill's `scripts/` directory are client-side safety
4helpers. They are not OMERO.server scripts and are never uploaded
5automatically.
6

Bundled Helpers and OMERO.server Scripts

The local files in this skill's scripts/ directory are client-side safety helpers. They are not OMERO.server scripts and are never uploaded automatically.

Raw lines 1 to 6
7## Shared Safety Model
8
9Every bundled executable:
11- uses `argparse`;
12- supports `--help` without OMERO installed;
13- imports `omero` only after argument parsing and only for `--execute`;
14- reads only named `OMERO_*` variables;
15- never loads `.env`;
16- never accepts or prints a password/session key;
17- defaults to local validation or dry-run output;
18- applies hard limits;
19- refuses unsafe output collisions/symlinks;
20- closes remote connections in `finally`.
22Remote helpers require `--execute`. That flag authorizes a read-only
23connection, not broader scope or mutation.

Shared Safety Model

Every bundled executable:

  • uses argparse;
  • supports --help without OMERO installed;
  • imports omero only after argument parsing and only for --execute;
  • reads only named OMERO_* variables;
  • never loads .env;
  • never accepts or prints a password/session key;
  • defaults to local validation or dry-run output;
  • applies hard limits;
  • refuses unsafe output collisions/symlinks;
  • closes remote connections in finally.

Remote helpers require --execute. That flag authorizes a read-only connection, not broader scope or mutation.

Raw lines 7 to 24
25## Local Endpoint Validation
27```bash
28python -B scripts/validate_config.py
29python -B scripts/validate_config.py --require-auth --json
30```
32By default it performs only local syntax checks. `--resolve-host` performs DNS
33resolution but does not connect to an OMERO port.
35Output reports which named variables are present and the authentication mode.
36It never displays credential values.
38Examples of failures:
40- host contains `http://`, a path, whitespace, or a leading hyphen;
41- port is not in `1..65535`;
42- `OMERO_SECURE` is not a recognized boolean;
43- only one of `OMERO_USER`/`OMERO_PASSWORD` is present;
44- `--require-auth` is used without either a session key or complete password
45 authentication.

Local Endpoint Validation

python -B scripts/validate_config.py
python -B scripts/validate_config.py --require-auth --json

By default it performs only local syntax checks. --resolve-host performs DNS resolution but does not connect to an OMERO port.

Output reports which named variables are present and the authentication mode. It never displays credential values.

Examples of failures:

  • host contains http://, a path, whitespace, or a leading hyphen;
  • port is not in 1..65535;
  • OMERO_SECURE is not a recognized boolean;
  • only one of OMERO_USER/OMERO_PASSWORD is present;
  • --require-auth is used without either a session key or complete password authentication.
Raw lines 25 to 46
Runs code scripts/validate_config.py :28
47## Read-Only Inventory
49Dry run:
51```bash
52python -B scripts/inventory.py \
53 --object-type Image \
54 --limit 50 \
55 --page-size 25
56```
58Execute after reviewing endpoint/group/scope:
60```bash
61python -B scripts/inventory.py \
62 --object-type Image \
63 --limit 50 \
64 --page-size 25 \
65 --group-id 42 \
66 --execute \
67 --output ./image-inventory.json
68```
70Properties:
72- allowlisted object types only;
73- overall cap at 1000 and page cap at 200;
74- stable `obj.id` ordering request;
75- one optional explicit group, never cross-group `-1`;
76- object names redacted unless `--include-names`;
77- JSON output written atomically with owner-only permissions;
78- existing output refused unless `--overwrite`.
80`limit_reached` means the requested cap was filled; it does not assert that
81more server rows exist.

Read-Only Inventory

Dry run:

python -B scripts/inventory.py \
  --object-type Image \
  --limit 50 \
  --page-size 25

Execute after reviewing endpoint/group/scope:

python -B scripts/inventory.py \
  --object-type Image \
  --limit 50 \
  --page-size 25 \
  --group-id 42 \
  --execute \
  --output ./image-inventory.json

Properties:

  • allowlisted object types only;
  • overall cap at 1000 and page cap at 200;
  • stable obj.id ordering request;
  • one optional explicit group, never cross-group -1;
  • object names redacted unless --include-names;
  • JSON output written atomically with owner-only permissions;
  • existing output refused unless --overwrite.

limit_reached means the requested cap was filled; it does not assert that more server rows exist.

Raw lines 47 to 82
Runs code scripts/inventory.py :52
83## Annotation and ROI Export
85Dry run:
87```bash
88python -B scripts/export_image_metadata.py \
89 --image-id 101 \
90 --image-id 102 \
91 --max-annotations-per-image 100 \
92 --max-rois-per-image 100 \
93 --max-shapes-per-roi 500 \
94 --output ./selected-image-metadata.json
95```
97Execute:
99```bash
100python -B scripts/export_image_metadata.py \
101 --image-id 101 \
102 --image-id 102 \
103 --group-id 42 \
104 --execute \
105 --output ./selected-image-metadata.json
106```
108Default redactions:
110- annotation values
111- owner names
112- FileAnnotation filenames
113- ROI/shape labels
114- mask bytes
116Optional inclusion flags are independent. The helper never retrieves pixels or
117FileAnnotation bytes. It uses the currently documented `IRoi.findByImage`
118pattern and records that `IRoi` is deprecated.
120Because `findByImage` has no page argument, the ROI caps bound serialization
121but not server-side assembly. `listAnnotations()` likewise loads annotations
122and values before local caps/redaction. ROI mask payloads can arrive in the
123service response even though their bytes are excluded from JSON. Do not run it on a known extreme image
124without reviewing the ROI count or using a site-approved paginated API.

Annotation and ROI Export

Dry run:

python -B scripts/export_image_metadata.py \
  --image-id 101 \
  --image-id 102 \
  --max-annotations-per-image 100 \
  --max-rois-per-image 100 \
  --max-shapes-per-roi 500 \
  --output ./selected-image-metadata.json

Execute:

python -B scripts/export_image_metadata.py \
  --image-id 101 \
  --image-id 102 \
  --group-id 42 \
  --execute \
  --output ./selected-image-metadata.json

Default redactions:

  • annotation values
  • owner names
  • FileAnnotation filenames
  • ROI/shape labels
  • mask bytes

Optional inclusion flags are independent. The helper never retrieves pixels or FileAnnotation bytes. It uses the currently documented IRoi.findByImage pattern and records that IRoi is deprecated.

Because findByImage has no page argument, the ROI caps bound serialization but not server-side assembly. listAnnotations() likewise loads annotations and values before local caps/redaction. ROI mask payloads can arrive in the service response even though their bytes are excluded from JSON. Do not run it on a known extreme image without reviewing the ROI count or using a site-approved paginated API.

Raw lines 83 to 125
Runs code scripts/export_image_metadata.py :88
126## Import/Export Planner
128The planner is always local and has no `--execute`.
130Import scan plan:
132```bash
133python -B scripts/plan_transfer.py import \
134 --target Dataset:id:42 \
135 --max-files 100 \
136 --scan-depth 4 \
137 ./explicit-input
138```
140It walks only explicit paths, does not follow directory symlinks, caps depth
141and file count, and proposes `omero import --depth N -f` plus a future import
142using the same depth. A depth cutoff or skipped symlink prevents marking the
143plan ready. Bio-Formats may discover related files beyond the local scan, so
144review the actual `-f` fileset list before importing. Local file counts are
145estimates, not an importer file limit. The planner invokes neither command.
147Per-image export plan:
149```bash
150python -B scripts/plan_transfer.py export \
151 --format ome-tiff \
152 --output-dir ./reviewed-existing-directory \
153 Image:101 Image:102
154```
156It accepts explicit `Image:<id>` selectors only, proposes one output per image,
157and reports collisions. Dataset iteration is intentionally excluded because
158the official export mode is experimental and too easy to broaden.
160Global `--output` and `--overwrite` arguments must precede the subcommand:
162```bash
163python -B scripts/plan_transfer.py \
164 --output ./transfer-plan.json \
165 import ./explicit-input
166```
168No proposed command includes `-w`, `--password`, `-k`, or a session value.

Import/Export Planner

The planner is always local and has no --execute.

Import scan plan:

python -B scripts/plan_transfer.py import \
  --target Dataset:id:42 \
  --max-files 100 \
  --scan-depth 4 \
  ./explicit-input

It walks only explicit paths, does not follow directory symlinks, caps depth and file count, and proposes omero import --depth N -f plus a future import using the same depth. A depth cutoff or skipped symlink prevents marking the plan ready. Bio-Formats may discover related files beyond the local scan, so review the actual -f fileset list before importing. Local file counts are estimates, not an importer file limit. The planner invokes neither command.

Per-image export plan:

python -B scripts/plan_transfer.py export \
  --format ome-tiff \
  --output-dir ./reviewed-existing-directory \
  Image:101 Image:102

It accepts explicit Image:<id> selectors only, proposes one output per image, and reports collisions. Dataset iteration is intentionally excluded because the official export mode is experimental and too easy to broaden.

Global --output and --overwrite arguments must precede the subcommand:

python -B scripts/plan_transfer.py \
  --output ./transfer-plan.json \
  import ./explicit-input

No proposed command includes -w, --password, -k, or a session value.

Raw lines 126 to 169
Runs code scripts/plan_transfer.py :133
170## Running Local Tests
172No real OMERO server is needed:
174```bash
175uv run --with pytest python -m pytest tests/omero-integration -q
176python tests/run_all.py --isolated omero-integration
177```
179The tests use temporary directories and fake gateway objects.

Running Local Tests

No real OMERO server is needed:

uv run --with pytest python -m pytest tests/omero-integration -q
python tests/run_all.py --isolated omero-integration

The tests use temporary directories and fake gateway objects.

Raw lines 170 to 180
Runs code python tests/run_all.py :176
181## OMERO.server Script Model
183OMERO.server scripts are Python plugins registered with the Script Service.
184Clients can launch them and receive typed outputs. Inputs often include an
185explicit data type, object IDs, thresholds, or options.
187A minimal structure:
189```python
190import omero
191import omero.scripts as scripts
192from omero.gateway import BlitzGateway
193from omero.rtypes import rlong, rstring
196def main():
197 client = scripts.client(
198 "Bounded_Image_Summary.py",
199 "Returns IDs for an explicit bounded image list.",
200 scripts.List(
201 "Image_IDs",
202 optional=False,
203 description="Explicit image IDs (maximum enforced by script)",
204 ).ofType(rlong(0)),
205 namespaces=[omero.constants.namespaces.NSDYNAMIC],
206 version="1.0",
207 )
209 try:
210 inputs = client.getInputs(unwrap=True)
211 image_ids = list(inputs["Image_IDs"])
212 if not 1 <= len(image_ids) <= 25:
213 raise ValueError("Image_IDs must contain 1..25 IDs")
215 conn = BlitzGateway(client_obj=client)
216 found = []
217 for image_id in image_ids:
218 image = conn.getObject("Image", image_id)
219 if image is not None:
220 found.append(image.getId())
222 client.setOutput("Message", rstring(f"Found {len(found)} images"))
223 finally:
224 client.closeSession()
227if __name__ == "__main__":
228 main()
229```
231The script session is supplied by OMERO. Do not read a password or create a
232second login inside a server script.

OMERO.server Script Model

OMERO.server scripts are Python plugins registered with the Script Service. Clients can launch them and receive typed outputs. Inputs often include an explicit data type, object IDs, thresholds, or options.

A minimal structure:

import omero
import omero.scripts as scripts
from omero.gateway import BlitzGateway
from omero.rtypes import rlong, rstring


def main():
    client = scripts.client(
        "Bounded_Image_Summary.py",
        "Returns IDs for an explicit bounded image list.",
        scripts.List(
            "Image_IDs",
            optional=False,
            description="Explicit image IDs (maximum enforced by script)",
        ).ofType(rlong(0)),
        namespaces=[omero.constants.namespaces.NSDYNAMIC],
        version="1.0",
    )

    try:
        inputs = client.getInputs(unwrap=True)
        image_ids = list(inputs["Image_IDs"])
        if not 1 <= len(image_ids) <= 25:
            raise ValueError("Image_IDs must contain 1..25 IDs")

        conn = BlitzGateway(client_obj=client)
        found = []
        for image_id in image_ids:
            image = conn.getObject("Image", image_id)
            if image is not None:
                found.append(image.getId())

        client.setOutput("Message", rstring(f"Found {len(found)} images"))
    finally:
        client.closeSession()


if __name__ == "__main__":
    main()

The script session is supplied by OMERO. Do not read a password or create a second login inside a server script.

Raw lines 181 to 233
234## Server-Script Safety
236Even a server script that only reads can be expensive. It must enforce:
238- maximum ID count;
239- per-container child cap;
240- plane/tile/byte limits;
241- fixed group context;
242- no cross-group fallback;
243- no user-controlled HQL/code strings;
244- bounded output size;
245- `client.closeSession()` in `finally`.
247For writes, additionally require an explicit “save” input or other reviewed
248gate and document every created/linked object. A client-side confirmation is
249not enough if the server script itself accepts unbounded inputs.
251Do not use Python `eval()` or `exec()` for parameters. Do not interpolate
252parameter text into HQL, filesystem paths, commands, or table conditions.

Server-Script Safety

Even a server script that only reads can be expensive. It must enforce:

  • maximum ID count;
  • per-container child cap;
  • plane/tile/byte limits;
  • fixed group context;
  • no cross-group fallback;
  • no user-controlled HQL/code strings;
  • bounded output size;
  • client.closeSession() in finally.

For writes, additionally require an explicit “save” input or other reviewed gate and document every created/linked object. A client-side confirmation is not enough if the server script itself accepts unbounded inputs.

Do not use Python eval() or exec() for parameters. Do not interpolate parameter text into HQL, filesystem paths, commands, or table conditions.

Raw lines 234 to 253
254## Upload and Launch
256Uploading registers executable code and is a mutation:
258```bash
259omero script upload ./Bounded_Image_Summary.py
260omero script list
261```
263Before upload:
2651. review source and dependencies;
2662. validate against the target OMERO.py/server pairing;
2673. confirm destination script path/category;
2684. confirm administrator authorization;
2695. record returned script ID/version.
271Launching is also a remote operation:
273```bash
274omero script launch <SCRIPT_ID> Image_IDs=101,102
275```
277Use an already prompted session. Confirm the exact script ID, version, group,
278input IDs, expected writes, and resource limits. Never launch based only on a
279script display name.

Upload and Launch

Uploading registers executable code and is a mutation:

omero script upload ./Bounded_Image_Summary.py
omero script list

Before upload:

  1. review source and dependencies;
  2. validate against the target OMERO.py/server pairing;
  3. confirm destination script path/category;
  4. confirm administrator authorization;
  5. record returned script ID/version.

Launching is also a remote operation:

omero script launch <SCRIPT_ID> Image_IDs=101,102

Use an already prompted session. Confirm the exact script ID, version, group, input IDs, expected writes, and resource limits. Never launch based only on a script display name.

Raw lines 254 to 280
281## Outputs and Temporary Files
283Server scripts may return strings, objects, images, or FileAnnotations. For a
284file output:
286- use a server-side temporary directory designed for scripts;
287- generate a safe filename independent of user text;
288- cap bytes;
289- classify content before attaching;
290- remove local temporary files in `finally`;
291- close any table or raw store before closing the script session.
293Do not place server paths, credentials, session IDs, or stack traces in client
294outputs.

Outputs and Temporary Files

Server scripts may return strings, objects, images, or FileAnnotations. For a file output:

  • use a server-side temporary directory designed for scripts;
  • generate a safe filename independent of user text;
  • cap bytes;
  • classify content before attaching;
  • remove local temporary files in finally;
  • close any table or raw store before closing the script session.

Do not place server paths, credentials, session IDs, or stack traces in client outputs.

Raw lines 281 to 295
296## Script Review Checklist
298- Client helper or server plugin clearly identified
299- Dry run and execution separated
300- Credentials absent from arguments/output
301- Object/group/file scope explicit
302- Hard bounds at every expansion
303- Output path safe and collision-aware
304- Lazy optional imports for local helpers
305- Stateful resources closed
306- `IRoi`/other deprecated service dependencies documented
307- No real-server test performed without explicit authorization

Script Review Checklist

  • Client helper or server plugin clearly identified
  • Dry run and execution separated
  • Credentials absent from arguments/output
  • Object/group/file scope explicit
  • Hard bounds at every expansion
  • Output path safe and collision-aware
  • Lazy optional imports for local helpers
  • Stateful resources closed
  • IRoi/other deprecated service dependencies documented
  • No real-server test performed without explicit authorization
Raw lines 296 to 307