From 2ca5956461fa2b4fa49ab6fabb8fa31d8a192c3d Mon Sep 17 00:00:00 2001 From: Forrest Williams Date: Sat, 7 Mar 2026 07:52:05 -0600 Subject: [PATCH 1/3] fix url issue --- .gitignore | 4 ++++ src/multirtc/dem.py | 2 +- tests/test_dem.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 293f627..b4bbe6b 100644 --- a/.gitignore +++ b/.gitignore @@ -243,3 +243,7 @@ tags # Data src/multirtc/multimetric/*/ + +# pixi environments +.pixi/* +!.pixi/config.toml diff --git a/src/multirtc/dem.py b/src/multirtc/dem.py index c7e818f..7a051a5 100644 --- a/src/multirtc/dem.py +++ b/src/multirtc/dem.py @@ -134,7 +134,7 @@ def get_dem_granule_url(lat: int, lon: int) -> str: lon_cardinal = 'W' if lon_tens < 0 else 'E' prefix = f'{lat_cardinal}{np.abs(lat_tens):02d}/{lat_cardinal}{np.abs(lat_tens):02d}_{lon_cardinal}{np.abs(lon_tens):03d}' - filename = f'DEM{lat_cardinal}{np.abs(lat):02d}_00_{lon_cardinal}{np.abs(lon):03d}_00_C01.tif' + filename = f'DEM_{lat_cardinal}{np.abs(lat):02d}_00_{lon_cardinal}{np.abs(lon):03d}_00_C01.tif' file_url = f'{URL}/{prefix}/{filename}' return file_url diff --git a/tests/test_dem.py b/tests/test_dem.py index c6735dc..add86fb 100644 --- a/tests/test_dem.py +++ b/tests/test_dem.py @@ -5,7 +5,7 @@ def test_get_granule_url(): test_url = ( - 'https://nisar.asf.earthdatacloud.nasa.gov/NISAR/DEM/v1.2/EPSG4326/S10/S10_W020/DEMS01_00_W001_00_C01.tif' + 'https://nisar.asf.earthdatacloud.nasa.gov/NISAR/DEM/v1.2/EPSG4326/S10/S10_W020/DEM_S01_00_W001_00_C01.tif' ) url = dem.get_dem_granule_url(-1, -1) assert url == test_url From e802880565803a6a4ed1ea1c29d32f582a7d67e0 Mon Sep 17 00:00:00 2001 From: Forrest Williams Date: Sat, 7 Mar 2026 08:17:53 -0600 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4f1b9e..b8991cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [PEP 440](https://www.python.org/dev/peps/pep-0440/) and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.5.4] + +### Fixed +* Copernicus DEM for NISAR URLs to fix 404 errors. + ## [0.5.3] ### Changed From 11b3fcf0f72a66e5a091bb648bee3341a09a0faa Mon Sep 17 00:00:00 2001 From: Forrest Williams Date: Sat, 7 Mar 2026 08:50:04 -0600 Subject: [PATCH 3/3] fix env var auth --- CHANGELOG.md | 1 + src/multirtc/__main__.py | 7 +++++++ src/multirtc/fetch.py | 15 +++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8991cc..ab8af55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed * Copernicus DEM for NISAR URLs to fix 404 errors. +* Support for EARTHDATA credentials passed as env vars. ## [0.5.3] diff --git a/src/multirtc/__main__.py b/src/multirtc/__main__.py index d0273fb..707c9b1 100644 --- a/src/multirtc/__main__.py +++ b/src/multirtc/__main__.py @@ -1,10 +1,17 @@ import argparse +import os from multirtc import dem, geocode, multirtc +from multirtc.fetch import write_credentials_to_netrc_file from multirtc.multimetric import ale, point_target, rle def main(): + username = os.getenv('EARTHDATA_USERNAME') + password = os.getenv('EARTHDATA_PASSWORD') + if username and password: + write_credentials_to_netrc_file(username, password, append=False) + global_parser = argparse.ArgumentParser( prog='multirtc', description='ISCE3-based multi-sensor RTC and cal/val tool', diff --git a/src/multirtc/fetch.py b/src/multirtc/fetch.py index ba3516a..f779632 100644 --- a/src/multirtc/fetch.py +++ b/src/multirtc/fetch.py @@ -11,6 +11,21 @@ from urllib3.util.retry import Retry +EARTHDATA_LOGIN_DOMAIN = 'urs.earthdata.nasa.gov' + + +def write_credentials_to_netrc_file( + username: str, password: str, domain: str = EARTHDATA_LOGIN_DOMAIN, append: bool = False +): + """Write credentials to .netrc file""" + netrc_file = Path.home() / '.netrc' + if netrc_file.exists() and not append: + logging.warning(f'Using existing .netrc file: {netrc_file}') + else: + with open(netrc_file, 'a') as f: + f.write(f'machine {domain} login {username} password {password}\n') + + def _get_download_path(url: str, content_disposition: str | None = None, directory: Path | str = '.'): filename = None if content_disposition is not None: