EODMS Command-line Interface (EODMS-CLI)

July 6, 2026 ยท View on GitHub

Overview

The EODMS-CLI is used to search, process and download imagery from the EODMS using API interfaces.

eodms-py Integration Contract

This wrapper follows the recommended integration contract for external CLI packages that use eodms-py:

  1. Logging remains package-level in eodms-py (debug/info/warning/error) without forcing handlers.
  2. End-user wording and CLI-facing error messages are defined in this wrapper CLI.
  3. Typed service exceptions from eodms-py are caught at the wrapper boundary and mapped to CLI exit policy.
  4. Logging integration is caller-controlled:
  • If a caller does nothing, it keeps default/root behavior.
  • If a caller configures root logging, eodms.* logs flow into that pipeline.
  • If a caller invokes eodms-py logging setup helpers, it explicitly opts into package handler setup.

Requirements

Python

The EODMS-CLI was designed using Python 3.10.

Python Packages

Package NameUseURL
eodms-pyThe EODMS Python package.https://github.com/eodms-sgdot/eodms-py
py-eodms-rapiThe EODMS RAPI Python package.https://github.com/eodms-sgdot/py-eodms-rapi
RequestsUsed to access the RAPI URL.https://pypi.org/project/requests/
dateparserUsed to parse a date like "24 hours".https://pypi.org/project/dateparser/
geometUsed to import WKT geometry text.https://pypi.org/project/geomet/
clickUsed for the command-line input.https://pypi.org/project/click/
fionaUsed for vector geospatial file I/O (e.g., shapefiles).https://pypi.org/project/Fiona/
shapelyUsed to determine the percentage of overlap with the AOI.https://pypi.org/project/Shapely/
python-dateutilUsed to parse dates.https://pypi.org/project/python-dateutil/
tqdmUsed to access the RAPI and download files.https://pypi.org/project/tqdm/
numpyUsed to close polygons.https://pypi.org/project/numpy/
packagingUsed for dependency/version comparisons.https://pypi.org/project/packaging/
coloramaUsed for cross-platform colored terminal output.https://pypi.org/project/colorama/

Setup

  1. Clone the repository:

    > git clone https://github.com/eodms-sgdot/eodms-cli.git
    
  2. Install required packages:

    > cd eodms-cli
    > pip install -r requirements.txt --upgrade
    
  3. Run the CLI using Python

    > python eodms_cli.py --help
    

NOTE: Depending on your installation of Python, you may have to run python3 eodms_cli.py --help.

Interactive Prompt Script

This repository also ships with eodms_prompt.py (formerly eodms_cli), the interactive prompt-oriented workflow that supports legacy search, order and download flows alongside SAR Toolbox submission helpers.

Show the prompt script help:

> python eodms_prompt.py --help

Run the prompt interactively and answer questions at each step:

> python eodms_prompt.py

Supported prompt process values for --process / -r are:

  • full: Search and optionally order/download imagery.
  • order_csv: Order/download using a CSV exported from the EODMS UI.
  • uuid: Order/download one or more items by UUID using --collection.
  • download_restored_items: Download requests that were previously in ItemsRestoring.
  • order_st: Submit a SAR Toolbox order from a JSON request file.
  • download_available: Download SAR Toolbox items that are ready with AVAILABLE_FOR_DOWNLOAD.

For non-interactive runs, combine the needed arguments with --silent.

Order a known UUID from a collection:

> python eodms_prompt.py -r uuid -c RCMImageProducts --uuid 342ea023-5a9d-5157-b494-e24ec7a3b014 -u %EODMS_USER% -p %EODMS_PASSWORD% --silent

Submit a SAR Toolbox request using a JSON file:

> python eodms_prompt.py -r order_st -st test\st_ard.json -u %EODMS_USER% -p %EODMS_PASSWORD% --silent

Download all SAR Toolbox items that are ready:

> python eodms_prompt.py -r download_available -u %EODMS_USER% -p %EODMS_PASSWORD% --silent

Configuration

Configuration for the CLI can be found in the config.ini file in the home folder under ".eodms".

Configuration options can be changed by running python eodms_cli.py configure.

