Skip to content

Commit 1c1e868

Browse files
authored
Merge pull request #342 from ASFHyP3/opera-rtc
Add OPERA RTC as job type
2 parents 5485bc5 + e6b87b9 commit 1c1e868

File tree

6 files changed

+90
-3
lines changed

6 files changed

+90
-3
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [PEP 440](https://www.python.org/dev/peps/pep-0440/)
77
and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## [7.4.0]
10+
11+
### Added
12+
* Added `HyP3.submit_opera_rtc_s1_job` and `HyP3.prepare_opera_rtc_s1_job` methods for submitting OPERA RTC-S1 jobs to HyP3. This job type is under development and is currently only available in `https://hyp3-test-api.asf.alaska.edu`
13+
* Added `hyp3_sdk.exceptions.ServiceUnavailableError` for handling 503 errors from HyP3.
14+
915
## [7.3.0]
1016

1117
### Added

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ A python wrapper around the HyP3 API
2323
## Install
2424

2525
In order to easily manage dependencies, we recommend using dedicated project environments
26-
via [Anaconda/Miniconda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html)
27-
or [Python virtual environments](https://docs.python.org/3/tutorial/venv.html).
26+
via [Anaconda/Miniconda](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html)
27+
or [Python virtual environments](https://docs.python.org/3/tutorial/venv.html).
2828

2929
The HyP3 SDK can be installed into a conda environment with
3030

@@ -68,6 +68,7 @@ insar_burst_job = hyp3.submit_insar_isce_burst_job('reference_granule_id', 'seco
6868
insar_multi_burst_job = hyp3.submit_insar_isce_multi_burst_job(['ref_id_1', 'ref_id_2'], ['sec_id_1', 'sec_id_2'], 'job_name')
6969
autorift_job = hyp3.submit_autorift_job('reference_granule_id', 'secondary_granule_id', 'job_name')
7070
aria_s1_gunw_job = hyp3.submit_aria_s1_gunw_job(['ref_id_1', 'ref_id_2'], ['sec_id_1', 'sec_id_2'], 'frame_id', 'job_name')
71+
opera_rtc_s1_job = hyp3.submit_opera_rtc_s1_job('granule_id')
7172
```
7273
Each of these functions will return an instance of the `Job` class that represents a new HyP3 job request.
7374

@@ -76,7 +77,7 @@ To find HyP3 jobs that were run previously, you can use the `hyp3.find_jobs()`
7677
```python
7778
batch = hyp3.find_jobs()
7879
```
79-
This will return a `Batch` instance representing all jobs owned by you. You can also pass parameters to
80+
This will return a `Batch` instance representing all jobs owned by you. You can also pass parameters to
8081
query to a specific set of jobs
8182

8283

src/hyp3_sdk/exceptions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,19 @@ class AuthenticationError(HyP3SDKError):
2424
"""Raise when authentication does not succeed"""
2525

2626

27+
class ServiceUnavailableError(HyP3SDKError):
28+
"""Raise when the HyP3 API is unavailable"""
29+
30+
2731
def _raise_for_hyp3_status(response: Response):
2832
try:
2933
response.raise_for_status()
3034
except HTTPError:
3135
if 400 <= response.status_code < 500:
3236
raise HyP3Error(f'{response} {response.json()["detail"]}')
37+
if response.status_code == 503:
38+
raise ServiceUnavailableError(f'{response} {response.json()["detail"]}')
39+
3340
raise ServerError
3441

3542

src/hyp3_sdk/hyp3.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,44 @@ def prepare_aria_s1_gunw_job(
607607
job_dict['name'] = name
608608
return job_dict
609609

610+
def submit_opera_rtc_s1_job(self, granule: str, name: str | None = None) -> Batch:
611+
"""Submit an OPERA RTC-S1 job.
612+
613+
Args:
614+
granule: The name of the S1 burst to use
615+
name: A name for the job (optional)
616+
617+
Returns:
618+
A Batch object containing the OPERA RTC-S1 job
619+
"""
620+
arguments = locals().copy()
621+
arguments.pop('self')
622+
job_dict = self.prepare_opera_rtc_s1_job(**arguments)
623+
return self.submit_prepared_jobs(prepared_jobs=job_dict)
624+
625+
@classmethod
626+
def prepare_opera_rtc_s1_job(cls, granule: str, name: str | None = None) -> dict:
627+
"""Prepare an OPERA RTC-S1 job.
628+
629+
Args:
630+
granule: The name of the S1 burst to use
631+
name: A name for the job
632+
633+
Returns:
634+
A dictionary containing the prepared OPERA RTC-S1 job
635+
"""
636+
job_parameters = locals().copy()
637+
for key in ['cls', 'name', 'granule']:
638+
job_parameters.pop(key)
639+
640+
job_dict = {
641+
'job_parameters': {'granules': [granule], **job_parameters},
642+
'job_type': 'OPERA_RTC_S1',
643+
}
644+
if name is not None:
645+
job_dict['name'] = name
646+
return job_dict
647+
610648
def my_info(self) -> dict:
611649
"""Returns:
612650
Your user information

tests/test_exceptions.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ def test_raise_for_hyp3_status():
2424
exceptions._raise_for_hyp3_status(response)
2525

2626

27+
def test_service_unavailable_error():
28+
response = Response()
29+
response.status_code = 503
30+
response._content = b'{ "detail" : "foo" }'
31+
with pytest.raises(exceptions.ServiceUnavailableError) as e:
32+
exceptions._raise_for_hyp3_status(response)
33+
assert 'foo' in str(e)
34+
35+
2736
def test_raise_for_search_status():
2837
response = Response()
2938
response.status_code = 400

tests/test_hyp3.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,22 @@ def test_prepare_insar_isce_multi_burst_job():
347347
}
348348

349349

350+
def test_prepare_opera_rtc_s1_job():
351+
assert HyP3.prepare_opera_rtc_s1_job(granule='g1') == {
352+
'job_type': 'OPERA_RTC_S1',
353+
'job_parameters': {
354+
'granules': ['g1'],
355+
},
356+
}
357+
assert HyP3.prepare_opera_rtc_s1_job(granule='g2', name='my_name') == {
358+
'job_type': 'OPERA_RTC_S1',
359+
'name': 'my_name',
360+
'job_parameters': {
361+
'granules': ['g2'],
362+
},
363+
}
364+
365+
350366
def test_prepare_aria_s1_gunw_job():
351367
assert HyP3.prepare_aria_s1_gunw_job(
352368
reference=['ref_granule1', 'ref_granule2'], secondary=['sec_granule1', 'sec_granule2'], frame_id=100
@@ -448,6 +464,16 @@ def test_submit_aria_s1_gunw_job(get_mock_hyp3, get_mock_job):
448464
assert batch.jobs[0] == job
449465

450466

467+
@responses.activate
468+
def test_submit_opera_rtc_s1_job(get_mock_hyp3, get_mock_job):
469+
job = get_mock_job('OPERA_RTC_S1', job_parameters={'granules': ['g1']})
470+
api_response = {'jobs': [job.to_dict()]}
471+
api = get_mock_hyp3()
472+
responses.add(responses.POST, urljoin(api.url, '/jobs'), json=api_response)
473+
batch = api.submit_opera_rtc_s1_job(['g1'])
474+
assert batch.jobs[0] == job
475+
476+
451477
@responses.activate
452478
def test_resubmit_previous_job(get_mock_hyp3, get_mock_job):
453479
job = get_mock_job()

0 commit comments

Comments
 (0)