Client CLI Usage¶
The following is a step-by-step guide that demonstrates how to use the Sen4CAP CLI.
Similar to the Python API client, the CLI client provides the following capabilities:
sen4cap-client list-processes: list existing processes,sen4cap-client get-process: get the details about a process,sen4cap-client validate-request: validate a given process execution request,sen4cap-client execute-process: execute a given process execution request,sen4cap-client list-jobs: list the jobs resulting from process executions, and finallysen4cap-client get-job: get a job's details,sen4cap-client get-job-results: get a successful job's results, and finallysen4cap-client dismiss-job: cancel a successful job.
In the following, we visit all the commands by example.
In [1]:
Copied!
!sen4cap-client --help
!sen4cap-client --help
Usage: sen4cap-client [OPTIONS] COMMAND [ARGS]...
Interact with the ESA Sen4CAP processing service.
`sen4cap-client` can be used to get the available processes, get process
details, execute processes, and manage the jobs originating from the latter.
It
herewith resembles the core functionality of the OGC API - Processes, Part 1.
For details see https://ogcapi.ogc.org/processes/.
You can use shorter command name aliases, e.g., use command name `vr`
for `validate-request`, or `lp` for `list-processes`.
The tool's exit codes are as follows:
* `0` - normal exit
* `1` - user errors, argument errors
* `2` - remote API errors
* `3` - local network transport errors
If the `--traceback` flag is set, the original Python exception traceback
will be shown and the exit code will always be `1`.
Otherwise, only the error message is shown.
+- Options -------------------------------------------------------------------+
| --version Show version and exit. |
| --traceback,--tb Show server exception traceback, if any. |
| --install-completion Install completion for the current shell. |
| --show-completion Show completion for the current shell, to |
| copy it or customize the installation. |
| --help Show this message and exit. |
+-----------------------------------------------------------------------------+
+- Commands ------------------------------------------------------------------+
| configure Configure the client tool. |
| list-processes List available processes. |
| get-process Get process details. |
| create-request Create an execution request (template) for a given |
| process. |
| validate-request Validate a process execution request. |
| execute-process Execute a process in asynchronous mode. |
| list-jobs List all jobs. |
| get-job Get job details. |
| dismiss-job Cancel a running or delete a finished job. |
| get-job-results Get job results. |
+-----------------------------------------------------------------------------+
In [2]:
Copied!
!sen4cap-client configure
!sen4cap-client configure
Client configuration written to C:\Users\norma\.eozilla\config
In [3]:
Copied!
!sen4cap-client list-processes
!sen4cap-client list-processes
links:
- href: http://127.0.0.1:8008/processes
hreflang: en
rel: self
title: get_processes
type: application/json
processes:
- description: Sleeps for `duration` seconds. Fails on purpose if `fail` is `True`.
Returns the effective amount of sleep in seconds.
id: sleep_a_while
title: Sleep Processor
version: 0.0.0
- description: Returns the list of prime numbers between a `min_val` and `max_val`.
id: primes_between
title: Prime Processor
version: 0.0.0
- description: Simulate a set scene images slices for testing. Creates an xarray dataset
with `periodicity` time slices and writes it as Zarr into a temporary location.
Requires installed `dask`, `xarray`, and `zarr` packages.
id: simulate_scene
title: Generate scene for testing
version: 0.0.0
- id: return_base_model
title: BaseModel Test
version: 0.0.0
In [4]:
Copied!
!sen4cap-client get-process primes_between
!sen4cap-client get-process primes_between
description: Returns the list of prime numbers between a `min_val` and `max_val`.
id: primes_between
inputs:
max_val:
minOccurs: 0
schema:
default: 100
maximum: 100.0
type: integer
title: Max Val
min_val:
minOccurs: 0
schema:
default: 0
minimum: 0.0
type: integer
title: Min Val
outputs:
return_value:
schema:
items:
type: integer
type: array
title: Return Value
title: Prime Processor
version: 0.0.0
In [5]:
Copied!
!sen4cap-client execute-process primes_between -i min_val=10 -i max_val=80
!sen4cap-client execute-process primes_between -i min_val=10 -i max_val=80
created: '2025-11-12T10:18:38.616131Z' jobID: job_2 processID: primes_between status: accepted type: process
In [6]:
Copied!
!sen4cap-client list-jobs
!sen4cap-client list-jobs
jobs: - created: '2025-11-12T10:14:54.537952Z' finished: '2025-11-12T10:14:54.739734Z' jobID: job_0 processID: sleep_a_while progress: 1 started: '2025-11-12T10:14:54.538644Z' status: dismissed type: process updated: '2025-11-12T10:14:54.639215Z' - created: '2025-11-12T10:14:54.565282Z' finished: '2025-11-12T10:14:54.771264Z' jobID: job_1 processID: sleep_a_while progress: 1 started: '2025-11-12T10:14:54.567659Z' status: dismissed type: process updated: '2025-11-12T10:14:54.670866Z' - created: '2025-11-12T10:18:38.616131Z' finished: '2025-11-12T10:18:38.617391Z' jobID: job_2 message: Done processID: primes_between started: '2025-11-12T10:18:38.617195Z' status: successful type: process updated: '2025-11-12T10:18:38.617356Z' links: - href: http://127.0.0.1:8008/jobs hreflang: en rel: self title: get_jobs type: application/json
In [7]:
Copied!
!sen4cap-client get-job job_0
!sen4cap-client get-job job_0
created: '2025-11-12T10:14:54.537952Z' finished: '2025-11-12T10:14:54.739734Z' jobID: job_0 processID: sleep_a_while progress: 1 started: '2025-11-12T10:14:54.538644Z' status: dismissed type: process updated: '2025-11-12T10:14:54.639215Z'
In [8]:
Copied!
!sen4cap-client get-job-results job_0
!sen4cap-client get-job-results job_0
+--------------------- Traceback (most recent call last) ---------------------+
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\api\transport\httpx.py:78 in _process_response |
| |
| 75 ), |
| 76 ) from e |
| 77 try: |
| > 78 response.raise_for_status() |
| 79 return args.get_response_for_status(response.status_code, |
| 80 except httpx.HTTPError as e: |
| 81 raise args.get_exception_for_status( |
| |
| +-------------------------------- locals ---------------------------------+ |
| | args = TransportArgs( | |
| | path='/jobs/{jobId}/results', | |
| | method='get', | |
| | path_params={'jobId': 'job_0'}, | |
| | query_params={}, | |
| | request=None, | |
| | return_types={ | |
| | '200': <class 'gavicore.models.JobResults'> | |
| | }, | |
| | error_types={ | |
| | '404': <class 'gavicore.models.ApiError'>, | |
| | '500': <class 'gavicore.models.ApiError'> | |
| | }, | |
| | extra_kwargs={} | |
| | ) | |
| | response = <Response [403 Forbidden]> | |
| | response_json = { | |
| | 'type': 'ApiError', | |
| | 'title': 'Forbidden', | |
| | 'status': 403, | |
| | 'detail': "Job 'job_0' has been cancelled" | |
| | } | |
| | self = <cuiman.api.transport.httpx.HttpxTransport object at | |
| | 0x00000215E1977770> | |
| +-------------------------------------------------------------------------+ |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \httpx\_models.py:829 in raise_for_status |
| |
| 826 } |
| 827 error_type = error_types.get(status_class, "Invalid status c |
| 828 message = message.format(self, error_type=error_type) |
| > 829 raise HTTPStatusError(message, request=request, response=sel |
| 830 |
| 831 def json(self, **kwargs: typing.Any) -> typing.Any: |
| 832 return jsonlib.loads(self.content, **kwargs) |
| |
| +-------------------------------- locals ---------------------------------+ |
| | error_type = 'Client error' | |
| | error_types = { | |
| | 1: 'Informational response', | |
| | 3: 'Redirect response', | |
| | 4: 'Client error', | |
| | 5: 'Server error' | |
| | } | |
| | message = "Client error '403 Forbidden' for url | |
| | 'http://127.0.0.1:8008/jobs/job_0/results'\n"+88 | |
| | request = <Request('GET', | |
| | 'http://127.0.0.1:8008/jobs/job_0/results')> | |
| | self = <Response [403 Forbidden]> | |
| | status_class = 4 | |
| +-------------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------+
HTTPStatusError: Client error '403 Forbidden' for url
'http://127.0.0.1:8008/jobs/job_0/results'
For more information check:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403
The above exception was the direct cause of the following exception:
+--------------------- Traceback (most recent call last) ---------------------+
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\cli\cli.py:370 in get_job_results |
| |
| 367 from .output import get_renderer, output |
| 368 |
| 369 with use_client(ctx, config_file) as client: |
| > 370 job_results = client.get_job_results(job_id) |
| 371 output(get_renderer(output_format).render_job_results(job_res |
| 372 |
| 373 return t |
| |
| +-------------------------------- locals ---------------------------------+ |
| | client = <cuiman.api.client.Client object at 0x00000215E1976F90> | |
| | config_file = None | |
| | ctx = <click.core.Context object at 0x00000215E19DC7D0> | |
| | job_id = 'job_0' | |
| | output_format = <OutputFormat.yaml: 'yaml'> | |
| +-------------------------------------------------------------------------+ |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\api\client.py:378 in get_job_results |
| |
| 375 - `404`: The requested URI was not found. |
| 376 - `500`: A server error occurred. |
| 377 """ |
| > 378 return self._transport.call( |
| 379 TransportArgs( |
| 380 path="/jobs/{jobId}/results", |
| 381 method="get", |
| |
| +----------------------------- locals -----------------------------+ |
| | job_id = 'job_0' | |
| | kwargs = {} | |
| | self = <cuiman.api.client.Client object at 0x00000215E1976F90> | |
| +------------------------------------------------------------------+ |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\api\transport\httpx.py:39 in call |
| |
| 36 response = self.sync_httpx.request(*args_, **kwargs_) |
| 37 except httpx.HTTPError as e: |
| 38 raise TransportError(f"{e}") from e |
| > 39 return self._process_response(args, response) |
| 40 |
| 41 async def async_call(self, args: TransportArgs) -> Any: |
| 42 if self.async_httpx is None: |
| |
| +-------------------------------- locals ---------------------------------+ |
| | args = TransportArgs( | |
| | path='/jobs/{jobId}/results', | |
| | method='get', | |
| | path_params={'jobId': 'job_0'}, | |
| | query_params={}, | |
| | request=None, | |
| | return_types={ | |
| | '200': <class 'gavicore.models.JobResults'> | |
| | }, | |
| | error_types={ | |
| | '404': <class 'gavicore.models.ApiError'>, | |
| | '500': <class 'gavicore.models.ApiError'> | |
| | }, | |
| | extra_kwargs={} | |
| | ) | |
| | args_ = ('GET', 'http://127.0.0.1:8008/jobs/job_0/results') | |
| | kwargs_ = {'params': {}, 'json': None} | |
| | response = <Response [403 Forbidden]> | |
| | self = <cuiman.api.transport.httpx.HttpxTransport object at | |
| | 0x00000215E1977770> | |
| +-------------------------------------------------------------------------+ |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\api\transport\httpx.py:81 in _process_response |
| |
| 78 response.raise_for_status() |
| 79 return args.get_response_for_status(response.status_code, |
| 80 except httpx.HTTPError as e: |
| > 81 raise args.get_exception_for_status( |
| 82 response.status_code, f"{e}", response_json |
| 83 ) from e |
| 84 |
| |
| +-------------------------------- locals ---------------------------------+ |
| | args = TransportArgs( | |
| | path='/jobs/{jobId}/results', | |
| | method='get', | |
| | path_params={'jobId': 'job_0'}, | |
| | query_params={}, | |
| | request=None, | |
| | return_types={ | |
| | '200': <class 'gavicore.models.JobResults'> | |
| | }, | |
| | error_types={ | |
| | '404': <class 'gavicore.models.ApiError'>, | |
| | '500': <class 'gavicore.models.ApiError'> | |
| | }, | |
| | extra_kwargs={} | |
| | ) | |
| | response = <Response [403 Forbidden]> | |
| | response_json = { | |
| | 'type': 'ApiError', | |
| | 'title': 'Forbidden', | |
| | 'status': 403, | |
| | 'detail': "Job 'job_0' has been cancelled" | |
| | } | |
| | self = <cuiman.api.transport.httpx.HttpxTransport object at | |
| | 0x00000215E1977770> | |
| +-------------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------+
ClientError: Client error '403 Forbidden' for url
'http://127.0.0.1:8008/jobs/job_0/results'
For more information check:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403 (status 403)
During handling of the above exception, another exception occurred:
+--------------------- Traceback (most recent call last) ---------------------+
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\cli\cli.py:369 in get_job_results |
| |
| 366 from .client import use_client |
| 367 from .output import get_renderer, output |
| 368 |
| > 369 with use_client(ctx, config_file) as client: |
| 370 job_results = client.get_job_results(job_id) |
| 371 output(get_renderer(output_format).render_job_results(job_res |
| 372 |
| |
| +-------------------------------- locals ---------------------------------+ |
| | client = <cuiman.api.client.Client object at 0x00000215E1976F90> | |
| | config_file = None | |
| | ctx = <click.core.Context object at 0x00000215E19DC7D0> | |
| | job_id = 'job_0' | |
| | output_format = <OutputFormat.yaml: 'yaml'> | |
| +-------------------------------------------------------------------------+ |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \cuiman\cli\client.py:61 in __exit__ |
| |
| 58 if api_error.traceback and show_traceback: |
| 59 message_lines.append(" traceback:") |
| 60 message_lines.extend(api_error.traceback) |
| > 61 typer.echo("\n".join(message_lines)) |
| 62 if not show_traceback: |
| 63 raise typer.Exit(code=2) |
| 64 elif isinstance(exc_value, TransportError): |
| |
| +-------------------------------- locals ---------------------------------+ |
| | api_error = ApiError( | |
| | type='ApiError', | |
| | title='Forbidden', | |
| | status=403, | |
| | detail="Job 'job_0' has been cancelled", | |
| | instance=None, | |
| | traceback=None | |
| | ) | |
| | client_error = ClientError("Client error '403 Forbidden' for url | |
| | 'http://127.0.0.1:8008/jobs/job_0/results'\nFor more | |
| | information check: | |
| | https://developer.mozilla.org/en-US/docs/Web/HTTP/Sta… | |
| | (status 403)") | |
| | exc_tb = <traceback object at 0x00000215E19E2A00> | |
| | exc_value = ClientError("Client error '403 Forbidden' for url | |
| | 'http://127.0.0.1:8008/jobs/job_0/results'\nFor more | |
| | information check: | |
| | https://developer.mozilla.org/en-US/docs/Web/HTTP/Sta… | |
| | (status 403)") | |
| | message_lines = [ | |
| | "\u274c Error: Client error '403 Forbidden' for url | |
| | 'http://127.0.0.1:8008/jobs/job_0/"+110, | |
| | 'Server-side error details:', | |
| | ' title: Forbidden', | |
| | ' status: 403', | |
| | ' type: ApiError', | |
| | " detail: Job 'job_0' has been cancelled" | |
| | ] | |
| | self = <cuiman.cli.client.UseClient object at | |
| | 0x00000215E1976E40> | |
| | show_traceback = False | |
| +-------------------------------------------------------------------------+ |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\site-packages |
| \click\utils.py:321 in echo |
| |
| C:\Users\norma\Projects\sen4cap-client\.pixi\envs\default\Lib\encodings\cp1 |
| 252.py:19 in encode |
| |
| 16 |
| 17 class IncrementalEncoder(codecs.IncrementalEncoder): |
| 18 def encode(self, input, final=False): |
| > 19 return codecs.charmap_encode(input,self.errors,encoding_table |
| 20 |
| 21 class IncrementalDecoder(codecs.IncrementalDecoder): |
| 22 def decode(self, input, final=False): |
| |
| +-------------------------------- locals ---------------------------------+ |
| | final = False | |
| | input = "\u274c Error: Client error '403 Forbidden' for url | |
| | 'http://127.0.0.1:8008/jobs/job_0/"+239 | |
| | self = <encodings.cp1252.IncrementalEncoder object at | |
| | 0x00000215DBD04AD0> | |
| +-------------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------+
UnicodeEncodeError: 'charmap' codec can't encode character '\u274c' in position
0: character maps to <undefined>
In [ ]:
Copied!
In [ ]:
Copied!
In [ ]:
Copied!
In [ ]:
Copied!