From d5c0d680b0128be437f3eef1778d6942c0581e8e Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Wed, 28 Jan 2026 19:27:49 +0100 Subject: [PATCH 1/7] Added MTR test service so we can test the UIs --- notebooks/client-api.ipynb | 588 ++++---------- notebooks/client-cli.ipynb | 4 + notebooks/client-gui.ipynb | 759 +----------------- pixi.lock | 181 +++-- pyproject.toml | 26 +- s2gos-client/src/s2gos_client/__init__.py | 11 - s2gos-client/src/s2gos_client/api.py | 24 +- s2gos-client/src/s2gos_client/cli.py | 7 +- s2gos-client/src/s2gos_client/defaults.py | 14 - s2gos-client/src/s2gos_client/gui.py | 8 +- s2gos-server/pyproject.toml | 2 + s2gos-server/src/s2gos_server/services/io.py | 133 +++ .../src/s2gos_server/services/testing.py | 257 ++++++ 13 files changed, 718 insertions(+), 1296 deletions(-) delete mode 100644 s2gos-client/src/s2gos_client/defaults.py create mode 100644 s2gos-server/src/s2gos_server/services/io.py create mode 100644 s2gos-server/src/s2gos_server/services/testing.py diff --git a/notebooks/client-api.ipynb b/notebooks/client-api.ipynb index e448148..7173bc1 100644 --- a/notebooks/client-api.ipynb +++ b/notebooks/client-api.ipynb @@ -25,6 +25,10 @@ "with a test configuration:\n", "\n", "```bash\n", + "s2gos-server run -- s2gos_server.services.testing:service\n", + "```\n", + "or\n", + "```bash\n", "s2gos-server run -- wraptile.services.local.testing:service\n", "```" ] @@ -49,12 +53,19 @@ { "data": { "application/json": { - "access_token": "1234", - "server_url": "http://127.0.0.1:8008", - "user_name": "bibo" + "api_key": null, + "api_key_header": "X-API-Key", + "api_url": "http://localhost:8008/", + "auth_type": "none", + "auth_url": null, + "password": null, + "token": null, + "token_header": "X-Auth-Token", + "use_bearer": false, + "username": null }, "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -80,111 +91,111 @@ { "data": { "application/json": { - "description": "Local test server implementing the OGC API - Processes 1.0 Standard", + "description": "Local DTE-S2GOS process server for testing", "links": [ { - "href": "http://127.0.0.1:8008/", + "href": "http://localhost:8008/", "hreflang": "en", "rel": "self", "title": "get_capabilities", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/openapi.json", + "href": "http://localhost:8008/openapi.json", "hreflang": "en", "rel": "service", "title": "openapi", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/docs", + "href": "http://localhost:8008/docs", "hreflang": "en", "rel": "service", "title": "swagger_ui_html", "type": "text/html" }, { - "href": "http://127.0.0.1:8008/docs/oauth2-redirect", + "href": "http://localhost:8008/docs/oauth2-redirect", "hreflang": "en", "rel": "service", "title": "swagger_ui_redirect", "type": "text/html" }, { - "href": "http://127.0.0.1:8008/redoc", + "href": "http://localhost:8008/redoc", "hreflang": "en", "rel": "service", "title": "redoc_html", "type": "text/html" }, { - "href": "http://127.0.0.1:8008/", + "href": "http://localhost:8008/", "hreflang": "en", "rel": "service", "title": "get_capabilities", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/conformance", + "href": "http://localhost:8008/conformance", "hreflang": "en", "rel": "service", "title": "get_conformance", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/processes", + "href": "http://localhost:8008/processes", "hreflang": "en", "rel": "service", "title": "get_processes", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/processes/{processID}", + "href": "http://localhost:8008/processes/{processID}", "hreflang": "en", "rel": "service", "title": "get_process", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/processes/{processID}/execution", + "href": "http://localhost:8008/processes/{processID}/execution", "hreflang": "en", "rel": "service", "title": "execute_process", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/jobs", + "href": "http://localhost:8008/jobs", "hreflang": "en", "rel": "service", "title": "get_jobs", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/jobs/{jobId}", + "href": "http://localhost:8008/jobs/{jobId}", "hreflang": "en", "rel": "service", "title": "get_job", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/jobs/{jobId}", + "href": "http://localhost:8008/jobs/{jobId}", "hreflang": "en", "rel": "service", "title": "dismiss_job", "type": "application/json" }, { - "href": "http://127.0.0.1:8008/jobs/{jobId}/results", + "href": "http://localhost:8008/jobs/{jobId}/results", "hreflang": "en", "rel": "service", "title": "get_job_results", "type": "application/json" } ], - "title": "Eozilla API Server (local dummy for testing)" + "title": "S2GOS Test-Server" }, "text/plain": [ - "Capabilities(title='Eozilla API Server (local dummy for testing)', description='Local test server implementing the OGC API - Processes 1.0 Standard', links=[Link(href='http://127.0.0.1:8008/', rel='self', type='application/json', hreflang='en', title='get_capabilities'), Link(href='http://127.0.0.1:8008/openapi.json', rel='service', type='application/json', hreflang='en', title='openapi'), Link(href='http://127.0.0.1:8008/docs', rel='service', type='text/html', hreflang='en', title='swagger_ui_html'), Link(href='http://127.0.0.1:8008/docs/oauth2-redirect', rel='service', type='text/html', hreflang='en', title='swagger_ui_redirect'), Link(href='http://127.0.0.1:8008/redoc', rel='service', type='text/html', hreflang='en', title='redoc_html'), Link(href='http://127.0.0.1:8008/', rel='service', type='application/json', hreflang='en', title='get_capabilities'), Link(href='http://127.0.0.1:8008/conformance', rel='service', type='application/json', hreflang='en', title='get_conformance'), Link(href='http://127.0.0.1:8008/processes', rel='service', type='application/json', hreflang='en', title='get_processes'), Link(href='http://127.0.0.1:8008/processes/{processID}', rel='service', type='application/json', hreflang='en', title='get_process'), Link(href='http://127.0.0.1:8008/processes/{processID}/execution', rel='service', type='application/json', hreflang='en', title='execute_process'), Link(href='http://127.0.0.1:8008/jobs', rel='service', type='application/json', hreflang='en', title='get_jobs'), Link(href='http://127.0.0.1:8008/jobs/{jobId}', rel='service', type='application/json', hreflang='en', title='get_job'), Link(href='http://127.0.0.1:8008/jobs/{jobId}', rel='service', type='application/json', hreflang='en', title='dismiss_job'), Link(href='http://127.0.0.1:8008/jobs/{jobId}/results', rel='service', type='application/json', hreflang='en', title='get_job_results')])" + "Capabilities(title='S2GOS Test-Server', description='Local DTE-S2GOS process server for testing', links=[Link(href='http://localhost:8008/', rel='self', type='application/json', hreflang='en', title='get_capabilities'), Link(href='http://localhost:8008/openapi.json', rel='service', type='application/json', hreflang='en', title='openapi'), Link(href='http://localhost:8008/docs', rel='service', type='text/html', hreflang='en', title='swagger_ui_html'), Link(href='http://localhost:8008/docs/oauth2-redirect', rel='service', type='text/html', hreflang='en', title='swagger_ui_redirect'), Link(href='http://localhost:8008/redoc', rel='service', type='text/html', hreflang='en', title='redoc_html'), Link(href='http://localhost:8008/', rel='service', type='application/json', hreflang='en', title='get_capabilities'), Link(href='http://localhost:8008/conformance', rel='service', type='application/json', hreflang='en', title='get_conformance'), Link(href='http://localhost:8008/processes', rel='service', type='application/json', hreflang='en', title='get_processes'), Link(href='http://localhost:8008/processes/{processID}', rel='service', type='application/json', hreflang='en', title='get_process'), Link(href='http://localhost:8008/processes/{processID}/execution', rel='service', type='application/json', hreflang='en', title='execute_process'), Link(href='http://localhost:8008/jobs', rel='service', type='application/json', hreflang='en', title='get_jobs'), Link(href='http://localhost:8008/jobs/{jobId}', rel='service', type='application/json', hreflang='en', title='get_job'), Link(href='http://localhost:8008/jobs/{jobId}', rel='service', type='application/json', hreflang='en', title='dismiss_job'), Link(href='http://localhost:8008/jobs/{jobId}/results', rel='service', type='application/json', hreflang='en', title='get_job_results')])" ] }, "execution_count": 3, @@ -246,7 +257,7 @@ "application/json": { "links": [ { - "href": "http://127.0.0.1:8008/processes", + "href": "http://localhost:8008/processes", "hreflang": "en", "rel": "self", "title": "get_processes", @@ -255,32 +266,19 @@ ], "processes": [ { - "description": "Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.", - "id": "sleep_a_while", - "title": "Sleep Processor", - "version": "0.0.0" - }, - { - "description": "Returns the list of prime numbers between a `min_val` and `max_val`.", - "id": "primes_between", - "title": "Prime Processor", - "version": "0.0.0" - }, - { - "description": "Simulate a set scene images slices for testing. Creates an xarray dataset with `periodicity` time slices and writes it as Zarr into a temporary location. Requires installed `dask`, `xarray`, and `zarr` packages.", - "id": "simulate_scene", - "title": "Generate scene for testing", + "description": "Generate 3D scene for MTR demo with seasonal variations.\n\nThis processor:\n1. Creates a scene generation configuration based on season/month\n2. Immediately runs the generation pipeline\n3. Returns path to the generated scene description YAML\n\nThe scene includes:\n- PNP location with 10km target area\n- Seasonal vegetation (summer/winter variants)\n- Heterogeneous atmosphere with aerosol layer\n- Tower XML scene at fixed location\n- Optional snow cover (June only)\n\nArgs:\n month: Month for simulation (controls seasonal variations)\n random_seed: Random seed for reproducible vegetation placement\n config_output_dir: Optional directory for generation config JSON\n scene_output_dir: Optional directory for scene description YAML\n\nReturns:\n Path to generated scene description YAML file, or None if validation fails", + "id": "mtr_demo_generation", "version": "0.0.0" }, { - "id": "return_base_model", - "title": "BaseModel Test", + "description": "Run simulation for MTR demo with configurable observation types.\n\nThis processor:\n1. Creates a simulation configuration based on observation type\n2. Immediately runs the simulation\n3. Returns path to the simulation output directory\n\nSupported observation types:\n- CHIME: Hyperspectral satellite sensor\n- MSI: Sentinel-2 multispectral sensor (configurable bands)\n- HYPSTAR: Ground-based hyperspectral sensor with HCRF processing\n- RGB_CAMERA: Perspective camera viewing tower from configurable position\n- SATELLITE_HDRF: [PLACEHOLDER - To be implemented]\n\nArgs:\n scene_description_path: Path to scene YAML from generation step\n month: Month for simulation (determines observation date)\n hour_utc: Hour of observation in UTC\n observation: Observation type configuration\n spp: Samples per pixel for Monte Carlo simulation\n config_output_dir: Optional directory for simulation config JSON\n simulation_output_dir: Optional directory for simulation outputs\n\nReturns:\n Path to simulation output directory, or None if observation type\n is not yet implemented or simulation fails", + "id": "mtr_demo_simulation", "version": "0.0.0" } ] }, "text/plain": [ - "ProcessList(processes=[ProcessSummary(title='Sleep Processor', description='Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.', keywords=None, metadata=None, additionalParameters=None, id='sleep_a_while', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Prime Processor', description='Returns the list of prime numbers between a `min_val` and `max_val`.', keywords=None, metadata=None, additionalParameters=None, id='primes_between', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Generate scene for testing', description='Simulate a set scene images slices for testing. Creates an xarray dataset with `periodicity` time slices and writes it as Zarr into a temporary location. Requires installed `dask`, `xarray`, and `zarr` packages.', keywords=None, metadata=None, additionalParameters=None, id='simulate_scene', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='BaseModel Test', description=None, keywords=None, metadata=None, additionalParameters=None, id='return_base_model', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], links=[Link(href='http://127.0.0.1:8008/processes', rel='self', type='application/json', hreflang='en', title='get_processes')])" + "ProcessList(processes=[ProcessSummary(title=None, description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n config_output_dir: Optional directory for generation config JSON\\n scene_output_dir: Optional directory for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title=None, description='Run simulation for MTR demo with configurable observation types.\\n\\nThis processor:\\n1. Creates a simulation configuration based on observation type\\n2. Immediately runs the simulation\\n3. Returns path to the simulation output directory\\n\\nSupported observation types:\\n- CHIME: Hyperspectral satellite sensor\\n- MSI: Sentinel-2 multispectral sensor (configurable bands)\\n- HYPSTAR: Ground-based hyperspectral sensor with HCRF processing\\n- RGB_CAMERA: Perspective camera viewing tower from configurable position\\n- SATELLITE_HDRF: [PLACEHOLDER - To be implemented]\\n\\nArgs:\\n scene_description_path: Path to scene YAML from generation step\\n month: Month for simulation (determines observation date)\\n hour_utc: Hour of observation in UTC\\n observation: Observation type configuration\\n spp: Samples per pixel for Monte Carlo simulation\\n config_output_dir: Optional directory for simulation config JSON\\n simulation_output_dir: Optional directory for simulation outputs\\n\\nReturns:\\n Path to simulation output directory, or None if observation type\\n is not yet implemented or simulation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_simulation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], links=[Link(href='http://localhost:8008/processes', rel='self', type='application/json', hreflang='en', title='get_processes')])" ] }, "execution_count": 5, @@ -298,49 +296,122 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "a629ba21-e389-4131-ae84-2ce5c5fc7aa9", "metadata": {}, "outputs": [ { "data": { "application/json": { - "description": "Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.", - "id": "sleep_a_while", + "description": "Generate 3D scene for MTR demo with seasonal variations.\n\nThis processor:\n1. Creates a scene generation configuration based on season/month\n2. Immediately runs the generation pipeline\n3. Returns path to the generated scene description YAML\n\nThe scene includes:\n- PNP location with 10km target area\n- Seasonal vegetation (summer/winter variants)\n- Heterogeneous atmosphere with aerosol layer\n- Tower XML scene at fixed location\n- Optional snow cover (June only)\n\nArgs:\n month: Month for simulation (controls seasonal variations)\n random_seed: Random seed for reproducible vegetation placement\n config_output_dir: Optional directory for generation config JSON\n scene_output_dir: Optional directory for scene description YAML\n\nReturns:\n Path to generated scene description YAML file, or None if validation fails", + "id": "mtr_demo_generation", "inputs": { - "duration": { + "config_output_dir": { + "description": "Path configuration that preserves credential reference through serialization.\n\nThis model allows paths to reference credentials by ID rather than embedding\nactual credentials. When serialized to JSON, only the path value and credential_id\nare stored (no actual credentials). When deserialized, credentials are resolved\nfrom the credential provider (environment variables or .secrets.yaml).\n\nAttributes:\n value: The actual path/URI\n cid: Optional reference to a Credential ID in the credential provider\n\nExample:\n # With credentials\n path = PathRef(\n path=\"https://data.earthdatahub.destine.eu/data.zarr\",\n cid=\"earthdatahub\"\n )\n\n # Without credentials (public or local path)\n path = PathRef(\"/local/path/data.zarr\")\n\n # Access the authenticated UPath\n upath = path.upath", + "minOccurs": 0, + "schema": { + "nullable": true, + "properties": { + "cid": { + "description": "Credential ID", + "nullable": true, + "title": "Cid", + "type": "string" + }, + "value": { + "description": "Full path URI", + "title": "Value", + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "title": "PathRef" + }, + "month": { + "description": "Month selection for MTR demo (limited to solstice dates).", + "minOccurs": 0, + "schema": { + "default": "december", + "enum": [ + "december", + "june" + ], + "type": "string" + }, + "title": "Month" + }, + "random_seed": { + "description": "RNG seed for vegetation placement", "minOccurs": 0, "schema": { - "default": 10, - "type": "number" + "default": 13, + "type": "integer" }, - "title": "Duration" + "title": "Random Seed" }, - "fail": { + "scene_output_dir": { + "description": "Path configuration that preserves credential reference through serialization.\n\nThis model allows paths to reference credentials by ID rather than embedding\nactual credentials. When serialized to JSON, only the path value and credential_id\nare stored (no actual credentials). When deserialized, credentials are resolved\nfrom the credential provider (environment variables or .secrets.yaml).\n\nAttributes:\n value: The actual path/URI\n cid: Optional reference to a Credential ID in the credential provider\n\nExample:\n # With credentials\n path = PathRef(\n path=\"https://data.earthdatahub.destine.eu/data.zarr\",\n cid=\"earthdatahub\"\n )\n\n # Without credentials (public or local path)\n path = PathRef(\"/local/path/data.zarr\")\n\n # Access the authenticated UPath\n upath = path.upath", "minOccurs": 0, "schema": { - "default": false, - "type": "boolean" + "nullable": true, + "properties": { + "cid": { + "description": "Credential ID", + "nullable": true, + "title": "Cid", + "type": "string" + }, + "value": { + "description": "Full path URI", + "title": "Value", + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" }, - "title": "Fail" + "title": "PathRef" } }, "outputs": { "return_value": { + "description": "Path configuration that preserves credential reference through serialization.\n\nThis model allows paths to reference credentials by ID rather than embedding\nactual credentials. When serialized to JSON, only the path value and credential_id\nare stored (no actual credentials). When deserialized, credentials are resolved\nfrom the credential provider (environment variables or .secrets.yaml).\n\nAttributes:\n value: The actual path/URI\n cid: Optional reference to a Credential ID in the credential provider\n\nExample:\n # With credentials\n path = PathRef(\n path=\"https://data.earthdatahub.destine.eu/data.zarr\",\n cid=\"earthdatahub\"\n )\n\n # Without credentials (public or local path)\n path = PathRef(\"/local/path/data.zarr\")\n\n # Access the authenticated UPath\n upath = path.upath", "schema": { - "type": "number" + "nullable": true, + "properties": { + "cid": { + "description": "Credential ID", + "nullable": true, + "title": "Cid", + "type": "string" + }, + "value": { + "description": "Full path URI", + "title": "Value", + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" }, - "title": "Return Value" + "title": "PathRef" } }, - "title": "Sleep Processor", "version": "0.0.0" }, "text/plain": [ - "ProcessDescription(title='Sleep Processor', description='Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.', keywords=None, metadata=None, additionalParameters=None, id='sleep_a_while', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'duration': InputDescription(title='Duration', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=10.0, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'fail': InputDescription(title='Fail', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=False, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Return Value', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})" + "ProcessDescription(title=None, description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n config_output_dir: Optional directory for generation config JSON\\n scene_output_dir: Optional directory for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'month': InputDescription(title='Month', description='Month selection for MTR demo (limited to solstice dates).', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=['december', 'june'], type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default='december', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'random_seed': InputDescription(title='Random Seed', description='RNG seed for vegetation placement', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=13, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'config_output_dir': InputDescription(title='PathRef', description='Path configuration that preserves credential reference through serialization.\\n\\nThis model allows paths to reference credentials by ID rather than embedding\\nactual credentials. When serialized to JSON, only the path value and credential_id\\nare stored (no actual credentials). When deserialized, credentials are resolved\\nfrom the credential provider (environment variables or .secrets.yaml).\\n\\nAttributes:\\n value: The actual path/URI\\n cid: Optional reference to a Credential ID in the credential provider\\n\\nExample:\\n # With credentials\\n path = PathRef(\\n path=\"https://data.earthdatahub.destine.eu/data.zarr\",\\n cid=\"earthdatahub\"\\n )\\n\\n # Without credentials (public or local path)\\n path = PathRef(\"/local/path/data.zarr\")\\n\\n # Access the authenticated UPath\\n upath = path.upath', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=['value'], enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties={'value': Schema(field_ref=None, title='Value', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description='Full path URI', format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'cid': Schema(field_ref=None, title='Cid', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description='Credential ID', format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)}, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'scene_output_dir': InputDescription(title='PathRef', description='Path configuration that preserves credential reference through serialization.\\n\\nThis model allows paths to reference credentials by ID rather than embedding\\nactual credentials. When serialized to JSON, only the path value and credential_id\\nare stored (no actual credentials). When deserialized, credentials are resolved\\nfrom the credential provider (environment variables or .secrets.yaml).\\n\\nAttributes:\\n value: The actual path/URI\\n cid: Optional reference to a Credential ID in the credential provider\\n\\nExample:\\n # With credentials\\n path = PathRef(\\n path=\"https://data.earthdatahub.destine.eu/data.zarr\",\\n cid=\"earthdatahub\"\\n )\\n\\n # Without credentials (public or local path)\\n path = PathRef(\"/local/path/data.zarr\")\\n\\n # Access the authenticated UPath\\n upath = path.upath', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=['value'], enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties={'value': Schema(field_ref=None, title='Value', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description='Full path URI', format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'cid': Schema(field_ref=None, title='Cid', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description='Credential ID', format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)}, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='PathRef', description='Path configuration that preserves credential reference through serialization.\\n\\nThis model allows paths to reference credentials by ID rather than embedding\\nactual credentials. When serialized to JSON, only the path value and credential_id\\nare stored (no actual credentials). When deserialized, credentials are resolved\\nfrom the credential provider (environment variables or .secrets.yaml).\\n\\nAttributes:\\n value: The actual path/URI\\n cid: Optional reference to a Credential ID in the credential provider\\n\\nExample:\\n # With credentials\\n path = PathRef(\\n path=\"https://data.earthdatahub.destine.eu/data.zarr\",\\n cid=\"earthdatahub\"\\n )\\n\\n # Without credentials (public or local path)\\n path = PathRef(\"/local/path/data.zarr\")\\n\\n # Access the authenticated UPath\\n upath = path.upath', keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=['value'], enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties={'value': Schema(field_ref=None, title='Value', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description='Full path URI', format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'cid': Schema(field_ref=None, title='Cid', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description='Credential ID', format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)}, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": { "application/json": { "root": "ProcessDescription object:" @@ -350,393 +421,72 @@ } ], "source": [ - "client.get_process(process_id=\"sleep_a_while\")" + "client.get_process(process_id=\"mtr_demo_generation\")" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "e4e20f28-0ed4-4e30-9fcd-23238a7d06a0", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "jobs": [ - { - "created": "2025-11-13T17:58:50.670036Z", - "finished": "2025-11-13T17:59:00.820523Z", - "jobID": "job_0", - "processID": "sleep_a_while", - "progress": 100, - "started": "2025-11-13T17:58:50.670374Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T17:59:00.720409Z" - }, - { - "created": "2025-11-13T17:58:56.296245Z", - "finished": "2025-11-13T17:59:11.321416Z", - "jobID": "job_1", - "message": "Woke up too early", - "processID": "sleep_a_while", - "progress": 50, - "started": "2025-11-13T17:58:56.296554Z", - "status": "failed", - "traceback": [ - "Traceback (most recent call last):\n", - " File \"C:\\Users\\Norman\\Projects\\s2gos-controller\\.pixi\\envs\\default\\Lib\\site-packages\\procodile\\job.py\", line 263, in run\n function_result = self.process.function(**function_kwargs)\n", - " File \"C:\\Users\\Norman\\Projects\\s2gos-controller\\.pixi\\envs\\default\\Lib\\site-packages\\wraptile\\services\\local\\testing.py\", line 42, in sleep_a_while\n raise RuntimeError(\"Woke up too early\")\n", - "RuntimeError: Woke up too early\n" - ], - "type": "process", - "updated": "2025-11-13T17:59:11.321345Z" - }, - { - "created": "2025-11-13T17:59:17.898138Z", - "finished": "2025-11-13T17:59:38.153405Z", - "jobID": "job_2", - "processID": "sleep_a_while", - "progress": 100, - "started": "2025-11-13T17:59:17.898503Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T17:59:37.952697Z" - }, - { - "created": "2025-11-13T18:01:10.775835Z", - "finished": "2025-11-13T18:01:13.176371Z", - "jobID": "job_3", - "processID": "simulate_scene", - "started": "2025-11-13T18:01:10.776288Z", - "status": "successful", - "type": "process" - }, - { - "created": "2025-11-13T18:01:20.568455Z", - "finished": "2025-11-13T18:01:20.648477Z", - "jobID": "job_4", - "processID": "simulate_scene", - "started": "2025-11-13T18:01:20.568998Z", - "status": "successful", - "type": "process" - }, - { - "created": "2025-11-13T18:02:35.468838Z", - "finished": "2025-11-13T18:02:35.469317Z", - "jobID": "job_5", - "message": "Done", - "processID": "primes_between", - "started": "2025-11-13T18:02:35.469254Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T18:02:35.469310Z" - } - ], - "links": [ - { - "href": "http://127.0.0.1:8008/jobs", - "hreflang": "en", - "rel": "self", - "title": "get_jobs", - "type": "application/json" - } - ] - }, - "text/plain": [ - "JobList(jobs=[JobInfo(processID='sleep_a_while', type=, jobID='job_0', status=, message=None, created=datetime.datetime(2025, 11, 13, 17, 58, 50, 670036, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 58, 50, 670374, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 0, 820523, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 0, 720409, tzinfo=TzInfo(0)), progress=100, links=None, traceback=None), JobInfo(processID='sleep_a_while', type=, jobID='job_1', status=, message='Woke up too early', created=datetime.datetime(2025, 11, 13, 17, 58, 56, 296245, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 58, 56, 296554, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 11, 321416, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 11, 321345, tzinfo=TzInfo(0)), progress=50, links=None, traceback=['Traceback (most recent call last):\\n', ' File \"C:\\\\Users\\\\Norman\\\\Projects\\\\s2gos-controller\\\\.pixi\\\\envs\\\\default\\\\Lib\\\\site-packages\\\\procodile\\\\job.py\", line 263, in run\\n function_result = self.process.function(**function_kwargs)\\n', ' File \"C:\\\\Users\\\\Norman\\\\Projects\\\\s2gos-controller\\\\.pixi\\\\envs\\\\default\\\\Lib\\\\site-packages\\\\wraptile\\\\services\\\\local\\\\testing.py\", line 42, in sleep_a_while\\n raise RuntimeError(\"Woke up too early\")\\n', 'RuntimeError: Woke up too early\\n']), JobInfo(processID='sleep_a_while', type=, jobID='job_2', status=, message=None, created=datetime.datetime(2025, 11, 13, 17, 59, 17, 898138, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 59, 17, 898503, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 38, 153405, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 37, 952697, tzinfo=TzInfo(0)), progress=100, links=None, traceback=None), JobInfo(processID='simulate_scene', type=, jobID='job_3', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 1, 10, 775835, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 1, 10, 776288, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 1, 13, 176371, tzinfo=TzInfo(0)), updated=None, progress=None, links=None, traceback=None), JobInfo(processID='simulate_scene', type=, jobID='job_4', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 1, 20, 568455, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 1, 20, 568998, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 1, 20, 648477, tzinfo=TzInfo(0)), updated=None, progress=None, links=None, traceback=None), JobInfo(processID='primes_between', type=, jobID='job_5', status=, message='Done', created=datetime.datetime(2025, 11, 13, 18, 2, 35, 468838, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 35, 469254, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 2, 35, 469317, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 18, 2, 35, 469310, tzinfo=TzInfo(0)), progress=None, links=None, traceback=None)], links=[Link(href='http://127.0.0.1:8008/jobs', rel='self', type='application/json', hreflang='en', title='get_jobs')])" - ] - }, - "execution_count": 7, - "metadata": { - "application/json": { - "root": "JobList object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.get_jobs()" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "cc034916-02db-4ec2-8682-71710d54edf6", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "created": "2025-11-13T18:02:59.857140Z", - "jobID": "job_6", - "processID": "sleep_a_while", - "status": "accepted", - "type": "process" - }, - "text/plain": [ - "JobInfo(processID='sleep_a_while', type=, jobID='job_6', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 2, 59, 857140, tzinfo=TzInfo(0)), started=None, finished=None, updated=None, progress=None, links=None, traceback=None)" - ] - }, - "execution_count": 8, - "metadata": { - "application/json": { - "root": "JobInfo object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.execute_process(process_id=\"sleep_a_while\", request=ProcessRequest(duration=2))" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "4cd38b1d-5989-4991-9b62-d1981d33a46e", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "created": "2025-11-13T18:02:59.866960Z", - "jobID": "job_7", - "processID": "sleep_a_while", - "status": "accepted", - "type": "process" - }, - "text/plain": [ - "JobInfo(processID='sleep_a_while', type=, jobID='job_7', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 2, 59, 866960, tzinfo=TzInfo(0)), started=None, finished=None, updated=None, progress=None, links=None, traceback=None)" - ] - }, - "execution_count": 9, - "metadata": { - "application/json": { - "root": "JobInfo object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.execute_process(process_id=\"sleep_a_while\", request={\"fail\": True})" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "21b94f40-5a1b-408f-a3a7-52de97b05b82", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "created": "2025-11-13T18:02:59.874333Z", - "finished": "2025-11-13T18:02:59.874817Z", - "jobID": "job_8", - "message": "Done", - "processID": "primes_between", - "started": "2025-11-13T18:02:59.874757Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T18:02:59.874808Z" - }, - "text/plain": [ - "JobInfo(processID='primes_between', type=, jobID='job_8', status=, message='Done', created=datetime.datetime(2025, 11, 13, 18, 2, 59, 874333, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 59, 874757, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 2, 59, 874817, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 18, 2, 59, 874808, tzinfo=TzInfo(0)), progress=None, links=None, traceback=None)" - ] - }, - "execution_count": 10, - "metadata": { - "application/json": { - "root": "JobInfo object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.execute_process(process_id=\"primes_between\", request={})" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "9cf5e867-d91e-45dd-91b3-a54bc2d087a7", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "jobs": [ - { - "created": "2025-11-13T17:58:50.670036Z", - "finished": "2025-11-13T17:59:00.820523Z", - "jobID": "job_0", - "processID": "sleep_a_while", - "progress": 100, - "started": "2025-11-13T17:58:50.670374Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T17:59:00.720409Z" - }, - { - "created": "2025-11-13T17:58:56.296245Z", - "finished": "2025-11-13T17:59:11.321416Z", - "jobID": "job_1", - "message": "Woke up too early", - "processID": "sleep_a_while", - "progress": 50, - "started": "2025-11-13T17:58:56.296554Z", - "status": "failed", - "traceback": [ - "Traceback (most recent call last):\n", - " File \"C:\\Users\\Norman\\Projects\\s2gos-controller\\.pixi\\envs\\default\\Lib\\site-packages\\procodile\\job.py\", line 263, in run\n function_result = self.process.function(**function_kwargs)\n", - " File \"C:\\Users\\Norman\\Projects\\s2gos-controller\\.pixi\\envs\\default\\Lib\\site-packages\\wraptile\\services\\local\\testing.py\", line 42, in sleep_a_while\n raise RuntimeError(\"Woke up too early\")\n", - "RuntimeError: Woke up too early\n" - ], - "type": "process", - "updated": "2025-11-13T17:59:11.321345Z" - }, - { - "created": "2025-11-13T17:59:17.898138Z", - "finished": "2025-11-13T17:59:38.153405Z", - "jobID": "job_2", - "processID": "sleep_a_while", - "progress": 100, - "started": "2025-11-13T17:59:17.898503Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T17:59:37.952697Z" - }, - { - "created": "2025-11-13T18:01:10.775835Z", - "finished": "2025-11-13T18:01:13.176371Z", - "jobID": "job_3", - "processID": "simulate_scene", - "started": "2025-11-13T18:01:10.776288Z", - "status": "successful", - "type": "process" - }, - { - "created": "2025-11-13T18:01:20.568455Z", - "finished": "2025-11-13T18:01:20.648477Z", - "jobID": "job_4", - "processID": "simulate_scene", - "started": "2025-11-13T18:01:20.568998Z", - "status": "successful", - "type": "process" - }, - { - "created": "2025-11-13T18:02:35.468838Z", - "finished": "2025-11-13T18:02:35.469317Z", - "jobID": "job_5", - "message": "Done", - "processID": "primes_between", - "started": "2025-11-13T18:02:35.469254Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T18:02:35.469310Z" - }, - { - "created": "2025-11-13T18:02:59.857140Z", - "jobID": "job_6", - "processID": "sleep_a_while", - "progress": 0, - "started": "2025-11-13T18:02:59.857825Z", - "status": "running", - "type": "process", - "updated": "2025-11-13T18:02:59.857854Z" - }, - { - "created": "2025-11-13T18:02:59.866960Z", - "jobID": "job_7", - "processID": "sleep_a_while", - "progress": 0, - "started": "2025-11-13T18:02:59.867467Z", - "status": "running", - "type": "process", - "updated": "2025-11-13T18:02:59.867491Z" - }, - { - "created": "2025-11-13T18:02:59.874333Z", - "finished": "2025-11-13T18:02:59.874817Z", - "jobID": "job_8", - "message": "Done", - "processID": "primes_between", - "started": "2025-11-13T18:02:59.874757Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T18:02:59.874808Z" - } - ], - "links": [ - { - "href": "http://127.0.0.1:8008/jobs", - "hreflang": "en", - "rel": "self", - "title": "get_jobs", - "type": "application/json" - } - ] - }, - "text/plain": [ - "JobList(jobs=[JobInfo(processID='sleep_a_while', type=, jobID='job_0', status=, message=None, created=datetime.datetime(2025, 11, 13, 17, 58, 50, 670036, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 58, 50, 670374, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 0, 820523, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 0, 720409, tzinfo=TzInfo(0)), progress=100, links=None, traceback=None), JobInfo(processID='sleep_a_while', type=, jobID='job_1', status=, message='Woke up too early', created=datetime.datetime(2025, 11, 13, 17, 58, 56, 296245, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 58, 56, 296554, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 11, 321416, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 11, 321345, tzinfo=TzInfo(0)), progress=50, links=None, traceback=['Traceback (most recent call last):\\n', ' File \"C:\\\\Users\\\\Norman\\\\Projects\\\\s2gos-controller\\\\.pixi\\\\envs\\\\default\\\\Lib\\\\site-packages\\\\procodile\\\\job.py\", line 263, in run\\n function_result = self.process.function(**function_kwargs)\\n', ' File \"C:\\\\Users\\\\Norman\\\\Projects\\\\s2gos-controller\\\\.pixi\\\\envs\\\\default\\\\Lib\\\\site-packages\\\\wraptile\\\\services\\\\local\\\\testing.py\", line 42, in sleep_a_while\\n raise RuntimeError(\"Woke up too early\")\\n', 'RuntimeError: Woke up too early\\n']), JobInfo(processID='sleep_a_while', type=, jobID='job_2', status=, message=None, created=datetime.datetime(2025, 11, 13, 17, 59, 17, 898138, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 59, 17, 898503, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 38, 153405, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 37, 952697, tzinfo=TzInfo(0)), progress=100, links=None, traceback=None), JobInfo(processID='simulate_scene', type=, jobID='job_3', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 1, 10, 775835, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 1, 10, 776288, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 1, 13, 176371, tzinfo=TzInfo(0)), updated=None, progress=None, links=None, traceback=None), JobInfo(processID='simulate_scene', type=, jobID='job_4', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 1, 20, 568455, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 1, 20, 568998, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 1, 20, 648477, tzinfo=TzInfo(0)), updated=None, progress=None, links=None, traceback=None), JobInfo(processID='primes_between', type=, jobID='job_5', status=, message='Done', created=datetime.datetime(2025, 11, 13, 18, 2, 35, 468838, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 35, 469254, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 2, 35, 469317, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 18, 2, 35, 469310, tzinfo=TzInfo(0)), progress=None, links=None, traceback=None), JobInfo(processID='sleep_a_while', type=, jobID='job_6', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 2, 59, 857140, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 59, 857825, tzinfo=TzInfo(0)), finished=None, updated=datetime.datetime(2025, 11, 13, 18, 2, 59, 857854, tzinfo=TzInfo(0)), progress=0, links=None, traceback=None), JobInfo(processID='sleep_a_while', type=, jobID='job_7', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 2, 59, 866960, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 59, 867467, tzinfo=TzInfo(0)), finished=None, updated=datetime.datetime(2025, 11, 13, 18, 2, 59, 867491, tzinfo=TzInfo(0)), progress=0, links=None, traceback=None), JobInfo(processID='primes_between', type=, jobID='job_8', status=, message='Done', created=datetime.datetime(2025, 11, 13, 18, 2, 59, 874333, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 59, 874757, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 2, 59, 874817, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 18, 2, 59, 874808, tzinfo=TzInfo(0)), progress=None, links=None, traceback=None)], links=[Link(href='http://127.0.0.1:8008/jobs', rel='self', type='application/json', hreflang='en', title='get_jobs')])" - ] - }, - "execution_count": 11, - "metadata": { - "application/json": { - "root": "JobList object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.get_jobs()" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "fe96d358-084e-4e2c-af93-4c6562b0f12e", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "created": "2025-11-13T17:59:17.898138Z", - "finished": "2025-11-13T17:59:38.153405Z", - "jobID": "job_2", - "processID": "sleep_a_while", - "progress": 100, - "started": "2025-11-13T17:59:17.898503Z", - "status": "successful", - "type": "process", - "updated": "2025-11-13T17:59:37.952697Z" - }, - "text/plain": [ - "JobInfo(processID='sleep_a_while', type=, jobID='job_2', status=, message=None, created=datetime.datetime(2025, 11, 13, 17, 59, 17, 898138, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 17, 59, 17, 898503, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 17, 59, 38, 153405, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 17, 59, 37, 952697, tzinfo=TzInfo(0)), progress=100, links=None, traceback=None)" - ] - }, - "execution_count": 12, - "metadata": { - "application/json": { - "root": "JobInfo object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.get_job(\"job_2\")" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "b7f99444-d724-4451-aeae-0c23e8245dd1", "metadata": {}, "outputs": [], @@ -746,7 +496,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "736d52d8-d91a-435b-8dfb-b016a5139201", "metadata": {}, "outputs": [], @@ -757,60 +507,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "4636fdfc-3f61-40b4-889e-497c2dd50d91", "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "jobs": [ - { - "created": "2025-11-13T18:02:59.857140Z", - "finished": "2025-11-13T18:02:59.958631Z", - "jobID": "job_6", - "processID": "sleep_a_while", - "progress": 0, - "started": "2025-11-13T18:02:59.857825Z", - "status": "dismissed", - "type": "process", - "updated": "2025-11-13T18:02:59.857854Z" - }, - { - "created": "2025-11-13T18:02:59.866960Z", - "finished": "2025-11-13T18:02:59.967590Z", - "jobID": "job_7", - "processID": "sleep_a_while", - "progress": 0, - "started": "2025-11-13T18:02:59.867467Z", - "status": "dismissed", - "type": "process", - "updated": "2025-11-13T18:02:59.867491Z" - } - ], - "links": [ - { - "href": "http://127.0.0.1:8008/jobs", - "hreflang": "en", - "rel": "self", - "title": "get_jobs", - "type": "application/json" - } - ] - }, - "text/plain": [ - "JobList(jobs=[JobInfo(processID='sleep_a_while', type=, jobID='job_6', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 2, 59, 857140, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 59, 857825, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 2, 59, 958631, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 18, 2, 59, 857854, tzinfo=TzInfo(0)), progress=0, links=None, traceback=None), JobInfo(processID='sleep_a_while', type=, jobID='job_7', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 2, 59, 866960, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 2, 59, 867467, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 2, 59, 967590, tzinfo=TzInfo(0)), updated=datetime.datetime(2025, 11, 13, 18, 2, 59, 867491, tzinfo=TzInfo(0)), progress=0, links=None, traceback=None)], links=[Link(href='http://127.0.0.1:8008/jobs', rel='self', type='application/json', hreflang='en', title='get_jobs')])" - ] - }, - "execution_count": 16, - "metadata": { - "application/json": { - "root": "JobList object:" - } - }, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "client.get_jobs()" ] diff --git a/notebooks/client-cli.ipynb b/notebooks/client-cli.ipynb index 0bb256a..d26054f 100644 --- a/notebooks/client-cli.ipynb +++ b/notebooks/client-cli.ipynb @@ -26,6 +26,10 @@ "with a test configuration:\n", "\n", "```bash\n", + "s2gos-server run -- s2gos_server.services.testing:service\n", + "```\n", + "or\n", + "```bash\n", "s2gos-server run -- wraptile.services.local.testing:service\n", "```" ] diff --git a/notebooks/client-gui.ipynb b/notebooks/client-gui.ipynb index 3a0a45f..abf2aba 100644 --- a/notebooks/client-gui.ipynb +++ b/notebooks/client-gui.ipynb @@ -20,7 +20,10 @@ "If you don't have one available, you can also run the project's server \n", "with a test configuration:\n", "\n", - "\n", + "```bash\n", + "s2gos-server run -- s2gos_server.services.testing:service\n", + "```\n", + "or\n", "```bash\n", "s2gos-server run -- wraptile.services.local.testing:service\n", "```" @@ -33,745 +36,21 @@ "metadata": {}, "outputs": [ { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "(function(root) {\n", - " function now() {\n", - " return new Date();\n", - " }\n", - "\n", - " const force = true;\n", - " const py_version = '3.8.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", - " const reloading = false;\n", - " const Bokeh = root.Bokeh;\n", - "\n", - " // Set a timeout for this load but only if we are not already initializing\n", - " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", - " root._bokeh_timeout = Date.now() + 5000;\n", - " root._bokeh_failed_load = false;\n", - " }\n", - "\n", - " function run_callbacks() {\n", - " try {\n", - " root._bokeh_onload_callbacks.forEach(function(callback) {\n", - " if (callback != null)\n", - " callback();\n", - " });\n", - " } finally {\n", - " delete root._bokeh_onload_callbacks;\n", - " }\n", - " console.debug(\"Bokeh: all callbacks have finished\");\n", - " }\n", - "\n", - " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", - " if (css_urls == null) css_urls = [];\n", - " if (js_urls == null) js_urls = [];\n", - " if (js_modules == null) js_modules = [];\n", - " if (js_exports == null) js_exports = {};\n", - "\n", - " root._bokeh_onload_callbacks.push(callback);\n", - "\n", - " if (root._bokeh_is_loading > 0) {\n", - " // Don't load bokeh if it is still initializing\n", - " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", - " return null;\n", - " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", - " // There is nothing to load\n", - " run_callbacks();\n", - " return null;\n", - " }\n", - "\n", - " function on_load() {\n", - " root._bokeh_is_loading--;\n", - " if (root._bokeh_is_loading === 0) {\n", - " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", - " run_callbacks()\n", - " }\n", - " }\n", - " window._bokeh_on_load = on_load\n", - "\n", - " function on_error(e) {\n", - " const src_el = e.srcElement\n", - " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", - " }\n", - "\n", - " const skip = [];\n", - " if (window.requirejs) {\n", - " window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {}});\n", - " require([\"tabulator\"], function(Tabulator) {\n", - " window.Tabulator = Tabulator\n", - " on_load()\n", - " })\n", - " require([\"moment\"], function(moment) {\n", - " window.moment = moment\n", - " on_load()\n", - " })\n", - " require([\"notyf\"], function() {\n", - " on_load()\n", - " })\n", - " root._bokeh_is_loading = css_urls.length + 3;\n", - " } else {\n", - " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", - " }\n", - "\n", - " const existing_stylesheets = []\n", - " const links = document.getElementsByTagName('link')\n", - " for (let i = 0; i < links.length; i++) {\n", - " const link = links[i]\n", - " if (link.href != null) {\n", - " existing_stylesheets.push(link.href)\n", - " }\n", - " }\n", - " for (let i = 0; i < css_urls.length; i++) {\n", - " const url = css_urls[i];\n", - " const escaped = encodeURI(url)\n", - " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", - " on_load()\n", - " continue;\n", - " }\n", - " const element = document.createElement(\"link\");\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.rel = \"stylesheet\";\n", - " element.type = \"text/css\";\n", - " element.href = url;\n", - " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", - " document.body.appendChild(element);\n", - " } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n", - " var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n", - " for (var i = 0; i < urls.length; i++) {\n", - " skip.push(encodeURI(urls[i]))\n", - " }\n", - " } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n", - " var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n", - " for (var i = 0; i < urls.length; i++) {\n", - " skip.push(encodeURI(urls[i]))\n", - " }\n", - " } if (((window.Notyf !== undefined) && (!(window.Notyf instanceof HTMLElement))) || window.requirejs) {\n", - " var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n", - " for (var i = 0; i < urls.length; i++) {\n", - " skip.push(encodeURI(urls[i]))\n", - " }\n", - " } var existing_scripts = []\n", - " const scripts = document.getElementsByTagName('script')\n", - " for (let i = 0; i < scripts.length; i++) {\n", - " var script = scripts[i]\n", - " if (script.src != null) {\n", - " existing_scripts.push(script.src)\n", - " }\n", - " }\n", - " for (let i = 0; i < js_urls.length; i++) {\n", - " const url = js_urls[i];\n", - " const escaped = encodeURI(url)\n", - " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", - " if (!window.requirejs) {\n", - " on_load();\n", - " }\n", - " continue;\n", - " }\n", - " const element = document.createElement('script');\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.src = url;\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " document.head.appendChild(element);\n", - " }\n", - " for (let i = 0; i < js_modules.length; i++) {\n", - " const url = js_modules[i];\n", - " const escaped = encodeURI(url)\n", - " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", - " if (!window.requirejs) {\n", - " on_load();\n", - " }\n", - " continue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onload = on_load;\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.src = url;\n", - " element.type = \"module\";\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " document.head.appendChild(element);\n", - " }\n", - " for (const name in js_exports) {\n", - " const url = js_exports[name];\n", - " const escaped = encodeURI(url)\n", - " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", - " if (!window.requirejs) {\n", - " on_load();\n", - " }\n", - " continue;\n", - " }\n", - " var element = document.createElement('script');\n", - " element.onerror = on_error;\n", - " element.async = false;\n", - " element.type = \"module\";\n", - " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", - " element.textContent = `\n", - " import ${name} from \"${url}\"\n", - " window.${name} = ${name}\n", - " window._bokeh_on_load()\n", - " `\n", - " document.head.appendChild(element);\n", - " }\n", - " if (!js_urls.length && !js_modules.length) {\n", - " on_load()\n", - " }\n", - " };\n", - "\n", - " function inject_raw_css(css) {\n", - " const element = document.createElement(\"style\");\n", - " element.appendChild(document.createTextNode(css));\n", - " document.body.appendChild(element);\n", - " }\n", - "\n", - " const js_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.1.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/panel.min.js\"];\n", - " const js_modules = [];\n", - " const js_exports = {};\n", - " const css_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/font-awesome/css/all.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/css/notifications.css\"];\n", - " const inline_js = [ function(Bokeh) {\n", - " Bokeh.set_log_level(\"info\");\n", - " },\n", - "function(Bokeh) {} // ensure no trailing comma for IE\n", - " ];\n", - "\n", - " function run_inline_js() {\n", - " if ((root.Bokeh !== undefined) || (force === true)) {\n", - " for (let i = 0; i < inline_js.length; i++) {\n", - " try {\n", - " inline_js[i].call(root, root.Bokeh);\n", - " } catch(e) {\n", - " if (!reloading) {\n", - " throw e;\n", - " }\n", - " }\n", - " }\n", - " // Cache old bokeh versions\n", - " if (Bokeh != undefined && !reloading) {\n", - " var NewBokeh = root.Bokeh;\n", - " if (Bokeh.versions === undefined) {\n", - " Bokeh.versions = new Map();\n", - " }\n", - " if (NewBokeh.version !== Bokeh.version) {\n", - " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", - " }\n", - " root.Bokeh = Bokeh;\n", - " }\n", - " } else if (Date.now() < root._bokeh_timeout) {\n", - " setTimeout(run_inline_js, 100);\n", - " } else if (!root._bokeh_failed_load) {\n", - " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", - " root._bokeh_failed_load = true;\n", - " }\n", - " root._bokeh_is_initializing = false\n", - " }\n", - "\n", - " function load_or_wait() {\n", - " // Implement a backoff loop that tries to ensure we do not load multiple\n", - " // versions of Bokeh and its dependencies at the same time.\n", - " // In recent versions we use the root._bokeh_is_initializing flag\n", - " // to determine whether there is an ongoing attempt to initialize\n", - " // bokeh, however for backward compatibility we also try to ensure\n", - " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", - " // before older versions are fully initialized.\n", - " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", - " // If the timeout and bokeh was not successfully loaded we reset\n", - " // everything and try loading again\n", - " root._bokeh_timeout = Date.now() + 5000;\n", - " root._bokeh_is_initializing = false;\n", - " root._bokeh_onload_callbacks = undefined;\n", - " root._bokeh_is_loading = 0\n", - " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", - " load_or_wait();\n", - " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", - " setTimeout(load_or_wait, 100);\n", - " } else {\n", - " root._bokeh_is_initializing = true\n", - " root._bokeh_onload_callbacks = []\n", - " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", - " if (!reloading && !bokeh_loaded) {\n", - " if (root.Bokeh) {\n", - " root.Bokeh = undefined;\n", - " }\n", - " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", - " }\n", - " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", - " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", - " run_inline_js();\n", - " });\n", - " }\n", - " }\n", - " // Give older versions of the autoload script a head-start to ensure\n", - " // they initialize before we start loading newer version.\n", - " setTimeout(load_or_wait, 100)\n", - "}(window));" - ], - "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n const py_version = '3.8.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = false;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {}});\n require([\"tabulator\"], function(Tabulator) {\n window.Tabulator = Tabulator\n on_load()\n })\n require([\"moment\"], function(moment) {\n window.moment = moment\n on_load()\n })\n require([\"notyf\"], function() {\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 3;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.Notyf !== undefined) && (!(window.Notyf instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.1.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/panel.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/font-awesome/css/all.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/css/notifications.css\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": [ - "\n", - "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", - " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", - "}\n", - "\n", - "\n", - " function JupyterCommManager() {\n", - " }\n", - "\n", - " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", - " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", - " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", - " comm_manager.register_target(comm_id, function(comm) {\n", - " comm.on_msg(msg_handler);\n", - " });\n", - " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", - " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", - " comm.onMsg = msg_handler;\n", - " });\n", - " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", - " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", - " var messages = comm.messages[Symbol.asyncIterator]();\n", - " function processIteratorResult(result) {\n", - " var message = result.value;\n", - " var content = {data: message.data, comm_id};\n", - " var buffers = []\n", - " for (var buffer of message.buffers || []) {\n", - " buffers.push(new DataView(buffer))\n", - " }\n", - " var metadata = message.metadata || {};\n", - " var msg = {content, buffers, metadata}\n", - " msg_handler(msg);\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " return messages.next().then(processIteratorResult);\n", - " })\n", - " }\n", - " }\n", - "\n", - " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", - " if (comm_id in window.PyViz.comms) {\n", - " return window.PyViz.comms[comm_id];\n", - " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", - " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", - " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", - " if (msg_handler) {\n", - " comm.on_msg(msg_handler);\n", - " }\n", - " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", - " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", - " let retries = 0;\n", - " const open = () => {\n", - " if (comm.active) {\n", - " comm.open();\n", - " } else if (retries > 3) {\n", - " console.warn('Comm target never activated')\n", - " } else {\n", - " retries += 1\n", - " setTimeout(open, 500)\n", - " }\n", - " }\n", - " if (comm.active) {\n", - " comm.open();\n", - " } else {\n", - " setTimeout(open, 500)\n", - " }\n", - " if (msg_handler) {\n", - " comm.onMsg = msg_handler;\n", - " }\n", - " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", - " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", - " comm_promise.then((comm) => {\n", - " window.PyViz.comms[comm_id] = comm;\n", - " if (msg_handler) {\n", - " var messages = comm.messages[Symbol.asyncIterator]();\n", - " function processIteratorResult(result) {\n", - " var message = result.value;\n", - " var content = {data: message.data};\n", - " var metadata = message.metadata || {comm_id};\n", - " var msg = {content, metadata}\n", - " msg_handler(msg);\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " return messages.next().then(processIteratorResult);\n", - " }\n", - " })\n", - " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", - " return comm_promise.then((comm) => {\n", - " comm.send(data, metadata, buffers, disposeOnDone);\n", - " });\n", - " };\n", - " var comm = {\n", - " send: sendClosure\n", - " };\n", - " }\n", - " window.PyViz.comms[comm_id] = comm;\n", - " return comm;\n", - " }\n", - " window.PyViz.comm_manager = new JupyterCommManager();\n", - " \n", - "\n", - "\n", - "var JS_MIME_TYPE = 'application/javascript';\n", - "var HTML_MIME_TYPE = 'text/html';\n", - "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", - "var CLASS_NAME = 'output';\n", - "\n", - "/**\n", - " * Render data to the DOM node\n", - " */\n", - "function render(props, node) {\n", - " var div = document.createElement(\"div\");\n", - " var script = document.createElement(\"script\");\n", - " node.appendChild(div);\n", - " node.appendChild(script);\n", - "}\n", - "\n", - "/**\n", - " * Handle when a new output is added\n", - " */\n", - "function handle_add_output(event, handle) {\n", - " var output_area = handle.output_area;\n", - " var output = handle.output;\n", - " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", - " return\n", - " }\n", - " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", - " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", - " if (id !== undefined) {\n", - " var nchildren = toinsert.length;\n", - " var html_node = toinsert[nchildren-1].children[0];\n", - " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", - " var scripts = [];\n", - " var nodelist = html_node.querySelectorAll(\"script\");\n", - " for (var i in nodelist) {\n", - " if (nodelist.hasOwnProperty(i)) {\n", - " scripts.push(nodelist[i])\n", - " }\n", - " }\n", - "\n", - " scripts.forEach( function (oldScript) {\n", - " var newScript = document.createElement(\"script\");\n", - " var attrs = [];\n", - " var nodemap = oldScript.attributes;\n", - " for (var j in nodemap) {\n", - " if (nodemap.hasOwnProperty(j)) {\n", - " attrs.push(nodemap[j])\n", - " }\n", - " }\n", - " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", - " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", - " oldScript.parentNode.replaceChild(newScript, oldScript);\n", - " });\n", - " if (JS_MIME_TYPE in output.data) {\n", - " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", - " }\n", - " output_area._hv_plot_id = id;\n", - " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", - " window.PyViz.plot_index[id] = Bokeh.index[id];\n", - " } else {\n", - " window.PyViz.plot_index[id] = null;\n", - " }\n", - " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", - " var bk_div = document.createElement(\"div\");\n", - " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", - " var script_attrs = bk_div.children[0].attributes;\n", - " for (var i = 0; i < script_attrs.length; i++) {\n", - " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", - " }\n", - " // store reference to server id on output_area\n", - " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", - " }\n", - "}\n", - "\n", - "/**\n", - " * Handle when an output is cleared or removed\n", - " */\n", - "function handle_clear_output(event, handle) {\n", - " var id = handle.cell.output_area._hv_plot_id;\n", - " var server_id = handle.cell.output_area._bokeh_server_id;\n", - " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", - " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", - " if (server_id !== null) {\n", - " comm.send({event_type: 'server_delete', 'id': server_id});\n", - " return;\n", - " } else if (comm !== null) {\n", - " comm.send({event_type: 'delete', 'id': id});\n", - " }\n", - " delete PyViz.plot_index[id];\n", - " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", - " var doc = window.Bokeh.index[id].model.document\n", - " doc.clear();\n", - " const i = window.Bokeh.documents.indexOf(doc);\n", - " if (i > -1) {\n", - " window.Bokeh.documents.splice(i, 1);\n", - " }\n", - " }\n", - "}\n", - "\n", - "/**\n", - " * Handle kernel restart event\n", - " */\n", - "function handle_kernel_cleanup(event, handle) {\n", - " delete PyViz.comms[\"hv-extension-comm\"];\n", - " window.PyViz.plot_index = {}\n", - "}\n", - "\n", - "/**\n", - " * Handle update_display_data messages\n", - " */\n", - "function handle_update_output(event, handle) {\n", - " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", - " handle_add_output(event, handle)\n", - "}\n", - "\n", - "function register_renderer(events, OutputArea) {\n", - " function append_mime(data, metadata, element) {\n", - " // create a DOM node to render to\n", - " var toinsert = this.create_output_subarea(\n", - " metadata,\n", - " CLASS_NAME,\n", - " EXEC_MIME_TYPE\n", - " );\n", - " this.keyboard_manager.register_events(toinsert);\n", - " // Render to node\n", - " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", - " render(props, toinsert[0]);\n", - " element.append(toinsert);\n", - " return toinsert\n", - " }\n", - "\n", - " events.on('output_added.OutputArea', handle_add_output);\n", - " events.on('output_updated.OutputArea', handle_update_output);\n", - " events.on('clear_output.CodeCell', handle_clear_output);\n", - " events.on('delete.Cell', handle_clear_output);\n", - " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", - "\n", - " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", - " safe: true,\n", - " index: 0\n", - " });\n", - "}\n", - "\n", - "if (window.Jupyter !== undefined) {\n", - " try {\n", - " var events = require('base/js/events');\n", - " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", - " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", - " register_renderer(events, OutputArea);\n", - " }\n", - " } catch(err) {\n", - " }\n", - "}\n" - ], - "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n let retries = 0;\n const open = () => {\n if (comm.active) {\n comm.open();\n } else if (retries > 3) {\n console.warn('Comm target never activated')\n } else {\n retries += 1\n setTimeout(open, 500)\n }\n }\n if (comm.active) {\n comm.open();\n } else {\n setTimeout(open, 500)\n }\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "3db4e053-8ccc-4dca-bdba-7c3526244494" - } - }, - "output_type": "display_data" - }, - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "NotificationArea()" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "be58d617-c8e6-40c7-9f3c-f14869b905f0" - } - }, - "output_type": "display_data" + "ename": "ModuleNotFoundError", + "evalue": "No module named 'pydantic_settings'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mModuleNotFoundError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01ms2gos_client\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mgui\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Client\n", + "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\s2gos-controller\\s2gos-client\\src\\s2gos_client\\__init__.py:7\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mimportlib\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmetadata\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m version\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient, Client, ClientConfig, ClientError\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mdefaults\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m DEFAULT_SERVER_URL, DEFAULT_USER_NAME, DEFAULT_ACCESS_TOKEN\n\u001b[32m 12\u001b[39m __version__ = version(\u001b[33m\"\u001b[39m\u001b[33ms2gos-client\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\s2gos-controller\\s2gos-client\\src\\s2gos_client\\api.py:5\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mcuiman\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient, Client, ClientConfig, ClientError\n\u001b[32m 7\u001b[39m __all__ = [\n\u001b[32m 8\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mAsyncClient\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 9\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mClient\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 10\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mClientConfig\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 11\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mClientError\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 12\u001b[39m ]\n", + "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\__init__.py:7\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by the Eozilla team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mimportlib\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmetadata\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m version\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01masync_client\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient\n\u001b[32m 8\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mclient\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Client\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mconfig\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m ClientConfig\n", + "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\api\\__init__.py:5\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by the Eozilla team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01masync_client\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient\n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mclient\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Client\n\u001b[32m 7\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mconfig\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m ClientConfig\n", + "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\api\\async_client.py:21\u001b[39m\n\u001b[32m 8\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mgavicore\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m (\n\u001b[32m 9\u001b[39m ApiError,\n\u001b[32m 10\u001b[39m Capabilities,\n\u001b[32m (...)\u001b[39m\u001b[32m 17\u001b[39m ProcessRequest,\n\u001b[32m 18\u001b[39m )\n\u001b[32m 20\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01masync_client_mixin\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClientMixin\n\u001b[32m---> \u001b[39m\u001b[32m21\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mconfig\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m ClientConfig\n\u001b[32m 22\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mishell\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m has_ishell \u001b[38;5;28;01mas\u001b[39;00m _ \u001b[38;5;66;03m# noqa F401\u001b[39;00m\n\u001b[32m 23\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mtransport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncTransport, TransportArgs\n", + "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\api\\config.py:10\u001b[39m\n\u001b[32m 8\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01myaml\u001b[39;00m\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpydantic\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Field, HttpUrl, field_validator\n\u001b[32m---> \u001b[39m\u001b[32m10\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpydantic_settings\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BaseSettings, SettingsConfigDict\n\u001b[32m 12\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mgavicore\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m InputDescription, ProcessDescription, ProcessSummary\n\u001b[32m 14\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mauth\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AuthConfig\n", + "\u001b[31mModuleNotFoundError\u001b[39m: No module named 'pydantic_settings'" + ] } ], "source": [ diff --git a/pixi.lock b/pixi.lock index d736b92..f8afcea 100644 --- a/pixi.lock +++ b/pixi.lock @@ -13,7 +13,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.11.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/appligator-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-25.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/argon2-cffi-bindings-25.1.0-py313h07c4f96_2.conda @@ -67,7 +66,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/crc32c-2.8-py313h54dd161_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-46.0.3-py313hafb0bba_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuiman-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.1.0-py313h07c4f96_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dask-2025.11.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.11.0-pyhcf101f3_0.conda @@ -92,7 +90,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fqdn-1.5.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2025.10.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/gavicore-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/genson-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ghp-import-2.1.0-pyhd8ed1ab_2.conda @@ -262,6 +259,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/param-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathlib-abc-0.5.2-pyh9692d8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda @@ -270,7 +268,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.8-unix_hf108a03_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/procodile-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -284,6 +281,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.4-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.41.5-py313h843e2db_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pymdown-extensions-10.17.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda @@ -349,6 +347,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing_utils-0.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-1.0.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/universal_pathlib-0.3.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda @@ -366,7 +365,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/websockets-15.0.1-py313h54dd161_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.15-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wrapt-1.17.3-py313h07c4f96_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wraptile-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.10.1-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda @@ -381,6 +379,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda - pypi: https://files.pythonhosted.org/packages/53/c7/d168dd2e2120b1a61ffdcf6eaa6d992620a793d3bf7e12a59704eda1d83b/apache_airflow_client-3.0.2-py3-none-any.whl + - pypi: ../eozilla/appligator + - pypi: ../eozilla/cuiman + - pypi: ../eozilla/gavicore + - pypi: ../eozilla/procodile + - pypi: ../eozilla/wraptile - pypi: ./s2gos-client - pypi: ./s2gos-server osx-64: @@ -388,7 +391,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.11.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/appligator-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-25.1.0-pyhd8ed1ab_0.conda @@ -442,7 +444,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.11.3-py313h0f4d31d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/crc32c-2.8-py313hcb05632_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuiman-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cytoolz-1.1.0-py313hf050af9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dask-2025.11.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.11.0-pyhcf101f3_0.conda @@ -466,7 +467,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fqdn-1.5.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2025.10.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/gavicore-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/genson-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/gflags-2.2.2-hac325c4_1005.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ghp-import-2.1.0-pyhd8ed1ab_2.conda @@ -627,6 +627,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/param-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathlib-abc-0.5.2-pyh9692d8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pillow-12.0.0-py313he918548_0.conda @@ -634,7 +635,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.8-unix_hf108a03_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/procodile-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/prometheus-cpp-1.3.0-h7802330_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -648,6 +648,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.4-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pydantic-core-2.41.5-py313hcc225dc_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pymdown-extensions-10.17.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pyobjc-core-12.0-py313h07bcf3a_2.conda @@ -713,6 +714,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing_utils-0.1.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-1.0.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/universal_pathlib-0.3.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda @@ -730,7 +732,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/websockets-15.0.1-py313h6865ccc_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.15-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/wrapt-1.17.3-py313h585f44e_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wraptile-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.10.1-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/xorg-libxau-1.0.12-h8616949_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/xorg-libxdmcp-1.1.5-h8616949_1.conda @@ -745,6 +746,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py313hcb05632_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h8210216_2.conda - pypi: https://files.pythonhosted.org/packages/53/c7/d168dd2e2120b1a61ffdcf6eaa6d992620a793d3bf7e12a59704eda1d83b/apache_airflow_client-3.0.2-py3-none-any.whl + - pypi: ../eozilla/appligator + - pypi: ../eozilla/cuiman + - pypi: ../eozilla/gavicore + - pypi: ../eozilla/procodile + - pypi: ../eozilla/wraptile - pypi: ./s2gos-client - pypi: ./s2gos-server win-64: @@ -753,7 +759,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.11.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/appligator-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argcomplete-3.6.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-25.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/argon2-cffi-bindings-25.1.0-py313h5ea7bf4_2.conda @@ -801,7 +806,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/coverage-7.11.3-py313hd650c13_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.9-py313hd8ed1ab_101.conda - conda: https://conda.anaconda.org/conda-forge/win-64/crc32c-2.8-py313h5fd188c_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cuiman-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/cytoolz-1.1.0-py313h5ea7bf4_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dask-2025.11.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.11.0-pyhcf101f3_0.conda @@ -825,7 +829,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.20.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fqdn-1.5.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2025.10.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/gavicore-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/genson-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ghp-import-2.1.0-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/griffe-1.15.0-pyhd8ed1ab_0.conda @@ -977,6 +980,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/param-2.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.5-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathlib-abc-0.5.2-pyh9692d8f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pillow-12.0.0-py313hf6db949_0.conda @@ -984,7 +988,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.8-win_hba80fca_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/procodile-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.23.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt_toolkit-3.0.52-hd8ed1ab_0.conda @@ -997,6 +1000,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.12.4-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pydantic-core-2.41.5-py313hfbe8231_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pymdown-extensions-10.17.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda @@ -1064,6 +1068,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uc-micro-py-1.0.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/universal_pathlib-0.3.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda @@ -1086,7 +1091,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda - conda: https://conda.anaconda.org/conda-forge/win-64/winpty-0.4.3-4.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/wrapt-1.17.3-py313h5ea7bf4_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wraptile-0.0.8-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.10.1-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.12-hba3369d_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/xorg-libxdmcp-1.1.5-hba3369d_1.conda @@ -1100,6 +1104,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py313h5fd188c_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-hbeecb71_2.conda - pypi: https://files.pythonhosted.org/packages/53/c7/d168dd2e2120b1a61ffdcf6eaa6d992620a793d3bf7e12a59704eda1d83b/apache_airflow_client-3.0.2-py3-none-any.whl + - pypi: ../eozilla/appligator + - pypi: ../eozilla/cuiman + - pypi: ../eozilla/gavicore + - pypi: ../eozilla/procodile + - pypi: ../eozilla/wraptile - pypi: ./s2gos-client - pypi: ./s2gos-server packages: @@ -1201,21 +1210,18 @@ packages: - python-dateutil - urllib3>=2.1.0 requires_python: ~=3.9 -- conda: https://conda.anaconda.org/conda-forge/noarch/appligator-0.0.8-pyhd8ed1ab_0.conda - sha256: e49616e68e9b2ccbbac37ab67a2d3151544502f5795dc3dc003ba99a30d8b31b - md5: 08a7f7d3c61c0b590de41b1e65e9d041 - depends: - - gavicore >=0.0.7 - - procodile >=0.0.7 +- pypi: ../eozilla/appligator + name: appligator + version: 0.0.9.dev0 + sha256: d257b8116666c35954fbbcc6f8c8d5661dcbad4224d50dc298df769a00a2c3c3 + requires_dist: - pydantic - - python >=3.10 - pyyaml - typer - license: Apache-2.0 - purls: - - pkg:pypi/appligator?source=hash-mapping - size: 16020 - timestamp: 1762858580072 + - gavicore>=0.0.7 + - procodile>=0.0.7 + requires_python: '>=3.10' + editable: true - conda: https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.4-pyhd8ed1ab_1.conda sha256: 8f032b140ea4159806e4969a68b4a3c0a7cab1ad936eb958a2b5ffe5335e19bf md5: 54898d0f524c9dee622d44bbb081a8ab @@ -2664,24 +2670,22 @@ packages: - pkg:pypi/cryptography?source=hash-mapping size: 1718808 timestamp: 1760605188769 -- conda: https://conda.anaconda.org/conda-forge/noarch/cuiman-0.0.8-pyhd8ed1ab_0.conda - sha256: 6a16d0d79f2bda1abc8e64dfb479ed571c673327427f4fc20ef19702bd279be6 - md5: b1a872de1a3d99b31af82bbfbde69994 - depends: +- pypi: ../eozilla/cuiman + name: cuiman + version: 0.0.9.dev0 + sha256: 3968086891b92dc68dba3ec9c7098e4013ebb225e4bad4e29248a4de73b17330 + requires_dist: - click - - gavicore >=0.0.7 - - httpx - panel - pydantic - - python >=3.10 + - pydantic-settings - pyyaml - typer - uri-template - license: Apache-2.0 - purls: - - pkg:pypi/cuiman?source=hash-mapping - size: 37456 - timestamp: 1762852263498 + - httpx + - gavicore>=0.0.7 + requires_python: '>=3.10' + editable: true - conda: https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.1.0-py313h07c4f96_1.conda sha256: a8ffc7cf31a698a57a46bf7977185ed1e644c5e35d4e166d8f260dca93af6ffb md5: bcca9afd203fe05d9582249ac12762da @@ -3099,18 +3103,16 @@ packages: - pkg:pypi/fsspec?source=compressed-mapping size: 146592 timestamp: 1761840236679 -- conda: https://conda.anaconda.org/conda-forge/noarch/gavicore-0.0.8-pyhd8ed1ab_0.conda - sha256: ebc079e560afae146f8e77f1003cd0beb88120f181669dea2d633cc14ada16dc - md5: 1e98a8762d387f6ec852d6093258ddc7 - depends: +- pypi: ../eozilla/gavicore + name: gavicore + version: 0.0.9.dev0 + sha256: 33b819fe8b7fce4c99bad8e3266e028b03cac32e23407811d949bd4500ec9ef3 + requires_dist: + - click - pydantic - - python >=3.10 - typer - license: Apache-2.0 - purls: - - pkg:pypi/gavicore?source=hash-mapping - size: 24205 - timestamp: 1762851993862 + requires_python: '>=3.10' + editable: true - conda: https://conda.anaconda.org/conda-forge/noarch/genson-1.3.0-pyhd8ed1ab_0.conda sha256: 2b9e4e8321e355bb8792ccf7722b81e481f3f664d145ad4b851a66ebac2d9c71 md5: d3c12a70d5dc21f05647a80f72a81aa1 @@ -7767,6 +7769,17 @@ packages: - pkg:pypi/partd?source=hash-mapping size: 20884 timestamp: 1715026639309 +- conda: https://conda.anaconda.org/conda-forge/noarch/pathlib-abc-0.5.2-pyh9692d8f_0.conda + sha256: 70fff431251c35a2fe82a04452e8b37afe71a1d9e04c84c75bc10b70a50ada09 + md5: 9c7e6958c1ddc27ceb271eb7422bee56 + depends: + - python >=3.10 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/pathlib-abc?source=hash-mapping + size: 23607 + timestamp: 1760357881073 - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda sha256: 9f64009cdf5b8e529995f18e03665b03f5d07c0b17445b8badef45bde76249ee md5: 617f15191456cc6a13db418a275435e5 @@ -7930,20 +7943,17 @@ packages: - pkg:pypi/pluggy?source=hash-mapping size: 24246 timestamp: 1747339794916 -- conda: https://conda.anaconda.org/conda-forge/noarch/procodile-0.0.8-pyhd8ed1ab_0.conda - sha256: 57958b69b8ed1850ec7cb4a4271a806c1a083090afffffd14401b9d7f313aa1f - md5: 180b22c3b9914cfdd7cc914f1b54f41c - depends: - - gavicore >=0.0.7 +- pypi: ../eozilla/procodile + name: procodile + version: 0.0.9.dev0 + sha256: 0cf211276bc8e38bce1e0c0690919da345e4954f3fcf2279652a9be41753360e + requires_dist: - pydantic - - python >=3.10 - pyyaml - typer - license: Apache-2.0 - purls: - - pkg:pypi/procodile?source=hash-mapping - size: 22993 - timestamp: 1762852066423 + - gavicore>=0.0.7 + requires_python: '>=3.10' + editable: true - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda sha256: 013669433eb447548f21c3c6b16b2ed64356f726b5f77c1b39d5ba17a8a4b8bc md5: a83f6a2fdc079e643237887a37460668 @@ -8294,6 +8304,20 @@ packages: - pkg:pypi/pydantic-core?source=compressed-mapping size: 1973031 timestamp: 1762989056610 +- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-settings-2.12.0-pyh3cfb1c2_0.conda + sha256: 17d552dd19501909d626ff50cd23753d56e03ab670ce9096f1c4068e1eb90f2a + md5: 0a3042ce18b785982c64a8567cc3e512 + depends: + - pydantic >=2.7.0 + - python >=3.10 + - python-dotenv >=0.21.0 + - typing-inspection >=0.4.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pydantic-settings?source=hash-mapping + size: 43752 + timestamp: 1762786342653 - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a md5: 6b6ece66ebcae2d5f326c77ef2c5a066 @@ -9007,10 +9031,11 @@ packages: - pypi: ./s2gos-server name: s2gos-server version: 0.1.0.dev0 - sha256: f4c7000a30dba249ffdc11683ec6b64b912eb0d59aa5225ff5e497a5532e431f + sha256: 6753bc219464862a8d39ca2bd30f5ef28c6eaf9a38a138242d03c59ac21397db requires_dist: - gavicore>=0.0.8 - wraptile>=0.0.8 + - universal-pathlib>=0.3.8,<0.4 requires_python: '>=3.10' editable: true - conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.6.0-h8399546_1.conda @@ -9581,6 +9606,19 @@ packages: purls: [] size: 694692 timestamp: 1756385147981 +- conda: https://conda.anaconda.org/conda-forge/noarch/universal_pathlib-0.3.8-pyhd8ed1ab_0.conda + sha256: d00bfe2b500ff5f2ad3c2dd115f5792ec409099b3b5d4ec1b17accb8ad4c8efd + md5: 78d52047472939af8e67f08e99efd302 + depends: + - fsspec >=2024.5.0 + - pathlib-abc >=0.5.1,<0.6.0 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/universal-pathlib?source=hash-mapping + size: 65629 + timestamp: 1768199829275 - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_1.conda sha256: e0eb6c8daf892b3056f08416a96d68b0a358b7c46b99c8a50481b22631a4dfc0 md5: e7cb0f5745e4c5035a460248334af7eb @@ -10058,23 +10096,20 @@ packages: - pkg:pypi/wrapt?source=hash-mapping size: 63385 timestamp: 1756851987645 -- conda: https://conda.anaconda.org/conda-forge/noarch/wraptile-0.0.8-pyhd8ed1ab_0.conda - sha256: 33aff6d7d98090448816b55088e6401534c6201127756b51ab33b61d6ba153fc - md5: 831533a291937737418394aae4835a6c - depends: +- pypi: ../eozilla/wraptile + name: wraptile + version: 0.0.9.dev0 + sha256: 51a85d04de266f412269a8e665749bd3af43cfd132b2fba7fe3fd049fbe07e2d + requires_dist: - fastapi - - gavicore >=0.0.7 - - procodile >=0.0.7 - pydantic - - python >=3.10 - pyyaml - typer - uvicorn - license: Apache-2.0 - purls: - - pkg:pypi/wraptile?source=hash-mapping - size: 26161 - timestamp: 1762857657232 + - gavicore>=0.0.7 + - procodile>=0.0.7 + requires_python: '>=3.10' + editable: true - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.10.1-pyhcf101f3_1.conda sha256: 57bfac2a070d2c63d34c1d75a409cb92e788ac42e658e9d9349cd19b12888ce7 md5: 515d0ed77a942ad39fa94cf636dcde44 diff --git a/pyproject.toml b/pyproject.toml index 9ed1e9c..2cf0290 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,12 +9,14 @@ channels = ["conda-forge"] platforms = ["linux-64", "win-64", "osx-64"] [tool.pixi.dependencies] -# Eozilla dependencies -appligator = ">=0.0.8,<0.0.9" -cuiman = ">=0.0.8,<0.0.9" -gavicore = ">=0.0.8,<0.0.9" -procodile = ">=0.0.8,<0.0.9" -wraptile = ">=0.0.8,<0.0.9" +# Eozilla dependencies. +# Comment out, if using the editable versions, +# see [tool.pixi.pypi-dependencies] below. +#appligator = ">=0.0.8,<0.0.9" +#cuiman = ">=0.0.8,<0.0.9" +#gavicore = ">=0.0.8,<0.0.9" +#procodile = ">=0.0.8,<0.0.9" +#wraptile = ">=0.0.8,<0.0.9" # Combined sub-workspace dependencies to prevent our editable # PyPI dependencies (our project's sub-workspaces) to install # PyPI packages instead of using conda packages. @@ -24,6 +26,7 @@ httpx = "*" pydantic = "*" pyyaml = "*" typer = "*" +universal_pathlib = ">=0.3.8,<0.4" uri-template = "*" uvicorn = "*" # IDE integration @@ -61,6 +64,7 @@ mkdocstrings = "*" mkdocstrings-python = "*" mkdocs-jupyter = "*" nbformat = "*" +pydantic-settings = ">=2.12.0,<3" [tool.pixi.pypi-dependencies] # I wished we could have "no-deps=true" here, @@ -72,11 +76,11 @@ s2gos-server = { path = "s2gos-server", editable = true } # Uncomment the following to allow using eozilla from sources # Note, using the wraptile server is for testing only # -#appligator = { path = "../eozilla/appligator", editable = true } -#cuiman = { path = "../eozilla/cuiman", editable = true } -#gavicore = { path = "../eozilla/gavicore", editable = true } -#procodile = { path = "../eozilla/procodile", editable = true } -#wraptile = { path = "../eozilla/wraptile", editable = true } +appligator = { path = "../eozilla/appligator", editable = true } +cuiman = { path = "../eozilla/cuiman", editable = true } +gavicore = { path = "../eozilla/gavicore", editable = true } +procodile = { path = "../eozilla/procodile", editable = true } +wraptile = { path = "../eozilla/wraptile", editable = true } # Airflow is only available on PyPI apache-airflow-client = "==3.0.2" diff --git a/s2gos-client/src/s2gos_client/__init__.py b/s2gos-client/src/s2gos_client/__init__.py index 4bf9399..6d179ca 100644 --- a/s2gos-client/src/s2gos_client/__init__.py +++ b/s2gos-client/src/s2gos_client/__init__.py @@ -6,9 +6,6 @@ from .api import AsyncClient, Client, ClientConfig, ClientError -from .defaults import DEFAULT_SERVER_URL, DEFAULT_USER_NAME, DEFAULT_ACCESS_TOKEN - - __version__ = version("s2gos-client") __all__ = [ @@ -18,11 +15,3 @@ "ClientError", "__version__", ] - -ClientConfig.set_default( - ClientConfig( - server_url=DEFAULT_SERVER_URL, - user_name=DEFAULT_USER_NAME, - access_token=DEFAULT_ACCESS_TOKEN, - ) -) diff --git a/s2gos-client/src/s2gos_client/api.py b/s2gos-client/src/s2gos_client/api.py index b06fd69..c51bc66 100644 --- a/s2gos-client/src/s2gos_client/api.py +++ b/s2gos-client/src/s2gos_client/api.py @@ -1,9 +1,31 @@ -# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors +# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors # Permissions are hereby granted under the terms of the Apache 2.0 License: # https://opensource.org/license/apache-2-0. +from pathlib import Path + +from pydantic_settings import SettingsConfigDict + from cuiman.api import AsyncClient, Client, ClientConfig, ClientError + +class S2GOSConfig(ClientConfig): + model_config = SettingsConfigDict( + env_prefix="S2GOS_", + env_file=".env", + extra="allow", # ClientConfig uses "forbid" + ) + + +ClientConfig.default_path = Path("~").expanduser() / ".sen4cap-client" +ClientConfig.default_config = S2GOSConfig( + api_url="http://localhost:8008/", + # auth_url="http://localhost:8080/auth/login", + # auth_type="token", + # use_bearer=True, + auth_type="none", +) + __all__ = [ "AsyncClient", "Client", diff --git a/s2gos-client/src/s2gos_client/cli.py b/s2gos-client/src/s2gos_client/cli.py index 003fc4e..64a5920 100644 --- a/s2gos-client/src/s2gos_client/cli.py +++ b/s2gos-client/src/s2gos_client/cli.py @@ -1,11 +1,16 @@ -# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors +# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors # Permissions are hereby granted under the terms of the Apache 2.0 License: # https://opensource.org/license/apache-2-0. +from importlib import import_module + from cuiman.cli import new_cli from s2gos_client import __version__ as version +# Force pre-configuration of Sen4CAP configuration +import_module("s2gos_client.api") + cli = new_cli( name="s2gos-client", version=version, diff --git a/s2gos-client/src/s2gos_client/defaults.py b/s2gos-client/src/s2gos_client/defaults.py deleted file mode 100644 index 377c5d5..0000000 --- a/s2gos-client/src/s2gos_client/defaults.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2025 by ESA Sen4CAP team and contributors -# Permissions are hereby granted under the terms of the Apache 2.0 License: -# https://opensource.org/license/apache-2-0. - -import os -from typing import Final - - -# TODO: adjust defaults -DEFAULT_SERVER_URL: Final = ( - os.environ.get("S2GOS_SERVER_URL") or "http://localhost:8008" -) -DEFAULT_USER_NAME: Final = os.environ.get("S2GOS_USERNAME") or "testuser" -DEFAULT_ACCESS_TOKEN: Final = os.environ.get("S2GOS_PASSWORD") or "1234" diff --git a/s2gos-client/src/s2gos_client/gui.py b/s2gos-client/src/s2gos_client/gui.py index eea6e26..ed27417 100644 --- a/s2gos-client/src/s2gos_client/gui.py +++ b/s2gos-client/src/s2gos_client/gui.py @@ -1,9 +1,15 @@ -# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors +# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors # Permissions are hereby granted under the terms of the Apache 2.0 License: # https://opensource.org/license/apache-2-0. +from importlib import import_module + from cuiman.gui import Client +# Force pre-configuration of Sen4CAP configuration +import_module("s2gos_client.api") + + __all__ = [ "Client", ] diff --git a/s2gos-server/pyproject.toml b/s2gos-server/pyproject.toml index e6fae2c..0028bd4 100644 --- a/s2gos-server/pyproject.toml +++ b/s2gos-server/pyproject.toml @@ -41,6 +41,8 @@ dependencies = [ # Eozilla dependencies "gavicore >=0.0.8", "wraptile >=0.0.8", + # Other + "universal_pathlib >=0.3.8,<0.4", ] [project.scripts] diff --git a/s2gos-server/src/s2gos_server/services/io.py b/s2gos-server/src/s2gos_server/services/io.py new file mode 100644 index 0000000..7ea8b96 --- /dev/null +++ b/s2gos-server/src/s2gos_server/services/io.py @@ -0,0 +1,133 @@ +import os + +from pydantic import BaseModel, Field, model_validator, PrivateAttr +from upath import UPath + + +class Credential: + def __init__(self, **upath_kwargs): + self.upath_kwargs = upath_kwargs + + +def get_credential(cid: str) -> Credential: + return Credential(cid=cid) + + +class PathRef(BaseModel): + """ + Path configuration that preserves credential reference through serialization. + + This model allows paths to reference credentials by ID rather than embedding + actual credentials. When serialized to JSON, only the path value and credential_id + are stored (no actual credentials). When deserialized, credentials are resolved + from the credential provider (environment variables or .secrets.yaml). + + Attributes: + value: The actual path/URI + cid: Optional reference to a Credential ID in the credential provider + + Example: + # With credentials + path = PathRef( + path="https://data.earthdatahub.destine.eu/data.zarr", + cid="earthdatahub" + ) + + # Without credentials (public or local path) + path = PathRef("/local/path/data.zarr") + + # Access the authenticated UPath + upath = path.upath + """ + + value: str = Field(description="Full path URI") + # TODO : rename to credential id + cid: str | None = Field(default=None, description="Credential ID") + _upath: UPath | None = PrivateAttr(default=None) + + def __init__(self, value, cid=None, **kwargs): + if isinstance(value, (UPath, os.PathLike)): + path = str(value) + elif isinstance(value, PathRef): + path = value.value + cid = value.cid + elif isinstance(value, dict): + path = value["value"] + cid = value["cid"] + else: + path = value + + super(PathRef, self).__init__(value=path, cid=cid, **kwargs) + + @model_validator(mode="before") + @classmethod + def convert_to_pathref(cls, value): + if isinstance(value, str): + return {"value": value} + + elif isinstance(value, UPath): + cid = value.storage_options.get("cid") + return {"value": str(value), "cid": cid} + + return value + + @property + def upath(self) -> UPath: + """ + Get the authenticated UPath by resolving credentials. + + If `cid` is set, retrieves the credential from the credential + provider and constructs an authenticated UPath. Otherwise, returns a + simple UPath without authentication. + + Returns: + UPath object with authentication if `cid` is set + + Raises: + ValueError: If `cid` is set but credential is not found + """ + if self._upath is not None: + return self._upath + + if self.cid: + # from s2gos_utils.setting.credentials import get_credential + + cred = get_credential(self.cid) + if not cred: + raise ValueError( + f"Credential '{self.cid}' not found. " + f"Set S2GOS_CRED_{self.cid}_* environment variables " + f"or add to .secrets.yaml" + ) + kwargs = cred.upath_kwargs + self._upath = UPath(self.value, **kwargs) + else: + # No credentials needed (local path or public URL) + self._upath = UPath(self.value) + + return self._upath + + def to_dict(self) -> dict[str, str]: + """Alias to `model_dump`.""" + return self.model_dump() + + def __truediv__(self, other) -> "PathRef": + """Returns the joined UPath.""" + + if isinstance(other, PathRef): + if other.cid != self.cid: + raise ValueError( + f"Joining paths with different credential ids! " + f"Left: {self.cid}, Right: {other.cid}." + ) + other_path = other.upath + else: + other_path = other + + return PathRef(self.upath / other_path, self.cid) + + def __str__(self) -> str: + """Return the path value as a string.""" + return self.value + + model_config = {"frozen": True} diff --git a/s2gos-server/src/s2gos_server/services/testing.py b/s2gos-server/src/s2gos_server/services/testing.py new file mode 100644 index 0000000..b3fa6f3 --- /dev/null +++ b/s2gos-server/src/s2gos_server/services/testing.py @@ -0,0 +1,257 @@ +# Copyright (c) 2026 by the Eozilla team and contributors +# Permissions are hereby granted under the terms of the Apache 2.0 License: +# https://opensource.org/license/apache-2-0. + +"""MTR Demo Processors - Self-contained generation and simulation workflows. + +This module provides two processors for the MTR (Multi-Temporal Radiometric) demo: +1. mtr_demo.generation - Creates scene with seasonal variations +2. mtr_demo.simulation - Runs simulation with configurable observation types + +The demo showcases: +- Seasonal variations (December=summer, June=winter in Patagonia) +- Multiple observation types (CHIME, MSI, HYPSTAR, RGB camera, satellite HDRF) +- Fixed demonstration dates (21st of month), flexible time +""" + +import enum +from typing import Annotated + +from pydantic import Field + +from procodile import JobContext +from wraptile.services.local import LocalService + +from .io import PathRef + +service = LocalService( + title="S2GOS Test-Server", + description="Local DTE-S2GOS process server for testing", +) + +registry = service.process_registry + +# ============================================================================ +# Constants +# ============================================================================ + +PNP_LAT = -46.917 +PNP_LON = -72.450 +PNP_SIZE_KM = 10.0 +TOWER_COORDS = (-220.0, 850.0) # meters in scene coordinates + +# ============================================================================ +# Enums +# ============================================================================ + + +class Month(enum.StrEnum): + """Month selection for MTR demo (limited to solstice dates).""" + + DECEMBER = "december" # Summer in Patagonia + JUNE = "june" # Winter in Patagonia + + +class ObservationType(enum.StrEnum): + """Available observation types for MTR demo.""" + + CHIME = "chime" + MSI = "msi" + SATELLITE_HDRF = "satellite_hdrf" + HYPSTAR = "hypstar" + RGB_CAMERA = "rgb_camera" + + +# ============================================================================ +# Processor 1: Scene Generation +# ============================================================================ + + +@registry.process(id="mtr_demo_generation") +def mtr_demo_generation( + month: Annotated[ + Month, + Field( + default=Month.DECEMBER, + description="Month for simulation (December=summer, June=winter in Patagonia)", + ), + ], + random_seed: Annotated[ + int, Field(default=13, description="RNG seed for vegetation placement") + ], + config_output_dir: Annotated[ + PathRef | None, + Field(..., description="Generation configuration output directory"), + ] = None, + scene_output_dir: Annotated[ + PathRef | None, + Field( + ..., description="Scene description and associated data output directory" + ), + ] = None, +) -> PathRef | None: + """Generate 3D scene for MTR demo with seasonal variations. + + This processor: + 1. Creates a scene generation configuration based on season/month + 2. Immediately runs the generation pipeline + 3. Returns path to the generated scene description YAML + + The scene includes: + - PNP location with 10km target area + - Seasonal vegetation (summer/winter variants) + - Heterogeneous atmosphere with aerosol layer + - Tower XML scene at fixed location + - Optional snow cover (June only) + + Args: + month: Month for simulation (controls seasonal variations) + random_seed: Random seed for reproducible vegetation placement + config_output_dir: Optional directory for generation config JSON + scene_output_dir: Optional directory for scene description YAML + + Returns: + Path to generated scene description YAML file, or None if validation fails + """ + ctx = JobContext.get() + + print("\n") + print("=" * 60) + print("MTR DEMO - SCENE GENERATION") + print("=" * 60) + print(f"Season: {month.value}") + print(f"Random seed: {random_seed}") + print() + + # Run generation pipeline + print("\n" + "=" * 60) + print("Running scene generation pipeline...") + print("=" * 60) + ctx.report_progress(message="Running scene generation pipeline...") + + scene_path = generation_from_config() + if scene_path: + print("\n" + "=" * 60) + print("SCENE GENERATION COMPLETE") + print("=" * 60) + print(f"Scene description: {scene_path}") + print() + ctx.report_progress(message=f"Scene description: {scene_path}") + + return scene_path + + +# ============================================================================ +# Processor 2: Simulation +# ============================================================================ + + +@registry.process(id="mtr_demo_simulation") +def mtr_demo_simulation( + scene_description_path: Annotated[ + PathRef, Field(..., description="Path to scene description YAML file") + ], + month: Annotated[ + Month, + Field( + default=Month.DECEMBER, + description="Month for simulation (December=summer, June=winter)", + ), + ], + hour_utc: Annotated[ + float, Field(..., description="Hour of observation in UTC (0-23)") + ], + observation: Annotated[ + ObservationType, + Field(..., description="Observation type (enum value)"), + ], + spp: Annotated[ + int, Field(..., description="Samples per pixel for Monte Carlo simulation") + ] = 8, + config_output_dir: Annotated[ + PathRef | None, + Field(..., description="Simulation configuration output directory"), + ] = None, + simulation_output_dir: Annotated[ + PathRef | None, + Field(..., description="Simulation results output directory"), + ] = None, +) -> PathRef | None: + """Run simulation for MTR demo with configurable observation types. + + This processor: + 1. Creates a simulation configuration based on observation type + 2. Immediately runs the simulation + 3. Returns path to the simulation output directory + + Supported observation types: + - CHIME: Hyperspectral satellite sensor + - MSI: Sentinel-2 multispectral sensor (configurable bands) + - HYPSTAR: Ground-based hyperspectral sensor with HCRF processing + - RGB_CAMERA: Perspective camera viewing tower from configurable position + - SATELLITE_HDRF: [PLACEHOLDER - To be implemented] + + Args: + scene_description_path: Path to scene YAML from generation step + month: Month for simulation (determines observation date) + hour_utc: Hour of observation in UTC + observation: Observation type configuration + spp: Samples per pixel for Monte Carlo simulation + config_output_dir: Optional directory for simulation config JSON + simulation_output_dir: Optional directory for simulation outputs + + Returns: + Path to simulation output directory, or None if observation type + is not yet implemented or simulation fails + """ + ctx = JobContext.get() + + print("\n") + print("=" * 60) + print("MTR DEMO - SIMULATION") + print("=" * 60) + + print(f"Observation type: {observation}") + print() + + # Check for placeholder observation type + if observation == ObservationType.SATELLITE_HDRF: + print("=" * 60) + print("SATELLITE HDRF (3x3 pixels around tower)") + print("Status: TO BE IMPLEMENTED") + print() + print("This observation type requires implementation of:") + print(" - Pixel coordinate calculation for tower location") + print(" - 3x3 grid generation around tower pixel") + print(" - Multiple HDRF measurements creation") + print("=" * 60) + return None + + # Run simulation + print("\n" + "=" * 60) + print("Running simulation...") + print("=" * 60) + + ctx.report_progress(message="Running simulation...") + + # TODO + output_path = simulation_from_config() + + if output_path: + print("\n" + "=" * 60) + print("SIMULATION COMPLETE") + print("=" * 60) + print(f"Output directory: {output_path}") + print() + + ctx.report_progress(message=f"Output directory: {output_path}") + + return output_path + + +def generation_from_config() -> PathRef: + return PathRef("/outputs/generation-result") + + +def simulation_from_config(): + return PathRef("/outputs/simulation-result") From 3dc95b114aee60bc0b5400a4c2cbd38b2ea8b7cf Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Wed, 28 Jan 2026 21:55:05 +0100 Subject: [PATCH 2/7] Added PathRef component --- .../s2gos_client/{gui.py => gui/__init__.py} | 3 + s2gos-client/src/s2gos_client/gui/pathref.py | 109 ++++++++++++++++++ 2 files changed, 112 insertions(+) rename s2gos-client/src/s2gos_client/{gui.py => gui/__init__.py} (85%) create mode 100644 s2gos-client/src/s2gos_client/gui/pathref.py diff --git a/s2gos-client/src/s2gos_client/gui.py b/s2gos-client/src/s2gos_client/gui/__init__.py similarity index 85% rename from s2gos-client/src/s2gos_client/gui.py rename to s2gos-client/src/s2gos_client/gui/__init__.py index ed27417..cb6e08a 100644 --- a/s2gos-client/src/s2gos_client/gui.py +++ b/s2gos-client/src/s2gos_client/gui/__init__.py @@ -5,10 +5,13 @@ from importlib import import_module from cuiman.gui import Client +from .pathref import register_component + # Force pre-configuration of Sen4CAP configuration import_module("s2gos_client.api") +register_component() __all__ = [ "Client", diff --git a/s2gos-client/src/s2gos_client/gui/pathref.py b/s2gos-client/src/s2gos_client/gui/pathref.py new file mode 100644 index 0000000..6b5c621 --- /dev/null +++ b/s2gos-client/src/s2gos_client/gui/pathref.py @@ -0,0 +1,109 @@ +# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors +# Permissions are hereby granted under the terms of the Apache 2.0 License: +# https://opensource.org/license/apache-2-0. +from typing import Any, Callable + +import panel as pn +import param + +from cuiman.gui.component import ( + Component, + ComponentContainer, + ComponentFactoryBase, + JsonValue, + JsonSchemaDict, +) + + +class PathRefEditor(pn.viewable.Viewer): + title = param.String(default="") + tooltip = param.String(default=None, allow_None=True) + + path = param.String(default="") + cid = param.String(default="") + + disabled = param.Boolean(default=False) + + def __init__(self, **params): + super().__init__(**params) + + self._path_input = pn.widgets.TextInput( + name="Path", + placeholder="Path or URL...", + value=self.path, + disabled=self.param.disabled, + ) + + self._cid_input = pn.widgets.TextInput( + name="CID", + placeholder="CID...", + value=self.cid, + disabled=self.param.disabled, + ) + + # widget ↔ param (two-way, explicit) + self._path_input.link(self, value="path") + self._cid_input.link(self, value="cid") + + header = ( + pn.pane.Markdown( + f"**{self.title}**", + tooltip=self.tooltip, + ) + if self.title + else None + ) + + self.view = pn.Column( + *([header] if header else []), + self._path_input, + self._cid_input, + ) + + def __panel__(self): + return self.view + + +class PathRefComponent(Component): + def __init__(self, editor: PathRefEditor): + # noinspection PyTypeChecker + super().__init__(editor) + + @property + def path_ref_editor(self) -> PathRefEditor: + # noinspection PyTypeChecker + return self.viewable + + def get_value(self) -> dict[str, Any]: + return { + "value": self.path_ref_editor.path, + "cid": self.path_ref_editor.cid or None, + } + + def set_value(self, value: dict[str, Any]): + self.path_ref_editor.path = value.get("value") or "" + self.path_ref_editor.cid = value.get("cid") or "" + + def watch_value(self, callback: Callable[[Any], Any]): + self.path_ref_editor.param.watch(callback, ["path", "cid"]) + + +class PathRefEditorFactory(ComponentFactoryBase): + type = "object" + format = "path_ref" + + def create_component( + self, value: JsonValue, title: str, schema: JsonSchemaDict + ) -> Component: + path_ref: dict[str, Any] = value + return PathRefComponent( + PathRefEditor( + title=title, + path=path_ref.get("value") or "", + cid=path_ref.get("cid") or "", + ) + ) + + +def register_component(): + PathRefEditorFactory.register_in(ComponentContainer.registry) From 8672727894bcdeb82e8c91f42732193b9560f86e Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Thu, 29 Jan 2026 14:39:55 +0100 Subject: [PATCH 3/7] Aligned process interfaces --- .../src/s2gos_server/services/testing.py | 89 +++++++++++-------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/s2gos-server/src/s2gos_server/services/testing.py b/s2gos-server/src/s2gos_server/services/testing.py index b3fa6f3..c021d15 100644 --- a/s2gos-server/src/s2gos_server/services/testing.py +++ b/s2gos-server/src/s2gos_server/services/testing.py @@ -22,7 +22,6 @@ from procodile import JobContext from wraptile.services.local import LocalService -from .io import PathRef service = LocalService( title="S2GOS Test-Server", @@ -67,29 +66,34 @@ class ObservationType(enum.StrEnum): # ============================================================================ -@registry.process(id="mtr_demo_generation") +# noinspection PyUnusedLocal +@registry.process(id="mtr_demo_generation", title="Scene Generation Demo") def mtr_demo_generation( month: Annotated[ Month, Field( default=Month.DECEMBER, description="Month for simulation (December=summer, June=winter in Patagonia)", + title="Month", ), ], random_seed: Annotated[ - int, Field(default=13, description="RNG seed for vegetation placement") + int, + Field( + default=13, + description="RNG seed for vegetation placement", + title="Vegetation RNG seed", + ), ], - config_output_dir: Annotated[ - PathRef | None, - Field(..., description="Generation configuration output directory"), - ] = None, - scene_output_dir: Annotated[ - PathRef | None, + scene_name: Annotated[ + str, Field( - ..., description="Scene description and associated data output directory" + ..., + description="Name of scene", + title="Scene name", ), ] = None, -) -> PathRef | None: +) -> str | None: """Generate 3D scene for MTR demo with seasonal variations. This processor: @@ -107,8 +111,7 @@ def mtr_demo_generation( Args: month: Month for simulation (controls seasonal variations) random_seed: Random seed for reproducible vegetation placement - config_output_dir: Optional directory for generation config JSON - scene_output_dir: Optional directory for scene description YAML + scene_name: Filename for scene description YAML Returns: Path to generated scene description YAML file, or None if validation fails @@ -146,37 +149,54 @@ def mtr_demo_generation( # ============================================================================ -@registry.process(id="mtr_demo_simulation") +# noinspection PyUnusedLocal +@registry.process(id="mtr_demo_simulation", title="Simulation Demo") def mtr_demo_simulation( - scene_description_path: Annotated[ - PathRef, Field(..., description="Path to scene description YAML file") + scene_name: Annotated[ + str, + Field( + ..., + description="Scene to sue for simulation", + title="Scene name", + ), ], month: Annotated[ Month, Field( default=Month.DECEMBER, description="Month for simulation (December=summer, June=winter)", + title="Month", ), ], hour_utc: Annotated[ - float, Field(..., description="Hour of observation in UTC (0-23)") + float, + Field( + ..., + description="Hour of observation in UTC (0-23) of the 21st of the chosen month, affects sun position ", + title="Hour (UTC)", + ), ], observation: Annotated[ ObservationType, - Field(..., description="Observation type (enum value)"), + Field(..., description="Observation type (enum value)", title="Observation"), ], spp: Annotated[ - int, Field(..., description="Samples per pixel for Monte Carlo simulation") + int, + Field( + ..., + description="Samples per pixel for Monte Carlo simulation", + title="Samples per pixel", + ), ] = 8, - config_output_dir: Annotated[ - PathRef | None, - Field(..., description="Simulation configuration output directory"), - ] = None, - simulation_output_dir: Annotated[ - PathRef | None, - Field(..., description="Simulation results output directory"), + sim_name: Annotated[ + str, + Field( + ..., + description="Simulation run name", + title="Name of run", + ), ] = None, -) -> PathRef | None: +) -> str | None: """Run simulation for MTR demo with configurable observation types. This processor: @@ -192,13 +212,12 @@ def mtr_demo_simulation( - SATELLITE_HDRF: [PLACEHOLDER - To be implemented] Args: - scene_description_path: Path to scene YAML from generation step + scene_name: Filename of the scene YAML from generation step month: Month for simulation (determines observation date) hour_utc: Hour of observation in UTC observation: Observation type configuration spp: Samples per pixel for Monte Carlo simulation - config_output_dir: Optional directory for simulation config JSON - simulation_output_dir: Optional directory for simulation outputs + sim_name: Filename for the for simulation config JSON Returns: Path to simulation output directory, or None if observation type @@ -235,7 +254,7 @@ def mtr_demo_simulation( ctx.report_progress(message="Running simulation...") # TODO - output_path = simulation_from_config() + output_path = simulation_from_config(scene_name) if output_path: print("\n" + "=" * 60) @@ -249,9 +268,9 @@ def mtr_demo_simulation( return output_path -def generation_from_config() -> PathRef: - return PathRef("/outputs/generation-result") +def generation_from_config(scene_name: str) -> str: + return f"/outputs/scenes/{scene_name}" -def simulation_from_config(): - return PathRef("/outputs/simulation-result") +def simulation_from_config(sim_name: str): + return f"/outputs/simulations/{sim_name}" From 022ec11914aa03590f8f892ba22fd61b1431a011 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Thu, 29 Jan 2026 14:50:20 +0100 Subject: [PATCH 4/7] Added support for PathRef component (not yet used) --- pixi.lock | 2 +- s2gos-client/src/s2gos_client/gui/pathref.py | 59 +++++++++----------- s2gos-client/tests/test_gui.py | 11 ++++ 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/pixi.lock b/pixi.lock index f8afcea..88557db 100644 --- a/pixi.lock +++ b/pixi.lock @@ -2673,7 +2673,7 @@ packages: - pypi: ../eozilla/cuiman name: cuiman version: 0.0.9.dev0 - sha256: 3968086891b92dc68dba3ec9c7098e4013ebb225e4bad4e29248a4de73b17330 + sha256: e621b5e81ee99a3741c2f154789fdf768d7efa26816b2527364cf55af80d627f requires_dist: - click - panel diff --git a/s2gos-client/src/s2gos_client/gui/pathref.py b/s2gos-client/src/s2gos_client/gui/pathref.py index 6b5c621..ea1ea42 100644 --- a/s2gos-client/src/s2gos_client/gui/pathref.py +++ b/s2gos-client/src/s2gos_client/gui/pathref.py @@ -19,7 +19,7 @@ class PathRefEditor(pn.viewable.Viewer): title = param.String(default="") tooltip = param.String(default=None, allow_None=True) - path = param.String(default="") + value = param.String(default="") cid = param.String(default="") disabled = param.Boolean(default=False) @@ -27,36 +27,29 @@ class PathRefEditor(pn.viewable.Viewer): def __init__(self, **params): super().__init__(**params) - self._path_input = pn.widgets.TextInput( - name="Path", - placeholder="Path or URL...", - value=self.path, + self._value_input = pn.widgets.TextInput( + name=f"{self.title} URI", + placeholder="URI or rel. path...", + value=self.value, disabled=self.param.disabled, + width=300, ) self._cid_input = pn.widgets.TextInput( - name="CID", - placeholder="CID...", + name=f"{self.title} CID (optional)", + placeholder="Credentials ID...", value=self.cid, disabled=self.param.disabled, + width=120, ) # widget ↔ param (two-way, explicit) - self._path_input.link(self, value="path") + self._value_input.link(self, value="value") self._cid_input.link(self, value="cid") - header = ( - pn.pane.Markdown( - f"**{self.title}**", - tooltip=self.tooltip, - ) - if self.title - else None - ) - - self.view = pn.Column( - *([header] if header else []), - self._path_input, + # TODO: set tooltip (how?) + self.view = pn.Row( + self._value_input, self._cid_input, ) @@ -74,33 +67,35 @@ def path_ref_editor(self) -> PathRefEditor: # noinspection PyTypeChecker return self.viewable - def get_value(self) -> dict[str, Any]: - return { - "value": self.path_ref_editor.path, - "cid": self.path_ref_editor.cid or None, - } + def get_value(self) -> dict[str, Any] | None: + value = self.path_ref_editor.value + cid = self.path_ref_editor.cid + if not (value and cid): + return None + return {"value": value, "cid": cid or None} - def set_value(self, value: dict[str, Any]): - self.path_ref_editor.path = value.get("value") or "" + def set_value(self, value: dict[str, Any] | None): + self.path_ref_editor.value = value.get("value") or "" self.path_ref_editor.cid = value.get("cid") or "" def watch_value(self, callback: Callable[[Any], Any]): - self.path_ref_editor.param.watch(callback, ["path", "cid"]) + self.path_ref_editor.param.watch(callback, ["value", "cid"]) class PathRefEditorFactory(ComponentFactoryBase): type = "object" - format = "path_ref" + format = "PathRef" def create_component( self, value: JsonValue, title: str, schema: JsonSchemaDict ) -> Component: - path_ref: dict[str, Any] = value + path_ref: dict[str, Any] | None = value return PathRefComponent( PathRefEditor( title=title, - path=path_ref.get("value") or "", - cid=path_ref.get("cid") or "", + value=(path_ref and path_ref.get("value")) or "", + cid=(path_ref and path_ref.get("cid")) or "", + tooltip=schema.get("description"), ) ) diff --git a/s2gos-client/tests/test_gui.py b/s2gos-client/tests/test_gui.py index e551555..e1f28c4 100644 --- a/s2gos-client/tests/test_gui.py +++ b/s2gos-client/tests/test_gui.py @@ -3,7 +3,18 @@ # https://opensource.org/license/apache-2-0. import s2gos_client.gui +from cuiman.gui.component import ComponentContainer, ComponentFactory def test_gui_ok(): assert {"Client"}.issubset(dir(s2gos_client.gui)) + + +def test_extra_gui_components_registered(): + factory = ComponentContainer.registry.find_factory({"type": "object"}) + assert factory is None + + factory = ComponentContainer.registry.find_factory( + {"type": "object", "format": "PathRef"} + ) + assert isinstance(factory, ComponentFactory) From fecf1c27d8ef0f962d50423685cfb1f86acde7a8 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Thu, 29 Jan 2026 14:50:26 +0100 Subject: [PATCH 5/7] Added support for PathRef component (not yet used) --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 3246525..1481bc9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ ## Changes in version 0.1.0 (in development) +Added GUI component support for +[PathRef](https://github.com/s2gos-dev/s2gos-utils/blob/MTR/src/s2gos_utils/io/paths.py) +object (not yet used). + Major parts of the S2GOS controller packages have been generic with respect to the primary interface used between the client and the gateway server, which is the From 4172c3cea02a46904c9c29a052a4728abffc68d2 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Thu, 29 Jan 2026 14:50:51 +0100 Subject: [PATCH 6/7] Update --- notebooks/client-gui.ipynb | 1628 ++++++++++++++++++------------------ 1 file changed, 800 insertions(+), 828 deletions(-) diff --git a/notebooks/client-gui.ipynb b/notebooks/client-gui.ipynb index abf2aba..0f767a9 100644 --- a/notebooks/client-gui.ipynb +++ b/notebooks/client-gui.ipynb @@ -7,7 +7,7 @@ "source": [ "# Client GUI\n", "\n", - "The GUI client extends the Python API client by adding dedicated GUI-widgets for specific features:\n", + "The S2GOS GUI client extends the Python API client by adding dedicated GUI-widgets for specific features:\n", "\n", "- `client.show()`: execute a given process execution request,\n", "- `client.show_jobs()`: show all jobs resulting from process execution,\n", @@ -34,186 +34,571 @@ "execution_count": 1, "id": "8be0d24e-00ad-4ce0-8217-27a6747b5767", "metadata": {}, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'pydantic_settings'", - "output_type": "error", - "traceback": [ - "\u001b[31m---------------------------------------------------------------------------\u001b[39m", - "\u001b[31mModuleNotFoundError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01ms2gos_client\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mgui\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Client\n", - "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\s2gos-controller\\s2gos-client\\src\\s2gos_client\\__init__.py:7\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mimportlib\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmetadata\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m version\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient, Client, ClientConfig, ClientError\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mdefaults\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m DEFAULT_SERVER_URL, DEFAULT_USER_NAME, DEFAULT_ACCESS_TOKEN\n\u001b[32m 12\u001b[39m __version__ = version(\u001b[33m\"\u001b[39m\u001b[33ms2gos-client\u001b[39m\u001b[33m\"\u001b[39m)\n", - "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\s2gos-controller\\s2gos-client\\src\\s2gos_client\\api.py:5\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mcuiman\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient, Client, ClientConfig, ClientError\n\u001b[32m 7\u001b[39m __all__ = [\n\u001b[32m 8\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mAsyncClient\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 9\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mClient\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 10\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mClientConfig\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 11\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mClientError\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 12\u001b[39m ]\n", - "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\__init__.py:7\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by the Eozilla team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mimportlib\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmetadata\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m version\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01masync_client\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient\n\u001b[32m 8\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mclient\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Client\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mapi\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mconfig\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m ClientConfig\n", - "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\api\\__init__.py:5\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# Copyright (c) 2025 by the Eozilla team and contributors\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# Permissions are hereby granted under the terms of the Apache 2.0 License:\u001b[39;00m\n\u001b[32m 3\u001b[39m \u001b[38;5;66;03m# https://opensource.org/license/apache-2-0.\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m5\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01masync_client\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClient\n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mclient\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Client\n\u001b[32m 7\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mconfig\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m ClientConfig\n", - "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\api\\async_client.py:21\u001b[39m\n\u001b[32m 8\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mgavicore\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m (\n\u001b[32m 9\u001b[39m ApiError,\n\u001b[32m 10\u001b[39m Capabilities,\n\u001b[32m (...)\u001b[39m\u001b[32m 17\u001b[39m ProcessRequest,\n\u001b[32m 18\u001b[39m )\n\u001b[32m 20\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01masync_client_mixin\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncClientMixin\n\u001b[32m---> \u001b[39m\u001b[32m21\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mconfig\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m ClientConfig\n\u001b[32m 22\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mishell\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m has_ishell \u001b[38;5;28;01mas\u001b[39;00m _ \u001b[38;5;66;03m# noqa F401\u001b[39;00m\n\u001b[32m 23\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mtransport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AsyncTransport, TransportArgs\n", - "\u001b[36mFile \u001b[39m\u001b[32m~\\Projects\\eozilla\\cuiman\\src\\cuiman\\api\\config.py:10\u001b[39m\n\u001b[32m 8\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01myaml\u001b[39;00m\n\u001b[32m 9\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpydantic\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Field, HttpUrl, field_validator\n\u001b[32m---> \u001b[39m\u001b[32m10\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpydantic_settings\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m BaseSettings, SettingsConfigDict\n\u001b[32m 12\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mgavicore\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mmodels\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m InputDescription, ProcessDescription, ProcessSummary\n\u001b[32m 14\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01mauth\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m AuthConfig\n", - "\u001b[31mModuleNotFoundError\u001b[39m: No module named 'pydantic_settings'" - ] - } - ], - "source": [ - "from s2gos_client.gui import Client" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "6c90402f-b2a2-4e1e-873c-8ceca7780ed6", - "metadata": {}, "outputs": [ { "data": { - "application/json": { - "access_token": "1234", - "server_url": "http://127.0.0.1:8008", - "user_name": "bibo" - }, - "text/plain": [ - "" + "text/html": [ + "" ] }, - "execution_count": 2, - "metadata": { - "application/json": { - "root": "Client configuration:" - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "client = Client()\n", - "client" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7154afcd-59a9-484f-8271-1b4773b8c636", - "metadata": {}, - "outputs": [ + "metadata": {}, + "output_type": "display_data" + }, { "data": { - "application/json": { - "links": [ - { - "href": "http://127.0.0.1:8008/processes", - "hreflang": "en", - "rel": "self", - "title": "get_processes", - "type": "application/json" - } - ], - "processes": [ - { - "description": "Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.", - "id": "sleep_a_while", - "title": "Sleep Processor", - "version": "0.0.0" - }, - { - "description": "Returns the list of prime numbers between a `min_val` and `max_val`.", - "id": "primes_between", - "title": "Prime Processor", - "version": "0.0.0" - }, - { - "description": "Simulate a set scene images slices for testing. Creates an xarray dataset with `periodicity` time slices and writes it as Zarr into a temporary location. Requires installed `dask`, `xarray`, and `zarr` packages.", - "id": "simulate_scene", - "title": "Generate scene for testing", - "version": "0.0.0" - }, - { - "id": "return_base_model", - "title": "BaseModel Test", - "version": "0.0.0" - } - ] - }, - "text/plain": [ - "ProcessList(processes=[ProcessSummary(title='Sleep Processor', description='Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.', keywords=None, metadata=None, additionalParameters=None, id='sleep_a_while', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Prime Processor', description='Returns the list of prime numbers between a `min_val` and `max_val`.', keywords=None, metadata=None, additionalParameters=None, id='primes_between', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Generate scene for testing', description='Simulate a set scene images slices for testing. Creates an xarray dataset with `periodicity` time slices and writes it as Zarr into a temporary location. Requires installed `dask`, `xarray`, and `zarr` packages.', keywords=None, metadata=None, additionalParameters=None, id='simulate_scene', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='BaseModel Test', description=None, keywords=None, metadata=None, additionalParameters=None, id='return_base_model', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], links=[Link(href='http://127.0.0.1:8008/processes', rel='self', type='application/json', hreflang='en', title='get_processes')])" - ] - }, - "execution_count": 3, - "metadata": { - "application/json": { - "root": "ProcessList object:" - } + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = true;\n", + " const py_version = '3.8.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = false;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {}});\n", + " require([\"tabulator\"], function(Tabulator) {\n", + " window.Tabulator = Tabulator\n", + " on_load()\n", + " })\n", + " require([\"moment\"], function(moment) {\n", + " window.moment = moment\n", + " on_load()\n", + " })\n", + " require([\"notyf\"], function() {\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 3;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.Notyf !== undefined) && (!(window.Notyf instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.1.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/panel.min.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/font-awesome/css/all.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/css/notifications.css\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n const py_version = '3.8.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = false;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {}});\n require([\"tabulator\"], function(Tabulator) {\n window.Tabulator = Tabulator\n on_load()\n })\n require([\"moment\"], function(moment) {\n window.moment = moment\n on_load()\n })\n require([\"notyf\"], function() {\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 3;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.Notyf !== undefined) && (!(window.Notyf instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.1.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.js\", \"https://cdn.holoviz.org/panel/1.8.3/dist/panel.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/notificationarea/notyf@3/notyf.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/bundled/font-awesome/css/all.min.css\", \"https://cdn.holoviz.org/panel/1.8.3/dist/css/notifications.css\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" }, - "output_type": "execute_result" - } - ], - "source": [ - "client.get_processes()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "67179e44-a969-4b5a-ab7a-03ba3b9c7054", - "metadata": {}, - "outputs": [ + "metadata": {}, + "output_type": "display_data" + }, { "data": { - "application/json": { - "description": "Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.", - "id": "sleep_a_while", - "inputs": { - "duration": { - "minOccurs": 0, - "schema": { - "default": 10, - "type": "number" - }, - "title": "Duration" - }, - "fail": { - "minOccurs": 0, - "schema": { - "default": false, - "type": "boolean" - }, - "title": "Fail" - } - }, - "outputs": { - "return_value": { - "schema": { - "type": "number" - }, - "title": "Return Value" - } - }, - "title": "Sleep Processor", - "version": "0.0.0" - }, - "text/plain": [ - "ProcessDescription(title='Sleep Processor', description='Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.', keywords=None, metadata=None, additionalParameters=None, id='sleep_a_while', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'duration': InputDescription(title='Duration', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=10.0, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'fail': InputDescription(title='Fail', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=False, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Return Value', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})" - ] - }, - "execution_count": 4, - "metadata": { - "application/json": { - "root": "ProcessDescription object:" - } + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " let retries = 0;\n", + " const open = () => {\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else if (retries > 3) {\n", + " console.warn('Comm target never activated')\n", + " } else {\n", + " retries += 1\n", + " setTimeout(open, 500)\n", + " }\n", + " }\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else {\n", + " setTimeout(open, 500)\n", + " }\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n let retries = 0;\n const open = () => {\n if (comm.active) {\n comm.open();\n } else if (retries > 3) {\n console.warn('Comm target never activated')\n } else {\n retries += 1\n setTimeout(open, 500)\n }\n }\n if (comm.active) {\n comm.open();\n } else {\n setTimeout(open, 500)\n }\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" }, - "output_type": "execute_result" - } - ], - "source": [ - "client.get_process(\"sleep_a_while\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "cc034916-02db-4ec2-8682-71710d54edf6", - "metadata": {}, - "outputs": [ - { - "data": {}, "metadata": {}, "output_type": "display_data" }, @@ -221,12 +606,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "" - ], - "text/plain": [ - "MainPanel(_processes=[ProcessSummary(title='Sleep Processor', description='Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.', keywords=None, metadata=None, additionalParameters=None, id='sleep_a_while', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Prime Processor', description='Returns the list of prime numbers between a `min_val` and `max_val`.', keywords=None, metadata=None, additionalParameters=None, id='primes_between', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Generate scene for testing', description='Simulate a set scene images slices for testing. Creates an xarray dataset with `periodicity` time slices and writes it as Zarr into a temporary location. Requires installed `dask`, `xarray`, and `zarr` packages.', keywords=None, metadata=None, additionalParameters=None, id='simulate_scene', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='BaseModel Test', description=None, keywords=None, metadata=None, additionalParameters=None, id='return_base_model', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], _processes_dict={'sleep_a_while': ProcessDescription(title='Sleep Processor', description='Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`. Returns the effective amount of sleep in seconds.', keywords=None, metadata=None, additionalParameters=None, id='sleep_a_while', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'duration': InputDescription(title='Duration', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=10.0, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'fail': InputDescription(title='Fail', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=False, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Return Value', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}), 'simulate_scene': ProcessDescription(title='Generate scene for testing', description='Simulate a set scene images slices for testing. Creates an xarray dataset with `periodicity` time slices and writes it as Zarr into a temporary location. Requires installed `dask`, `xarray`, and `zarr` packages.', keywords=None, metadata=None, additionalParameters=None, id='simulate_scene', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'var_names': InputDescription(title='Variable names', description='Comma-separated list of variable names.', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default='a, b, c', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'bbox': InputDescription(title='Bounding box', description='Bounding box in geographical coordinates.', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=4, minItems=4, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), properties=None, additionalProperties=True, description=None, format='bbox', default=[-180, -90, 180, 90], nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'resolution': InputDescription(title='Spatial resolution', description='Spatial resolution in degree.', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=1.0, exclusiveMaximum=False, minimum=0.01, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=0.5, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'start_date': InputDescription(title='Start date', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format='date', default='2025-01-01', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'end_date': InputDescription(title='End date', description=None, keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format='date', default='2025-02-01', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'periodicity': InputDescription(title='Periodicity', description='Size of time steps in days.', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=10.0, exclusiveMaximum=False, minimum=1.0, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=1, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'output_path': InputDescription(title='Output path', description='Local output path or URI.', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Link', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=['href'], enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties={'href': Schema(field_ref=None, title='Href', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'rel': Schema(field_ref=None, title='Rel', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=['service'], deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'type': Schema(field_ref=None, title='Type', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=['application/json'], deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'hreflang': Schema(field_ref=None, title='Hreflang', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=['en'], deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None), 'title': Schema(field_ref=None, title='Title', multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)}, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})}, name='MainPanel00124')" ] }, - "execution_count": 7, "metadata": { "application/vnd.holoviews_exec.v0+json": { - "id": "fe51966a-f9fa-46ea-a2ab-7c2f2a682190" - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "client.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "736d52d8-d91a-435b-8dfb-b016a5139201", - "metadata": {}, - "outputs": [ - { - "data": { - "application/json": { - "dotpath": true, - "inputs": { - "bbox": [ - -13.504397, - 32.322417, - 6.534666, - 45.643231 - ], - "end_date": "2025-02-01", - "output_path": "test.zarr", - "periodicity": 1, - "resolution": 0.5, - "start_date": "2025-01-01", - "var_names": "a, b, c" - }, - "process_id": "simulate_scene" - }, - "text/plain": [ - "ExecutionRequest(inputs={'var_names': 'a, b, c', 'bbox': [-13.504397, 32.322417, 6.534666, 45.643231], 'resolution': 0.5, 'start_date': '2025-01-01', 'end_date': '2025-02-01', 'periodicity': 1, 'output_path': 'test.zarr'}, outputs=None, response=, subscriber=None, process_id='simulate_scene', dotpath=True)" - ] - }, - "execution_count": 10, - "metadata": { - "application/json": { - "root": "ExecutionRequest object:" + "id": "28631613-08e1-4934-ace0-68b36c1c2db7" } }, - "output_type": "execute_result" - } - ], - "source": [ - "_request" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "027d2bbc-1816-4c14-9616-8239b9210d1f", - "metadata": {}, - "outputs": [], - "source": [ - "# client.stop_updating()" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "8c52f9fb-300f-4de0-b64d-9f37fd028890", - "metadata": {}, - "outputs": [ + "output_type": "display_data" + }, { "data": {}, "metadata": {}, @@ -377,12 +694,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "" ], "text/plain": [ - "JobsPanel(name='JobsPanel00372')" + "NotificationArea()" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "f261e48f-4abd-4bb5-a399-92fb29bd6b01" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "from s2gos_client.gui import Client" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "6c90402f-b2a2-4e1e-873c-8ceca7780ed6", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "api_key": null, + "api_key_header": "X-API-Key", + "api_url": "http://localhost:8008/", + "auth_type": "none", + "auth_url": null, + "password": null, + "token": null, + "token_header": "X-Auth-Token", + "use_bearer": false, + "username": null + }, + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": { + "application/json": { + "root": "Client configuration:" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "client = Client()\n", + "client" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "7154afcd-59a9-484f-8271-1b4773b8c636", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "links": [ + { + "href": "http://localhost:8008/processes", + "hreflang": "en", + "rel": "self", + "title": "get_processes", + "type": "application/json" + } + ], + "processes": [ + { + "description": "Generate 3D scene for MTR demo with seasonal variations.\n\nThis processor:\n1. Creates a scene generation configuration based on season/month\n2. Immediately runs the generation pipeline\n3. Returns path to the generated scene description YAML\n\nThe scene includes:\n- PNP location with 10km target area\n- Seasonal vegetation (summer/winter variants)\n- Heterogeneous atmosphere with aerosol layer\n- Tower XML scene at fixed location\n- Optional snow cover (June only)\n\nArgs:\n month: Month for simulation (controls seasonal variations)\n random_seed: Random seed for reproducible vegetation placement\n scene_name: Filename for scene description YAML\n\nReturns:\n Path to generated scene description YAML file, or None if validation fails", + "id": "mtr_demo_generation", + "title": "Scene Generation Demo", + "version": "0.0.0" + }, + { + "description": "Run simulation for MTR demo with configurable observation types.\n\nThis processor:\n1. Creates a simulation configuration based on observation type\n2. Immediately runs the simulation\n3. Returns path to the simulation output directory\n\nSupported observation types:\n- CHIME: Hyperspectral satellite sensor\n- MSI: Sentinel-2 multispectral sensor (configurable bands)\n- HYPSTAR: Ground-based hyperspectral sensor with HCRF processing\n- RGB_CAMERA: Perspective camera viewing tower from configurable position\n- SATELLITE_HDRF: [PLACEHOLDER - To be implemented]\n\nArgs:\n scene_name: Filename of the scene YAML from generation step\n month: Month for simulation (determines observation date)\n hour_utc: Hour of observation in UTC\n observation: Observation type configuration\n spp: Samples per pixel for Monte Carlo simulation\n sim_name: Filename for the for simulation config JSON\n\nReturns:\n Path to simulation output directory, or None if observation type\n is not yet implemented or simulation fails", + "id": "mtr_demo_simulation", + "title": "Simulation Demo", + "version": "0.0.0" + } + ] + }, + "text/plain": [ + "ProcessList(processes=[ProcessSummary(title='Scene Generation Demo', description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n scene_name: Filename for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Simulation Demo', description='Run simulation for MTR demo with configurable observation types.\\n\\nThis processor:\\n1. Creates a simulation configuration based on observation type\\n2. Immediately runs the simulation\\n3. Returns path to the simulation output directory\\n\\nSupported observation types:\\n- CHIME: Hyperspectral satellite sensor\\n- MSI: Sentinel-2 multispectral sensor (configurable bands)\\n- HYPSTAR: Ground-based hyperspectral sensor with HCRF processing\\n- RGB_CAMERA: Perspective camera viewing tower from configurable position\\n- SATELLITE_HDRF: [PLACEHOLDER - To be implemented]\\n\\nArgs:\\n scene_name: Filename of the scene YAML from generation step\\n month: Month for simulation (determines observation date)\\n hour_utc: Hour of observation in UTC\\n observation: Observation type configuration\\n spp: Samples per pixel for Monte Carlo simulation\\n sim_name: Filename for the for simulation config JSON\\n\\nReturns:\\n Path to simulation output directory, or None if observation type\\n is not yet implemented or simulation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_simulation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], links=[Link(href='http://localhost:8008/processes', rel='self', type='application/json', hreflang='en', title='get_processes')])" + ] + }, + "execution_count": 3, + "metadata": { + "application/json": { + "root": "ProcessList object:" + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "client.get_processes()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "67179e44-a969-4b5a-ab7a-03ba3b9c7054", + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "description": "Generate 3D scene for MTR demo with seasonal variations.\n\nThis processor:\n1. Creates a scene generation configuration based on season/month\n2. Immediately runs the generation pipeline\n3. Returns path to the generated scene description YAML\n\nThe scene includes:\n- PNP location with 10km target area\n- Seasonal vegetation (summer/winter variants)\n- Heterogeneous atmosphere with aerosol layer\n- Tower XML scene at fixed location\n- Optional snow cover (June only)\n\nArgs:\n month: Month for simulation (controls seasonal variations)\n random_seed: Random seed for reproducible vegetation placement\n scene_name: Filename for scene description YAML\n\nReturns:\n Path to generated scene description YAML file, or None if validation fails", + "id": "mtr_demo_generation", + "inputs": { + "month": { + "description": "Month selection for MTR demo (limited to solstice dates).", + "minOccurs": 0, + "schema": { + "default": "december", + "enum": [ + "december", + "june" + ], + "type": "string" + }, + "title": "Month" + }, + "random_seed": { + "description": "RNG seed for vegetation placement", + "minOccurs": 0, + "schema": { + "default": 13, + "type": "integer" + }, + "title": "Vegetation RNG seed" + }, + "scene_name": { + "description": "Name of scene", + "minOccurs": 0, + "schema": { + "type": "string" + }, + "title": "Scene name" + } + }, + "outputs": { + "return_value": { + "schema": { + "nullable": true, + "type": "string" + }, + "title": "Return Value" + } + }, + "title": "Scene Generation Demo", + "version": "0.0.0" + }, + "text/plain": [ + "ProcessDescription(title='Scene Generation Demo', description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n scene_name: Filename for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'month': InputDescription(title='Month', description='Month selection for MTR demo (limited to solstice dates).', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=['december', 'june'], type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default='december', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'random_seed': InputDescription(title='Vegetation RNG seed', description='RNG seed for vegetation placement', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=13, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'scene_name': InputDescription(title='Scene name', description='Name of scene', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Return Value', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})" ] }, - "execution_count": 13, + "execution_count": 4, "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "3761c588-1563-4739-9c51-61dad83c3b2a" + "application/json": { + "root": "ProcessDescription object:" } }, "output_type": "execute_result" } ], "source": [ - "client.show_jobs()" + "client.get_process(\"mtr_demo_generation\")" ] }, { "cell_type": "code", - "execution_count": 11, - "id": "d3815528-3ba8-4328-b9e2-a97797bea532", + "execution_count": 5, + "id": "cc034916-02db-4ec2-8682-71710d54edf6", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Update thread is now running\n" + ] + }, { "data": {}, "metadata": {}, @@ -480,12 +963,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "" ], "text/plain": [ - "JobInfoPanel(client_error=None, job_info=JobInfo(processID='simulate_scene', type=, jobID='job_4', status=, message=None, created=datetime.datetime(2025, 11, 13, 18, 1, 20, 568455, tzinfo=TzInfo(0)), started=datetime.datetime(2025, 11, 13, 18, 1, 20, 568998, tzinfo=TzInfo(0)), finished=datetime.datetime(2025, 11, 13, 18, 1, 20, 648477, tzinfo=TzInfo(0)), updated=None, progress=None, links=None, traceback=None), name='JobInfoPanel00487')" + "MainPanel(_processes=[ProcessSummary(title='Scene Generation Demo', description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n scene_name: Filename for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Simulation Demo', description='Run simulation for MTR demo with configurable observation types.\\n\\nThis processor:\\n1. Creates a simulation configuration based on observation type\\n2. Immediately runs the simulation\\n3. Returns path to the simulation output directory\\n\\nSupported observation types:\\n- CHIME: Hyperspectral satellite sensor\\n- MSI: Sentinel-2 multispectral sensor (configurable bands)\\n- HYPSTAR: Ground-based hyperspectral sensor with HCRF processing\\n- RGB_CAMERA: Perspective camera viewing tower from configurable position\\n- SATELLITE_HDRF: [PLACEHOLDER - To be implemented]\\n\\nArgs:\\n scene_name: Filename of the scene YAML from generation step\\n month: Month for simulation (determines observation date)\\n hour_utc: Hour of observation in UTC\\n observation: Observation type configuration\\n spp: Samples per pixel for Monte Carlo simulation\\n sim_name: Filename for the for simulation config JSON\\n\\nReturns:\\n Path to simulation output directory, or None if observation type\\n is not yet implemented or simulation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_simulation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], _processes_dict={'mtr_demo_generation': ProcessDescription(title='Scene Generation Demo', description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n scene_name: Filename for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'month': InputDescription(title='Month', description='Month selection for MTR demo (limited to solstice dates).', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=['december', 'june'], type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default='december', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'random_seed': InputDescription(title='Vegetation RNG seed', description='RNG seed for vegetation placement', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=13, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'scene_name': InputDescription(title='Scene name', description='Name of scene', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Return Value', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})}, name='MainPanel00124')" ] }, - "execution_count": 11, + "execution_count": 5, "metadata": { "application/vnd.holoviews_exec.v0+json": { - "id": "5a8c1d03-f263-4f21-96c7-8cfe317f3b1f" + "id": "9f352105-17f1-4b8e-ba8e-91593fd18cce" } }, "output_type": "execute_result" } ], "source": [ - "client.show_job(\"job_4\")" + "client.show()" ] }, { "cell_type": "code", - "execution_count": 14, - "id": "133234e0-e393-4384-972c-de5cbaa3d91c", + "execution_count": 6, + "id": "736d52d8-d91a-435b-8dfb-b016a5139201", "metadata": {}, "outputs": [ { - "data": { - "application/json": { - "return_value": { - "href": "file:///C:/Users/Norman/Projects/s2gos-controller/test.zarr", - "hreflang": null, - "rel": null, - "title": null, - "type": "application/zarr" - } - }, - "text/plain": [ - "{'return_value': {'href': 'file:///C:/Users/Norman/Projects/s2gos-controller/test.zarr',\n", - " 'rel': None,\n", - " 'type': 'application/zarr',\n", - " 'hreflang': None,\n", - " 'title': None}}" - ] - }, - "execution_count": 14, - "metadata": { - "application/json": { - "root": "Results:" - } - }, - "output_type": "execute_result" + "ename": "NameError", + "evalue": "name '_request' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43m_request\u001b[49m\n", + "\u001b[31mNameError\u001b[39m: name '_request' is not defined" + ] } ], + "source": [ + "_request" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "027d2bbc-1816-4c14-9616-8239b9210d1f", + "metadata": {}, + "outputs": [], + "source": [ + "# client.stop_updating()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c52f9fb-300f-4de0-b64d-9f37fd028890", + "metadata": {}, + "outputs": [], + "source": [ + "client.show_jobs()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3815528-3ba8-4328-b9e2-a97797bea532", + "metadata": {}, + "outputs": [], + "source": [ + "client.show_job(\"job_4\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "133234e0-e393-4384-972c-de5cbaa3d91c", + "metadata": {}, + "outputs": [], "source": [ "_results" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "cea797e0-9977-4727-98df-b4d6a3cccf65", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset> Size: 804kB\n",
-       "Dimensions:  (time: 31, lat: 27, lon: 40)\n",
-       "Coordinates:\n",
-       "  * time     (time) datetime64[ns] 248B 2025-01-01 2025-01-02 ... 2025-01-31\n",
-       "  * lat      (lat) float64 216B 32.57 33.07 33.56 34.05 ... 44.41 44.9 45.39\n",
-       "  * lon      (lon) float64 320B -13.25 -12.75 -12.25 ... 5.283 5.784 6.285\n",
-       "Data variables:\n",
-       "    a        (time, lat, lon) float64 268kB ...\n",
-       "    b        (time, lat, lon) float64 268kB ...\n",
-       "    c        (time, lat, lon) float64 268kB ...
" - ], - "text/plain": [ - " Size: 804kB\n", - "Dimensions: (time: 31, lat: 27, lon: 40)\n", - "Coordinates:\n", - " * time (time) datetime64[ns] 248B 2025-01-01 2025-01-02 ... 2025-01-31\n", - " * lat (lat) float64 216B 32.57 33.07 33.56 34.05 ... 44.41 44.9 45.39\n", - " * lon (lon) float64 320B -13.25 -12.75 -12.25 ... 5.283 5.784 6.285\n", - "Data variables:\n", - " a (time, lat, lon) float64 268kB ...\n", - " b (time, lat, lon) float64 268kB ...\n", - " c (time, lat, lon) float64 268kB ..." - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import xarray as xr\n", "xr.open_dataset(_results[\"return_value\"][\"href\"])" From 60570d696da68c07d54ed04a7787ebe7586ff76d Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Fri, 30 Jan 2026 10:05:17 +0100 Subject: [PATCH 7/7] introduced an advanced input --- notebooks/client-gui.ipynb | 316 +++++++----------- .../src/s2gos_server/services/testing.py | 20 +- 2 files changed, 142 insertions(+), 194 deletions(-) diff --git a/notebooks/client-gui.ipynb b/notebooks/client-gui.ipynb index 0f767a9..6bc7480 100644 --- a/notebooks/client-gui.ipynb +++ b/notebooks/client-gui.ipynb @@ -606,12 +606,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "" ], "text/plain": [ - "MainPanel(_processes=[ProcessSummary(title='Scene Generation Demo', description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n scene_name: Filename for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None), ProcessSummary(title='Simulation Demo', description='Run simulation for MTR demo with configurable observation types.\\n\\nThis processor:\\n1. Creates a simulation configuration based on observation type\\n2. Immediately runs the simulation\\n3. Returns path to the simulation output directory\\n\\nSupported observation types:\\n- CHIME: Hyperspectral satellite sensor\\n- MSI: Sentinel-2 multispectral sensor (configurable bands)\\n- HYPSTAR: Ground-based hyperspectral sensor with HCRF processing\\n- RGB_CAMERA: Perspective camera viewing tower from configurable position\\n- SATELLITE_HDRF: [PLACEHOLDER - To be implemented]\\n\\nArgs:\\n scene_name: Filename of the scene YAML from generation step\\n month: Month for simulation (determines observation date)\\n hour_utc: Hour of observation in UTC\\n observation: Observation type configuration\\n spp: Samples per pixel for Monte Carlo simulation\\n sim_name: Filename for the for simulation config JSON\\n\\nReturns:\\n Path to simulation output directory, or None if observation type\\n is not yet implemented or simulation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_simulation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None)], _processes_dict={'mtr_demo_generation': ProcessDescription(title='Scene Generation Demo', description='Generate 3D scene for MTR demo with seasonal variations.\\n\\nThis processor:\\n1. Creates a scene generation configuration based on season/month\\n2. Immediately runs the generation pipeline\\n3. Returns path to the generated scene description YAML\\n\\nThe scene includes:\\n- PNP location with 10km target area\\n- Seasonal vegetation (summer/winter variants)\\n- Heterogeneous atmosphere with aerosol layer\\n- Tower XML scene at fixed location\\n- Optional snow cover (June only)\\n\\nArgs:\\n month: Month for simulation (controls seasonal variations)\\n random_seed: Random seed for reproducible vegetation placement\\n scene_name: Filename for scene description YAML\\n\\nReturns:\\n Path to generated scene description YAML file, or None if validation fails', keywords=None, metadata=None, additionalParameters=None, id='mtr_demo_generation', version='0.0.0', jobControlOptions=None, outputTransmission=None, links=None, inputs={'month': InputDescription(title='Month', description='Month selection for MTR demo (limited to solstice dates).', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=['december', 'june'], type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default='december', nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'random_seed': InputDescription(title='Vegetation RNG seed', description='RNG seed for vegetation placement', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=13, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None)), 'scene_name': InputDescription(title='Scene name', description='Name of scene', keywords=None, metadata=None, additionalParameters=None, minOccurs=0, maxOccurs=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=False, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))}, outputs={'return_value': OutputDescription(title='Return Value', description=None, keywords=None, metadata=None, additionalParameters=None, schema_=Schema(field_ref=None, title=None, multipleOf=None, maximum=None, exclusiveMaximum=False, minimum=None, exclusiveMinimum=False, maxLength=None, minLength=0, pattern=None, maxItems=None, minItems=0, uniqueItems=False, maxProperties=None, minProperties=0, required=None, enum=None, type=, not_=None, allOf=None, oneOf=None, anyOf=None, discriminator=None, items=None, properties=None, additionalProperties=True, description=None, format=None, default=None, nullable=True, readOnly=False, writeOnly=False, example=None, examples=None, deprecated=False, contentMediaType=None, contentEncoding=None, contentSchema=None))})}, name='MainPanel00124')" + "MainPanelView(name='MainPanelView00124')" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": { "application/vnd.holoviews_exec.v0+json": { - "id": "9f352105-17f1-4b8e-ba8e-91593fd18cce" + "id": "7a00addf-510a-4f13-8433-d0a2ca6a6cba" } }, "output_type": "execute_result" @@ -1053,7 +896,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "id": "736d52d8-d91a-435b-8dfb-b016a5139201", "metadata": {}, "outputs": [ @@ -1064,7 +907,7 @@ "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", - "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43m_request\u001b[49m\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[4]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43m_request\u001b[49m\n", "\u001b[31mNameError\u001b[39m: name '_request' is not defined" ] } @@ -1085,24 +928,107 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "8c52f9fb-300f-4de0-b64d-9f37fd028890", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "JobsPanelView(name='JobsPanelView00222')" + ] + }, + "execution_count": 5, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "060fb01b-f2bd-40db-853d-70ce49fd78a5" + } + }, + "output_type": "execute_result" + } + ], "source": [ "client.show_jobs()" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "d3815528-3ba8-4328-b9e2-a97797bea532", - "metadata": {}, - "outputs": [], - "source": [ - "client.show_job(\"job_4\")" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1140,6 +1066,16 @@ "id": "70d50fbf-a6cb-48d6-907b-770e38647af1", "metadata": {}, "outputs": [], + "source": [ + "client.show_job(\"job_3\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21671653-65ac-4590-b1c0-0b91c3f30ceb", + "metadata": {}, + "outputs": [], "source": [] } ], diff --git a/s2gos-server/src/s2gos_server/services/testing.py b/s2gos-server/src/s2gos_server/services/testing.py index c021d15..9a6e684 100644 --- a/s2gos-server/src/s2gos_server/services/testing.py +++ b/s2gos-server/src/s2gos_server/services/testing.py @@ -19,7 +19,9 @@ from pydantic import Field -from procodile import JobContext +from gavicore.models import InputDescription +from procodile import JobContext, additional_parameters + from wraptile.services.local import LocalService @@ -30,6 +32,12 @@ registry = service.process_registry +# noinspection PyTypeChecker +advanced_input = InputDescription( + additionalParameters=additional_parameters({"level": "advanced"}), + schema={}, +) + # ============================================================================ # Constants # ============================================================================ @@ -132,7 +140,7 @@ def mtr_demo_generation( print("=" * 60) ctx.report_progress(message="Running scene generation pipeline...") - scene_path = generation_from_config() + scene_path = generation_from_config(scene_name) if scene_path: print("\n" + "=" * 60) print("SCENE GENERATION COMPLETE") @@ -149,8 +157,12 @@ def mtr_demo_generation( # ============================================================================ -# noinspection PyUnusedLocal -@registry.process(id="mtr_demo_simulation", title="Simulation Demo") +# noinspection PyUnusedLocal,PyArgumentList,PyTypeChecker +@registry.process( + id="mtr_demo_simulation", + title="Simulation Demo", + inputs=dict(spp=advanced_input), +) def mtr_demo_simulation( scene_name: Annotated[ str,