Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v1.4.0 #109

Merged
merged 45 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
01e7554
working on better downloads
forrestfwilliams Oct 10, 2024
33c453b
working async
forrestfwilliams Oct 11, 2024
5f2fb83
remove unused code
forrestfwilliams Oct 11, 2024
de0b6b8
working with .netrc
forrestfwilliams Oct 11, 2024
feb2152
little better
forrestfwilliams Oct 11, 2024
215c1ca
improve names
forrestfwilliams Oct 14, 2024
6c968de
cleanup
forrestfwilliams Oct 14, 2024
be360e7
finish cleanup
forrestfwilliams Oct 14, 2024
f4927e0
add docstrings
forrestfwilliams Oct 14, 2024
5a2238a
start work on search
forrestfwilliams Oct 14, 2024
807ab68
undo search changes
forrestfwilliams Oct 14, 2024
ead30dd
workking async thread download
forrestfwilliams Oct 15, 2024
934e3e6
Merge branch 'develop' into downloads
forrestfwilliams Nov 15, 2024
b4d7a43
remove multithreading
forrestfwilliams Nov 15, 2024
c09cc3c
remove parallel arg
forrestfwilliams Nov 15, 2024
0823e19
fix bug in burst2stack
forrestfwilliams Nov 18, 2024
f4917fb
turn off forcing
forrestfwilliams Nov 18, 2024
7e02c75
refactor and add filetype check
forrestfwilliams Nov 19, 2024
ad78957
account for race condition
forrestfwilliams Nov 19, 2024
9f6a36a
add support for edl tokens
forrestfwilliams Nov 19, 2024
1b03538
minor old changes
forrestfwilliams Dec 19, 2024
e34aa21
Bump ASFHyP3/actions from 0.12.0 to 0.13.2
dependabot[bot] Dec 23, 2024
0b97f4b
working tokens
forrestfwilliams Jan 2, 2025
90369ca
Merge pull request #106 from ASFHyP3/dependabot/github_actions/ASFHyP…
forrestfwilliams Jan 2, 2025
3277cd0
Merge branch 'develop' into downloads
forrestfwilliams Jan 2, 2025
949dfb0
remove unused class
forrestfwilliams Jan 2, 2025
727465f
update changelog
forrestfwilliams Jan 2, 2025
e766f1b
fix ruff
forrestfwilliams Jan 2, 2025
cc76a7a
fix fstring quotes
forrestfwilliams Jan 2, 2025
ed769c6
fix python version
forrestfwilliams Jan 2, 2025
a71a7c9
refactor auth for review
forrestfwilliams Jan 3, 2025
a39d445
remove references to EDL_TOKEN
forrestfwilliams Jan 3, 2025
e333241
remove old download methods
forrestfwilliams Jan 3, 2025
6bce965
fix docstring
forrestfwilliams Jan 3, 2025
3aa8aaa
clean up search
forrestfwilliams Jan 3, 2025
2c2d4ab
remove unused function
forrestfwilliams Jan 4, 2025
2f22c7d
remove download tests
forrestfwilliams Jan 4, 2025
67b89bf
refactor search
forrestfwilliams Jan 4, 2025
8dd7baf
remove unused type
forrestfwilliams Jan 4, 2025
be78818
add search test
forrestfwilliams Jan 4, 2025
17532e6
fix xml check
forrestfwilliams Jan 6, 2025
f1f08eb
update readme
forrestfwilliams Jan 6, 2025
752e420
update readme 2
forrestfwilliams Jan 6, 2025
d42e377
update changelog
forrestfwilliams Jan 6, 2025
0b91f47
Merge pull request #108 from ASFHyP3/downloads
forrestfwilliams Jan 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/changelog-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@

jobs:
call-changelog-check-workflow:
uses: ASFHyP3/actions/.github/workflows/reusable-changelog-check.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-changelog-check.yml@v0.13.2
2 changes: 1 addition & 1 deletion .github/workflows/create-jira-issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

