Skip to content

Commit bb8d9a1

Browse files
committed
Fix ID for invalid objects with stac_version.
Also adds "type" field in Collection/Catalog migration
1 parent f9573f8 commit bb8d9a1

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

pystac/serialization/identify.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ class OldExtensionShortIDs(Enum):
3131
FILE = "file"
3232

3333

34+
class STACType(str, Enum):
35+
def __str__(self) -> str:
36+
return str(self.value)
37+
38+
CATALOG = "Catalog"
39+
COLLECTION = "Collection"
40+
ITEM = "Feature"
41+
42+
3443
@total_ordering
3544
class STACVersionID:
3645
"""Defines STAC versions in an object that is orderable based on version number.
@@ -180,17 +189,34 @@ def identify_stac_object_type(
180189
Args:
181190
json_dict : The dict of JSON to identify.
182191
"""
183-
# Try to identify using 'type' property, if present
184-
if "type" in json_dict:
185-
# Try to find 'type' property in known STACObjectType values
186-
for t in pystac.STACObjectType:
187-
if json_dict["type"].lower() == t.value.lower():
188-
return t
189-
192+
stac_version = (
193+
STACVersionID(json_dict["stac_version"])
194+
if "stac_version" in json_dict
195+
else None
196+
)
190197
obj_type = json_dict.get("type")
191198

199+
# Try to identify using 'type' property for v1.0.0-rc.1 and higher
200+
introduced_type_attribute = STACVersionID("1.0.0-rc.1")
201+
if stac_version is not None and stac_version >= introduced_type_attribute:
202+
203+
# Since v1.0.0-rc.1 requires a "type" field for all STAC objects, any object
204+
# that is missing this attribute is not a valid STAC object.
205+
if obj_type is None:
206+
return None
207+
208+
# Try to match the "type" attribute
209+
if obj_type == STACType.CATALOG:
210+
return pystac.STACObjectType.CATALOG
211+
elif obj_type == STACType.COLLECTION:
212+
return pystac.STACObjectType.COLLECTION
213+
elif obj_type == STACType.ITEM:
214+
return pystac.STACObjectType.ITEM
215+
else:
216+
return None
217+
192218
# For pre-1.0 objects for version 0.8.* or later 'stac_version' must be present
193-
if "stac_version" in json_dict:
219+
if stac_version is not None:
194220
# Pre-1.0 STAC objects with 'type' == "Feature" are Items
195221
if obj_type == "Feature":
196222
return pystac.STACObjectType.ITEM

pystac/serialization/migrate.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
OldExtensionShortIDs,
88
STACJSONDescription,
99
STACVersionID,
10+
STACType,
1011
)
1112

1213
if TYPE_CHECKING:
@@ -18,6 +19,7 @@ def _migrate_catalog(
1819
) -> None:
1920
if version < "0.8":
2021
d["stac_extensions"] = list(info.extensions)
22+
d["type"] = STACType.CATALOG
2123

2224

2325
def _migrate_collection_summaries(
@@ -36,6 +38,7 @@ def _migrate_collection(
3638
d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription
3739
) -> None:
3840
_migrate_catalog(d, version, info)
41+
d["type"] = STACType.COLLECTION
3942
_migrate_collection_summaries(d, version, info)
4043

4144

tests/serialization/test_identify.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,31 @@ def test_identify_non_stac_type(self) -> None:
5656

5757
self.assertIsNone(identify_stac_object_type(plain_feature_dict))
5858

59+
def test_identify_invalid_stac_object_with_version(self) -> None:
60+
# Has stac_version but is not a valid STAC object
61+
invalid_dict = {
62+
"id": "concepts",
63+
"title": "Concepts catalogs",
64+
"links": [
65+
{
66+
"rel": "self",
67+
"type": "application/json",
68+
"href": "https://tamn.snapplanet.io/catalogs/concepts",
69+
},
70+
{
71+
"rel": "root",
72+
"type": "application/json",
73+
"href": "https://tamn.snapplanet.io",
74+
},
75+
],
76+
"stac_version": "1.0.0",
77+
}
78+
79+
with self.assertRaises(pystac.STACTypeError) as ctx:
80+
identify_stac_object(invalid_dict)
81+
82+
self.assertIn("JSON does not represent a STAC object", str(ctx.exception))
83+
5984
def test_identify_non_stac_raises_error(self) -> None:
6085
plain_feature_dict = {
6186
"type": "Feature",

0 commit comments

Comments
 (0)