sentinelhub 3.11.1__tar.gz → 3.11.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/PKG-INFO +2 -3
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/README.md +0 -1
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/pyproject.toml +3 -1
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/__init__.py +0 -7
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/_version.py +1 -1
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/__init__.py +0 -6
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/batch/__init__.py +1 -4
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/batch/base.py +1 -4
- sentinelhub-3.11.1/sentinelhub/api/batch/process_v2.py → sentinelhub-3.11.3/sentinelhub/api/batch/process.py +1 -1
- sentinelhub-3.11.3/sentinelhub/api/batch/process_v2.py +14 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/batch/utils.py +3 -130
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/areas.py +2 -78
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/config.py +2 -2
- sentinelhub-3.11.1/sentinelhub/api/batch/process.py +0 -576
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/.gitignore +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/LICENSE.md +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/.utmzones.geojson +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/base.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/base_request.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/batch/statistical.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/byoc.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/catalog.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/fis.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/ogc.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/opensearch.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/process.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/statistical.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/utils.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/api/wfs.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/__init__.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/batch.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/client.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/commands.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/constants.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/data.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/data_safe.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/aws/request.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/base.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/commands.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/constants.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/data_collections.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/data_collections_bands.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/data_utils.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/decoding.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/__init__.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/client.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/handlers.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/models.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/rate_limit.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/sentinelhub_client.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/sentinelhub_statistical_client.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/session.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/evalscript.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/exceptions.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/geo_utils.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/geometry.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/geopedia/__init__.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/geopedia/core.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/geopedia/request.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/io_utils.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/py.typed +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/testing_utils.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/time_utils.py +0 -0
- {sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: sentinelhub
|
|
3
|
-
Version: 3.11.
|
|
3
|
+
Version: 3.11.3
|
|
4
4
|
Summary: Python API for Sentinel Hub
|
|
5
5
|
Project-URL: Homepage, https://github.com/sentinel-hub/sentinelhub-py
|
|
6
6
|
Project-URL: Documentation, https://sentinelhub-py.readthedocs.io
|
|
@@ -159,7 +159,6 @@ A high-level overview of the main functionalities:
|
|
|
159
159
|
* [BYOC API](https://docs.sentinel-hub.com/api/latest/api/byoc/),
|
|
160
160
|
* [Statistical API](https://docs.sentinel-hub.com/api/latest/api/statistical/),
|
|
161
161
|
* [OGC services (WMS/WCS/WFS)](https://docs.sentinel-hub.com/api/latest/api/ogc/),
|
|
162
|
-
* [FIS](https://www.sentinel-hub.com/develop/api/ogc/fis-request/),
|
|
163
162
|
* authentication and rate-limit handling,
|
|
164
163
|
|
|
165
164
|
- geospatial utilities
|
|
@@ -60,7 +60,6 @@ A high-level overview of the main functionalities:
|
|
|
60
60
|
* [BYOC API](https://docs.sentinel-hub.com/api/latest/api/byoc/),
|
|
61
61
|
* [Statistical API](https://docs.sentinel-hub.com/api/latest/api/statistical/),
|
|
62
62
|
* [OGC services (WMS/WCS/WFS)](https://docs.sentinel-hub.com/api/latest/api/ogc/),
|
|
63
|
-
* [FIS](https://www.sentinel-hub.com/develop/api/ogc/fis-request/),
|
|
64
63
|
* authentication and rate-limit handling,
|
|
65
64
|
|
|
66
65
|
- geospatial utilities
|
|
@@ -63,7 +63,7 @@ docs = [
|
|
|
63
63
|
"matplotlib",
|
|
64
64
|
"nbsphinx",
|
|
65
65
|
"sphinx==7.1.2",
|
|
66
|
-
"sphinx_mdinclude==0.5.4",
|
|
66
|
+
"sphinx_mdinclude==0.5.4", # version fixed because 0.6.0 didnt work at release time of 3.10.2
|
|
67
67
|
"sphinx_rtd_theme==1.3.0",
|
|
68
68
|
]
|
|
69
69
|
dev = [
|
|
@@ -199,6 +199,7 @@ max-args = 10
|
|
|
199
199
|
max-attributes = 21
|
|
200
200
|
max-locals = 20
|
|
201
201
|
min-public-methods = 0
|
|
202
|
+
max-positional-arguments = 10
|
|
202
203
|
|
|
203
204
|
[tool.pylint.similarities]
|
|
204
205
|
min-similarity-lines = 5
|
|
@@ -232,6 +233,7 @@ disallow_untyped_decorators = true
|
|
|
232
233
|
warn_unreachable = true
|
|
233
234
|
strict_equality = true
|
|
234
235
|
pretty = true
|
|
236
|
+
files=["sentinelhub"]
|
|
235
237
|
|
|
236
238
|
[tool.nbqa.addopts]
|
|
237
239
|
ruff = ["--extend-ignore=E402,T201,B015,B018,NPY002,UP,FA"]
|
|
@@ -5,20 +5,16 @@ This module lists all externally useful classes and functions
|
|
|
5
5
|
from ._version import __version__
|
|
6
6
|
from .api import (
|
|
7
7
|
AsyncProcessRequest,
|
|
8
|
-
BatchCollection,
|
|
9
8
|
BatchProcessClient,
|
|
10
9
|
BatchProcessRequest,
|
|
11
|
-
BatchRequest,
|
|
12
10
|
BatchRequestStatus,
|
|
13
11
|
BatchStatisticalRequest,
|
|
14
|
-
BatchTileStatus,
|
|
15
12
|
BatchUserAction,
|
|
16
13
|
ByocCollection,
|
|
17
14
|
ByocCollectionAdditionalData,
|
|
18
15
|
ByocCollectionBand,
|
|
19
16
|
ByocTile,
|
|
20
17
|
FisRequest,
|
|
21
|
-
SentinelHubBatch,
|
|
22
18
|
SentinelHubBatchStatistical,
|
|
23
19
|
SentinelHubBYOC,
|
|
24
20
|
SentinelHubCatalog,
|
|
@@ -28,8 +24,6 @@ from .api import (
|
|
|
28
24
|
WebFeatureService,
|
|
29
25
|
WmsRequest,
|
|
30
26
|
get_async_running_status,
|
|
31
|
-
monitor_batch_analysis,
|
|
32
|
-
monitor_batch_job,
|
|
33
27
|
monitor_batch_process_analysis,
|
|
34
28
|
monitor_batch_process_job,
|
|
35
29
|
monitor_batch_statistical_analysis,
|
|
@@ -40,7 +34,6 @@ from .api.fis import HistogramType
|
|
|
40
34
|
from .api.ogc import CustomUrlParam
|
|
41
35
|
from .api.opensearch import get_area_dates, get_area_info, get_tile_info, get_tile_info_id
|
|
42
36
|
from .areas import (
|
|
43
|
-
BatchSplitter,
|
|
44
37
|
BBoxSplitter,
|
|
45
38
|
CustomGridSplitter,
|
|
46
39
|
OsmSplitter,
|
|
@@ -3,18 +3,12 @@ The part of the package that implements interface with Sentinel Hub services.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from .batch import (
|
|
6
|
-
BatchCollection,
|
|
7
6
|
BatchProcessClient,
|
|
8
7
|
BatchProcessRequest,
|
|
9
|
-
BatchRequest,
|
|
10
8
|
BatchRequestStatus,
|
|
11
9
|
BatchStatisticalRequest,
|
|
12
|
-
BatchTileStatus,
|
|
13
10
|
BatchUserAction,
|
|
14
|
-
SentinelHubBatch,
|
|
15
11
|
SentinelHubBatchStatistical,
|
|
16
|
-
monitor_batch_analysis,
|
|
17
|
-
monitor_batch_job,
|
|
18
12
|
monitor_batch_process_analysis,
|
|
19
13
|
monitor_batch_process_job,
|
|
20
14
|
monitor_batch_statistical_analysis,
|
|
@@ -3,12 +3,9 @@ The part of the package that implements interface with Sentinel Hub services.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from .base import BatchRequestStatus, BatchUserAction
|
|
6
|
-
from .process import
|
|
7
|
-
from .process_v2 import BatchProcessClient, BatchProcessRequest
|
|
6
|
+
from .process import BatchProcessClient, BatchProcessRequest
|
|
8
7
|
from .statistical import BatchStatisticalRequest, SentinelHubBatchStatistical
|
|
9
8
|
from .utils import (
|
|
10
|
-
monitor_batch_analysis,
|
|
11
|
-
monitor_batch_job,
|
|
12
9
|
monitor_batch_process_analysis,
|
|
13
10
|
monitor_batch_process_job,
|
|
14
11
|
monitor_batch_statistical_analysis,
|
|
@@ -26,8 +26,6 @@ class BatchRequestStatus(Enum):
|
|
|
26
26
|
PROCESSING = "PROCESSING"
|
|
27
27
|
DONE = "DONE"
|
|
28
28
|
FAILED = "FAILED"
|
|
29
|
-
PARTIAL = "PARTIAL"
|
|
30
|
-
CANCELED = "CANCELED"
|
|
31
29
|
STOPPED = "STOPPED"
|
|
32
30
|
|
|
33
31
|
|
|
@@ -36,9 +34,8 @@ class BatchUserAction(Enum):
|
|
|
36
34
|
|
|
37
35
|
START = "START"
|
|
38
36
|
ANALYSE = "ANALYSE"
|
|
39
|
-
NONE = "NONE"
|
|
40
|
-
CANCEL = "CANCEL"
|
|
41
37
|
STOP = "STOP"
|
|
38
|
+
NONE = "NONE"
|
|
42
39
|
|
|
43
40
|
|
|
44
41
|
class StoppedStatusReason(Enum):
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deprecated module for Batch Processing v2 API. The contents have been moved to `sentinelhub.api.batch.process`.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
from sentinelhub.api.batch.process import * # noqa: F403 # pylint: disable=unused-wildcard-import, wildcard-import
|
|
8
|
+
from sentinelhub.exceptions import SHDeprecationWarning
|
|
9
|
+
|
|
10
|
+
warnings.warn(
|
|
11
|
+
"The module sentinelhub.api.batch.process_v2 has been renamed, please use sentinelhub.api.batch.process instead.",
|
|
12
|
+
SHDeprecationWarning,
|
|
13
|
+
stacklevel=2,
|
|
14
|
+
)
|
|
@@ -6,7 +6,6 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
import time
|
|
9
|
-
from collections import defaultdict
|
|
10
9
|
from typing import Union
|
|
11
10
|
|
|
12
11
|
from tqdm.auto import tqdm
|
|
@@ -14,13 +13,11 @@ from tqdm.auto import tqdm
|
|
|
14
13
|
from ...config import SHConfig
|
|
15
14
|
from ...types import JsonDict
|
|
16
15
|
from .base import BatchRequestStatus
|
|
17
|
-
from .process import
|
|
18
|
-
from .process_v2 import BatchProcessClient, BatchProcessRequest
|
|
16
|
+
from .process import BatchProcessClient, BatchProcessRequest
|
|
19
17
|
from .statistical import BatchStatisticalRequest, SentinelHubBatchStatistical
|
|
20
18
|
|
|
21
19
|
LOGGER = logging.getLogger(__name__)
|
|
22
20
|
|
|
23
|
-
BatchProcessRequestSpec = Union[str, dict, BatchRequest]
|
|
24
21
|
BatchStatisticalRequestSpec = Union[str, dict, BatchStatisticalRequest]
|
|
25
22
|
|
|
26
23
|
|
|
@@ -32,81 +29,6 @@ _MIN_ANALYSIS_SLEEP_TIME = 5
|
|
|
32
29
|
_DEFAULT_ANALYSIS_SLEEP_TIME = 10
|
|
33
30
|
|
|
34
31
|
|
|
35
|
-
def monitor_batch_job(
|
|
36
|
-
batch_request: BatchProcessRequestSpec,
|
|
37
|
-
config: SHConfig | None = None,
|
|
38
|
-
sleep_time: int = _DEFAULT_SLEEP_TIME,
|
|
39
|
-
analysis_sleep_time: int = _DEFAULT_ANALYSIS_SLEEP_TIME,
|
|
40
|
-
) -> defaultdict[BatchTileStatus, list[dict]]:
|
|
41
|
-
"""A utility function that keeps checking for number of processed tiles until the given batch request finishes.
|
|
42
|
-
During the process it shows a progress bar and at the end it reports information about finished and failed tiles.
|
|
43
|
-
|
|
44
|
-
Notes:
|
|
45
|
-
|
|
46
|
-
- Before calling this function make sure to start a batch job by calling `SentinelHubBatch.start_job` method. In
|
|
47
|
-
case a batch job is still being analysed this function will wait until the analysis ends.
|
|
48
|
-
- This function will be continuously collecting tile information from Sentinel Hub service. To avoid making too
|
|
49
|
-
many requests please make sure to adjust `sleep_time` parameter according to the size of your job. Larger jobs
|
|
50
|
-
don't need very frequent tile status updates.
|
|
51
|
-
- Some information about the progress of this function is reported to logging level INFO.
|
|
52
|
-
|
|
53
|
-
:param batch_request: An object with information about a batch request. Alternatively, it could only be a batch
|
|
54
|
-
request id or a payload.
|
|
55
|
-
:param config: A configuration object with required parameters `sh_client_id`, `sh_client_secret`, and
|
|
56
|
-
`sh_auth_base_url` which is used for authentication and `sh_base_url` which defines the service deployment
|
|
57
|
-
where Batch API will be called.
|
|
58
|
-
:param sleep_time: Number of seconds to sleep between consecutive progress bar updates.
|
|
59
|
-
:param analysis_sleep_time: Number of seconds between consecutive status updates during analysis phase.
|
|
60
|
-
:return: A dictionary mapping a tile status to a list of tile payloads.
|
|
61
|
-
"""
|
|
62
|
-
if sleep_time < _MIN_SLEEP_TIME:
|
|
63
|
-
raise ValueError(f"To avoid making too many service requests please set sleep_time>={_MIN_SLEEP_TIME}")
|
|
64
|
-
|
|
65
|
-
batch_request = monitor_batch_analysis(batch_request, config=config, sleep_time=analysis_sleep_time)
|
|
66
|
-
if batch_request.status is BatchRequestStatus.PROCESSING:
|
|
67
|
-
LOGGER.info("Batch job is running")
|
|
68
|
-
|
|
69
|
-
batch_client = SentinelHubBatch(config=config)
|
|
70
|
-
|
|
71
|
-
tiles_per_status = _get_batch_tiles_per_status(batch_request, batch_client)
|
|
72
|
-
success_count = len(tiles_per_status[BatchTileStatus.PROCESSED])
|
|
73
|
-
finished_count = success_count + len(tiles_per_status[BatchTileStatus.FAILED])
|
|
74
|
-
|
|
75
|
-
progress_bar = tqdm(total=batch_request.tile_count, initial=finished_count, desc="Progress rate")
|
|
76
|
-
success_bar = tqdm(total=finished_count, initial=success_count, desc="Success rate")
|
|
77
|
-
|
|
78
|
-
monitoring_status = [BatchRequestStatus.ANALYSIS_DONE, BatchRequestStatus.PROCESSING]
|
|
79
|
-
with progress_bar, success_bar:
|
|
80
|
-
while finished_count < batch_request.tile_count and batch_request.status in monitoring_status:
|
|
81
|
-
time.sleep(sleep_time)
|
|
82
|
-
batch_request = batch_client.get_request(batch_request)
|
|
83
|
-
|
|
84
|
-
tiles_per_status = _get_batch_tiles_per_status(batch_request, batch_client)
|
|
85
|
-
new_success_count = len(tiles_per_status[BatchTileStatus.PROCESSED])
|
|
86
|
-
new_finished_count = new_success_count + len(tiles_per_status[BatchTileStatus.FAILED])
|
|
87
|
-
|
|
88
|
-
progress_bar.update(new_finished_count - finished_count)
|
|
89
|
-
if new_finished_count != finished_count:
|
|
90
|
-
success_bar.total = new_finished_count
|
|
91
|
-
success_bar.refresh()
|
|
92
|
-
success_bar.update(new_success_count - success_count)
|
|
93
|
-
|
|
94
|
-
finished_count = new_finished_count
|
|
95
|
-
success_count = new_success_count
|
|
96
|
-
|
|
97
|
-
failed_tiles_num = finished_count - success_count
|
|
98
|
-
if failed_tiles_num:
|
|
99
|
-
LOGGER.info("Batch job failed for %d tiles", failed_tiles_num)
|
|
100
|
-
|
|
101
|
-
while batch_request.status is BatchRequestStatus.PROCESSING:
|
|
102
|
-
LOGGER.info("Waiting on batch job status update.")
|
|
103
|
-
time.sleep(sleep_time)
|
|
104
|
-
batch_request = batch_client.get_request(batch_request)
|
|
105
|
-
|
|
106
|
-
LOGGER.info("Batch job finished with status %s", batch_request.status.value)
|
|
107
|
-
return tiles_per_status
|
|
108
|
-
|
|
109
|
-
|
|
110
32
|
def monitor_batch_process_job(
|
|
111
33
|
request: BatchProcessRequest,
|
|
112
34
|
client: BatchProcessClient,
|
|
@@ -155,23 +77,6 @@ def monitor_batch_process_job(
|
|
|
155
77
|
return batch_request
|
|
156
78
|
|
|
157
79
|
|
|
158
|
-
def _get_batch_tiles_per_status(
|
|
159
|
-
batch_request: BatchRequest, batch_client: SentinelHubBatch
|
|
160
|
-
) -> defaultdict[BatchTileStatus, list[dict]]:
|
|
161
|
-
"""A helper function that queries information about batch tiles and returns information about tiles, grouped by
|
|
162
|
-
tile status.
|
|
163
|
-
|
|
164
|
-
:return: A dictionary mapping a tile status to a list of tile payloads.
|
|
165
|
-
"""
|
|
166
|
-
tiles_per_status = defaultdict(list)
|
|
167
|
-
|
|
168
|
-
for tile in batch_client.iter_tiles(batch_request):
|
|
169
|
-
status = BatchTileStatus(tile["status"])
|
|
170
|
-
tiles_per_status[status].append(tile)
|
|
171
|
-
|
|
172
|
-
return tiles_per_status
|
|
173
|
-
|
|
174
|
-
|
|
175
80
|
def monitor_batch_statistical_job(
|
|
176
81
|
batch_request: BatchStatisticalRequestSpec,
|
|
177
82
|
config: SHConfig | None = None,
|
|
@@ -217,38 +122,6 @@ def monitor_batch_statistical_job(
|
|
|
217
122
|
return request_status
|
|
218
123
|
|
|
219
124
|
|
|
220
|
-
def monitor_batch_analysis(
|
|
221
|
-
batch_request: BatchProcessRequestSpec,
|
|
222
|
-
config: SHConfig | None = None,
|
|
223
|
-
sleep_time: int = _DEFAULT_ANALYSIS_SLEEP_TIME,
|
|
224
|
-
) -> BatchRequest:
|
|
225
|
-
"""A utility function that is waiting until analysis phase of a batch job finishes and regularly checks its status.
|
|
226
|
-
In case analysis phase failed it raises an error at the end.
|
|
227
|
-
|
|
228
|
-
:param batch_request: An object with information about a batch request. Alternatively, it could only be a batch
|
|
229
|
-
request id or a payload.
|
|
230
|
-
:param config: A configuration object with required parameters `sh_client_id`, `sh_client_secret`, and
|
|
231
|
-
`sh_auth_base_url` which is used for authentication and `sh_base_url` which defines the service deployment
|
|
232
|
-
where Batch API will be called.
|
|
233
|
-
:param sleep_time: Number of seconds between consecutive status updates during analysis phase.
|
|
234
|
-
:return: Batch request info
|
|
235
|
-
"""
|
|
236
|
-
if sleep_time < _MIN_ANALYSIS_SLEEP_TIME:
|
|
237
|
-
raise ValueError(
|
|
238
|
-
f"To avoid making too many service requests please set analysis sleep time >={_MIN_ANALYSIS_SLEEP_TIME}"
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
batch_client = SentinelHubBatch(config=config)
|
|
242
|
-
batch_request = batch_client.get_request(batch_request)
|
|
243
|
-
while batch_request.status in [BatchRequestStatus.CREATED, BatchRequestStatus.ANALYSING]:
|
|
244
|
-
LOGGER.info("Batch job has a status %s, sleeping for %d seconds", batch_request.status.value, sleep_time)
|
|
245
|
-
time.sleep(sleep_time)
|
|
246
|
-
batch_request = batch_client.get_request(batch_request)
|
|
247
|
-
|
|
248
|
-
batch_request.raise_for_status(status=[BatchRequestStatus.FAILED, BatchRequestStatus.CANCELED])
|
|
249
|
-
return batch_request
|
|
250
|
-
|
|
251
|
-
|
|
252
125
|
def monitor_batch_process_analysis(
|
|
253
126
|
request: BatchProcessRequest,
|
|
254
127
|
client: BatchProcessClient,
|
|
@@ -272,7 +145,7 @@ def monitor_batch_process_analysis(
|
|
|
272
145
|
time.sleep(sleep_time)
|
|
273
146
|
batch_request = client.get_request(batch_request)
|
|
274
147
|
|
|
275
|
-
batch_request.raise_for_status(status=[BatchRequestStatus.FAILED, BatchRequestStatus.
|
|
148
|
+
batch_request.raise_for_status(status=[BatchRequestStatus.FAILED, BatchRequestStatus.STOPPED])
|
|
276
149
|
return batch_request
|
|
277
150
|
|
|
278
151
|
|
|
@@ -305,5 +178,5 @@ def monitor_batch_statistical_analysis(
|
|
|
305
178
|
request_status = BatchRequestStatus(batch_client.get_status(batch_request)["status"])
|
|
306
179
|
|
|
307
180
|
batch_request = batch_client.get_request(batch_request)
|
|
308
|
-
batch_request.raise_for_status(status=[BatchRequestStatus.FAILED, BatchRequestStatus.
|
|
181
|
+
batch_request.raise_for_status(status=[BatchRequestStatus.FAILED, BatchRequestStatus.STOPPED])
|
|
309
182
|
return batch_request
|
|
@@ -17,13 +17,12 @@ import shapely.ops
|
|
|
17
17
|
from shapely.geometry import GeometryCollection, MultiPolygon, Polygon
|
|
18
18
|
from shapely.geometry.base import BaseGeometry
|
|
19
19
|
|
|
20
|
-
from .api import
|
|
20
|
+
from .api import SentinelHubCatalog
|
|
21
21
|
from .config import SHConfig
|
|
22
22
|
from .constants import CRS
|
|
23
23
|
from .data_collections import DataCollection
|
|
24
24
|
from .geo_utils import transform_point
|
|
25
25
|
from .geometry import BBox, Geometry, _BaseGeometry
|
|
26
|
-
from .types import JsonDict
|
|
27
26
|
|
|
28
27
|
T = TypeVar("T", float, int)
|
|
29
28
|
|
|
@@ -534,7 +533,7 @@ class BaseUtmSplitter(AreaSplitter, metaclass=ABCMeta):
|
|
|
534
533
|
geo_object for geo_object in intersection if isinstance(geo_object, (Polygon, MultiPolygon))
|
|
535
534
|
)
|
|
536
535
|
|
|
537
|
-
if
|
|
536
|
+
if intersection.area > 0:
|
|
538
537
|
intersection = Geometry(intersection, CRS.WGS84).transform(utm_crs)
|
|
539
538
|
|
|
540
539
|
bbox_partition = self._align_bbox_to_size(intersection.bbox).get_partition(size_x=size_x, size_y=size_y)
|
|
@@ -624,81 +623,6 @@ class UtmZoneSplitter(BaseUtmSplitter):
|
|
|
624
623
|
return list(zip(utm_geom_list, utm_prop_list))
|
|
625
624
|
|
|
626
625
|
|
|
627
|
-
class BatchSplitter(AreaSplitter):
|
|
628
|
-
"""A splitter that obtains split bounding boxes from Sentinel Hub Batch API"""
|
|
629
|
-
|
|
630
|
-
def __init__(
|
|
631
|
-
self,
|
|
632
|
-
*,
|
|
633
|
-
request_id: str | None = None,
|
|
634
|
-
batch_request: BatchRequest | None = None,
|
|
635
|
-
config: SHConfig | None = None,
|
|
636
|
-
):
|
|
637
|
-
"""
|
|
638
|
-
:param request_id: An ID of a batch request
|
|
639
|
-
:param batch_request: A batch request object. It is an alternative to the `request_id` parameter
|
|
640
|
-
:param config: A configuration object with credentials and information about which service deployment to
|
|
641
|
-
use.
|
|
642
|
-
"""
|
|
643
|
-
self.batch_client = SentinelHubBatch(config=config)
|
|
644
|
-
|
|
645
|
-
if batch_request is None:
|
|
646
|
-
if request_id is None:
|
|
647
|
-
raise ValueError("One of the parameters request_id and batch_request has to be given")
|
|
648
|
-
batch_request = self.batch_client.get_request(request_id)
|
|
649
|
-
|
|
650
|
-
self.batch_request = batch_request
|
|
651
|
-
self.tile_size = self._get_tile_size()
|
|
652
|
-
self.tile_buffer = self._get_tile_buffer()
|
|
653
|
-
|
|
654
|
-
batch_geometry: _BaseGeometry | None = batch_request.geometry or batch_request.bbox
|
|
655
|
-
if batch_geometry is None:
|
|
656
|
-
raise ValueError("Batch request has both `bbox` and `geometry` set to `None`, which is invalid.")
|
|
657
|
-
|
|
658
|
-
super().__init__([batch_geometry.geometry], batch_geometry.crs)
|
|
659
|
-
|
|
660
|
-
def _get_tile_size(self) -> tuple[float, float]:
|
|
661
|
-
"""Collects a tile size from the tiling grid info in units of the grid CRS."""
|
|
662
|
-
tiling_grid_id = self.batch_request.tiling_grid["id"]
|
|
663
|
-
grid_info = self.batch_client.get_tiling_grid(tiling_grid_id)
|
|
664
|
-
|
|
665
|
-
return grid_info["properties"]["tileWidth"], grid_info["properties"]["tileHeight"]
|
|
666
|
-
|
|
667
|
-
def _get_tile_buffer(self) -> tuple[float, float]:
|
|
668
|
-
"""Calculates tile buffer in units of the grid CRS."""
|
|
669
|
-
grid_info = self.batch_request.tiling_grid
|
|
670
|
-
resolution = grid_info["resolution"]
|
|
671
|
-
return grid_info.get("bufferX", 0) * resolution, grid_info.get("bufferY", 0) * resolution
|
|
672
|
-
|
|
673
|
-
def _make_split(self) -> tuple[list[BBox], list[dict[str, object]]]:
|
|
674
|
-
"""This method actually loads bounding boxes from the service and prepares the lists"""
|
|
675
|
-
tile_info_list = list(self.batch_client.iter_tiles(self.batch_request))
|
|
676
|
-
|
|
677
|
-
bbox_list = [self._reconstruct_bbox(tile_info) for tile_info in tile_info_list]
|
|
678
|
-
info_list = [
|
|
679
|
-
{key: value for key, value in tile_info.items() if key != "geometry"} for tile_info in tile_info_list
|
|
680
|
-
]
|
|
681
|
-
|
|
682
|
-
return bbox_list, info_list
|
|
683
|
-
|
|
684
|
-
def _reconstruct_bbox(self, tile_info: JsonDict) -> BBox:
|
|
685
|
-
"""Reconstructs a bounding box from tile and grid properties."""
|
|
686
|
-
tile_crs = CRS(tile_info["origin"]["crs"]["properties"]["name"])
|
|
687
|
-
|
|
688
|
-
upper_left_corner = tile_info["origin"]["coordinates"]
|
|
689
|
-
width, height = self.tile_size
|
|
690
|
-
|
|
691
|
-
return BBox(
|
|
692
|
-
(
|
|
693
|
-
upper_left_corner[0] - self.tile_buffer[0],
|
|
694
|
-
upper_left_corner[1] - height - self.tile_buffer[1],
|
|
695
|
-
upper_left_corner[0] + width + self.tile_buffer[0],
|
|
696
|
-
upper_left_corner[1] + self.tile_buffer[1],
|
|
697
|
-
),
|
|
698
|
-
tile_crs,
|
|
699
|
-
)
|
|
700
|
-
|
|
701
|
-
|
|
702
626
|
def _parse_to_pair(parameter: T | tuple[T, T], allowed_types: tuple[type, ...], param_name: str = "") -> tuple[T, T]:
|
|
703
627
|
"""Parses the parameters defining the splitting of the BBox."""
|
|
704
628
|
|
|
@@ -216,5 +216,5 @@ class SHConfig(_SHConfig):
|
|
|
216
216
|
@classmethod
|
|
217
217
|
def get_config_location(cls) -> str:
|
|
218
218
|
"""Returns the default location of the user configuration file on disk."""
|
|
219
|
-
|
|
220
|
-
return os.path.join(
|
|
219
|
+
config_folder = os.getenv("XDG_CONFIG_HOME", os.path.expanduser("~/.config"))
|
|
220
|
+
return os.path.join(config_folder, "sentinelhub", "config.toml")
|
|
@@ -1,576 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module implementing an interface with
|
|
3
|
-
`Sentinel Hub Batch Processing API <https://docs.sentinel-hub.com/api/latest/api/batch/>`__.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
# ruff: noqa: FA100
|
|
7
|
-
# do not use `from __future__ import annotations`, it clashes with `dataclass_json`
|
|
8
|
-
import datetime as dt
|
|
9
|
-
import logging
|
|
10
|
-
from dataclasses import dataclass, field
|
|
11
|
-
from enum import Enum
|
|
12
|
-
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
|
|
13
|
-
|
|
14
|
-
from dataclasses_json import CatchAll, LetterCase, Undefined, dataclass_json
|
|
15
|
-
from dataclasses_json import config as dataclass_config
|
|
16
|
-
|
|
17
|
-
from ...constants import RequestType
|
|
18
|
-
from ...data_collections import DataCollection
|
|
19
|
-
from ...geometry import CRS, BBox, Geometry
|
|
20
|
-
from ...types import Json, JsonDict
|
|
21
|
-
from ..base import BaseCollection, SentinelHubFeatureIterator
|
|
22
|
-
from ..process import SentinelHubRequest
|
|
23
|
-
from ..utils import datetime_config, enum_config, remove_undefined
|
|
24
|
-
from .base import BaseBatchClient, BaseBatchRequest, BatchRequestStatus, BatchUserAction
|
|
25
|
-
|
|
26
|
-
LOGGER = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
|
-
BatchRequestType = Union[str, dict, "BatchRequest"]
|
|
29
|
-
BatchCollectionType = Union[str, dict, "BatchCollection"]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class BatchTileStatus(Enum):
|
|
33
|
-
"""An enum class with all possible batch tile statuses"""
|
|
34
|
-
|
|
35
|
-
PENDING = "PENDING"
|
|
36
|
-
SCHEDULED = "SCHEDULED"
|
|
37
|
-
QUEUED = "QUEUED"
|
|
38
|
-
PROCESSING = "PROCESSING"
|
|
39
|
-
PROCESSED = "PROCESSED"
|
|
40
|
-
FAILED = "FAILED"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class SentinelHubBatch(BaseBatchClient):
|
|
44
|
-
"""An interface class for Sentinel Hub Batch API
|
|
45
|
-
|
|
46
|
-
For more info check `Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#tag/batch_process>`__.
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
# pylint: disable=too-many-public-methods
|
|
50
|
-
@staticmethod
|
|
51
|
-
def _get_service_url(base_url: str) -> str:
|
|
52
|
-
"""Provides URL to Catalog API"""
|
|
53
|
-
return f"{base_url}/api/v1/batch"
|
|
54
|
-
|
|
55
|
-
def create(
|
|
56
|
-
self,
|
|
57
|
-
sentinelhub_request: Union[SentinelHubRequest, JsonDict],
|
|
58
|
-
tiling_grid: Dict[str, Any],
|
|
59
|
-
output: Optional[Dict[str, Any]] = None,
|
|
60
|
-
bucket_name: Optional[str] = None,
|
|
61
|
-
description: Optional[str] = None,
|
|
62
|
-
**kwargs: Any,
|
|
63
|
-
) -> "BatchRequest":
|
|
64
|
-
"""Create a new batch request
|
|
65
|
-
|
|
66
|
-
`Batch API reference
|
|
67
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/createNewBatchProcessingRequest>`__
|
|
68
|
-
|
|
69
|
-
:param sentinelhub_request: An instance of SentinelHubRequest class containing all request parameters.
|
|
70
|
-
Alternatively, it can also be just a payload dictionary for Process API request
|
|
71
|
-
:param tiling_grid: A dictionary with tiling grid parameters. It can be built with `tiling_grid` method
|
|
72
|
-
:param output: A dictionary with output parameters. It can be built with `output` method. Alternatively, one
|
|
73
|
-
can set `bucket_name` parameter instead.
|
|
74
|
-
:param bucket_name: A name of an S3 bucket where to save data. Alternatively, one can set `output` parameter
|
|
75
|
-
to specify more output parameters.
|
|
76
|
-
:param description: A description of a batch request
|
|
77
|
-
:param kwargs: Any other arguments to be added to a dictionary of parameters.
|
|
78
|
-
:return: An instance of `SentinelHubBatch` object that represents a newly created batch request.
|
|
79
|
-
"""
|
|
80
|
-
|
|
81
|
-
if isinstance(sentinelhub_request, SentinelHubRequest):
|
|
82
|
-
request_dict = sentinelhub_request.download_list[0].post_values
|
|
83
|
-
else:
|
|
84
|
-
request_dict = sentinelhub_request
|
|
85
|
-
|
|
86
|
-
if not isinstance(request_dict, dict):
|
|
87
|
-
raise ValueError(
|
|
88
|
-
"Parameter sentinelhub_request should be an instance of SentinelHubRequest or a "
|
|
89
|
-
"dictionary with a request payload"
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
payload = {
|
|
93
|
-
"processRequest": request_dict,
|
|
94
|
-
"tilingGrid": tiling_grid,
|
|
95
|
-
"output": output,
|
|
96
|
-
"bucketName": bucket_name,
|
|
97
|
-
"description": description,
|
|
98
|
-
**kwargs,
|
|
99
|
-
}
|
|
100
|
-
payload = remove_undefined(payload)
|
|
101
|
-
|
|
102
|
-
url = self._get_processing_url()
|
|
103
|
-
request_info = self.client.get_json_dict(url, post_values=payload, use_session=True)
|
|
104
|
-
|
|
105
|
-
return BatchRequest.from_dict(request_info)
|
|
106
|
-
|
|
107
|
-
@staticmethod
|
|
108
|
-
def tiling_grid(
|
|
109
|
-
grid_id: int, resolution: float, buffer: Optional[Tuple[int, int]] = None, **kwargs: Any
|
|
110
|
-
) -> JsonDict:
|
|
111
|
-
"""A helper method to build a dictionary with tiling grid parameters
|
|
112
|
-
|
|
113
|
-
:param grid_id: An ID of a tiling grid
|
|
114
|
-
:param resolution: A grid resolution
|
|
115
|
-
:param buffer: Optionally, a buffer around each tile can be defined. It can be defined with a tuple of integers
|
|
116
|
-
`(buffer_x, buffer_y)`, which specifies a number of buffer pixels in horizontal and vertical directions.
|
|
117
|
-
:param kwargs: Any other arguments to be added to a dictionary of parameters
|
|
118
|
-
:return: A dictionary with parameters
|
|
119
|
-
"""
|
|
120
|
-
payload = {"id": grid_id, "resolution": resolution, **kwargs}
|
|
121
|
-
if buffer:
|
|
122
|
-
payload = {**payload, "bufferX": buffer[0], "bufferY": buffer[1]}
|
|
123
|
-
return payload
|
|
124
|
-
|
|
125
|
-
@staticmethod
|
|
126
|
-
def output(
|
|
127
|
-
*,
|
|
128
|
-
default_tile_path: Optional[str] = None,
|
|
129
|
-
overwrite: Optional[bool] = None,
|
|
130
|
-
skip_existing: Optional[bool] = None,
|
|
131
|
-
cog_output: Optional[bool] = None,
|
|
132
|
-
cog_parameters: Optional[Dict[str, Any]] = None,
|
|
133
|
-
create_collection: Optional[bool] = None,
|
|
134
|
-
collection_id: Optional[str] = None,
|
|
135
|
-
responses: Optional[List[str]] = None,
|
|
136
|
-
**kwargs: Any,
|
|
137
|
-
) -> Dict[str, Any]:
|
|
138
|
-
"""A helper method to build a dictionary with tiling grid parameters
|
|
139
|
-
|
|
140
|
-
:param default_tile_path: A path or a template on an s3 bucket where to store results. More info at Batch API
|
|
141
|
-
documentation
|
|
142
|
-
:param overwrite: A flag specifying if a request should overwrite existing outputs without failing
|
|
143
|
-
:param skip_existing: A flag specifying if existing outputs should be overwritten
|
|
144
|
-
:param cog_output: A flag specifying if outputs should be written in COGs (cloud-optimized GeoTIFFs )or
|
|
145
|
-
normal GeoTIFFs
|
|
146
|
-
:param cog_parameters: A dictionary specifying COG creation parameters
|
|
147
|
-
:param create_collection: If True the results will be written in COGs and a batch collection will be created
|
|
148
|
-
:param collection_id: If True results will be added to an existing collection
|
|
149
|
-
:param responses: Specification of path template for individual outputs/responses
|
|
150
|
-
:param kwargs: Any other arguments to be added to a dictionary of parameters
|
|
151
|
-
:return: A dictionary of output parameters
|
|
152
|
-
"""
|
|
153
|
-
return remove_undefined(
|
|
154
|
-
{
|
|
155
|
-
"defaultTilePath": default_tile_path,
|
|
156
|
-
"overwrite": overwrite,
|
|
157
|
-
"skipExisting": skip_existing,
|
|
158
|
-
"cogOutput": cog_output,
|
|
159
|
-
"cogParameters": cog_parameters,
|
|
160
|
-
"createCollection": create_collection,
|
|
161
|
-
"collectionId": collection_id,
|
|
162
|
-
"responses": responses,
|
|
163
|
-
**kwargs,
|
|
164
|
-
}
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
def iter_tiling_grids(self, **kwargs: Any) -> SentinelHubFeatureIterator:
|
|
168
|
-
"""An iterator over tiling grids
|
|
169
|
-
|
|
170
|
-
`Batch API reference
|
|
171
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/getBatchTilingGridsProperties>`__
|
|
172
|
-
|
|
173
|
-
:param kwargs: Any other request query parameters
|
|
174
|
-
:return: An iterator over tiling grid definitions
|
|
175
|
-
"""
|
|
176
|
-
return SentinelHubFeatureIterator(
|
|
177
|
-
client=self.client,
|
|
178
|
-
url=self._get_tiling_grids_url(),
|
|
179
|
-
params=remove_undefined(kwargs),
|
|
180
|
-
exception_message="Failed to obtain information about available tiling grids",
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
def get_tiling_grid(self, grid_id: Union[int, str]) -> JsonDict:
|
|
184
|
-
"""Provides a single tiling grid
|
|
185
|
-
|
|
186
|
-
`Batch API reference
|
|
187
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/getBatchTilingGridProperties>`__
|
|
188
|
-
|
|
189
|
-
:param grid_id: An ID of a requested tiling grid
|
|
190
|
-
:return: A tiling grid definition
|
|
191
|
-
"""
|
|
192
|
-
url = self._get_tiling_grids_url(grid_id)
|
|
193
|
-
return self.client.get_json_dict(url=url, use_session=True)
|
|
194
|
-
|
|
195
|
-
def iter_requests(
|
|
196
|
-
self, user_id: Optional[str] = None, search: Optional[str] = None, sort: Optional[str] = None, **kwargs: Any
|
|
197
|
-
) -> Iterator["BatchRequest"]:
|
|
198
|
-
"""Iterate existing batch requests
|
|
199
|
-
|
|
200
|
-
`Batch API reference
|
|
201
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/getAllBatchProcessRequests>`__
|
|
202
|
-
|
|
203
|
-
:param user_id: Filter requests by a user id who defined a request
|
|
204
|
-
:param search: A search query to filter requests
|
|
205
|
-
:param sort: A sort query
|
|
206
|
-
:param kwargs: Any additional parameters to include in a request query
|
|
207
|
-
:return: An iterator over existing batch requests
|
|
208
|
-
"""
|
|
209
|
-
params = remove_undefined({"userid": user_id, "search": search, "sort": sort, **kwargs})
|
|
210
|
-
feature_iterator = SentinelHubFeatureIterator(
|
|
211
|
-
client=self.client, url=self._get_processing_url(), params=params, exception_message="No requests found"
|
|
212
|
-
)
|
|
213
|
-
for request_info in feature_iterator:
|
|
214
|
-
yield BatchRequest.from_dict(request_info)
|
|
215
|
-
|
|
216
|
-
def get_latest_request(self) -> "BatchRequest":
|
|
217
|
-
"""Provides a batch request that has been created the latest
|
|
218
|
-
|
|
219
|
-
:return: Batch request info
|
|
220
|
-
"""
|
|
221
|
-
latest_request_iter = self.iter_requests(sort="created:desc", count=1)
|
|
222
|
-
try:
|
|
223
|
-
return next(latest_request_iter)
|
|
224
|
-
except StopIteration as exception:
|
|
225
|
-
raise ValueError("No batch request is available") from exception
|
|
226
|
-
|
|
227
|
-
def get_request(self, batch_request: BatchRequestType) -> "BatchRequest":
|
|
228
|
-
"""Collects information about a single batch request
|
|
229
|
-
|
|
230
|
-
`Batch API reference
|
|
231
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/getSingleBatchProcessRequestById>`__
|
|
232
|
-
|
|
233
|
-
:return: Batch request info
|
|
234
|
-
"""
|
|
235
|
-
request_id = self._parse_request_id(batch_request)
|
|
236
|
-
request_info = self.client.get_json_dict(url=self._get_processing_url(request_id), use_session=True)
|
|
237
|
-
return BatchRequest.from_dict(request_info)
|
|
238
|
-
|
|
239
|
-
def update_request(
|
|
240
|
-
self,
|
|
241
|
-
batch_request: BatchRequestType,
|
|
242
|
-
output: Optional[Dict[str, Any]] = None,
|
|
243
|
-
description: Optional[str] = None,
|
|
244
|
-
**kwargs: Any,
|
|
245
|
-
) -> Json:
|
|
246
|
-
"""Update batch job request parameters
|
|
247
|
-
|
|
248
|
-
`Batch API reference
|
|
249
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/updateBatchProcessRequest>`__
|
|
250
|
-
|
|
251
|
-
Similarly to `update_info` method, this method also updates local information in the current instance of
|
|
252
|
-
`SentinelHubBatch`.
|
|
253
|
-
|
|
254
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
255
|
-
request ID.
|
|
256
|
-
:param output: A dictionary with output parameters to be updated.
|
|
257
|
-
:param description: A description of a batch request to be updated.
|
|
258
|
-
:param kwargs: Any other arguments to be added to a dictionary of parameters.
|
|
259
|
-
"""
|
|
260
|
-
request_id = self._parse_request_id(batch_request)
|
|
261
|
-
payload = remove_undefined({"output": output, "description": description, **kwargs})
|
|
262
|
-
return self.client.get_json(
|
|
263
|
-
url=self._get_processing_url(request_id),
|
|
264
|
-
post_values=payload,
|
|
265
|
-
request_type=RequestType.PUT,
|
|
266
|
-
use_session=True,
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
def delete_request(self, batch_request: BatchRequestType) -> Json:
|
|
270
|
-
"""Delete a batch job request
|
|
271
|
-
|
|
272
|
-
`Batch API reference
|
|
273
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/deleteBatchProcessRequest>`__
|
|
274
|
-
|
|
275
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
276
|
-
request ID.
|
|
277
|
-
"""
|
|
278
|
-
request_id = self._parse_request_id(batch_request)
|
|
279
|
-
return self.client.get_json(
|
|
280
|
-
url=self._get_processing_url(request_id), request_type=RequestType.DELETE, use_session=True
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
def start_analysis(self, batch_request: BatchRequestType) -> Json:
|
|
284
|
-
"""Starts analysis of a batch job request
|
|
285
|
-
|
|
286
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/batchAnalyse>`__
|
|
287
|
-
|
|
288
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
289
|
-
request ID.
|
|
290
|
-
"""
|
|
291
|
-
return self._call_job(batch_request, "analyse")
|
|
292
|
-
|
|
293
|
-
def start_job(self, batch_request: BatchRequestType) -> Json:
|
|
294
|
-
"""Starts running a batch job
|
|
295
|
-
|
|
296
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/batchStartProcessRequest>`__
|
|
297
|
-
|
|
298
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
299
|
-
request ID.
|
|
300
|
-
"""
|
|
301
|
-
return self._call_job(batch_request, "start")
|
|
302
|
-
|
|
303
|
-
def cancel_job(self, batch_request: BatchRequestType) -> Json:
|
|
304
|
-
"""Cancels a batch job
|
|
305
|
-
|
|
306
|
-
`Batch API reference
|
|
307
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/batchCancelProcessRequest>`__
|
|
308
|
-
|
|
309
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
310
|
-
request ID.
|
|
311
|
-
"""
|
|
312
|
-
return self._call_job(batch_request, "cancel")
|
|
313
|
-
|
|
314
|
-
def restart_job(self, batch_request: BatchRequestType) -> Json:
|
|
315
|
-
"""Restarts only those parts of a job that failed
|
|
316
|
-
|
|
317
|
-
`Batch API reference
|
|
318
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/batchRestartPartialProcessRequest>`__
|
|
319
|
-
|
|
320
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
321
|
-
request ID.
|
|
322
|
-
"""
|
|
323
|
-
return self._call_job(batch_request, "restartpartial")
|
|
324
|
-
|
|
325
|
-
def iter_tiles(
|
|
326
|
-
self, batch_request: BatchRequestType, status: Union[None, "BatchTileStatus", str] = None, **kwargs: Any
|
|
327
|
-
) -> SentinelHubFeatureIterator:
|
|
328
|
-
"""Iterate over info about batch request tiles
|
|
329
|
-
|
|
330
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/getAllBatchProcessTiles>`__
|
|
331
|
-
|
|
332
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
333
|
-
request ID.
|
|
334
|
-
:param status: A filter to obtain only tiles with a certain status
|
|
335
|
-
:param kwargs: Any additional parameters to include in a request query
|
|
336
|
-
:return: An iterator over information about each tile
|
|
337
|
-
"""
|
|
338
|
-
request_id = self._parse_request_id(batch_request)
|
|
339
|
-
if isinstance(status, BatchTileStatus):
|
|
340
|
-
status = status.value
|
|
341
|
-
|
|
342
|
-
return SentinelHubFeatureIterator(
|
|
343
|
-
client=self.client,
|
|
344
|
-
url=self._get_tiles_url(request_id),
|
|
345
|
-
params={"status": status, **kwargs},
|
|
346
|
-
exception_message="No tiles found, please run analysis on batch request before calling this method",
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
def get_tile(self, batch_request: BatchRequestType, tile_id: Optional[int]) -> JsonDict:
|
|
350
|
-
"""Provides information about a single batch request tile
|
|
351
|
-
|
|
352
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/getBatchTileById>`__
|
|
353
|
-
|
|
354
|
-
:param batch_request: It could be a batch request object, a raw batch request payload or only a batch
|
|
355
|
-
request ID.
|
|
356
|
-
:param tile_id: An ID of a tile
|
|
357
|
-
:return: Information about a tile
|
|
358
|
-
"""
|
|
359
|
-
request_id = self._parse_request_id(batch_request)
|
|
360
|
-
url = self._get_tiles_url(request_id, tile_id=tile_id)
|
|
361
|
-
return self.client.get_json_dict(url, use_session=True)
|
|
362
|
-
|
|
363
|
-
def iter_collections(self, search: Optional[str] = None, **kwargs: Any) -> SentinelHubFeatureIterator:
|
|
364
|
-
"""Iterate over batch collections
|
|
365
|
-
|
|
366
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/getAllBatchCollections>`__
|
|
367
|
-
|
|
368
|
-
:param search: A search query to filter collections
|
|
369
|
-
:param kwargs: Any additional parameters to include in a request query
|
|
370
|
-
:return: An iterator over existing batch collections
|
|
371
|
-
"""
|
|
372
|
-
return SentinelHubFeatureIterator(
|
|
373
|
-
client=self.client,
|
|
374
|
-
url=self._get_collections_url(),
|
|
375
|
-
params={"search": search, **kwargs},
|
|
376
|
-
exception_message="Failed to obtain information about available Batch collections",
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
def get_collection(self, collection_id: str) -> JsonDict:
|
|
380
|
-
"""Get batch collection by its id
|
|
381
|
-
|
|
382
|
-
`Batch API reference
|
|
383
|
-
<https://docs.sentinel-hub.com/api/latest/reference/#operation/getSingleBatchCollectionById>`__
|
|
384
|
-
|
|
385
|
-
:param collection_id: A batch collection id
|
|
386
|
-
:return: A dictionary of the collection parameters
|
|
387
|
-
"""
|
|
388
|
-
url = self._get_collections_url(collection_id)
|
|
389
|
-
return self.client.get_json_dict(url=url, use_session=True, extract_key="data")
|
|
390
|
-
|
|
391
|
-
def create_collection(self, collection: Union["BatchCollection", dict]) -> JsonDict:
|
|
392
|
-
"""Create a new batch collection
|
|
393
|
-
|
|
394
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/createNewBatchCollection>`__
|
|
395
|
-
|
|
396
|
-
:param collection: Batch collection definition
|
|
397
|
-
:return: A dictionary of a newly created collection
|
|
398
|
-
"""
|
|
399
|
-
collection_payload = self._parse_collection_to_dict(collection)
|
|
400
|
-
url = self._get_collections_url()
|
|
401
|
-
return self.client.get_json_dict(url=url, post_values=collection_payload, use_session=True, extract_key="data")
|
|
402
|
-
|
|
403
|
-
def update_collection(self, collection: Union["BatchCollection", dict]) -> Json:
|
|
404
|
-
"""Update an existing batch collection
|
|
405
|
-
|
|
406
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/updateBatchCollection>`__
|
|
407
|
-
|
|
408
|
-
:param collection: Batch collection definition
|
|
409
|
-
"""
|
|
410
|
-
collection_id = self._parse_collection_id(collection)
|
|
411
|
-
return self.client.get_json(
|
|
412
|
-
url=self._get_collections_url(collection_id),
|
|
413
|
-
post_values=self._parse_collection_to_dict(collection),
|
|
414
|
-
request_type=RequestType.PUT,
|
|
415
|
-
use_session=True,
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
def delete_collection(self, collection: BatchCollectionType) -> Json:
|
|
419
|
-
"""Delete an existing batch collection
|
|
420
|
-
|
|
421
|
-
`Batch API reference <https://docs.sentinel-hub.com/api/latest/reference/#operation/deleteBatchCollection>`__
|
|
422
|
-
|
|
423
|
-
:param collection: Batch collection id or object
|
|
424
|
-
"""
|
|
425
|
-
collection_id = self._parse_collection_id(collection)
|
|
426
|
-
return self.client.get_json(
|
|
427
|
-
url=self._get_collections_url(collection_id), request_type=RequestType.DELETE, use_session=True
|
|
428
|
-
)
|
|
429
|
-
|
|
430
|
-
def _get_processing_url(self, request_id: Optional[str] = None) -> str:
|
|
431
|
-
"""Creates a URL for process endpoint"""
|
|
432
|
-
url = f"{self.service_url}/process"
|
|
433
|
-
if request_id is None:
|
|
434
|
-
return url
|
|
435
|
-
return f"{url}/{request_id}"
|
|
436
|
-
|
|
437
|
-
def _get_tiles_url(self, request_id: str, tile_id: Union[None, str, int] = None) -> str:
|
|
438
|
-
"""Creates a URL for tiles endpoint"""
|
|
439
|
-
url = f"{self._get_processing_url(request_id)}/tiles"
|
|
440
|
-
if tile_id is None:
|
|
441
|
-
return url
|
|
442
|
-
return f"{url}/{tile_id}"
|
|
443
|
-
|
|
444
|
-
def _get_tiling_grids_url(self, grid_id: Union[None, str, int] = None) -> str:
|
|
445
|
-
"""Creates a URL for tiling grids endpoint"""
|
|
446
|
-
url = f"{self.service_url}/tilinggrids"
|
|
447
|
-
if grid_id is None:
|
|
448
|
-
return url
|
|
449
|
-
return f"{url}/{grid_id}"
|
|
450
|
-
|
|
451
|
-
def _get_collections_url(self, collection_id: Optional[str] = None) -> str:
|
|
452
|
-
"""Creates a URL for batch collections endpoint"""
|
|
453
|
-
url = f"{self.service_url}/collections"
|
|
454
|
-
if collection_id is None:
|
|
455
|
-
return url
|
|
456
|
-
return f"{url}/{collection_id}"
|
|
457
|
-
|
|
458
|
-
@staticmethod
|
|
459
|
-
def _parse_collection_id(data: BatchCollectionType) -> Optional[str]:
|
|
460
|
-
"""Parses batch collection id from multiple possible inputs"""
|
|
461
|
-
if isinstance(data, (BatchCollection, DataCollection)):
|
|
462
|
-
return data.collection_id
|
|
463
|
-
if isinstance(data, dict):
|
|
464
|
-
return data["id"]
|
|
465
|
-
if isinstance(data, str):
|
|
466
|
-
return data
|
|
467
|
-
raise ValueError(f"Expected a BatchCollection dataclass, dictionary or a string, got {data}.")
|
|
468
|
-
|
|
469
|
-
@staticmethod
|
|
470
|
-
def _parse_collection_to_dict(data: Union["BatchCollection", dict]) -> dict:
|
|
471
|
-
"""Constructs a dictionary from given object"""
|
|
472
|
-
if isinstance(data, BatchCollection):
|
|
473
|
-
return data.to_dict() # type: ignore[attr-defined]
|
|
474
|
-
if isinstance(data, dict):
|
|
475
|
-
return data
|
|
476
|
-
raise ValueError(f"Expected either a BatchCollection or a dict, got {data}.")
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.INCLUDE)
|
|
480
|
-
@dataclass(repr=False)
|
|
481
|
-
class BatchRequest(BaseBatchRequest): # pylint: disable=abstract-method
|
|
482
|
-
"""A dataclass object that holds information about a batch request"""
|
|
483
|
-
|
|
484
|
-
# dataclass_json doesn't handle parameter inheritance correctly
|
|
485
|
-
# pylint: disable=duplicate-code
|
|
486
|
-
|
|
487
|
-
request_id: str = field(metadata=dataclass_config(field_name="id"))
|
|
488
|
-
process_request: dict
|
|
489
|
-
tile_count: int
|
|
490
|
-
status: BatchRequestStatus = field(metadata=enum_config(BatchRequestStatus))
|
|
491
|
-
user_id: Optional[str] = None
|
|
492
|
-
created: Optional[dt.datetime] = field(metadata=datetime_config, default=None)
|
|
493
|
-
tiling_grid: dict = field(default_factory=dict)
|
|
494
|
-
output: dict = field(default_factory=dict)
|
|
495
|
-
bucket_name: Optional[str] = None
|
|
496
|
-
description: Optional[str] = None
|
|
497
|
-
value_estimate: Optional[float] = None
|
|
498
|
-
tile_width_px: Optional[int] = None
|
|
499
|
-
tile_height_px: Optional[int] = None
|
|
500
|
-
user_action: Optional[BatchUserAction] = field(metadata=enum_config(BatchUserAction), default=None)
|
|
501
|
-
user_action_updated: Optional[str] = field(metadata=datetime_config, default=None)
|
|
502
|
-
error: Optional[str] = None
|
|
503
|
-
other_data: CatchAll = field(default_factory=dict)
|
|
504
|
-
|
|
505
|
-
_REPR_PARAM_NAMES = (
|
|
506
|
-
"request_id",
|
|
507
|
-
"description",
|
|
508
|
-
"bucket_name",
|
|
509
|
-
"created",
|
|
510
|
-
"status",
|
|
511
|
-
"user_action",
|
|
512
|
-
"value_estimate",
|
|
513
|
-
"tile_count",
|
|
514
|
-
)
|
|
515
|
-
|
|
516
|
-
@property
|
|
517
|
-
def evalscript(self) -> str:
|
|
518
|
-
"""Provides an evalscript used by a batch request
|
|
519
|
-
|
|
520
|
-
:return: An evalscript
|
|
521
|
-
"""
|
|
522
|
-
return self.process_request["evalscript"]
|
|
523
|
-
|
|
524
|
-
@property
|
|
525
|
-
def bbox(self) -> Optional[BBox]:
|
|
526
|
-
"""Provides a bounding box used by a batch request
|
|
527
|
-
|
|
528
|
-
:return: An area bounding box together with CRS
|
|
529
|
-
:raises: ValueError
|
|
530
|
-
"""
|
|
531
|
-
bbox, _, crs = self._parse_bounds_payload()
|
|
532
|
-
return None if bbox is None else BBox(bbox, crs) # type: ignore[arg-type]
|
|
533
|
-
|
|
534
|
-
@property
|
|
535
|
-
def geometry(self) -> Optional[Geometry]:
|
|
536
|
-
"""Provides a geometry used by a batch request
|
|
537
|
-
|
|
538
|
-
:return: An area geometry together with CRS
|
|
539
|
-
:raises: ValueError
|
|
540
|
-
"""
|
|
541
|
-
_, geometry, crs = self._parse_bounds_payload()
|
|
542
|
-
return None if geometry is None else Geometry(geometry, crs)
|
|
543
|
-
|
|
544
|
-
def _parse_bounds_payload(self) -> Tuple[Optional[List[float]], Optional[list], CRS]:
|
|
545
|
-
"""Parses bbox, geometry and crs from batch request payload. If bbox or geometry don't exist it returns None
|
|
546
|
-
instead.
|
|
547
|
-
"""
|
|
548
|
-
bounds_definition = self.process_request["input"]["bounds"]
|
|
549
|
-
crs = CRS(bounds_definition["properties"]["crs"].rsplit("/", 1)[-1])
|
|
550
|
-
|
|
551
|
-
return bounds_definition.get("bbox"), bounds_definition.get("geometry"), crs
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.INCLUDE)
|
|
555
|
-
@dataclass
|
|
556
|
-
class BatchCollectionBatchData:
|
|
557
|
-
"""Dataclass to hold batch collection batchData part of the payload"""
|
|
558
|
-
|
|
559
|
-
tiling_grid_id: Optional[int] = None
|
|
560
|
-
other_data: CatchAll = field(default_factory=dict)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.INCLUDE)
|
|
564
|
-
@dataclass
|
|
565
|
-
class BatchCollectionAdditionalData:
|
|
566
|
-
"""Dataclass to hold batch collection additionalData part of the payload"""
|
|
567
|
-
|
|
568
|
-
bands: Optional[Dict[str, Any]] = None
|
|
569
|
-
other_data: CatchAll = field(default_factory=dict)
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
class BatchCollection(BaseCollection):
|
|
573
|
-
"""Dataclass for batch collections"""
|
|
574
|
-
|
|
575
|
-
batch_data: Optional[BatchCollectionBatchData] = None
|
|
576
|
-
additional_data: Optional[BatchCollectionAdditionalData] = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sentinelhub-3.11.1 → sentinelhub-3.11.3}/sentinelhub/download/sentinelhub_statistical_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|