In the config file, you can:

  • Store credentials (these must be entered using the script)
  • Set the paths for downloading images, saving results files and storing log file(s).
  • Set the timeout interval for querying and ordering
  • Set the minimum dates for keeping downloaded images and results files

For more in-depth information on the configuration file, visit Config File.

Updating

To update eodms-cli and its dependencies, follow these steps:

  1. Pull from the most recent Github repository

    > cd eodms-cli  # your eodms-cli repository file location
    > git pull origin main
    
  2. Install or upgrade required dependencies:

    > cd eodms-cli
    

pip install -r requirements.txt --upgrade ```

  1. Run the CLI using Python

    > python eodms_cli.py --help
    

End-to-end Example

List Commands

> python eodms_cli.py --help                             

Usage: eodms_cli.py [OPTIONS] COMMAND [ARGS]...

  EODMS CLI v2: STAC/DDS-first, non-interactive with minimal legacy ports.

Options:
  -h, --help  Show this message and exit.

Commands:
  search    STAC geotemporal/queryables and GeoJSON output.
  process   Processing Service for RADARDAT data; Level-1, SAR Toolbox,...
  download  Data Delivery Service (DDS) Bulk downloads


### Search

Listing available collections...

```bash
> python eodms_cli.py search --list

Using unauthenticated catalog: https://www.eodms-sgdot.nrcan-rncan.gc.ca/search
Found 10 collection(s):
- Radarsat-1-L1-COG
- Sentinel-1
- Radarsat-2_Tropical_Forest_Products
- RCMImageProducts
- rcm-ard: RADARSAT Constellation Mission, CEOS-ARD
- Radarsat-1-FRED
- SGBAirPhotos
- NAPL
- Sentinel-2
- Radarsat-1-Raw

Login w/ authorized account to see restricted collections...

> python eodms_cli.py search --list -u %EODMS_USER% -p %EODMS_PASSWORD%

[ eodms_aaa ] Current Refresh Token has expired. Getting new Tokens...
[ eodms_aaa ] Successfully logged in using AAA API
[ eodms_aaa ] Updating Access Token...
[ eodms_aaa ] Updating Refresh Token...
[ eodms_aaa ] Updating Access Expiration as 2026-05-21 16:35:45.715067...
[ eodms_aaa ] Updating Refresh Expiration as 2026-05-21 17:24:45.715067...
Using authenticated catalog: https://www.eodms-sgdot.nrcan-rncan.gc.ca/search
Found 20 collection(s):
- Radarsat-1-L1-COG
- Sentinel-1
- Radarsat-2_Tropical_Forest_Products
- RCMImageProducts
- rcm-ard: RADARSAT Constellation Mission, CEOS-ARD
- ALOS-2
- WorldView-4
- Radarsat-1-FRED
- PlanetScope
- SGBAirPhotos
- WorldView-2
- RapidEye
- Radarsat2
- NAPL
- WorldView-1
- WorldView-3
- Sentinel-2
- Radarsat-1-Raw
- Pleiades
- GeoEye-1

Grab 20 results from the rcm-ard collection...

> python eodms_cli.py search -c rcm-ard -l 20 -o rcm.geojson

Using unauthenticated catalog: https://www.eodms-sgdot.nrcan-rncan.gc.ca/search
Searching up to limit of 20...
https://eodms-sgdot.nrcan-rncan.gc.ca/search/collections/rcm-ard/items?limit=20
Page 1 (MjAyNS0wMy0wNFQyMzowMDoxOS4zNTJa): (20 collected so far)
Found 20 items (limited to 20)
Found 20 item(s).
Saved 20 item(s) to rcm.geojson

Take a look...

> cat rcm.geojson

