mapchete-eo 2025.7.0__py2.py3-none-any.whl

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 (87) hide show
  1. mapchete_eo/__init__.py +1 -0
  2. mapchete_eo/archives/__init__.py +0 -0
  3. mapchete_eo/archives/base.py +65 -0
  4. mapchete_eo/array/__init__.py +0 -0
  5. mapchete_eo/array/buffer.py +16 -0
  6. mapchete_eo/array/color.py +29 -0
  7. mapchete_eo/array/convert.py +157 -0
  8. mapchete_eo/base.py +528 -0
  9. mapchete_eo/blacklist.txt +175 -0
  10. mapchete_eo/cli/__init__.py +30 -0
  11. mapchete_eo/cli/bounds.py +22 -0
  12. mapchete_eo/cli/options_arguments.py +243 -0
  13. mapchete_eo/cli/s2_brdf.py +77 -0
  14. mapchete_eo/cli/s2_cat_results.py +146 -0
  15. mapchete_eo/cli/s2_find_broken_products.py +93 -0
  16. mapchete_eo/cli/s2_jp2_static_catalog.py +166 -0
  17. mapchete_eo/cli/s2_mask.py +71 -0
  18. mapchete_eo/cli/s2_mgrs.py +45 -0
  19. mapchete_eo/cli/s2_rgb.py +114 -0
  20. mapchete_eo/cli/s2_verify.py +129 -0
  21. mapchete_eo/cli/static_catalog.py +123 -0
  22. mapchete_eo/eostac.py +30 -0
  23. mapchete_eo/exceptions.py +87 -0
  24. mapchete_eo/geometry.py +271 -0
  25. mapchete_eo/image_operations/__init__.py +12 -0
  26. mapchete_eo/image_operations/color_correction.py +136 -0
  27. mapchete_eo/image_operations/compositing.py +247 -0
  28. mapchete_eo/image_operations/dtype_scale.py +43 -0
  29. mapchete_eo/image_operations/fillnodata.py +130 -0
  30. mapchete_eo/image_operations/filters.py +319 -0
  31. mapchete_eo/image_operations/linear_normalization.py +81 -0
  32. mapchete_eo/image_operations/sigmoidal.py +114 -0
  33. mapchete_eo/io/__init__.py +37 -0
  34. mapchete_eo/io/assets.py +492 -0
  35. mapchete_eo/io/items.py +147 -0
  36. mapchete_eo/io/levelled_cubes.py +228 -0
  37. mapchete_eo/io/path.py +144 -0
  38. mapchete_eo/io/products.py +413 -0
  39. mapchete_eo/io/profiles.py +45 -0
  40. mapchete_eo/known_catalogs.py +42 -0
  41. mapchete_eo/platforms/sentinel2/__init__.py +17 -0
  42. mapchete_eo/platforms/sentinel2/archives.py +190 -0
  43. mapchete_eo/platforms/sentinel2/bandpass_adjustment.py +104 -0
  44. mapchete_eo/platforms/sentinel2/brdf/__init__.py +8 -0
  45. mapchete_eo/platforms/sentinel2/brdf/config.py +32 -0
  46. mapchete_eo/platforms/sentinel2/brdf/correction.py +260 -0
  47. mapchete_eo/platforms/sentinel2/brdf/hls.py +251 -0
  48. mapchete_eo/platforms/sentinel2/brdf/models.py +44 -0
  49. mapchete_eo/platforms/sentinel2/brdf/protocols.py +27 -0
  50. mapchete_eo/platforms/sentinel2/brdf/ross_thick.py +136 -0
  51. mapchete_eo/platforms/sentinel2/brdf/sun_angle_arrays.py +76 -0
  52. mapchete_eo/platforms/sentinel2/config.py +181 -0
  53. mapchete_eo/platforms/sentinel2/driver.py +78 -0
  54. mapchete_eo/platforms/sentinel2/masks.py +325 -0
  55. mapchete_eo/platforms/sentinel2/metadata_parser.py +734 -0
  56. mapchete_eo/platforms/sentinel2/path_mappers/__init__.py +29 -0
  57. mapchete_eo/platforms/sentinel2/path_mappers/base.py +56 -0
  58. mapchete_eo/platforms/sentinel2/path_mappers/earthsearch.py +34 -0
  59. mapchete_eo/platforms/sentinel2/path_mappers/metadata_xml.py +135 -0
  60. mapchete_eo/platforms/sentinel2/path_mappers/sinergise.py +105 -0
  61. mapchete_eo/platforms/sentinel2/preprocessing_tasks.py +26 -0
  62. mapchete_eo/platforms/sentinel2/processing_baseline.py +160 -0
  63. mapchete_eo/platforms/sentinel2/product.py +669 -0
  64. mapchete_eo/platforms/sentinel2/types.py +109 -0
  65. mapchete_eo/processes/__init__.py +0 -0
  66. mapchete_eo/processes/config.py +51 -0
  67. mapchete_eo/processes/dtype_scale.py +112 -0
  68. mapchete_eo/processes/eo_to_xarray.py +19 -0
  69. mapchete_eo/processes/merge_rasters.py +235 -0
  70. mapchete_eo/product.py +278 -0
  71. mapchete_eo/protocols.py +56 -0
  72. mapchete_eo/search/__init__.py +14 -0
  73. mapchete_eo/search/base.py +222 -0
  74. mapchete_eo/search/config.py +42 -0
  75. mapchete_eo/search/s2_mgrs.py +314 -0
  76. mapchete_eo/search/stac_search.py +251 -0
  77. mapchete_eo/search/stac_static.py +236 -0
  78. mapchete_eo/search/utm_search.py +251 -0
  79. mapchete_eo/settings.py +24 -0
  80. mapchete_eo/sort.py +48 -0
  81. mapchete_eo/time.py +53 -0
  82. mapchete_eo/types.py +73 -0
  83. mapchete_eo-2025.7.0.dist-info/METADATA +38 -0
  84. mapchete_eo-2025.7.0.dist-info/RECORD +87 -0
  85. mapchete_eo-2025.7.0.dist-info/WHEEL +5 -0
  86. mapchete_eo-2025.7.0.dist-info/entry_points.txt +11 -0
  87. mapchete_eo-2025.7.0.dist-info/licenses/LICENSE +21 -0
mapchete_eo/base.py ADDED
@@ -0,0 +1,528 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from functools import cached_property
5
+ from typing import Any, Callable, List, Optional, Type, Union
6
+
7
+ import croniter
8
+ import numpy.ma as ma
9
+ import xarray as xr
10
+ from dateutil.tz import tzutc
11
+ from mapchete.config.parse import guess_geometry
12
+ from mapchete.formats import base
13
+ from mapchete.geometry import reproject_geometry
14
+ from mapchete.io.vector import IndexedFeatures
15
+ from mapchete.path import MPath
16
+ from mapchete.tile import BufferedTile
17
+ from mapchete.types import MPathLike, NodataVal, NodataVals
18
+ from pydantic import BaseModel
19
+ from rasterio.enums import Resampling
20
+ from shapely.geometry.base import BaseGeometry
21
+
22
+ from mapchete_eo.archives.base import Archive
23
+ from mapchete_eo.exceptions import CorruptedProductMetadata, PreprocessingNotFinished
24
+ from mapchete_eo.io import (
25
+ products_to_np_array,
26
+ products_to_xarray,
27
+ read_levelled_cube_to_np_array,
28
+ read_levelled_cube_to_xarray,
29
+ )
30
+ from mapchete_eo.product import EOProduct
31
+ from mapchete_eo.protocols import EOProductProtocol
32
+ from mapchete_eo.search.stac_static import STACStaticCatalog
33
+ from mapchete_eo.settings import mapchete_eo_settings
34
+ from mapchete_eo.sort import SortMethodConfig, TargetDateSort
35
+ from mapchete_eo.time import to_datetime
36
+ from mapchete_eo.types import DateTimeLike, MergeMethod, TimeRange
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ class BaseDriverConfig(BaseModel):
42
+ format: str
43
+ time: Union[TimeRange, List[TimeRange]]
44
+ cat_baseurl: Optional[str] = None
45
+ cache: Optional[Any] = None
46
+ footprint_buffer: float = 0
47
+ area: Optional[Union[MPathLike, dict, type[BaseGeometry]]] = None
48
+ preprocessing_tasks: bool = False
49
+ archive: Optional[Type[Archive]] = None
50
+
51
+
52
+ class EODataCube(base.InputTile):
53
+ """Target Tile representation of input data."""
54
+
55
+ default_read_merge_method: MergeMethod = MergeMethod.first
56
+ default_read_merge_products_by: Optional[str] = None
57
+ default_read_nodataval: NodataVal = None
58
+ default_read_resampling: Resampling = Resampling.nearest
59
+
60
+ tile: BufferedTile
61
+ eo_bands: dict
62
+ time: List[TimeRange]
63
+ area: BaseGeometry
64
+
65
+ def __init__(
66
+ self,
67
+ tile: BufferedTile,
68
+ products: Optional[List[EOProductProtocol]],
69
+ eo_bands: dict,
70
+ time: List[TimeRange],
71
+ input_key: Optional[str] = None,
72
+ area: Optional[BaseGeometry] = None,
73
+ **kwargs,
74
+ ) -> None:
75
+ """Initialize."""
76
+ self.tile = tile
77
+ self._products = products
78
+ self.eo_bands = eo_bands
79
+ self.time = time
80
+ self.input_key = input_key
81
+ self.area = tile.bbox if area is None else area
82
+
83
+ @cached_property
84
+ def products(self) -> IndexedFeatures[EOProductProtocol]:
85
+ # during task graph processing, the products have to be fetched as preprocessing task results
86
+ if self._products is None: # pragma: no cover
87
+ return IndexedFeatures(
88
+ [
89
+ item
90
+ for item in self.preprocessing_tasks_results.values()
91
+ if not isinstance(item, CorruptedProductMetadata)
92
+ ],
93
+ crs=self.tile.crs,
94
+ )
95
+
96
+ # just return the prouducts as is
97
+ return IndexedFeatures(
98
+ [
99
+ item
100
+ for item in self._products
101
+ if not isinstance(item, CorruptedProductMetadata)
102
+ ],
103
+ crs=self.tile.crs,
104
+ )
105
+
106
+ def read(
107
+ self,
108
+ assets: Optional[List[str]] = None,
109
+ eo_bands: Optional[List[str]] = None,
110
+ start_time: Optional[DateTimeLike] = None,
111
+ end_time: Optional[DateTimeLike] = None,
112
+ timestamps: Optional[List[DateTimeLike]] = None,
113
+ time_pattern: Optional[str] = None,
114
+ resampling: Optional[Union[Resampling, str]] = None,
115
+ merge_products_by: Optional[str] = None,
116
+ merge_method: Optional[MergeMethod] = None,
117
+ sort: Optional[SortMethodConfig] = None,
118
+ nodatavals: NodataVals = None,
119
+ raise_empty: bool = True,
120
+ **kwargs,
121
+ ) -> xr.Dataset:
122
+ """
123
+ Read reprojected & resampled input data.
124
+
125
+ Returns
126
+ -------
127
+ data : xarray.Dataset
128
+ """
129
+ return products_to_xarray(
130
+ products=self.filter_products(
131
+ start_time=start_time,
132
+ end_time=end_time,
133
+ timestamps=timestamps,
134
+ time_pattern=time_pattern,
135
+ ),
136
+ eo_bands=eo_bands,
137
+ assets=assets,
138
+ grid=self.tile,
139
+ raise_empty=raise_empty,
140
+ product_read_kwargs=kwargs,
141
+ sort=sort,
142
+ **self.default_read_values(
143
+ merge_products_by=merge_products_by,
144
+ merge_method=merge_method,
145
+ resampling=resampling,
146
+ nodatavals=nodatavals,
147
+ ),
148
+ )
149
+
150
+ def read_np_array(
151
+ self,
152
+ assets: Optional[List[str]] = None,
153
+ eo_bands: Optional[List[str]] = None,
154
+ start_time: Optional[DateTimeLike] = None,
155
+ end_time: Optional[DateTimeLike] = None,
156
+ timestamps: Optional[List[DateTimeLike]] = None,
157
+ time_pattern: Optional[str] = None,
158
+ resampling: Optional[Union[Resampling, str]] = None,
159
+ merge_products_by: Optional[str] = None,
160
+ merge_method: Optional[MergeMethod] = None,
161
+ sort: Optional[SortMethodConfig] = None,
162
+ nodatavals: NodataVals = None,
163
+ raise_empty: bool = True,
164
+ **kwargs,
165
+ ) -> ma.MaskedArray:
166
+ return products_to_np_array(
167
+ products=self.filter_products(
168
+ start_time=start_time,
169
+ end_time=end_time,
170
+ timestamps=timestamps,
171
+ time_pattern=time_pattern,
172
+ ),
173
+ eo_bands=eo_bands,
174
+ assets=assets,
175
+ grid=self.tile,
176
+ product_read_kwargs=kwargs,
177
+ raise_empty=raise_empty,
178
+ sort=sort,
179
+ **self.default_read_values(
180
+ merge_products_by=merge_products_by,
181
+ merge_method=merge_method,
182
+ resampling=resampling,
183
+ nodatavals=nodatavals,
184
+ ),
185
+ )
186
+
187
+ def read_levelled(
188
+ self,
189
+ target_height: int,
190
+ assets: Optional[List[str]] = None,
191
+ eo_bands: Optional[List[str]] = None,
192
+ start_time: Optional[DateTimeLike] = None,
193
+ end_time: Optional[DateTimeLike] = None,
194
+ timestamps: Optional[List[DateTimeLike]] = None,
195
+ time_pattern: Optional[str] = None,
196
+ resampling: Optional[Union[Resampling, str]] = None,
197
+ nodatavals: NodataVals = None,
198
+ merge_products_by: Optional[str] = None,
199
+ merge_method: Optional[MergeMethod] = None,
200
+ sort: SortMethodConfig = TargetDateSort(),
201
+ raise_empty: bool = True,
202
+ slice_axis_name: str = "layers",
203
+ band_axis_name: str = "bands",
204
+ x_axis_name: str = "x",
205
+ y_axis_name: str = "y",
206
+ **kwargs,
207
+ ) -> xr.Dataset:
208
+ return read_levelled_cube_to_xarray(
209
+ products=self.filter_products(
210
+ start_time=start_time,
211
+ end_time=end_time,
212
+ timestamps=timestamps,
213
+ time_pattern=time_pattern,
214
+ ),
215
+ target_height=target_height,
216
+ assets=assets,
217
+ eo_bands=eo_bands,
218
+ grid=self.tile,
219
+ raise_empty=raise_empty,
220
+ product_read_kwargs=kwargs,
221
+ slice_axis_name=slice_axis_name,
222
+ band_axis_name=band_axis_name,
223
+ x_axis_name=x_axis_name,
224
+ y_axis_name=y_axis_name,
225
+ sort=sort,
226
+ **self.default_read_values(
227
+ merge_products_by=merge_products_by,
228
+ merge_method=merge_method,
229
+ resampling=resampling,
230
+ nodatavals=nodatavals,
231
+ ),
232
+ )
233
+
234
+ def read_levelled_np_array(
235
+ self,
236
+ target_height: int,
237
+ assets: Optional[List[str]] = None,
238
+ eo_bands: Optional[List[str]] = None,
239
+ start_time: Optional[DateTimeLike] = None,
240
+ end_time: Optional[DateTimeLike] = None,
241
+ timestamps: Optional[List[DateTimeLike]] = None,
242
+ time_pattern: Optional[str] = None,
243
+ resampling: Optional[Union[Resampling, str]] = None,
244
+ nodatavals: NodataVals = None,
245
+ merge_products_by: Optional[str] = None,
246
+ merge_method: Optional[MergeMethod] = None,
247
+ sort: SortMethodConfig = TargetDateSort(),
248
+ raise_empty: bool = True,
249
+ **kwargs,
250
+ ) -> ma.MaskedArray:
251
+ return read_levelled_cube_to_np_array(
252
+ products=self.filter_products(
253
+ start_time=start_time,
254
+ end_time=end_time,
255
+ timestamps=timestamps,
256
+ time_pattern=time_pattern,
257
+ ),
258
+ target_height=target_height,
259
+ assets=assets,
260
+ eo_bands=eo_bands,
261
+ grid=self.tile,
262
+ raise_empty=raise_empty,
263
+ product_read_kwargs=kwargs,
264
+ sort=sort,
265
+ **self.default_read_values(
266
+ merge_products_by=merge_products_by,
267
+ merge_method=merge_method,
268
+ resampling=resampling,
269
+ nodatavals=nodatavals,
270
+ ),
271
+ )
272
+
273
+ def read_masks(
274
+ self,
275
+ start_time: Optional[DateTimeLike] = None,
276
+ end_time: Optional[DateTimeLike] = None,
277
+ timestamps: Optional[List[DateTimeLike]] = None,
278
+ time_pattern: Optional[str] = None,
279
+ nodatavals: NodataVals = None,
280
+ **kwargs,
281
+ ):
282
+ from mapchete_eo.platforms.sentinel2.masks import read_masks
283
+
284
+ return read_masks(
285
+ products=self.filter_products(
286
+ start_time=start_time,
287
+ end_time=end_time,
288
+ timestamps=timestamps,
289
+ time_pattern=time_pattern,
290
+ ),
291
+ grid=self.tile,
292
+ nodatavals=nodatavals,
293
+ product_read_kwargs=kwargs,
294
+ )
295
+
296
+ def filter_products(
297
+ self,
298
+ start_time: Optional[DateTimeLike] = None,
299
+ end_time: Optional[DateTimeLike] = None,
300
+ timestamps: Optional[List[DateTimeLike]] = None,
301
+ time_pattern: Optional[str] = None,
302
+ ):
303
+ """
304
+ Return a filtered list of input products.
305
+ """
306
+ if any([start_time, end_time, timestamps]):
307
+ raise NotImplementedError("time subsets are not yet implemented")
308
+
309
+ if time_pattern:
310
+ # filter products by time pattern
311
+ tz = tzutc()
312
+ coord_time = [
313
+ t.replace(tzinfo=tz)
314
+ for t in croniter.croniter_range(
315
+ to_datetime(self.start_time),
316
+ to_datetime(self.end_time),
317
+ time_pattern,
318
+ )
319
+ ]
320
+ return [
321
+ product
322
+ for product in self.products
323
+ if product.item.datetime in coord_time
324
+ ]
325
+ else:
326
+ return self.products
327
+
328
+ def is_empty(self) -> bool: # pragma: no cover
329
+ """
330
+ Check if there is data within this tile.
331
+
332
+ Returns
333
+ -------
334
+ is empty : bool
335
+ """
336
+ return len(self.products) == 0
337
+
338
+ def default_read_values(
339
+ self,
340
+ resampling: Optional[Union[Resampling, str]] = None,
341
+ nodatavals: NodataVals = None,
342
+ merge_products_by: Optional[str] = None,
343
+ merge_method: Optional[MergeMethod] = None,
344
+ ) -> dict:
345
+ """Provide proper read values depending on user input and defaults."""
346
+ if nodatavals is None:
347
+ nodatavals = self.default_read_nodataval
348
+ merge_products_by = merge_products_by or self.default_read_merge_products_by
349
+ merge_method = merge_method or self.default_read_merge_method
350
+ if resampling is None:
351
+ resampling = self.default_read_resampling
352
+ else:
353
+ resampling = (
354
+ resampling
355
+ if isinstance(resampling, Resampling)
356
+ else Resampling[resampling]
357
+ )
358
+ return dict(
359
+ resampling=resampling,
360
+ nodatavals=nodatavals,
361
+ merge_products_by=merge_products_by,
362
+ merge_method=merge_method,
363
+ )
364
+
365
+
366
+ class InputData(base.InputData):
367
+ default_preprocessing_task: Callable = staticmethod(EOProduct.from_stac_item)
368
+ driver_config_model: Type[BaseDriverConfig] = BaseDriverConfig
369
+ params: BaseDriverConfig
370
+ archive: Archive
371
+ time: Union[TimeRange, List[TimeRange]]
372
+ area: BaseGeometry
373
+ _products: Optional[IndexedFeatures] = None
374
+
375
+ def __init__(
376
+ self,
377
+ input_params: dict,
378
+ readonly: bool = False,
379
+ input_key: Optional[str] = None,
380
+ standalone: bool = False,
381
+ **kwargs,
382
+ ) -> None:
383
+ """Initialize."""
384
+ super().__init__(input_params, **kwargs)
385
+ self.readonly = readonly
386
+ self.input_key = input_key
387
+ self.standalone = standalone
388
+
389
+ self.params = self.driver_config_model(**input_params["abstract"])
390
+ # we have to make sure, the cache path is absolute
391
+ # not quite fond of this solution
392
+ if self.params.cache:
393
+ self.params.cache.path = MPath.from_inp(
394
+ self.params.cache.dict()
395
+ ).absolute_path(base_dir=input_params.get("conf_dir"))
396
+ self.area = self._init_area(input_params)
397
+ self.time = self.params.time
398
+ if self.readonly: # pragma: no cover
399
+ return
400
+
401
+ self.set_archive(base_dir=input_params["conf_dir"])
402
+
403
+ # don't use preprocessing tasks for Sentinel-2 products:
404
+ if self.params.preprocessing_tasks or self.params.cache is not None:
405
+ for item in self.archive.items():
406
+ self.add_preprocessing_task(
407
+ self.default_preprocessing_task,
408
+ fargs=(item,),
409
+ fkwargs=dict(cache_config=self.params.cache, cache_all=True),
410
+ key=item.id,
411
+ geometry=reproject_geometry(
412
+ item.geometry,
413
+ src_crs=mapchete_eo_settings.default_catalog_crs,
414
+ dst_crs=self.crs,
415
+ ),
416
+ )
417
+ else:
418
+ logger.debug("do preprocessing tasks now rather than later")
419
+ self._products = IndexedFeatures(
420
+ [
421
+ self.default_preprocessing_task(
422
+ item, cache_config=self.params.cache, cache_all=True
423
+ )
424
+ for item in self.archive.items()
425
+ ]
426
+ )
427
+
428
+ def _init_area(self, input_params: dict) -> BaseGeometry:
429
+ """Returns valid driver area for this process."""
430
+ process_area = input_params["delimiters"]["effective_area"]
431
+ if self.params.area:
432
+ # read area parameter and intersect with effective area
433
+ configured_area, configured_area_crs = guess_geometry(self.params.area)
434
+ return process_area.intersection(
435
+ reproject_geometry(
436
+ configured_area,
437
+ src_crs=configured_area_crs or self.crs,
438
+ dst_crs=self.crs,
439
+ )
440
+ )
441
+ return process_area
442
+
443
+ def set_archive(self, base_dir: MPath):
444
+ # this only works with some static archive:
445
+ if self.params.cat_baseurl:
446
+ self.archive = Archive(
447
+ catalog=STACStaticCatalog(
448
+ baseurl=MPath(self.params.cat_baseurl).absolute_path(
449
+ base_dir=base_dir
450
+ ),
451
+ ),
452
+ area=self.bbox(mapchete_eo_settings.default_catalog_crs),
453
+ time=self.time,
454
+ )
455
+ else:
456
+ raise NotImplementedError()
457
+
458
+ def bbox(self, out_crs: Optional[str] = None) -> BaseGeometry:
459
+ """Return data bounding box."""
460
+ return reproject_geometry(
461
+ self.area,
462
+ src_crs=self.pyramid.crs,
463
+ dst_crs=self.pyramid.crs if out_crs is None else out_crs,
464
+ segmentize_on_clip=True,
465
+ )
466
+
467
+ @cached_property
468
+ def products(self) -> IndexedFeatures:
469
+ """Hold preprocessed S2Products in an IndexedFeatures container."""
470
+
471
+ # nothing to index here
472
+ if self.readonly:
473
+ return IndexedFeatures([])
474
+
475
+ elif self._products is not None:
476
+ return self._products
477
+
478
+ # TODO: copied it from mapchete_satellite, not yet sure which use case this is
479
+ elif self.standalone:
480
+ raise NotImplementedError()
481
+
482
+ # if preprocessing tasks are ready, index them for further use
483
+ elif self.preprocessing_tasks_results:
484
+ return IndexedFeatures(
485
+ [
486
+ self.get_preprocessing_task_result(item.id)
487
+ for item in self.archive.items()
488
+ if not isinstance(item, CorruptedProductMetadata)
489
+ ],
490
+ crs=self.crs,
491
+ )
492
+
493
+ elif not self.preprocessing_tasks:
494
+ return IndexedFeatures([])
495
+
496
+ # this happens on task graph execution when preprocessing task results are not ready
497
+ else: # pragma: no cover
498
+ raise PreprocessingNotFinished(
499
+ f"products are not ready yet because {len(self.preprocessing_tasks)} preprocessing task(s) were not executed."
500
+ )
501
+
502
+ def open(self, tile, **kwargs) -> EODataCube:
503
+ """
504
+ Return InputTile object.
505
+ """
506
+ try:
507
+ tile_products = self.products.filter(
508
+ reproject_geometry(
509
+ tile.bbox,
510
+ src_crs=tile.crs,
511
+ dst_crs=mapchete_eo_settings.default_catalog_crs,
512
+ ).bounds
513
+ )
514
+ except PreprocessingNotFinished: # pragma: no cover
515
+ tile_products = None
516
+ return self.input_tile_cls(
517
+ tile,
518
+ products=tile_products,
519
+ eo_bands=self.archive.catalog.eo_bands,
520
+ time=self.time,
521
+ # passing on the input key is essential so dependent preprocessing tasks can be found!
522
+ input_key=self.input_key,
523
+ area=self.area.intersection(tile.bbox),
524
+ )
525
+
526
+ def cleanup(self):
527
+ for product in self.products:
528
+ product.clear_cached_data()