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 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..6bc7480 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", @@ -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", "```" @@ -603,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')" + "MainPanelView(name='MainPanelView00124')" ] }, - "execution_count": 7, + "execution_count": 3, "metadata": { "application/vnd.holoviews_exec.v0+json": { - "id": "fe51966a-f9fa-46ea-a2ab-7c2f2a682190" + "id": "7a00addf-510a-4f13-8433-d0a2ca6a6cba" } }, "output_type": "execute_result" @@ -1032,41 +896,20 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "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:" - } - }, - "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[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" + ] } ], "source": [ @@ -1085,7 +928,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 5, "id": "8c52f9fb-300f-4de0-b64d-9f37fd028890", "metadata": {}, "outputs": [ @@ -1098,12 +941,12 @@ "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ - "
\n", - "
\n", + "
\n", + "
\n", "
\n", "" ], "text/plain": [ - "JobsPanel(name='JobsPanel00372')" + "JobsPanelView(name='JobsPanelView00222')" ] }, - "execution_count": 13, + "execution_count": 5, "metadata": { "application/vnd.holoviews_exec.v0+json": { - "id": "3761c588-1563-4739-9c51-61dad83c3b2a" + "id": "060fb01b-f2bd-40db-853d-70ce49fd78a5" } }, "output_type": "execute_result" @@ -1188,686 +1031,20 @@ }, { "cell_type": "code", - "execution_count": 11, - "id": "d3815528-3ba8-4328-b9e2-a97797bea532", - "metadata": {}, - "outputs": [ - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\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')" - ] - }, - "execution_count": 11, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "5a8c1d03-f263-4f21-96c7-8cfe317f3b1f" - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "client.show_job(\"job_4\")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "133234e0-e393-4384-972c-de5cbaa3d91c", "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" - } - ], + "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\"])" @@ -1889,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/pixi.lock b/pixi.lock index d736b92..88557db 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: e621b5e81ee99a3741c2f154789fdf768d7efa26816b2527364cf55af80d627f + 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 deleted file mode 100644 index eea6e26..0000000 --- a/s2gos-client/src/s2gos_client/gui.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2025 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 cuiman.gui import Client - -__all__ = [ - "Client", -] diff --git a/s2gos-client/src/s2gos_client/gui/__init__.py b/s2gos-client/src/s2gos_client/gui/__init__.py new file mode 100644 index 0000000..cb6e08a --- /dev/null +++ b/s2gos-client/src/s2gos_client/gui/__init__.py @@ -0,0 +1,18 @@ +# 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 +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..ea1ea42 --- /dev/null +++ b/s2gos-client/src/s2gos_client/gui/pathref.py @@ -0,0 +1,104 @@ +# 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) + + value = param.String(default="") + cid = param.String(default="") + + disabled = param.Boolean(default=False) + + def __init__(self, **params): + super().__init__(**params) + + 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=f"{self.title} CID (optional)", + placeholder="Credentials ID...", + value=self.cid, + disabled=self.param.disabled, + width=120, + ) + + # widget ↔ param (two-way, explicit) + self._value_input.link(self, value="value") + self._cid_input.link(self, value="cid") + + # TODO: set tooltip (how?) + self.view = pn.Row( + self._value_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] | 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] | 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, ["value", "cid"]) + + +class PathRefEditorFactory(ComponentFactoryBase): + type = "object" + format = "PathRef" + + def create_component( + self, value: JsonValue, title: str, schema: JsonSchemaDict + ) -> Component: + path_ref: dict[str, Any] | None = value + return PathRefComponent( + PathRefEditor( + title=title, + value=(path_ref and path_ref.get("value")) or "", + cid=(path_ref and path_ref.get("cid")) or "", + tooltip=schema.get("description"), + ) + ) + + +def register_component(): + PathRefEditorFactory.register_in(ComponentContainer.registry) 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) 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..9a6e684 --- /dev/null +++ b/s2gos-server/src/s2gos_server/services/testing.py @@ -0,0 +1,288 @@ +# 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 gavicore.models import InputDescription +from procodile import JobContext, additional_parameters + +from wraptile.services.local import LocalService + + +service = LocalService( + title="S2GOS Test-Server", + description="Local DTE-S2GOS process server for testing", +) + +registry = service.process_registry + +# noinspection PyTypeChecker +advanced_input = InputDescription( + additionalParameters=additional_parameters({"level": "advanced"}), + schema={}, +) + +# ============================================================================ +# 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 +# ============================================================================ + + +# 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", + title="Vegetation RNG seed", + ), + ], + scene_name: Annotated[ + str, + Field( + ..., + description="Name of scene", + title="Scene name", + ), + ] = None, +) -> str | 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 + scene_name: Filename 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(scene_name) + 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 +# ============================================================================ + + +# 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, + 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) of the 21st of the chosen month, affects sun position ", + title="Hour (UTC)", + ), + ], + observation: Annotated[ + ObservationType, + Field(..., description="Observation type (enum value)", title="Observation"), + ], + spp: Annotated[ + int, + Field( + ..., + description="Samples per pixel for Monte Carlo simulation", + title="Samples per pixel", + ), + ] = 8, + sim_name: Annotated[ + str, + Field( + ..., + description="Simulation run name", + title="Name of run", + ), + ] = None, +) -> str | 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_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 + sim_name: Filename for the for simulation config JSON + + 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(scene_name) + + 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(scene_name: str) -> str: + return f"/outputs/scenes/{scene_name}" + + +def simulation_from_config(sim_name: str): + return f"/outputs/simulations/{sim_name}"