@@ -175,7 +175,7 @@ def load_collection(
175
175
bands : Union [Iterable [str ], Parameter , str , None ] = None ,
176
176
fetch_metadata : bool = True ,
177
177
properties : Union [
178
- None , Dict [str , Union [str , PGNode , typing .Callable ]], List [CollectionProperty ], CollectionProperty
178
+ Dict [str , Union [PGNode , typing .Callable ]], List [CollectionProperty ], CollectionProperty , None
179
179
] = None ,
180
180
max_cloud_cover : Optional [float ] = None ,
181
181
) -> DataCube :
@@ -250,27 +250,13 @@ def load_collection(
250
250
metadata = metadata .filter_bands (bands )
251
251
arguments ['bands' ] = bands
252
252
253
- if isinstance (properties , list ):
254
- # TODO: warn about items that are not CollectionProperty objects instead of silently dropping them.
255
- properties = {p .name : p .from_node () for p in properties if isinstance (p , CollectionProperty )}
256
- if isinstance (properties , CollectionProperty ):
257
- properties = {properties .name : properties .from_node ()}
258
- elif properties is None :
259
- properties = {}
260
- if max_cloud_cover :
261
- properties ["eo:cloud_cover" ] = lambda v : v <= max_cloud_cover
262
- if properties :
263
- summaries = metadata and metadata .get ("summaries" ) or {}
264
- undefined_properties = set (properties .keys ()).difference (summaries .keys ())
265
- if undefined_properties :
266
- warnings .warn (
267
- f"{ collection_id } property filtering with properties that are undefined "
268
- f"in the collection metadata (summaries): { ', ' .join (undefined_properties )} ." ,
269
- stacklevel = 2 ,
270
- )
271
- arguments ["properties" ] = {
272
- prop : build_child_callback (pred , parent_parameters = ["value" ]) for prop , pred in properties .items ()
273
- }
253
+ properties = cls ._build_load_properties_argument (
254
+ properties = properties ,
255
+ supported_properties = (metadata .get ("summaries" , default = {}).keys () if metadata else None ),
256
+ max_cloud_cover = max_cloud_cover ,
257
+ )
258
+ if properties is not None :
259
+ arguments ["properties" ] = properties
274
260
275
261
pg = PGNode (
276
262
process_id = 'load_collection' ,
@@ -282,6 +268,50 @@ def load_collection(
282
268
load_collection , name = "create_collection" , since = "0.4.6"
283
269
)
284
270
271
+ @classmethod
272
+ def _build_load_properties_argument (
273
+ cls ,
274
+ properties : Union [
275
+ Dict [str , Union [PGNode , typing .Callable ]],
276
+ List [CollectionProperty ],
277
+ CollectionProperty ,
278
+ None ,
279
+ ],
280
+ * ,
281
+ supported_properties : Optional [typing .Collection [str ]] = None ,
282
+ max_cloud_cover : Optional [float ] = None ,
283
+ ) -> Union [Dict [str , PGNode ], None ]:
284
+ """
285
+ Helper to convert/build the ``properties`` argument
286
+ for ``load_collection`` and ``load_stac`` from user input
287
+ """
288
+ if isinstance (properties , CollectionProperty ):
289
+ properties = [properties ]
290
+ if isinstance (properties , list ):
291
+ if not all (isinstance (p , CollectionProperty ) for p in properties ):
292
+ raise ValueError (
293
+ f"When providing load properties as a list, all items must be CollectionProperty objects, but got { properties } "
294
+ )
295
+ properties = {p .name : p .from_node () for p in properties }
296
+
297
+ if max_cloud_cover is not None :
298
+ properties = properties or {}
299
+ properties ["eo:cloud_cover" ] = lambda v : v <= max_cloud_cover
300
+
301
+ if isinstance (properties , dict ):
302
+ if supported_properties :
303
+ unsupported_properties = set (properties .keys ()).difference (supported_properties )
304
+ if unsupported_properties :
305
+ warnings .warn (
306
+ f"Property filtering with unsupported properties according to collection/STAC metadata: { unsupported_properties } (supported: { supported_properties } )." ,
307
+ stacklevel = 3 ,
308
+ )
309
+ properties = {
310
+ prop : build_child_callback (pred , parent_parameters = ["value" ]) for prop , pred in properties .items ()
311
+ }
312
+
313
+ return properties
314
+
285
315
@classmethod
286
316
@deprecated (reason = "Depends on non-standard process, replace with :py:meth:`openeo.rest.connection.Connection.load_stac` where possible." ,version = "0.25.0" )
287
317
def load_disk_collection (cls , connection : Connection , file_format : str , glob_pattern : str , ** options ) -> DataCube :
@@ -314,7 +344,9 @@ def load_stac(
314
344
spatial_extent : Union [dict , Parameter , shapely .geometry .base .BaseGeometry , str , pathlib .Path , None ] = None ,
315
345
temporal_extent : Union [Sequence [InputDate ], Parameter , str , None ] = None ,
316
346
bands : Union [Iterable [str ], Parameter , str , None ] = None ,
317
- properties : Optional [Dict [str , Union [str , PGNode , Callable ]]] = None ,
347
+ properties : Union [
348
+ Dict [str , Union [PGNode , typing .Callable ]], List [CollectionProperty ], CollectionProperty , None
349
+ ] = None ,
318
350
connection : Optional [Connection ] = None ,
319
351
) -> DataCube :
320
352
"""
@@ -409,14 +441,19 @@ def load_stac(
409
441
The value must be a condition (user-defined process) to be evaluated against a STAC API.
410
442
This parameter is not supported for static STAC.
411
443
444
+ See :py:func:`~openeo.rest.graph_building.collection_property` for easy construction of property filters.
445
+
412
446
:param connection: The connection to use to connect with the backend.
413
447
414
448
.. versionadded:: 0.33.0
415
449
416
450
.. versionchanged:: 0.37.0
417
451
Argument ``spatial_extent``: add support for passing a Shapely geometry or a local path to a GeoJSON file.
452
+
453
+ .. versionchanged:: 0.41.0
454
+ Add support for :py:func:`~openeo.rest.graph_building.collection_property` based property filters
418
455
"""
419
- arguments = {"url" : url }
456
+ arguments : dict = {"url" : url }
420
457
if spatial_extent :
421
458
arguments ["spatial_extent" ] = _get_geometry_argument (
422
459
argument = spatial_extent ,
@@ -434,10 +471,11 @@ def load_stac(
434
471
bands = cls ._get_bands (bands , process_id = "load_stac" )
435
472
if bands is not None :
436
473
arguments ["bands" ] = bands
437
- if properties :
438
- arguments ["properties" ] = {
439
- prop : build_child_callback (pred , parent_parameters = ["value" ]) for prop , pred in properties .items ()
440
- }
474
+
475
+ properties = cls ._build_load_properties_argument (properties = properties )
476
+ if properties is not None :
477
+ arguments ["properties" ] = properties
478
+
441
479
graph = PGNode ("load_stac" , arguments = arguments )
442
480
try :
443
481
metadata = metadata_from_stac (url )
0 commit comments