Skip to content

eodms-sgdot/eodms-cli

Repository files navigation

EODMS Command-line Interface (EODMS-CLI)

Overview

The EODMS-CLI is used to search, order 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 Name Use URL
py-eodms-rapi The EODMS RAPI Python package. https://github.com/eodms-sgdot/py-eodms-rapi
eodms-py The EODMS Python package. https://github.com/eodms-sgdot/eodms-py
Requests Used to access the RAPI URL. https://pypi.org/project/requests/
dateparser Used to parse a date like "24 hours". https://pypi.org/project/dateparser/
geomet Used to import WKT geometry text. https://pypi.org/project/geomet/
click Used for the command-line input. https://pypi.org/project/click/
fiona Used for vector geospatial file I/O (e.g., shapefiles). https://pypi.org/project/Fiona/
shapely Used to determine the percentage of overlap with the AOI. https://pypi.org/project/Shapely/
python-dateutil Used to parse dates. https://pypi.org/project/python-dateutil/
tqdm Used to access the RAPI and download files. https://pypi.org/project/tqdm/
numpy Used to close polygons. https://pypi.org/project/numpy/
packaging Used for dependency/version comparisons. https://pypi.org/project/packaging/
colorama Used 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.

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

User Guide

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

About

The EODMS CLI Python script is used to search, order and download imagery from the Earth Observation Data Management System using the REST API service.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages