sentinelhub 3.11.1__tar.gz → 3.11.2__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.
Files changed (64) hide show
  1. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/PKG-INFO +2 -3
  2. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/README.md +0 -1
  3. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/pyproject.toml +3 -1
  4. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/__init__.py +0 -7
  5. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/_version.py +1 -1
  6. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/__init__.py +0 -6
  7. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/batch/__init__.py +1 -4
  8. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/batch/base.py +1 -4
  9. sentinelhub-3.11.2/sentinelhub/api/batch/process_v2.py +14 -0
  10. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/batch/utils.py +3 -130
  11. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/areas.py +2 -78
  12. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/config.py +2 -2
  13. sentinelhub-3.11.1/sentinelhub/api/batch/process.py +0 -576
  14. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/.gitignore +0 -0
  15. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/LICENSE.md +0 -0
  16. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/.utmzones.geojson +0 -0
  17. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/base.py +0 -0
  18. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/base_request.py +0 -0
  19. /sentinelhub-3.11.1/sentinelhub/api/batch/process_v2.py → /sentinelhub-3.11.2/sentinelhub/api/batch/process.py +0 -0
  20. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/batch/statistical.py +0 -0
  21. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/byoc.py +0 -0
  22. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/catalog.py +0 -0
  23. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/fis.py +0 -0
  24. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/ogc.py +0 -0
  25. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/opensearch.py +0 -0
  26. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/process.py +0 -0
  27. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/statistical.py +0 -0
  28. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/utils.py +0 -0
  29. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/api/wfs.py +0 -0
  30. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/__init__.py +0 -0
  31. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/batch.py +0 -0
  32. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/client.py +0 -0
  33. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/commands.py +0 -0
  34. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/constants.py +0 -0
  35. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/data.py +0 -0
  36. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/data_safe.py +0 -0
  37. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/aws/request.py +0 -0
  38. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/base.py +0 -0
  39. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/commands.py +0 -0
  40. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/constants.py +0 -0
  41. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/data_collections.py +0 -0
  42. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/data_collections_bands.py +0 -0
  43. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/data_utils.py +0 -0
  44. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/decoding.py +0 -0
  45. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/__init__.py +0 -0
  46. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/client.py +0 -0
  47. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/handlers.py +0 -0
  48. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/models.py +0 -0
  49. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/rate_limit.py +0 -0
  50. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/sentinelhub_client.py +0 -0
  51. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/sentinelhub_statistical_client.py +0 -0
  52. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/download/session.py +0 -0
  53. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/evalscript.py +0 -0
  54. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/exceptions.py +0 -0
  55. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/geo_utils.py +0 -0
  56. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/geometry.py +0 -0
  57. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/geopedia/__init__.py +0 -0
  58. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/geopedia/core.py +0 -0
  59. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/geopedia/request.py +0 -0
  60. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/io_utils.py +0 -0
  61. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/py.typed +0 -0
  62. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/testing_utils.py +0 -0
  63. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/time_utils.py +0 -0
  64. {sentinelhub-3.11.1 → sentinelhub-3.11.2}/sentinelhub/types.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: sentinelhub
3
- Version: 3.11.1
3
+ Version: 3.11.2
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", # version fixed because 0.6.0 didnt work at release time of 3.10.2
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,
@@ -1,3 +1,3 @@
1
1
  """Version of the sentinelhub package."""
2
2
 
3
- __version__ = "3.11.1"
3
+ __version__ = "3.11.2"
@@ -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 BatchCollection, BatchRequest, BatchTileStatus, SentinelHubBatch
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 BatchRequest, BatchTileStatus, SentinelHubBatch
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.CANCELED])
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.CANCELED])
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 BatchRequest, SentinelHubBatch, SentinelHubCatalog
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 not intersection.is_empty:
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
- user_folder = os.path.expanduser("~")
220
- return os.path.join(user_folder, ".config", "sentinelhub", "config.toml")
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