mapchete-eo 2026.1.0__tar.gz → 2026.2.0__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 (90) hide show
  1. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/.gitignore +2 -0
  2. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/PKG-INFO +7 -5
  3. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/README.rst +2 -2
  4. mapchete_eo-2026.2.0/mapchete_eo/__init__.py +1 -0
  5. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/base.py +49 -5
  6. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/compositing.py +12 -0
  7. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/driver.py +5 -1
  8. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/masks.py +6 -2
  9. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preprocessing_tasks.py +4 -1
  10. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/product.py +15 -2
  11. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/product.py +43 -3
  12. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/base.py +24 -2
  13. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/stac_search.py +8 -0
  14. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/stac_static.py +4 -0
  15. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/utm_search.py +4 -0
  16. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/sort.py +1 -3
  17. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/source.py +3 -1
  18. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/time.py +12 -3
  19. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/types.py +6 -3
  20. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/pyproject.toml +10 -3
  21. mapchete_eo-2026.1.0/mapchete_eo/__init__.py +0 -1
  22. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/LICENSE +0 -0
  23. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/__init__.py +0 -0
  24. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/buffer.py +0 -0
  25. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/color.py +0 -0
  26. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/convert.py +0 -0
  27. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/blacklist.txt +0 -0
  28. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/__init__.py +0 -0
  29. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/bounds.py +0 -0
  30. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/options_arguments.py +0 -0
  31. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_brdf.py +0 -0
  32. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_cat_results.py +0 -0
  33. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_find_broken_products.py +0 -0
  34. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_jp2_static_catalog.py +0 -0
  35. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_mask.py +0 -0
  36. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_mgrs.py +0 -0
  37. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_rgb.py +0 -0
  38. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_verify.py +0 -0
  39. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/static_catalog.py +0 -0
  40. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/eostac.py +0 -0
  41. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/exceptions.py +0 -0
  42. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/__init__.py +0 -0
  43. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/blend_functions.py +0 -0
  44. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/color_correction.py +0 -0
  45. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/dtype_scale.py +0 -0
  46. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/fillnodata.py +0 -0
  47. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/filters.py +0 -0
  48. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/linear_normalization.py +0 -0
  49. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/sigmoidal.py +0 -0
  50. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/__init__.py +0 -0
  51. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/assets.py +0 -0
  52. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/items.py +0 -0
  53. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/levelled_cubes.py +0 -0
  54. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/path.py +0 -0
  55. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/products.py +0 -0
  56. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/profiles.py +0 -0
  57. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/__init__.py +0 -0
  58. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/_mapper_registry.py +0 -0
  59. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/bandpass_adjustment.py +0 -0
  60. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/__init__.py +0 -0
  61. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/config.py +0 -0
  62. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/correction.py +0 -0
  63. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/hls.py +0 -0
  64. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/models.py +0 -0
  65. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/protocols.py +0 -0
  66. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/ross_thick.py +0 -0
  67. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/sun_angle_arrays.py +0 -0
  68. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/config.py +0 -0
  69. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/__init__.py +0 -0
  70. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/base.py +0 -0
  71. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/default_path_mapper.py +0 -0
  72. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/models.py +0 -0
  73. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/s2metadata.py +0 -0
  74. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/__init__.py +0 -0
  75. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/guessers.py +0 -0
  76. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/item_mappers.py +0 -0
  77. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/metadata_xml_mappers.py +0 -0
  78. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/processing_baseline.py +0 -0
  79. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/source.py +0 -0
  80. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/types.py +0 -0
  81. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/__init__.py +0 -0
  82. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/config.py +0 -0
  83. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/dtype_scale.py +0 -0
  84. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/eo_to_xarray.py +0 -0
  85. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/merge_rasters.py +0 -0
  86. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/protocols.py +0 -0
  87. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/__init__.py +0 -0
  88. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/config.py +0 -0
  89. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/s2_mgrs.py +0 -0
  90. {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/settings.py +0 -0
@@ -3,6 +3,7 @@ build/
3
3
  .coverage
4
4
  .coverage.*
5
5
  dist/
6
+ docs/build/html
6
7
  *.egg-info
7
8
  .eggs
8
9
  examples/sentinel-2*/
@@ -14,3 +15,4 @@ __pycache__
14
15
  .pytest*
15
16
  .ruff_cache
16
17
  .vscode/
18
+ .venv
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapchete-eo
3
- Version: 2026.1.0
3
+ Version: 2026.2.0
4
4
  Summary: mapchete EO data reader
5
5
  Project-URL: Homepage, https://gitlab.eox.at/maps/mapchete_eo
6
6
  Author-email: Joachim Ungar <joachim.ungar@eox.at>, Petr Sevcik <petr.sevcik@eox.at>
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Topic :: Scientific/Engineering :: GIS
17
+ Requires-Python: >=3.10
17
18
  Requires-Dist: click
18
19
  Requires-Dist: croniter
19
20
  Requires-Dist: lxml
@@ -30,8 +31,9 @@ Requires-Dist: scipy
30
31
  Requires-Dist: tqdm
31
32
  Requires-Dist: xarray
32
33
  Provides-Extra: docs
33
- Requires-Dist: sphinx; extra == 'docs'
34
- Requires-Dist: sphinx-rtd-theme; extra == 'docs'
34
+ Requires-Dist: myst-parser; extra == 'docs'
35
+ Requires-Dist: sphinx-rtd-theme>=3.0.2; extra == 'docs'
36
+ Requires-Dist: sphinx>=8.0; extra == 'docs'
35
37
  Provides-Extra: test
36
38
  Requires-Dist: pytest; extra == 'test'
37
39
  Requires-Dist: pytest-coverage; extra == 'test'
@@ -80,10 +82,10 @@ You must have ``mapchete`` with ``s3`` installed, so let's grab the ``complete``
80
82
 
81
83
  .. code-block:: bash
82
84
 
83
- pip install mapchete[complete]
85
+ uv pip install mapchete[complete]
84
86
 
85
87
  Then install mapchete-eo:
86
88
 
87
89
  .. code-block:: bash
88
90
 
89
- pip install mapchete-eo
91
+ uv pip install mapchete-eo
@@ -40,10 +40,10 @@ You must have ``mapchete`` with ``s3`` installed, so let's grab the ``complete``
40
40
 
41
41
  .. code-block:: bash
42
42
 
43
- pip install mapchete[complete]
43
+ uv pip install mapchete[complete]
44
44
 
45
45
  Then install mapchete-eo:
46
46
 
47
47
  .. code-block:: bash
48
48
 
49
- pip install mapchete-eo
49
+ uv pip install mapchete-eo
@@ -0,0 +1 @@
1
+ __version__ = "2026.2.0"
@@ -44,6 +44,10 @@ logger = logging.getLogger(__name__)
44
44
 
45
45
 
46
46
  class BaseDriverConfig(BaseModel):
47
+ """
48
+ Configuration for mapchete-eo drivers.
49
+ """
50
+
47
51
  format: str
48
52
  source: Sequence[Source]
49
53
  time: Optional[Union[TimeRange, List[TimeRange]]] = None
@@ -114,6 +118,9 @@ class EODataCube(base.InputTile):
114
118
 
115
119
  @cached_property
116
120
  def products(self) -> IndexedFeatures[EOProductProtocol]:
121
+ """
122
+ Indexed products.
123
+ """
117
124
  # during task graph processing, the products have to be fetched as preprocessing task results
118
125
  if self._products is None: # pragma: no cover
119
126
  return IndexedFeatures(
@@ -158,11 +165,7 @@ class EODataCube(base.InputTile):
158
165
  **kwargs,
159
166
  ) -> xr.Dataset:
160
167
  """
161
- Read reprojected & resampled input data.
162
-
163
- Returns
164
- -------
165
- data : xarray.Dataset
168
+ Read input data into an xarray.Dataset.
166
169
  """
167
170
  return products_to_xarray(
168
171
  products=self.filter_products(
@@ -201,6 +204,9 @@ class EODataCube(base.InputTile):
201
204
  raise_empty: bool = True,
202
205
  **kwargs,
203
206
  ) -> ma.MaskedArray:
207
+ """
208
+ Read input data as a MaskedArray.
209
+ """
204
210
  return products_to_np_array(
205
211
  products=self.filter_products(
206
212
  start_time=start_time,
@@ -286,6 +292,27 @@ class EODataCube(base.InputTile):
286
292
  raise_empty: bool = True,
287
293
  **kwargs,
288
294
  ) -> ma.MaskedArray:
295
+ """
296
+ Read levelled data (cubes with depth) as a MaskedArray.
297
+
298
+ Args:
299
+ target_height: Target stack height.
300
+ assets: List of asset names.
301
+ eo_bands: List of EO bands.
302
+ start_time: Start time.
303
+ end_time: End time.
304
+ timestamps: List of timestamps.
305
+ time_pattern: Time pattern.
306
+ resampling: Resampling method.
307
+ nodatavals: Nodata values.
308
+ merge_products_by: Property to merge by.
309
+ merge_method: Merge method.
310
+ sort: Sorting configuration.
311
+ raise_empty: Raise error if no data found.
312
+
313
+ Returns:
314
+ ma.MaskedArray: Output data array.
315
+ """
289
316
  return read_levelled_cube_to_np_array(
290
317
  products=self.filter_products(
291
318
  start_time=start_time,
@@ -317,6 +344,19 @@ class EODataCube(base.InputTile):
317
344
  nodatavals: NodataVals = None,
318
345
  **kwargs,
319
346
  ):
347
+ """
348
+ Read product masks.
349
+
350
+ Args:
351
+ start_time: Start time.
352
+ end_time: End time.
353
+ timestamps: List of timestamps.
354
+ time_pattern: Time pattern.
355
+ nodatavals: Nodata values.
356
+
357
+ Returns:
358
+ ma.MaskedArray: Mask data.
359
+ """
320
360
  from mapchete_eo.platforms.sentinel2.masks import read_masks
321
361
 
322
362
  return read_masks(
@@ -423,6 +463,10 @@ class EODataCube(base.InputTile):
423
463
 
424
464
 
425
465
  class InputData(base.InputData):
466
+ """
467
+ Main driver class used by mapchete to handle input data discovery and indexing.
468
+ """
469
+
426
470
  default_preprocessing_task: Callable = staticmethod(EOProduct.from_stac_item)
427
471
  driver_config_model: Type[BaseDriverConfig] = BaseDriverConfig
428
472
  params: BaseDriverConfig
@@ -153,6 +153,18 @@ METHODS = {
153
153
  def composite(
154
154
  method: str, bg: np.ndarray, fg: np.ndarray, opacity: float = 1
155
155
  ) -> ma.MaskedArray:
156
+ """
157
+ Composite two image arrays using a named blending method.
158
+
159
+ Args:
160
+ method: Blending method name (e.g., 'multiply', 'screen').
161
+ bg: Background image array (channels-first).
162
+ fg: Foreground image array (channels-first).
163
+ opacity: Opacity of the foreground layer (0-1).
164
+
165
+ Returns:
166
+ ma.MaskedArray: Blended RGBA result.
167
+ """
156
168
  return METHODS[method](bg, fg, opacity)
157
169
 
158
170
 
@@ -17,6 +17,10 @@ METADATA: dict = {
17
17
 
18
18
 
19
19
  class Sentinel2Cube(base.EODataCube):
20
+ """
21
+ Sentinel-2 data cube for Mapchete.
22
+ """
23
+
20
24
  # Sentinel-2 driver specific default values:
21
25
  default_read_merge_method: MergeMethod = MergeMethod.average
22
26
  default_read_merge_products_by: Optional[str] = "s2:datastrip_id"
@@ -29,7 +33,7 @@ Sentinel2CubeGroup = List[Tuple[str, Sentinel2Cube]]
29
33
 
30
34
  class InputData(base.InputData):
31
35
  """
32
- Main driver class used by mapchete.
36
+ Sentinel-2 driver for Mapchete.
33
37
  """
34
38
 
35
39
  # Sentinel-2 driver specific parameters:
@@ -61,7 +61,9 @@ def masks_to_xarray(
61
61
  raise_empty: bool = True,
62
62
  product_read_kwargs: dict = {},
63
63
  ) -> xr.Dataset:
64
- """Read grid window of EOProducts and merge into a 4D xarray."""
64
+ """
65
+ Read masks of products and merge into an xarray.Dataset.
66
+ """
65
67
  data_vars = [
66
68
  s
67
69
  for s in generate_slice_masks_dataarrays(
@@ -307,7 +309,9 @@ def product_masks_to_slices(
307
309
  group_by_property: Optional[str] = None,
308
310
  sort: Optional[SortMethodConfig] = None,
309
311
  ) -> List[Slice]:
310
- """Group products per given property into Slice objects and optionally sort slices."""
312
+ """
313
+ Group products by a property into Slices and optionally sort.
314
+ """
311
315
  if group_by_property:
312
316
  grouped = defaultdict(list)
313
317
  for product in products:
@@ -19,7 +19,10 @@ def parse_s2_product(
19
19
  cache_config: Optional[CacheConfig] = None,
20
20
  cache_all: bool = False,
21
21
  ) -> Union[S2Product, CorruptedProductMetadata]:
22
- # use mapper from source if applickable
22
+ """
23
+ Parse a Sentinel-2 STAC Item into an S2Product.
24
+ """
25
+ # use mapper from source if applicable
23
26
  source: Union[Sentinel2Source, None] = item.properties.pop(
24
27
  "mapchete_eo:source", None
25
28
  )
@@ -143,6 +143,10 @@ class Cache:
143
143
 
144
144
 
145
145
  class S2Product(EOProduct, EOProductProtocol):
146
+ """
147
+ Sentinel-2 specific EOProduct implementation.
148
+ """
149
+
146
150
  _item_dict: Optional[dict] = None
147
151
  cache: Optional[Cache] = None
148
152
  _scl_cache: Dict[GridProtocol, np.ndarray]
@@ -245,6 +249,9 @@ class S2Product(EOProduct, EOProductProtocol):
245
249
  read_mask: Optional[np.ndarray] = None,
246
250
  **kwargs,
247
251
  ) -> ma.MaskedArray:
252
+ """
253
+ Read Sentinel-2 assets into a MaskedArray with masks and BRDF.
254
+ """
248
255
  assets = assets or []
249
256
  eo_bands = eo_bands or []
250
257
  apply_offset = apply_offset and not self.metadata.boa_offset_applied
@@ -451,7 +458,9 @@ class S2Product(EOProduct, EOProductProtocol):
451
458
  grid: Union[GridProtocol, Resolution] = Resolution["20m"],
452
459
  cached_read: bool = False,
453
460
  ) -> ReferencedRaster:
454
- """Return SCL mask."""
461
+ """
462
+ Read Scene Classification Layer mask.
463
+ """
455
464
  grid = (
456
465
  self.metadata.grid(grid)
457
466
  if isinstance(grid, Resolution)
@@ -519,7 +528,9 @@ class S2Product(EOProduct, EOProductProtocol):
519
528
  mask_config: MaskConfig = MaskConfig(),
520
529
  target_mask: Optional[np.ndarray] = None,
521
530
  ) -> ReferencedRaster:
522
- """Merge masks into one 2D array."""
531
+ """
532
+ Merge all configured masks into one.
533
+ """
523
534
  grid = (
524
535
  self.metadata.grid(grid)
525
536
  if isinstance(grid, Resolution)
@@ -619,6 +630,8 @@ class S2Product(EOProduct, EOProductProtocol):
619
630
  logger.debug(
620
631
  "mask for product %s already full, skip reading other masks", self.id
621
632
  )
633
+ except FileNotFoundError as exc: # pragma: no cover
634
+ raise CorruptedProduct from exc
622
635
 
623
636
  # ATTENTION: target_mask and out have to be combined *after* mask was buffered!
624
637
  # use 'logical or' not '+' !!!
@@ -26,7 +26,9 @@ logger = logging.getLogger(__name__)
26
26
 
27
27
 
28
28
  class EOProduct(EOProductProtocol):
29
- """Wrapper class around a Item which provides read functions."""
29
+ """
30
+ Wrapper class around a STAC Item which provides data reading capabilities.
31
+ """
30
32
 
31
33
  id: str
32
34
  default_dtype: DTypeLike = np.uint16
@@ -70,7 +72,22 @@ class EOProduct(EOProductProtocol):
70
72
  raise_empty: bool = True,
71
73
  **kwargs,
72
74
  ) -> xr.Dataset:
73
- """Read bands and assets into xarray."""
75
+ """
76
+ Read bands and assets into an xarray.Dataset.
77
+
78
+ Args:
79
+ assets: List of asset names.
80
+ eo_bands: List of EO band names.
81
+ grid: Target grid protocol.
82
+ resampling: Resampling algorithm.
83
+ nodatavals: Custom nodata values.
84
+ x_axis_name: Name of X axis in output.
85
+ y_axis_name: Name of Y axis in output.
86
+ raise_empty: Raise exception if no data is found.
87
+
88
+ Returns:
89
+ xr.Dataset: Dataset with assets as data variables.
90
+ """
74
91
  # developer info: all fancy stuff for special platforms like Sentinel-2
75
92
  # should be implemented in the respective read_np_array() methods which get
76
93
  # called by this method. No need to apply masks etc. here too.
@@ -121,6 +138,21 @@ class EOProduct(EOProductProtocol):
121
138
  apply_offset: bool = True,
122
139
  **kwargs,
123
140
  ) -> ma.MaskedArray:
141
+ """
142
+ Read assets or EO bands into a MaskedArray.
143
+
144
+ Args:
145
+ assets: List of asset names.
146
+ eo_bands: List of EO band names.
147
+ grid: Target grid.
148
+ resampling: Resampling method.
149
+ nodatavals: Nodata values.
150
+ raise_empty: Raise if empty.
151
+ apply_offset: Apply offset/scale metadata if present.
152
+
153
+ Returns:
154
+ ma.MaskedArray: Output array.
155
+ """
124
156
  assets = assets or []
125
157
  eo_bands = eo_bands or []
126
158
  bands = assets or eo_bands
@@ -182,7 +214,15 @@ def eo_bands_to_band_locations(
182
214
  role: Literal["data", "reflectance", "visual"] = "data",
183
215
  ) -> List[BandLocation]:
184
216
  """
185
- Find out location (asset and band index) of EO band.
217
+ Map EO band names to asset locations.
218
+
219
+ Args:
220
+ item: STAC Item.
221
+ eo_bands: List of common band names.
222
+ role: Functional role of the assets.
223
+
224
+ Returns:
225
+ List[BandLocation]: List of location objects.
186
226
  """
187
227
  return [find_eo_band(item, eo_band, role=role) for eo_band in eo_bands]
188
228
 
@@ -50,7 +50,7 @@ class FSSpecStacIO(StacApiIO):
50
50
 
51
51
  class CollectionSearcher(ABC):
52
52
  """
53
- This class serves as a bridge between an Archive and a catalog implementation.
53
+ Bridge between a Source and a catalog implementation.
54
54
  """
55
55
 
56
56
  config_cls: Type[BaseModel]
@@ -129,7 +129,29 @@ class StaticCollectionWriterMixin(CollectionSearcher):
129
129
  stac_io: DefaultStacIO = FSSpecStacIO(),
130
130
  progress_callback: Optional[Callable] = None,
131
131
  ) -> MPath:
132
- """Dump static version of current items."""
132
+ """
133
+ Export a static STAC catalog from the search results.
134
+
135
+ Args:
136
+ output_path: Destination directory for the static catalog.
137
+ bounds: Spatial filter bounds.
138
+ area: Spatial filter geometry.
139
+ time: Temporal filter range.
140
+ search_kwargs: Additional search arguments.
141
+ name: Catalog name.
142
+ description: Catalog description.
143
+ assets: List of assets to download.
144
+ assets_dst_resolution: Sub-sampling resolution for assets.
145
+ assets_convert_profile: Output profile for assets (e.g. for COG conversion).
146
+ copy_metadata: Whether to copy sidecar metadata files.
147
+ metadata_parser_classes: Custom parser classes for metadata.
148
+ overwrite: Overwrite existing files.
149
+ stac_io: Custom STAC IO implementation.
150
+ progress_callback: Optional function for progress reporting.
151
+
152
+ Returns:
153
+ MPath: Path to the generated catalog.json.
154
+ """
133
155
  output_path = MPath.from_inp(output_path)
134
156
  assets = assets or []
135
157
  # initialize catalog
@@ -21,6 +21,10 @@ logger = logging.getLogger(__name__)
21
21
 
22
22
 
23
23
  class STACSearchCollection(StaticCollectionWriterMixin, CollectionSearcher):
24
+ """
25
+ Search implementation for STAC APIs.
26
+ """
27
+
24
28
  collection: str
25
29
  config_cls = StacSearchConfig
26
30
 
@@ -206,6 +210,10 @@ class STACSearchCollection(StaticCollectionWriterMixin, CollectionSearcher):
206
210
 
207
211
 
208
212
  class SpatialSearchChunks:
213
+ """
214
+ Split spatial search areas into smaller chunks for large queries.
215
+ """
216
+
209
217
  bounds: Bounds
210
218
  area: BaseGeometry
211
219
  search_kw: str
@@ -29,6 +29,10 @@ StacIO.set_default(FSSpecStacIO)
29
29
 
30
30
 
31
31
  class STACStaticCollection(StaticCollectionWriterMixin, CollectionSearcher):
32
+ """
33
+ Search implementation for static STAC collections.
34
+ """
35
+
32
36
  config_cls = StacStaticConfig
33
37
 
34
38
  @cached_property
@@ -28,6 +28,10 @@ logger = logging.getLogger(__name__)
28
28
 
29
29
 
30
30
  class UTMSearchCatalog(StaticCollectionWriterMixin, CollectionSearcher):
31
+ """
32
+ Search implementation for UTM-grid based catalogs (e.g. Sentinel-2 on AWS).
33
+ """
34
+
31
35
  config_cls = UTMSearchConfig
32
36
 
33
37
  @cached_property
@@ -22,9 +22,7 @@ def sort_objects_by_target_date(
22
22
  **kwargs,
23
23
  ) -> List[DateTimeProtocol]:
24
24
  """
25
- Return sorted list of objects according to their distance to the target_date.
26
-
27
- Default for target date is the middle between the objects start date and end date.
25
+ Sort objects by their distance to a target date.
28
26
  """
29
27
  if len(objects) == 0:
30
28
  return objects
@@ -17,7 +17,9 @@ from mapchete_eo.types import TimeRange
17
17
 
18
18
 
19
19
  class Source(BaseModel):
20
- """All information required to consume EO products."""
20
+ """
21
+ All information required to consume EO products.
22
+ """
21
23
 
22
24
  collection: str
23
25
  catalog_crs: Optional[CRSLike] = mapchete_eo_settings.default_catalog_crs
@@ -9,7 +9,9 @@ _time = {"min": datetime.datetime.min.time(), "max": datetime.datetime.max.time(
9
9
 
10
10
 
11
11
  def to_datetime(t: DateTimeLike, append_time="min") -> datetime.datetime:
12
- """Convert input into datetime object."""
12
+ """
13
+ Convert input into datetime object.
14
+ """
13
15
  if isinstance(t, datetime.datetime):
14
16
  return t
15
17
  elif isinstance(t, datetime.date):
@@ -22,7 +24,9 @@ def time_ranges_intersect(
22
24
  t1: Tuple[DateTimeLike, DateTimeLike],
23
25
  t2: Tuple[DateTimeLike, DateTimeLike],
24
26
  ) -> bool:
25
- """Check if two time ranges intersect."""
27
+ """
28
+ Check if two time ranges intersect.
29
+ """
26
30
  t1_start = to_datetime(t1[0], "min").replace(tzinfo=None)
27
31
  t1_end = to_datetime(t1[1], "max").replace(tzinfo=None)
28
32
  t2_start = to_datetime(t2[0], "min").replace(tzinfo=None)
@@ -31,7 +35,9 @@ def time_ranges_intersect(
31
35
 
32
36
 
33
37
  def timedelta(date: DateTimeLike, target: DateTimeLike, seconds: bool = True):
34
- """Return difference between two time stamps."""
38
+ """
39
+ Return difference between two time stamps in seconds or days.
40
+ """
35
41
  delta = to_datetime(date) - to_datetime(target)
36
42
  if seconds:
37
43
  return abs(delta.total_seconds())
@@ -43,6 +49,9 @@ def day_range(
43
49
  start_date: Union[datetime.datetime, datetime.date],
44
50
  end_date: Union[datetime.datetime, datetime.date],
45
51
  ) -> List[datetime.date]:
52
+ """
53
+ Return a list of dates between start and end.
54
+ """
46
55
  start_date = (
47
56
  start_date.date() if isinstance(start_date, datetime.datetime) else start_date
48
57
  )
@@ -10,8 +10,9 @@ from pystac import Asset
10
10
 
11
11
 
12
12
  class GeodataType(str, Enum):
13
- vector = "vector"
14
- raster = "raster"
13
+ """
14
+ Type of geodata (vector or raster).
15
+ """
15
16
 
16
17
 
17
18
  class MergeMethod(str, Enum):
@@ -42,12 +43,14 @@ class BandLocation:
42
43
  roles: List[str] = field(default_factory=list)
43
44
  eo_band_name: Optional[str] = None
44
45
 
45
- @staticmethod
46
46
  def from_asset(
47
47
  asset: Asset,
48
48
  name: str,
49
49
  band_index: PositiveInt,
50
50
  ) -> BandLocation:
51
+ """
52
+ Extract band location info from STAC Asset.
53
+ """
51
54
  try:
52
55
  bands_info = asset.extra_fields.get(
53
56
  "eo:bands", asset.extra_fields.get("bands", [])
@@ -5,6 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "mapchete-eo"
7
7
  dynamic = ["version"]
8
+ requires-python = ">=3.10"
8
9
  description = "mapchete EO data reader"
9
10
  readme = "README.rst"
10
11
  license = "MIT"
@@ -42,8 +43,9 @@ dependencies = [
42
43
 
43
44
  [project.optional-dependencies]
44
45
  docs = [
45
- "sphinx",
46
- "sphinx-rtd-theme"
46
+ "sphinx>=8.0",
47
+ "sphinx-rtd-theme>=3.0.2",
48
+ "myst-parser",
47
49
  ]
48
50
  test = [
49
51
  "pytest",
@@ -87,4 +89,9 @@ testpaths = ["tests"]
87
89
  markers = [
88
90
  "remote: marks tests which require acces to remote resources (deselect with '-m \"not remote\"')",
89
91
  "use_cdse_test_env: enables CDSE S3 environment access",
90
- ]
92
+ ]
93
+
94
+ [tool.pyproject2conda]
95
+ channels = ["conda-forge"]
96
+ # Maps PyPI names to Conda-Forge names if they differ
97
+ map_deps = { "opencv-python-headless" = "opencv", "pystac-client" = "python-pystac-client" }
@@ -1 +0,0 @@
1
- __version__ = "2026.1.0"
File without changes