jobs:
call-create-jira-issue-workflow:
uses: ASFHyP3/actions/.github/workflows/reusable-create-jira-issue.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-create-jira-issue.yml@v0.13.2
secrets:
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
JIRA_PROJECT: ${{ secrets.JIRA_PROJECT }}
JIRA_FIELDS: ${{ secrets.JIRA_FIELDS }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions Job or Workflow does not set permissions
2 changes: 1 addition & 1 deletion .github/workflows/labeled-pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@

jobs:
call-labeled-pr-check-workflow:
uses: ASFHyP3/actions/.github/workflows/reusable-labeled-pr-check.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-labeled-pr-check.yml@v0.13.2
2 changes: 1 addition & 1 deletion .github/workflows/release-checklist-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
call-release-workflow:
uses: ASFHyP3/actions/.github/workflows/reusable-release-checklist-comment.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-release-checklist-comment.yml@v0.13.2
permissions:
pull-requests: write
secrets:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
jobs:
call-release-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-release.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-release.yml@v0.13.2
with:
release_prefix: burst2safe
secrets:
USER_TOKEN: ${{ secrets.TOOLS_BOT_PAK }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions Job or Workflow does not set permissions
4 changes: 2 additions & 2 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
jobs:
call-secrets-analysis-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-secrets-analysis.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-secrets-analysis.yml@v0.13.2

check-with-black:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions Job or Workflow does not set permissions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -18,4 +18,4 @@

call-ruff-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-ruff.yml@v0.12.0
uses: ASFHyP3/actions/.github/workflows/reusable-ruff.yml@v0.13.2
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ 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).

## [1.4.0]

### Added
* download.py to support asynchronous downloads.
* Support for EDL token based authentication.

### Changed
* Authorization behavior so that EDL credentials from an EDL token are prioritized above a username/password in either a netrc or the environment.
* Authorization behavior so that EDL username/password from a user's netrc are prioritized. Now writes username/password to the netrc if they are provided as environment variables.
* Switched to an asynchronous download approach.
* In burst2stack.py all input files are now downloaded first.

## [1.3.1]

### Changed
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ conda install -c conda-forge burst2safe

### Credentials
To use `burst2safe`, you must provide your Earthdata Login credentials via two environment variables
(`EARTHDATA_USERNAME` and `EARTHDATA_PASSWORD`), or via your `.netrc` file.
(`EARTHDATA_USERNAME` and `EARTHDATA_PASSWORD`), or via your `.netrc` file. Alternatively, you can use an Earthdata Login Token stored in the `EARTHDATA_TOKEN` environment variable.

If you do not already have an Earthdata account, you can sign up [here](https://urs.earthdata.nasa.gov/home).

If you would like to set up Earthdata Login via your `.netrc` file, check out this [guide](https://harmony.earthdata.nasa.gov/docs#getting-started) to get started.

If you would like to set up Earthdata Login via a token, check out this [guide](https://urs.earthdata.nasa.gov/documentation/for_users/user_token) to get started.

Note that `burst2safe` will prefer authorization information in this order: token > .netrc > username/password in environment. So if you have both a .netrc file and a token configured, it will use the token.

## burst2safe usage
The `burst2safe` command line tool can be run using the following structure:
```bash
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies:
- tifffile>=2022.04.22
- asf_search
- dateparser!=1.1.0
- aiohttp
# For packaging, and testing
- pytest
- pytest-cov
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies = [
"tifffile>=2022.04.22",
"asf_search",
"dateparser!=1.1.0",
"aiohttp",
]

[project.urls]
Expand Down
49 changes: 40 additions & 9 deletions src/burst2safe/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@


EARTHDATA_HOST = 'urs.earthdata.nasa.gov'
TOKEN_ENV_VAR = 'EARTHDATA_TOKEN'


def get_netrc() -> Path:
Expand Down Expand Up @@ -57,21 +58,51 @@ def find_creds_in_netrc(service) -> Tuple[str, str]:
return None, None


def get_earthdata_credentials() -> Tuple[str, str]:
"""Get NASA EarthData credentials from the environment or netrc file.
def write_credentials_to_netrc_file(username: str, password: str) -> None:
"""Write credentials to netrc file

Args:
username: NASA EarthData username
password: NASA EarthData password
"""
netrc_file = get_netrc()
if not netrc_file.exists():
netrc_file.touch()

with open(netrc_file, 'a') as f:
f.write(f'machine {EARTHDATA_HOST} login {username} password {password}\n')


def check_earthdata_credentials(append=False) -> str:
"""Check for NASA EarthData credentials in the netrc file or environment variables.
Will preferentially use the netrc file, and write credentials to the netrc file if found in the environment.

Args:
append: Whether to append the credentials to the netrc file if creds found in the environment

Returns:
Tuple of the NASA EarthData username and password
The location of the preferred credentials ('netrc' or 'token')
"""
username, password = find_creds_in_env('EARTHDATA_USERNAME', 'EARTHDATA_PASSWORD')
if username and password:
return username, password
if os.getenv(TOKEN_ENV_VAR):
return 'token'

username, password = find_creds_in_netrc(EARTHDATA_HOST)
if username and password:
return username, password
return 'netrc'

username, password = find_creds_in_env('EARTHDATA_USERNAME', 'EARTHDATA_PASSWORD')
if username and password:
if append:
write_credentials_to_netrc_file(username, password)
return 'netrc'
else:
raise ValueError(
'NASA Earthdata credentials only found in environment variables,'
'but appending to netrc file not allowed. Please allow appending to netrc.'
)

raise ValueError(
'Please provide NASA EarthData credentials via the '
'EARTHDATA_USERNAME and EARTHDATA_PASSWORD environment variables, or your netrc file.'
'Please provide NASA Earthdata credentials via your .netrc file,'
'the EARTHDATA_USERNAME and EARTHDATA_PASSWORD environment variables,'
'or an EDL Token via the EARTHDATA_TOKEN environment variable.'
)
3 changes: 2 additions & 1 deletion src/burst2safe/burst2safe.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
from shapely.geometry import Polygon

from burst2safe import utils
from burst2safe.download import download_bursts
from burst2safe.safe import Safe
from burst2safe.search import download_bursts, find_bursts
from burst2safe.search import find_bursts


DESCRIPTION = """Convert a set of ASF burst SLCs to the ESA SAFE format.
Expand Down
66 changes: 44 additions & 22 deletions src/burst2safe/burst2stack.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""A tool for converting stacks of ASF burst SLCs to stacks of SAFEs"""

from argparse import ArgumentParser
from collections.abc import Iterable
from datetime import datetime
from pathlib import Path
from typing import Optional
from typing import Iterable, List, Optional

from shapely.geometry import Polygon

from burst2safe import utils
from burst2safe.burst2safe import burst2safe
from burst2safe.search import find_stack_orbits
from burst2safe.download import download_bursts
from burst2safe.safe import Safe
from burst2safe.search import find_group


DESCRIPTION = """Convert a stack of ASF burst SLCs to a stack of ESA SAFEs.
Expand All @@ -32,7 +32,7 @@ def burst2stack(
all_anns: bool = False,
keep_files: bool = False,
work_dir: Optional[Path] = None,
) -> Path:
) -> List[Path]:
"""Convert a stack of burst granules to a stack of ESA SAFEs.
Wraps the burst2safe function to handle multiple dates.

Expand All @@ -41,30 +41,52 @@ def burst2stack(
start_date: The start date of the bursts
end_date: The end date of the bursts
extent: The bounding box of the bursts
swaths: List of swaths to include
polarizations: List of polarizations to include
swaths: List of swaths to include
mode: The collection mode to use (IW or EW) (default: IW)
min_bursts: The minimum number of bursts per swath (default: 1)
all_anns: Include product annotation files for all swaths, regardless of included bursts
keep_files: Keep the intermediate files
work_dir: The directory to create the SAFE in (default: current directory)
"""
absolute_orbits = find_stack_orbits(rel_orbit, extent, start_date, end_date)
print(f'Creating SAFEs for {len(absolute_orbits)} time periods...')
for orbit in absolute_orbits:
print()
burst2safe(
granules=None,
orbit=orbit,
extent=extent,
polarizations=polarizations,
swaths=swaths,
mode=mode,
min_bursts=min_bursts,
all_anns=all_anns,
keep_files=keep_files,
work_dir=work_dir,
)
burst_search_results = find_group(
rel_orbit,
extent,
polarizations,
swaths,
mode,
min_bursts,
use_relative_orbit=True,
start_date=start_date,
end_date=end_date,
)
burst_infos = utils.get_burst_infos(burst_search_results, work_dir)
abs_orbits = utils.drop_duplicates([burst_info.absolute_orbit for burst_info in burst_infos])
print(f'Found {len(burst_infos)} burst(s), comprising {len(abs_orbits)} SAFE(s).')

print('Check burst group validities...')
burst_sets = [[bi for bi in burst_infos if bi.absolute_orbit == orbit] for orbit in abs_orbits]
# Checking burst group validities before download to fail faster
for burst_set in burst_sets:
Safe.check_group_validity(burst_set)

print('Downloading data...')
download_bursts(burst_infos)
print('Download complete.')

print('Creating SAFEs...')
safe_paths = []
for burst_set in burst_sets:
[info.add_shape_info() for info in burst_set]
[info.add_start_stop_utc() for info in burst_set]
safe = Safe(burst_set, all_anns, work_dir)
safe_path = safe.create_safe()
safe_paths.append(safe_path)
if not keep_files:
safe.cleanup()
print('SAFEs creaated!')

return safe_paths


def main() -> None:
Expand Down
Loading
Loading