...
        "rl_thumbnail": {
          "href": "https://rcm-ceos-ard.s3.ca-central-1.amazonaws.com/MLC/2025/03/04/RCM3_OK3308170_PK3507604_1_SC30MCPC_20250304_230019_CH_CV_MLC/RCM3_OK3308170_PK3507604_1_SC30MCPC_20250304_230019_RL_quickLook.tif",
          "title": "Backscatter RL Polarization Quicklook",
          "description": null,
          "type": "image/tiff; application=geotiff",
          "roles": null
        },
        "rrrl": {
          "href": "https://rcm-ceos-ard.s3.ca-central-1.amazonaws.com/MLC/2025/03/04/RCM3_OK3308170_PK3507604_1_SC30MCPC_20250304_230019_CH_CV_MLC/RCM3_OK3308170_PK3507604_1_SC30MCPC_20250304_230019_RRRL.tif",
          "title": "Normalized Polarimetric Radar Covariance Matrix (CovMat)",
          "description": null,
          "type": "image/tiff; application=geotiff; profile=cloud-optimized",
          "roles": [
            "data",
            "covmat"
          ]
        }
      },
      "bbox": [
        -78.067174,
        44.281466,
        -76.312189,
        45.112074
      ]
    }
  ]
}

Refine the search. Supply some geotemporal criteria...

> python eodms_cli.py search -c Sentinel-1 -d "2026-05-01/2026-05-20" --aoi test/ottawa.geojson -o may-ottawa.geojson

Loaded 1 polygon(s) from AOI file
Using unauthenticated catalog: https://www.eodms-sgdot.nrcan-rncan.gc.ca/search
Searching AOI geometry: Ottawa, ON, CA
Searching up to limit of 1000...
https://eodms-sgdot.nrcan-rncan.gc.ca/search/collections/Sentinel-1/items?limit=1000&datetime=2026-05-01T00:00:00Z/2026-05-20T23:59:59Z&filter=S_INTERSECTS(geometry,+POLYGON+((-75.9+45.2,+-75.5+45.2,+-75.5+45.5,+-75.9+45.5,+-75.9+45.2)))&filter-lang=cql2-text
Page 1 (MjAyNi0wNS0yMFQyMjo1MToyNi43MDFa): (10 collected so far)
Detected repeated page token during pagination; stopping to avoid an infinite loop.
Found 10 items (limited to 1000)
Found 10 item(s).
Saved 10 item(s) to may-ottawa.geojson

Tighten by collection-specifics. What are the queryables?

> python eodms_cli.py search -c RCMImageProducts --queryables

Using unauthenticated catalog: https://www.eodms-sgdot.nrcan-rncan.gc.ca/search
      * pixel_data_type (string) e.g. pixel_data_type = 'Floating-Point' | constraints: enum=[Floating-Point, Integer]
      * beam_mnemonic (string) e.g. beam_mnemonic = 'example' | constraints: pattern=\w{2,13}
      * orbit_direction (string) e.g. orbit_direction = 'Ascending' | constraints: enum=[Ascending, Descending]
      * datetime (string) e.g. datetime >= DATE('2019-06-29')
      * order_key (string) e.g. order_key = 'example'
      * stop_datetime (string) e.g. stop_datetime >= DATE('2019-06-29')
      * relative_orbit (integer) e.g. relative_orbit = 1 | constraints: min=1 max=179
      * product:type (string) e.g. product:type = 'GCC' | constraints: enum=[GCC, GCD, GRC, GRD, MLC, ...]
      * geometry (geometry-any) e.g. S_INTERSECTS(geometry, POLYGON((-100 45, -95 45, -95 50, -100 50, -100 45)))
      * sample_type (string) e.g. sample_type = 'Complex' | constraints: enum=[Complex, Magnitude Detected, Mixed]
      * applied_lut (string) e.g. applied_lut = 'example'
      * polarization (string) e.g. polarization = 'CH CV' | constraints: enum=[CH CV, HH, HH HV, HH HV VH VV, HH VV, ...]

How about some high-res 5-metre...

> python eodms_cli.py search -u %EODMS_USER% -p %EODMS_PASSWORD% -c RCMImageProducts -d "2025-03-01/2026-05-20" --aoi test/ottawa.geojson -f "beam_mnemonic LIKE '5M%'" -o test/rcm_5m.geojson

