Skip to content

Commit 6ea313b

Browse files
chore(platform): fix race condition in e2e test due to caching (#206)
* feat(platform): Support for tags in custom sdk metadata, run and item-level * feat(platform): Support created_at and updated_at in custom sdk metadata, run and item-level * feat(platform): Support nocache=True on cached operations * feat(platform): Custom run and item metadata can be updated * chore(platform): Improved depth of tests * chore(platform): Fix race condition in e2e test due to caching by using nocache * chore(platform): Start with submit-and-find e2e tests later replacing submit-and-wait * feat(application): Custom run and item metadata can be dumped as JSON via the CLI * feat(application): custom run metadata can be updated via the CLI * feat(application): Custom run metadata can be edited via the GUI (admins only) * feat(application): Allow to submit tags via CLI and find back runs via tags * chore(qupath): Enable complex automated test scenario covering creating QuPath projects * chore(deps): bump * docs(AI): update
1 parent 27e7f9a commit 6ea313b

38 files changed

+5135
-486
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ repos:
5252
args: ["--baseline", ".secrets.baseline"]
5353
additional_dependencies: ["gibberish-detector"]
5454
- repo: https://github.com/astral-sh/uv-pre-commit
55-
rev: 0.8.9
55+
rev: 0.9.5
5656
hooks:
5757
- id: uv-lock
5858
- repo: local

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,5 +1762,3 @@
17621762

17631763

17641764
* @helmut-hoffer-von-ankershoffen made their first contribution
1765-
1766-

CLAUDE.md

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -509,20 +509,24 @@ Some modules have conditional loading based on dependencies:
509509
* 5-minute refresh buffer before expiry
510510
* OAuth 2.0 device flow
511511

512-
### SDK Metadata System (NEW in v1.0.0-beta.7)
512+
### SDK Metadata System (ENHANCED - Run v0.0.4, Item v0.0.3)
513513

514-
**Automatic Run Tracking**: Every application run submitted through the SDK automatically includes comprehensive metadata about the execution context.
514+
**Automatic Run & Item Tracking**: Every application run and item submitted through the SDK automatically includes comprehensive metadata about the execution context, with support for tags and timestamps.
515515

516516
**Key Features:**
517517

518-
* **Automatic Attachment**: SDK metadata added to every run without user action
518+
* **Automatic Attachment**: SDK metadata added to every run and item without user action
519519
* **Environment Detection**: Automatically detects script/CLI/GUI and user/test/bridge contexts
520520
* **CI/CD Integration**: Captures GitHub Actions workflow information and pytest test context
521521
* **User Information**: Includes authenticated user and organization details
522-
* **Schema Validation**: Pydantic-based validation with JSON Schema (v0.0.1)
523-
* **Versioned Schema**: Published JSON Schema at `docs/source/_static/sdk_metadata_schema_*.json`
522+
* **Schema Validation**: Pydantic-based validation with JSON Schema (Run: v0.0.4, Item: v0.0.3)
523+
* **Versioned Schema**: Published JSON Schema at `docs/source/_static/sdk_{run|item}_custom_metadata_schema_*.json`
524+
* **Tags Support** (NEW): Associate runs and items with searchable tags
525+
* **Timestamps** (NEW): Track creation and update times (`created_at`, `updated_at`)
526+
* **Metadata Updates** (NEW): Update custom metadata via CLI and GUI
527+
* **Item Metadata** (NEW): Separate schema for item-level metadata including platform bucket information
524528

525-
**What's Tracked:**
529+
**What's Tracked (Run Level):**
526530

527531
* Submission metadata (date, interface, initiator)
528532
* Enhanced user agent with platform and CI/CD context
@@ -532,21 +536,41 @@ Some modules have conditional loading based on dependencies:
532536
* Workflow control flags (validate_only, onboard_to_portal)
533537
* Scheduling information (due dates, deadlines)
534538
* Optional user notes
539+
* **Tags** (NEW): Set of tags for filtering (`set[str]`)
540+
* **Timestamps** (NEW): `created_at`, `updated_at`
535541

536-
**CLI Command:**
542+
**What's Tracked (Item Level - NEW):**
543+
544+
* **Platform Bucket Metadata**: Cloud storage location (bucket name, object key, signed URL)
545+
* **Tags**: Item-level tags (`set[str]`)
546+
* **Timestamps**: `created_at`, `updated_at`
547+
548+
**CLI Commands:**
537549

538550
```bash
539-
# Export SDK metadata JSON Schema
540-
aignostics sdk metadata-schema --pretty > schema.json
551+
# Export SDK run metadata JSON Schema
552+
aignostics sdk metadata-schema --pretty > run_schema.json
553+
554+
# Update run custom metadata (including tags)
555+
aignostics application run custom-metadata update RUN_ID \
556+
--custom-metadata '{"sdk": {"tags": ["experiment-1", "batch-A"]}}'
557+
558+
# Dump run custom metadata as JSON
559+
aignostics application run custom-metadata dump RUN_ID --pretty
560+
561+
# Find runs by tags
562+
aignostics application run list --tags experiment-1,batch-A
541563
```
542564

543565
**Implementation:**
544566

545567
* Module: `platform._sdk_metadata`
546-
* Functions: `build_sdk_metadata()`, `validate_sdk_metadata()`, `get_sdk_metadata_json_schema()`
568+
* **Run Functions**: `build_run_sdk_metadata()`, `validate_run_sdk_metadata()`, `get_run_sdk_metadata_json_schema()`
569+
* **Item Functions** (NEW): `build_item_sdk_metadata()`, `validate_item_sdk_metadata()`, `get_item_sdk_metadata_json_schema()`
547570
* Integration: Automatic in `platform.resources.runs.submit()`
548571
* User Agent: Enhanced `utils.user_agent()` with CI/CD context
549572
* Tests: Comprehensive test suite in `tests/aignostics/platform/sdk_metadata_test.py`
573+
* **Schema Files**: `sdk_run_custom_metadata_schema_v0.0.4.json` and `sdk_item_custom_metadata_schema_v0.0.3.json`
550574

551575
See `platform/CLAUDE.md` for detailed documentation.
552576

@@ -616,10 +640,19 @@ AIGNOSTICS_RUN_TIMEOUT=30.0
616640
AIGNOSTICS_RUN_CACHE_TTL=15
617641
```
618642

643+
**Cache Control:**
644+
645+
```python
646+
# Bypass cache for specific operations (useful in tests or when fresh data is required)
647+
run = client.runs.details(run_id, nocache=True) # Force API call
648+
applications = client.applications.list(nocache=True) # Bypass cache
649+
```
650+
619651
**Design Decisions:**
620652

621653
***Read-Only Retries**: Only safe, idempotent read operations retry
622654
***Global Cache Clearing**: Simple consistency model - clear everything on writes
655+
***Cache Bypass** (NEW): `nocache=True` parameter forces fresh API calls
623656
***Logging**: Warnings logged before retry sleeps for observability
624657
***Re-raise**: Original exception re-raised after exhausting retries
625658

CLI_REFERENCE.md

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,11 @@ $ aignostics application run [OPTIONS] COMMAND [ARGS]...
162162
* `submit`: Submit run by referencing the metadata CSV...
163163
* `list`: List runs.
164164
* `describe`: Describe run.
165+
* `dump-metadata`: Dump custom metadata of a run as JSON to...
166+
* `dump-item-metadata`: Dump custom metadata of an item as JSON to...
165167
* `cancel`: Cancel run.
168+
* `update-metadata`: Update custom metadata for a run.
169+
* `update-item-metadata`: Update custom metadata for an item in a run.
166170
* `result`: Download or delete run results.
167171

168172
#### `aignostics application run execute`
@@ -200,7 +204,7 @@ $ aignostics application run execute [OPTIONS] APPLICATION_ID METADATA_CSV_FILE
200204
* `--application-version TEXT`: Version of the application. If not provided, the latest version will be used.
201205
* `--create-subdirectory-for-run / --no-create-subdirectory-for-run`: Create a subdirectory for the results of the run in the destination directory [default: create-subdirectory-for-run]
202206
* `--create-subdirectory-per-item / --no-create-subdirectory-per-item`: Create a subdirectory per item in the destination directory [default: create-subdirectory-per-item]
203-
* `--upload-prefix TEXT`: Prefix for the upload destination. If not given will be set to current milliseconds. [default: 1761393428019.061]
207+
* `--upload-prefix TEXT`: Prefix for the upload destination. If not given will be set to current milliseconds. [default: 1761499056785.385]
204208
* `--wait-for-completion / --no-wait-for-completion`: Wait for run completion and download results incrementally [default: wait-for-completion]
205209
* `--note TEXT`: Optional note to include with the run submission via custom metadata.
206210
* `--due-date TEXT`: Optional soft due date to include with the run submission, ISO8601 format. The scheduler will try to complete the run by this date, taking the subscription tierand available GPU resources into account.
@@ -263,7 +267,7 @@ $ aignostics application run upload [OPTIONS] APPLICATION_ID METADATA_CSV_FILE
263267
**Options**:
264268

265269
* `--application-version TEXT`: Version of the application. If not provided, the latest version will be used.
266-
* `--upload-prefix TEXT`: Prefix for the upload destination. If not given will be set to current milliseconds. [default: 1761393428019.1792]
270+
* `--upload-prefix TEXT`: Prefix for the upload destination. If not given will be set to current milliseconds. [default: 1761499056785.492]
267271
* `--onboard-to-aignostics-portal / --no-onboard-to-aignostics-portal`: If set, the run will be onboarded to the Aignostics Portal. [default: no-onboard-to-aignostics-portal]
268272
* `--help`: Show this message and exit.
269273

@@ -291,6 +295,7 @@ $ aignostics application run submit [OPTIONS] APPLICATION_ID METADATA_CSV_FILE
291295

292296
* `--application-version TEXT`: Version of the application to generate the metadata for. If not provided, the latest version will be used.
293297
* `--note TEXT`: Optional note to include with the run submission via custom metadata.
298+
* `--tags TEXT`: Optional comma-separated list of tags to attach to the run for filtering.
294299
* `--due-date TEXT`: Optional soft due date to include with the run submission, ISO8601 format. The scheduler will try to complete the run by this date, taking the subscription tierand available GPU resources into account.
295300
* `--deadline TEXT`: Optional hard deadline to include with the run submission, ISO8601 format. If processing exceeds this deadline, the run can be aborted.
296301
* `--onboard-to-aignostics-portal / --no-onboard-to-aignostics-portal`: If True, onboard the run to the Aignostics Portal. [default: no-onboard-to-aignostics-portal]
@@ -311,6 +316,10 @@ $ aignostics application run list [OPTIONS]
311316

312317
* `--verbose / --no-verbose`: Show application details [default: no-verbose]
313318
* `--limit INTEGER`: Maximum number of runs to display
319+
* `--tags TEXT`: Optional comma-separated list of tags to filter runs. All tags must match.
320+
* `--note-regex TEXT`: Optional regex pattern to filter runs by note metadata.
321+
* `--query TEXT`: Optional query string to filter runs by note OR tags.
322+
* `--note-case-insensitive / --no-note-case-insensitive`: Make note regex search case-insensitive. [default: note-case-insensitive]
314323
* `--help`: Show this message and exit.
315324

316325
#### `aignostics application run describe`
@@ -331,6 +340,45 @@ $ aignostics application run describe [OPTIONS] RUN_ID
331340

332341
* `--help`: Show this message and exit.
333342

343+
#### `aignostics application run dump-metadata`
344+
345+
Dump custom metadata of a run as JSON to stdout.
346+
347+
**Usage**:
348+
349+
```console
350+
$ aignostics application run dump-metadata [OPTIONS] RUN_ID
351+
```
352+
353+
**Arguments**:
354+
355+
* `RUN_ID`: Id of the run to dump custom metadata for [required]
356+
357+
**Options**:
358+
359+
* `--pretty / --no-pretty`: Pretty print JSON output with indentation [default: no-pretty]
360+
* `--help`: Show this message and exit.
361+
362+
#### `aignostics application run dump-item-metadata`
363+
364+
Dump custom metadata of an item as JSON to stdout.
365+
366+
**Usage**:
367+
368+
```console
369+
$ aignostics application run dump-item-metadata [OPTIONS] RUN_ID EXTERNAL_ID
370+
```
371+
372+
**Arguments**:
373+
374+
* `RUN_ID`: Id of the run containing the item [required]
375+
* `EXTERNAL_ID`: External ID of the item to dump custom metadata for [required]
376+
377+
**Options**:
378+
379+
* `--pretty / --no-pretty`: Pretty print JSON output with indentation [default: no-pretty]
380+
* `--help`: Show this message and exit.
381+
334382
#### `aignostics application run cancel`
335383

336384
Cancel run.
@@ -349,6 +397,45 @@ $ aignostics application run cancel [OPTIONS] RUN_ID
349397

350398
* `--help`: Show this message and exit.
351399

400+
#### `aignostics application run update-metadata`
401+
402+
Update custom metadata for a run.
403+
404+
**Usage**:
405+
406+
```console
407+
$ aignostics application run update-metadata [OPTIONS] RUN_ID METADATA_JSON
408+
```
409+
410+
**Arguments**:
411+
412+
* `RUN_ID`: Id of the run to update [required]
413+
* `METADATA_JSON`: Custom metadata as JSON string (e.g., '{"key": "value"}') [required]
414+
415+
**Options**:
416+
417+
* `--help`: Show this message and exit.
418+
419+
#### `aignostics application run update-item-metadata`
420+
421+
Update custom metadata for an item in a run.
422+
423+
**Usage**:
424+
425+
```console
426+
$ aignostics application run update-item-metadata [OPTIONS] RUN_ID EXTERNAL_ID METADATA_JSON
427+
```
428+
429+
**Arguments**:
430+
431+
* `RUN_ID`: Id of the run containing the item [required]
432+
* `EXTERNAL_ID`: External ID of the item to update [required]
433+
* `METADATA_JSON`: Custom metadata as JSON string (e.g., '{"key": "value"}') [required]
434+
435+
**Options**:
436+
437+
* `--help`: Show this message and exit.
438+
352439
#### `aignostics application run result`
353440

354441
Download or delete run results.
@@ -644,9 +731,6 @@ WHERE
644731

645732
Download from manifest file, identifier, or comma-separate set of identifiers.
646733

647-
Raises:
648-
typer.Exit: If the target directory does not exist.
649-
650734
**Usage**:
651735

652736
```console
@@ -655,7 +739,7 @@ $ aignostics dataset idc download [OPTIONS] SOURCE [TARGET]
655739

656740
**Arguments**:
657741

658-
* `SOURCE`: Identifier or comma-separated set of identifiers. IDs matched against collection_id, PatientId, StudyInstanceUID, SeriesInstanceUID or SOPInstanceUID. [required]
742+
* `SOURCE`: Identifier or comma-separated set of identifiers. IDs matched against collection_id, PatientId, StudyInstanceUID, SeriesInstanceUID or SOPInstanceUID. Example: 1.3.6.1.4.1.5962.99.1.1069745200.1645485340.1637452317744.2.0 [required]
659743
* `[TARGET]`: target directory for download [default: /Users/helmut/Library/Application Support/aignostics/datasets/idc]
660744

661745
**Options**:
@@ -694,7 +778,7 @@ $ aignostics dataset aignostics download [OPTIONS] SOURCE_URL [DESTINATION_DIREC
694778

695779
**Arguments**:
696780

697-
* `SOURCE_URL`: URL to download, e.g. gs://aignx-storage-service-dev/sample_data_formatted/9375e3ed-28d2-4cf3-9fb9-8df9d11a6627.tiff [required]
781+
* `SOURCE_URL`: URL to download. Example: gs://aignx-storage-service-dev/sample_data_formatted/9375e3ed-28d2-4cf3-9fb9-8df9d11a6627.tiff [required]
698782
* `[DESTINATION_DIRECTORY]`: Destination directory to download to [default: /Users/helmut/Library/Application Support/aignostics/datasets/aignostics]
699783

700784
**Options**:

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.195
1+
0.2.196

docs/source/_static/sdk_item_custom_metadata_schema_latest.json

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,33 @@
3737
"title": "Schema Version",
3838
"type": "string"
3939
},
40+
"created_at": {
41+
"description": "ISO 8601 timestamp when the metadata was first created",
42+
"title": "Created At",
43+
"type": "string"
44+
},
45+
"updated_at": {
46+
"description": "ISO 8601 timestamp when the metadata was last updated",
47+
"title": "Updated At",
48+
"type": "string"
49+
},
50+
"tags": {
51+
"anyOf": [
52+
{
53+
"items": {
54+
"type": "string"
55+
},
56+
"type": "array",
57+
"uniqueItems": true
58+
},
59+
{
60+
"type": "null"
61+
}
62+
],
63+
"default": null,
64+
"description": "Optional list of tags associated with the item",
65+
"title": "Tags"
66+
},
4067
"platform_bucket": {
4168
"anyOf": [
4269
{
@@ -51,10 +78,12 @@
5178
}
5279
},
5380
"required": [
54-
"schema_version"
81+
"schema_version",
82+
"created_at",
83+
"updated_at"
5584
],
5685
"title": "ItemSdkMetadata",
5786
"type": "object",
5887
"$schema": "https://json-schema.org/draft/2020-12/schema",
59-
"$id": "https://raw.githubusercontent.com/aignostics/python-sdk/main/docs/source/_static/item_sdk_metadata_schema_v0.0.1.json"
88+
"$id": "https://raw.githubusercontent.com/aignostics/python-sdk/main/docs/source/_static/item_sdk_metadata_schema_v0.0.3.json"
6089
}

0 commit comments

Comments
 (0)