Skip to content

Commit f0f7f37

Browse files
pomadchinlossyrob
andauthored
Add an extra SELF_CONTAINED catalog test (#658)
* Add an extra SELF_CONTAINED catalog test * Improve unit test * Run pre-commit * Make linter happy * Update test to avoid checking 'self' link 'self' link is always absolute; PySTAC avoids writing the link if the Catalog is self contained or relative published (besides the root catalog in the latter case). * Inline test issue-specific catalog; check raw json * Set root on resolved links when setting on Catalog When setting the root on a Catalog, also set the root on any child or item objects that are resolved. This handles the case where child items and catalogs were created, added to a catalog, and then that catalog added to another catalog, invalidating the originally set root links of the leaf items and catalogs. * Close file properly in test * Message which catalog failed for better debugging * Don't recursively clear the root of children/items When clearing the root link of a Catalog, avoid clearing the root link of the children/items. This is to avoid the root link clearing in the "clone" method to avoid touching the un-cloned linked STAC Objects. * Use STACObject.set_root in full_copy This avoids logic in the child class implementations that are incompatible with the full_copy logic, such as the Catalog's call of set_root on of child and item links. This crawling logic is handled by full_copy itself. * Update CHANGELOG Co-authored-by: Rob Emanuele <[email protected]>
1 parent c815552 commit f0f7f37

File tree

4 files changed

+63
-3
lines changed

4 files changed

+63
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323

2424
### Fixed
2525

26-
- `generate_subcatalogs` can include multiple template values in a single subfolder layer
26+
- `generate_subcatalogs` can include multiple template values in a single subfolder layer
2727
([#595](https://github.com/stac-utils/pystac/pull/595))
2828
- Avoid implicit re-exports ([#591](https://github.com/stac-utils/pystac/pull/591))
29+
- Fix issue that caused incorrect root links when constructing multi-leveled catalogs ([#658](https://github.com/stac-utils/pystac/pull/658))
2930
- Regression where string `Enum` values were not serialized properly in methods like `Link.to_dict` ([#654](https://github.com/stac-utils/pystac/pull/654))
3031

3132
### Deprecated

pystac/catalog.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ def set_root(self, root: Optional["Catalog"]) -> None:
191191
root._resolved_objects, self._resolved_objects
192192
)
193193

194+
# Walk through resolved object links and update the root
195+
for link in self.links:
196+
if link.rel == pystac.RelType.CHILD or link.rel == pystac.RelType.ITEM:
197+
target = link.target
198+
if isinstance(target, STACObject):
199+
target.set_root(root)
200+
194201
def is_relative(self) -> bool:
195202
return self.catalog_type in [
196203
CatalogType.RELATIVE_PUBLISHED,

pystac/stac_object.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,11 @@ def full_copy(
362362
if root is None and isinstance(clone, pystac.Catalog):
363363
root = clone
364364

365-
clone.set_root(cast(pystac.Catalog, root))
365+
# Set the root of the STAC Object using the base class,
366+
# avoiding child class overrides
367+
# extra logic which can be incompatible with the full copy.
368+
STACObject.set_root(clone, cast(pystac.Catalog, root))
369+
366370
if parent:
367371
clone.set_parent(parent)
368372

tests/test_catalog.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,54 @@ def check_all_absolute(cat: Catalog) -> None:
837837
c2.catalog_type = CatalogType.ABSOLUTE_PUBLISHED
838838
check_all_absolute(c2)
839839

840+
def test_self_contained_catalog_collection_item_links(self) -> None:
841+
"""See issue https://github.com/stac-utils/pystac/issues/657"""
842+
with tempfile.TemporaryDirectory() as tmp_dir:
843+
catalog = pystac.Catalog(
844+
id="catalog-issue-657", description="catalog-issue-657"
845+
)
846+
collection = pystac.Collection(
847+
"collection-issue-657",
848+
"collection-issue-657",
849+
pystac.Extent(
850+
spatial=pystac.SpatialExtent([[-180.0, -90.0, 180.0, 90.0]]),
851+
temporal=pystac.TemporalExtent([[datetime(2021, 11, 1), None]]),
852+
),
853+
license="proprietary",
854+
)
855+
856+
item = pystac.Item(
857+
id="item-issue-657",
858+
stac_extensions=[],
859+
geometry=ARBITRARY_GEOM,
860+
bbox=ARBITRARY_BBOX,
861+
datetime=datetime(2021, 11, 1),
862+
properties={},
863+
)
864+
865+
collection.add_item(item)
866+
catalog.add_child(collection)
867+
868+
catalog.normalize_hrefs(tmp_dir)
869+
catalog.validate_all()
870+
871+
catalog.save(catalog_type=CatalogType.SELF_CONTAINED)
872+
with open(
873+
f"{tmp_dir}/collection-issue-657/item-issue-657/item-issue-657.json"
874+
) as f:
875+
item_json = json.load(f)
876+
877+
for link in item_json["links"]:
878+
# self links are always absolute
879+
if link["rel"] == "self":
880+
continue
881+
882+
href = link["href"]
883+
self.assertFalse(
884+
is_absolute_href(href),
885+
msg=f"Link with rel={link['rel']} is absolute!",
886+
)
887+
840888
def test_full_copy_and_normalize_works_with_created_stac(self) -> None:
841889
cat = TestCases.test_case_3()
842890
cat_copy = cat.full_copy()
@@ -1071,7 +1119,7 @@ def check_item(self, item: Item, tag: str) -> None:
10711119
self.check_link(link, tag)
10721120

10731121
def check_catalog(self, c: Catalog, tag: str) -> None:
1074-
self.assertEqual(len(c.get_links("root")), 1)
1122+
self.assertEqual(len(c.get_links("root")), 1, msg=f"{c}")
10751123

10761124
for link in c.links:
10771125
self.check_link(link, tag)

0 commit comments

Comments
 (0)