@@ -298,40 +298,59 @@ def _identify_stac_extensions(
298
298
return list (stac_extensions )
299
299
300
300
301
- def identify_stac_object_type (json_dict : Dict [str , Any ]) -> "STACObjectType_Type" :
302
- """Determines the STACObjectType of the provided JSON dict.
301
+ def identify_stac_object_type (
302
+ json_dict : Dict [str , Any ]
303
+ ) -> Optional ["STACObjectType_Type" ]:
304
+ """Determines the STACObjectType of the provided JSON dict. If the JSON dict does
305
+ not represent a STAC object, returns ``None``.
306
+
307
+ Will first try to identify the object using ``"type"`` field as described in the
308
+ guidelines in :stac-spec:`How to Differentiate STAC Files
309
+ <best-practices.md#how-to-differentiate-stac-files>`. If this fails, will fall back
310
+ to using the pre-1.0 heuristic described in `this issue
311
+ <https://github.com/radiantearth/stac-spec/issues/889#issuecomment-684529444>`__
303
312
304
313
Args:
305
- json_dict : The dict of STAC JSON to identify.
306
-
307
- Returns:
308
- STACObjectType: The object type represented by the JSON.
314
+ json_dict : The dict of JSON to identify.
309
315
"""
310
- object_type = None
311
-
312
- if "type" in json_dict : # Try to identify using 'type' property
316
+ # Try to identify using 'type' property, if present
317
+ if "type" in json_dict :
318
+ # Try to find 'type' property in known STACObjectType values
313
319
for t in pystac .STACObjectType :
314
320
if json_dict ["type" ].lower () == t .value .lower ():
315
- object_type = t
316
- break
317
-
318
- if object_type is None : # Use old-approach based on other properties
319
- # Identify pre-1.0 ITEMCOLLECTION (since removed)
320
- if "type" in json_dict and "assets" not in json_dict :
321
- if "stac_version" in json_dict and json_dict ["stac_version" ].startswith (
322
- "0"
323
- ):
324
- if json_dict ["type" ] == "FeatureCollection" :
325
- object_type = pystac .STACObjectType .ITEMCOLLECTION
326
-
327
- if "extent" in json_dict :
328
- object_type = pystac .STACObjectType .COLLECTION
329
- elif "assets" in json_dict :
330
- object_type = pystac .STACObjectType .ITEM
321
+ return t
322
+
323
+ obj_type = json_dict .get ("type" )
324
+
325
+ # For pre-1.0 objects for version 0.8.* or later 'stac_version' must be present,
326
+ # except for in ItemCollections (which are handled in the else clause)
327
+ if "stac_version" in json_dict :
328
+ # Pre-1.0 STAC objects with 'type' == "Feature" are Items
329
+ if obj_type == "Feature" :
330
+ return pystac .STACObjectType .ITEM
331
+ # Pre-1.0 STAC objects with 'type' == "FeatureCollection" are ItemCollections
332
+ if obj_type == "FeatureCollection" :
333
+ return pystac .STACObjectType .ITEMCOLLECTION
334
+ # Anything else with a 'type' field is not a STAC object
335
+ if obj_type is not None :
336
+ return None
337
+
338
+ # Collections will contain either an 'extent' or a 'license' (or both)
339
+ if "extent" in json_dict or "license" in json_dict :
340
+ return pystac .STACObjectType .COLLECTION
341
+ # Everything else that has a stac_version is a Catalog
331
342
else :
332
- object_type = pystac .STACObjectType .CATALOG
333
-
334
- return object_type
343
+ return pystac .STACObjectType .CATALOG
344
+ else :
345
+ # Prior to STAC 0.9 ItemCollections did not have a stac_version field and could
346
+ # only be identified by the fact that all of their 'features' are STAC Items
347
+ if obj_type == "FeatureCollection" :
348
+ if all (
349
+ identify_stac_object_type (feat ) == pystac .STACObjectType .ITEM
350
+ for feat in json_dict .get ("features" , [])
351
+ ):
352
+ return pystac .STACObjectType .ITEMCOLLECTION
353
+ return None
335
354
336
355
337
356
def identify_stac_object (json_dict : Dict [str , Any ]) -> STACJSONDescription :
@@ -346,6 +365,9 @@ def identify_stac_object(json_dict: Dict[str, Any]) -> STACJSONDescription:
346
365
"""
347
366
object_type = identify_stac_object_type (json_dict )
348
367
368
+ if object_type is None :
369
+ raise pystac .STACTypeError ("JSON does not represent a STAC object." )
370
+
349
371
version_range = STACVersionRange ()
350
372
351
373
stac_version = json_dict .get ("stac_version" )
0 commit comments