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.
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/.gitignore +2 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/PKG-INFO +7 -5
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/README.rst +2 -2
- mapchete_eo-2026.2.0/mapchete_eo/__init__.py +1 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/base.py +49 -5
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/compositing.py +12 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/driver.py +5 -1
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/masks.py +6 -2
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preprocessing_tasks.py +4 -1
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/product.py +15 -2
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/product.py +43 -3
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/base.py +24 -2
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/stac_search.py +8 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/stac_static.py +4 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/utm_search.py +4 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/sort.py +1 -3
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/source.py +3 -1
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/time.py +12 -3
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/types.py +6 -3
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/pyproject.toml +10 -3
- mapchete_eo-2026.1.0/mapchete_eo/__init__.py +0 -1
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/LICENSE +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/buffer.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/color.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/array/convert.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/blacklist.txt +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/bounds.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/options_arguments.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_brdf.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_cat_results.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_find_broken_products.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_jp2_static_catalog.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_mask.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_mgrs.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_rgb.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/s2_verify.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/cli/static_catalog.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/eostac.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/exceptions.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/blend_functions.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/color_correction.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/dtype_scale.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/fillnodata.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/filters.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/linear_normalization.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/sigmoidal.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/assets.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/items.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/levelled_cubes.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/path.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/products.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/io/profiles.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/_mapper_registry.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/bandpass_adjustment.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/config.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/correction.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/hls.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/models.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/protocols.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/ross_thick.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/sun_angle_arrays.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/config.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/base.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/default_path_mapper.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/models.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/metadata_parser/s2metadata.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/guessers.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/item_mappers.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preconfigured_sources/metadata_xml_mappers.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/processing_baseline.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/source.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/types.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/config.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/dtype_scale.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/eo_to_xarray.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/processes/merge_rasters.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/protocols.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/__init__.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/config.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/search/s2_mgrs.py +0 -0
- {mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/settings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mapchete-eo
|
|
3
|
-
Version: 2026.
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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:
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/preprocessing_tasks.py
RENAMED
|
@@ -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
|
-
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"""
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
"""
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
46
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/blend_functions.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/color_correction.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/image_operations/linear_normalization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/_mapper_registry.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/bandpass_adjustment.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/__init__.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/config.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/correction.py
RENAMED
|
File without changes
|
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/models.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/protocols.py
RENAMED
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/brdf/ross_thick.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapchete_eo-2026.1.0 → mapchete_eo-2026.2.0}/mapchete_eo/platforms/sentinel2/processing_baseline.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|