Loaded 1 polygon(s) from AOI file
Using authenticated catalog: https://www.eodms-sgdot.nrcan-rncan.gc.ca/search
Searching AOI geometry: Ottawa, ON, CA
Searching up to limit of 1000...
https://eodms-sgdot.nrcan-rncan.gc.ca/search/collections/RCMImageProducts/items?limit=1000&datetime=2025-01-01T00:00:00Z/2026-05-20T23:59:59Z&filter=(beam_mnemonic+LIKE+'3M%')+AND+S_INTERSECTS(geometry,+POLYGON+((-75.9+45.2,+-75.5+45.2,+-75.5+45.5,+-75.9+45.5,+-75.9+45.2)))&filter-lang=cql2-text
Page 1 (MjAyNS0wMi0yMFQxMTowNDoyNy42OTVa): (15 collected so far)
Found 15 items (limited to 1000)
Found 15 item(s).

Ok, 342ea023-5a9d-5157-b494-e24ec7a3b014 (RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH_HV_GRD) looks good.

Download

Let us download this (level-1) image

> python eodms_cli.py download -c RCMImageProducts --uuid 342ea023-5a9d-5157-b494-e24ec7a3b014 -u %EODMS_USER% -p %EODMS_PASSWORD%      

Downloading UUID: 342ea023-5a9d-5157-b494-e24ec7a3b014
[ eodms_logger ] RCMImageProducts/342ea023-5a9d-5157-b494-e24ec7a3b014 is being prepared; currentstatus is Queued.
Item has no download URL: collection=RCMImageProducts, uuid=342ea023-5a9d-5157-b494-e24ec7a3b014

Ok, its Queued. Wait 30s... try again:

> python eodms_cli.py download -c RCMImageProducts --uuid 342ea023-5a9d-5157-b494-e24ec7a3b014 -u %EODMS_USER% -p %EODMS_PASSWORD%     

Downloading UUID: 342ea023-5a9d-5157-b494-e24ec7a3b014
[ eodms_logger ] Successfully got item RCMImageProducts/342ea023-5a9d-5157-b494-e24ec7a3b014
[ eodms_logger ] Downloading image to .\RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH_HV_GRD.zip...

There it goes!

Process

Ok, let us instead now pre-process this scene. What processes are available?

> python eodms_cli.py process --list_processes                                           

[ eodms_processes ] Successfully listed available processes

### EODMS Processing Service.

Radarsat1CEOSL0RAW (v0.0.1): Generate a Radarsat-1 CEOS L0 RAW product
Radarsat1GAMMAL1SLC (v0.0.1): Generate a Radarsat-1 L1 product in GAMMA SLC format - Maximum of 2 frames per process request - Use 'start_time' and 'stop_time' to limit the frames processed
Echo (v0.0.1): N/A
Radarsat1CEOSL1SLC (v0.0.1): Generate Radarsat-1 L1 product in CEOS SLC (16-bit) - Maximum of 2 frames per process request - Use 'start_time' and 'stop_time' to limit the frames processed

### EODMS SAR Toolbox

SAR_Toolbox (vX.X): Filters, Ortho-rectification and mosaic Radiometry, Polarimetry, Interferometry, Analysis Ready Data. Support for RADARSAT-2, RCMImageProducts.

Ok, Analysis Ready Data looks good. How is it called?

At the moment SAR_Toolbox and Processing Service have separate submission structures (they will all be under OGC API - Processes based Processing Service in future). SAR_Toolbox's items block takes recordId not uuid, which we don't have for our 3m image. Let us look it up using uuid from above:

> python eodms_cli.py search --uuid2record -c RCMImageProducts --uuid 342ea023-5a9d-5157-b494-e24ec7a3b014

...
| EODMSRAPI | 2026-05-22 16:08:00 | RAPI Query URL: https://www.eodms-sgdot.nrcan-rncan.gc.ca/wes/rapi/search?collection=RCMImageProducts&query=%28CATALOG_IMAGE.START_DATETIME%3E%3D%272025-02-20T11%3A04%3A27Z%27+AND+CATALOG_IMAGE.START_DATETIME%3C%3D%272025-02-21T11%3A04%3A27Z%27%29+AND+ARCHIVE_IMAGE.ORDER_KEY%3D%27RCM2_OK3294733_PK3492600_1_3MCP36_20250220_110427_CH_CV_GRD%27&resultField=CATALOG_IMAGE.THE_GEOM_4326%2CSENSOR_BEAM.SPATIAL_RESOLUTION%2CARCHIVE_IMAGE.UNIQUE_IDENTIFIER&format=json&maxResults=5
| EODMSRAPI | 2026-05-22 16:08:04 | Number of RCMImageProducts images returned from RAPI: 1
3fa6cf78-0de9-572b-b735-52f5b9a4e284: order_key=RCM2_OK3294733_PK3492600_1_3MCP36_20250220_110427_CH_CV_GRD; record_id=31756869

