Skip to content

Commit 47017df

Browse files
committed
Remove ITEMCOLLECTION from STACObjectTypes
1 parent 2bb16a1 commit 47017df

File tree

8 files changed

+56
-128
lines changed

8 files changed

+56
-128
lines changed

pystac/item_collection.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def from_dict(cls, d: Dict[str, Any]) -> "ItemCollection":
140140
Arguments:
141141
d : The dictionary from which the :class:`~ItemCollection` will be created
142142
"""
143-
if identify_stac_object_type(d) != pystac.STACObjectType.ITEMCOLLECTION:
143+
if not cls.is_item_collection(d):
144144
raise STACTypeError("Dict is not a valid ItemCollection")
145145

146146
items = [pystac.Item.from_dict(item) for item in d.get("features", [])]
@@ -184,3 +184,29 @@ def save_object(
184184
stac_io = pystac.StacIO.default()
185185

186186
stac_io.save_json(dest_href, self.to_dict())
187+
188+
@staticmethod
189+
def is_item_collection(d: Dict[str, Any]) -> bool:
190+
"""Checks if the given dictionary represents a valid :class:`ItemCollection`.
191+
192+
Args:
193+
d : Dictionary to check
194+
"""
195+
typ = d.get("type")
196+
197+
# All ItemCollections are GeoJSON FeatureCollections
198+
if typ != "FeatureCollection":
199+
return False
200+
201+
# If it is a FeatureCollection and has a "stac_version" field, then it is an
202+
# ItemCollection. This will cover ItemCollections from STAC 0.9 to
203+
# <1.0.0-beta.1, when ItemCollections were removed from the core STAC Spec
204+
if "stac_version" in d:
205+
return True
206+
207+
# Prior to STAC 0.9 ItemCollections did not have a stac_version field and could
208+
# only be identified by the fact that all of their 'features' are STAC Items.
209+
return all(
210+
identify_stac_object_type(feature) == pystac.STACObjectType.ITEM
211+
for feature in d.get("features", [])
212+
)

pystac/serialization/identify.py

+5-67
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from enum import Enum
22
from functools import total_ordering
3-
from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, Union, cast
3+
from typing import Any, Dict, Optional, Set, TYPE_CHECKING, Union
44

55
import pystac
66
from pystac.version import STACVersion
@@ -165,44 +165,6 @@ def __repr__(self) -> str:
165165
)
166166

167167

168-
def _identify_stac_extensions(
169-
object_type: str, d: Dict[str, Any], version_range: STACVersionRange
170-
) -> List[str]:
171-
"""Identifies extensions for STAC Objects that don't list their
172-
extensions in a 'stac_extensions' property.
173-
174-
Returns a list of stac_extensions. May mutate the version_range to update
175-
min or max version.
176-
"""
177-
stac_extensions: Set[str] = set([])
178-
179-
# assets (collection assets)
180-
181-
if object_type == pystac.STACObjectType.ITEMCOLLECTION:
182-
if "assets" in d:
183-
stac_extensions.add("assets")
184-
version_range.set_min(STACVersionID("0.8.0"))
185-
186-
# checksum
187-
if "links" in d:
188-
for link in d["links"]:
189-
link_props = cast(Dict[str, Any], link).keys()
190-
191-
if any(prop.startswith("checksum:") for prop in link_props):
192-
stac_extensions.add(OldExtensionShortIDs.CHECKSUM.value)
193-
version_range.set_min(STACVersionID("0.6.2"))
194-
195-
# Single File STAC
196-
if object_type == pystac.STACObjectType.ITEMCOLLECTION:
197-
if "collections" in d:
198-
stac_extensions.add(OldExtensionShortIDs.SINGLE_FILE_STAC.value)
199-
version_range.set_min(STACVersionID("0.8.0"))
200-
if "stac_extensions" not in d:
201-
version_range.set_max(STACVersionID("0.8.1"))
202-
203-
return list(stac_extensions)
204-
205-
206168
def identify_stac_object_type(
207169
json_dict: Dict[str, Any]
208170
) -> Optional["STACObjectType_Type"]:
@@ -227,15 +189,11 @@ def identify_stac_object_type(
227189

228190
obj_type = json_dict.get("type")
229191

230-
# For pre-1.0 objects for version 0.8.* or later 'stac_version' must be present,
231-
# except for in ItemCollections (which are handled in the else clause)
192+
# For pre-1.0 objects for version 0.8.* or later 'stac_version' must be present
232193
if "stac_version" in json_dict:
233194
# Pre-1.0 STAC objects with 'type' == "Feature" are Items
234195
if obj_type == "Feature":
235196
return pystac.STACObjectType.ITEM
236-
# Pre-1.0 STAC objects with 'type' == "FeatureCollection" are ItemCollections
237-
if obj_type == "FeatureCollection":
238-
return pystac.STACObjectType.ITEMCOLLECTION
239197
# Anything else with a 'type' field is not a STAC object
240198
if obj_type is not None:
241199
return None
@@ -246,16 +204,8 @@ def identify_stac_object_type(
246204
# Everything else that has a stac_version is a Catalog
247205
else:
248206
return pystac.STACObjectType.CATALOG
249-
else:
250-
# Prior to STAC 0.9 ItemCollections did not have a stac_version field and could
251-
# only be identified by the fact that all of their 'features' are STAC Items
252-
if obj_type == "FeatureCollection":
253-
if all(
254-
identify_stac_object_type(feat) == pystac.STACObjectType.ITEM
255-
for feat in json_dict.get("features", [])
256-
):
257-
return pystac.STACObjectType.ITEMCOLLECTION
258-
return None
207+
208+
return None
259209

260210

261211
def identify_stac_object(json_dict: Dict[str, Any]) -> STACJSONDescription:
@@ -287,19 +237,7 @@ def identify_stac_object(json_dict: Dict[str, Any]) -> STACJSONDescription:
287237
version_range.set_min(STACVersionID("0.8.0"))
288238

289239
if stac_extensions is None:
290-
# If this is post-0.8, we can assume there are no extensions
291-
# if the stac_extensions property doesn't exist for everything
292-
# but ItemCollection (except after 0.9.0, when ItemCollection also got
293-
# the stac_extensions property).
294-
if (
295-
object_type == pystac.STACObjectType.ITEMCOLLECTION
296-
and not version_range.is_later_than("0.8.1")
297-
):
298-
stac_extensions = _identify_stac_extensions(
299-
object_type, json_dict, version_range
300-
)
301-
else:
302-
stac_extensions = []
240+
stac_extensions = []
303241

304242
# Between 1.0.0-beta.2 and 1.0.0-RC1, STAC extensions changed from
305243
# being split between 'common' and custom extensions, with common

pystac/serialization/migrate.py

-10
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,7 @@ def _migrate_item(
3333
pass
3434

3535

36-
def _migrate_itemcollection(
37-
d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription
38-
) -> None:
39-
if version < "0.9.0":
40-
d["stac_extensions"] = list(info.extensions)
41-
42-
4336
# Extensions
44-
45-
4637
def _migrate_item_assets(
4738
d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription
4839
) -> Optional[Set[str]]:
@@ -83,7 +74,6 @@ def _get_object_migrations() -> Dict[
8374
pystac.STACObjectType.CATALOG: _migrate_catalog,
8475
pystac.STACObjectType.COLLECTION: _migrate_collection,
8576
pystac.STACObjectType.ITEM: _migrate_item,
86-
pystac.STACObjectType.ITEMCOLLECTION: _migrate_itemcollection,
8777
}
8878

8979

pystac/stac_object.py

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ def __str__(self) -> str:
1818
CATALOG = "CATALOG"
1919
COLLECTION = "COLLECTION"
2020
ITEM = "ITEM"
21-
ITEMCOLLECTION = "ITEMCOLLECTION"
2221

2322

2423
class STACObject(ABC):

pystac/validation/schema_uri_map.py

-7
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,6 @@ class DefaultSchemaUriMap(SchemaUriMap):
7171
None,
7272
),
7373
STACObjectType.ITEM: ("item-spec/json-schema/item.json", None),
74-
STACObjectType.ITEMCOLLECTION: (
75-
None,
76-
[
77-
STACVersionRange(min_version="v0.8.0-rc1", max_version="0.9.0"),
78-
"item-spec/json-schema/itemcollection.json",
79-
],
80-
),
8174
}
8275

8376
@classmethod

tests/serialization/test_identify.py

-36
Original file line numberDiff line numberDiff line change
@@ -68,47 +68,11 @@ def test_identify_non_stac_raises_error(self) -> None:
6868

6969
self.assertIn("JSON does not represent a STAC object", str(ctx.exception))
7070

71-
def test_identify_0_8_itemcollection_type(self) -> None:
72-
itemcollection_path = TestCases.get_path(
73-
"data-files/examples/0.8.1/item-spec/"
74-
"examples/itemcollection-sample-full.json"
75-
)
76-
itemcollection_dict = pystac.StacIO.default().read_json(itemcollection_path)
77-
78-
self.assertEqual(
79-
identify_stac_object_type(itemcollection_dict),
80-
pystac.STACObjectType.ITEMCOLLECTION,
81-
)
82-
83-
def test_identify_0_9_itemcollection(self) -> None:
84-
itemcollection_path = TestCases.get_path(
85-
"data-files/examples/0.9.0/item-spec/"
86-
"examples/itemcollection-sample-full.json"
87-
)
88-
itemcollection_dict = pystac.StacIO.default().read_json(itemcollection_path)
89-
90-
self.assertEqual(
91-
identify_stac_object_type(itemcollection_dict),
92-
pystac.STACObjectType.ITEMCOLLECTION,
93-
)
94-
9571
def test_identify_invalid_with_stac_version(self) -> None:
9672
not_stac = {"stac_version": "0.9.0", "type": "Custom"}
9773

9874
self.assertIsNone(identify_stac_object_type(not_stac))
9975

100-
def test_identify_0_8_itemcollection(self) -> None:
101-
itemcollection_path = TestCases.get_path(
102-
"data-files/examples/0.8.1/item-spec/"
103-
"examples/itemcollection-sample-full.json"
104-
)
105-
itemcollection_dict = pystac.StacIO.default().read_json(itemcollection_path)
106-
107-
actual = identify_stac_object(itemcollection_dict)
108-
109-
self.assertEqual(actual.object_type, pystac.STACObjectType.ITEMCOLLECTION)
110-
self.assertTrue(actual.version_range.contains("0.8.1"))
111-
11276

11377
class VersionTest(unittest.TestCase):
11478
def test_version_ordering(self) -> None:

tests/serialization/test_migrate.py

-6
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,6 @@ def test_migrate(self) -> None:
4949
e_id.endswith(".json"), f"{e_id} is not a JSON schema URI"
5050
)
5151

52-
# Test that PySTAC can read it without errors.
53-
if info.object_type != pystac.STACObjectType.ITEMCOLLECTION:
54-
self.assertIsInstance(
55-
pystac.read_dict(migrated_d, href=path), pystac.STACObject
56-
)
57-
5852
def test_migrates_removed_extension(self) -> None:
5953
item = pystac.Item.from_file(
6054
TestCases.get_path(

tests/test_item_collection.py

+24
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,27 @@ def test_add_other_raises_error(self) -> None:
125125

126126
with self.assertRaises(TypeError):
127127
_ = item_collection + 2
128+
129+
def test_identify_0_8_itemcollection_type(self) -> None:
130+
itemcollection_path = TestCases.get_path(
131+
"data-files/examples/0.8.1/item-spec/"
132+
"examples/itemcollection-sample-full.json"
133+
)
134+
itemcollection_dict = pystac.StacIO.default().read_json(itemcollection_path)
135+
136+
self.assertTrue(
137+
pystac.ItemCollection.is_item_collection(itemcollection_dict),
138+
msg="Did not correctly identify valid STAC 0.8 ItemCollection.",
139+
)
140+
141+
def test_identify_0_9_itemcollection(self) -> None:
142+
itemcollection_path = TestCases.get_path(
143+
"data-files/examples/0.9.0/item-spec/"
144+
"examples/itemcollection-sample-full.json"
145+
)
146+
itemcollection_dict = pystac.StacIO.default().read_json(itemcollection_path)
147+
148+
self.assertTrue(
149+
pystac.ItemCollection.is_item_collection(itemcollection_dict),
150+
msg="Did not correctly identify valid STAC 0.9 ItemCollection.",
151+
)

0 commit comments

Comments
 (0)