Ok record_id=32522100. Plug this into the provided ./test/st_ard.json, along with label for the sequence_1, LabelName fields. Submit the ARD request using this:

py eodms_cli.py process -pi SAR_Toolbox --inputs_json test\st_ard.json -u %EODMS_USER% -p %EODMS_PASSWORD% --submit

| EODMSRAPI | 2026-05-22 18:05:20 | Submitting order items...
| EODMSRAPI | 2026-05-22 18:05:20 | RAPI URL:

https://www.eodms-sgdot.nrcan-rncan.gc.ca/wes/rapi/order

| EODMSRAPI | 2026-05-22 18:05:20 | RAPI POST:

{"items": [{"collectionId": "RCMImageProducts", "recordId": "32522100", "parameters": {}}], "destinations": [], "vapRequest": {"sequence": {"sequence_1": "32522100_ard"}, "method": {"method-901-1": {"Category": "900", "Method": "901", "LabelName": "32522100_ard"}}, "deliveryLocation": "DOWNLOAD", "AllPol": "on", "pr_users_username": null}}

Wait...


[
  {
    "recordId": "32522100",
    "itemId": "10948941",
    "orderId": "3253864",
    "collectionId": "RCMImageProducts",
    "status": "AVAILABLE_FOR_STREAM",
    "dateRapiOrdered": "2026-05-22T18:05:20.531184-04:00"
  }
]

There we go. Submitted w/ orderId=3253864. We can check on it using...

> py eodms_cli.py download --list --order-id 3253864

...
  [4]  order_id : 3168001
        status   : AVAILABLE_FOR_STREAM
        items    : 1
        priority : Medium
        submitted: 2026-05-22T22:05:58Z
        name     : RAPI_Order_d1fa1655-4b76-4dd7-81b0-f44e070d62ef
        record_id: 32522100
        collection: RCMImageProducts
...

Not ready yet. Needs to say AVAILABLE_FOR_DOWNLOAD, not AVAILABLE_FOR_STREAM. Check again later...

> py eodms_cli.py download --list --order-id 3253864

...
  "order_id": "3168001",
  "status": "AVAILABLE_FOR_DOWNLOAD",
  "submitted": "2026-05-22T22:05:58Z",
...
  "destinations": [
    "https://data.eodms-sgdot.nrcan-rncan.gc.ca/rcm/carts/1bf52c4e-ecd7-4eb5-8948-2fd7b68f6d08/10948941/d1fa1655-4b76-4dd7-81b0-f44e070d62ef"
...

Says AVAILABLE_FOR_DOWNLOAD. Download the whole directory using

> py eodms_cli.py download --download-available      

Found 1 AVAILABLE_FOR_DOWNLOAD item(s).
Downloading 1 item(s) to .\downloads

| EODMSRAPI | 2026-05-22 20:58:50 | Downloading images...
| EODMSRAPI | 2026-05-22 20:59:00 | Getting list of current orders...
| EODMSRAPI | 2026-05-22 20:59:08 | Downloading image from Collection RCMImageProducts with Record Id 32522100 (RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH_HV_GRD\RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH.tif).
...

CEOS ARD downloaded locally, ready to use!

> ls .\downloads\RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH_HV_GRD               
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_bitmask.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_gammaToSigmaRatio.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HH_quickLook.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HV.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_HV_quickLook.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_localContributingArea.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_localIncAngle.tif
RCM1_OK3584454_PK3585363_1_5M19_20250429_110414_product.xml
RCM_EULA_GC_v3-1_20210202_UNCLASSIFIED.pdf

Contact

If you have any questions or require support, please contact the EODMS Support Team at eodms-sgdot@nrcan-rncan.gc.ca.

License

MIT License