From 0c7d98289da76c6b9aa4fead5f2fb294b8739647 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Wed, 22 Feb 2023 09:03:49 -0700 Subject: [PATCH 1/5] feat: add Catalog.fully_resolve --- pystac/catalog.py | 14 ++++++++++++++ tests/test_catalog.py | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/pystac/catalog.py b/pystac/catalog.py index 40174966f..260d23bbb 100644 --- a/pystac/catalog.py +++ b/pystac/catalog.py @@ -911,6 +911,20 @@ def walk( for child in self.get_children(): yield from child.walk() + def fully_resolve(self) -> None: + """Resolves every link in this catalog. + + Useful if, e.g., you'd like to read a catalog from a filesystem, upgrade + every object in the catalog to the latest STAC version, and save it back + to the filesystem. By default, :py:meth:`~pystac.Catalog.save` skips + unresolved links. + """ + for _, _, items in self.walk(): + # items is a generator, so we need to consume it to resolve the + # items + for item in items: + pass + def validate_all(self) -> None: """Validates each catalog, collection contained within this catalog. diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 6bf42d972..dfe3d37d1 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -7,6 +7,7 @@ from collections import defaultdict from copy import deepcopy from datetime import datetime +from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union, cast import pytest @@ -1467,3 +1468,11 @@ def test_remove_hierarchical_links(label_catalog: Catalog, add_canonical: bool) for link in label_catalog.links: assert not link.is_hierarchical() assert bool(label_catalog.get_single_link("canonical")) == add_canonical + + +def test_fully_resolve(tmp_path: Path, label_catalog: Catalog) -> None: + label_catalog.save(dest_href=str(tmp_path / "before")) + assert len(list((tmp_path / "before").glob("**/*.json"))) == 1 + label_catalog.fully_resolve() + label_catalog.save(dest_href=str(tmp_path / "after")) + assert len(list((tmp_path / "after").glob("**/*.json"))) == 15 From 50a165668857ab72fe64b2a2a96c9ffdbd253134 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Wed, 22 Feb 2023 09:05:45 -0700 Subject: [PATCH 2/5] gh: tweak PR template --- .github/pull_request_template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 5eb1e74a3..16ae25126 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,9 @@ -**Related Issue(s):** # +**Related Issue(s):** +- # **Description:** - **PR Checklist:** - [ ] Code is formatted (run `pre-commit run --all-files`) From f3ac251db17f048c441e0a955e37a5076d060b37 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Wed, 22 Feb 2023 09:07:35 -0700 Subject: [PATCH 3/5] chore: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e45c8a8e6..8374366b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - `RetryStacIO` ([#986](https://github.com/stac-utils/pystac/pull/986)) - `STACObject.remove_hierarchical_links` and `Link.is_hierarchical` ([#999](https://github.com/stac-utils/pystac/pull/999)) - `extra_fields` to `AssetDefinition` in the item assets extension ([#1003](https://github.com/stac-utils/pystac/pull/1003)) +- `Catalog.fully_resolve` ([#1001](https://github.com/stac-utils/pystac/pull/1001)) ### Removed From 071b013fe413e54bb7a4ac61bf0a66eeac3b6e82 Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Wed, 22 Feb 2023 09:09:01 -0700 Subject: [PATCH 4/5] docs: make the build status badge a link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac6e2fc75..4791950c2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PySTAC -![Build Status](https://github.com/stac-utils/pystac/workflows/CI/badge.svg?branch=main) +[![Build Status](https://github.com/stac-utils/pystac/workflows/CI/badge.svg?branch=main)](https://github.com/stac-utils/pystac/actions/workflows/continuous-integration.yml) [![PyPI version](https://badge.fury.io/py/pystac.svg)](https://badge.fury.io/py/pystac) [![Conda (channel only)](https://img.shields.io/conda/vn/conda-forge/pystac)](https://anaconda.org/conda-forge/pystac) [![Documentation](https://readthedocs.org/projects/pystac/badge/?version=latest)](https://pystac.readthedocs.io/en/latest/) From a263672786d052ba4837d4aa3074403de539585a Mon Sep 17 00:00:00 2001 From: Pete Gadomski Date: Thu, 23 Feb 2023 13:37:17 -0800 Subject: [PATCH 5/5] tests, refactor: rename to test_case_1_catalog --- tests/conftest.py | 2 +- tests/test_catalog.py | 18 ++++++++++-------- tests/test_collection.py | 6 ++++-- tests/test_item.py | 6 ++++-- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index fa525042a..58ad09162 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,5 +25,5 @@ def item() -> Item: @pytest.fixture -def label_catalog() -> Catalog: +def test_case_1_catalog() -> Catalog: return TestCases.case_1() diff --git a/tests/test_catalog.py b/tests/test_catalog.py index dfe3d37d1..fb984ba6c 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1463,16 +1463,18 @@ def from_dict( @pytest.mark.parametrize("add_canonical", (True, False)) -def test_remove_hierarchical_links(label_catalog: Catalog, add_canonical: bool) -> None: - label_catalog.remove_hierarchical_links(add_canonical=add_canonical) - for link in label_catalog.links: +def test_remove_hierarchical_links( + test_case_1_catalog: Catalog, add_canonical: bool +) -> None: + test_case_1_catalog.remove_hierarchical_links(add_canonical=add_canonical) + for link in test_case_1_catalog.links: assert not link.is_hierarchical() - assert bool(label_catalog.get_single_link("canonical")) == add_canonical + assert bool(test_case_1_catalog.get_single_link("canonical")) == add_canonical -def test_fully_resolve(tmp_path: Path, label_catalog: Catalog) -> None: - label_catalog.save(dest_href=str(tmp_path / "before")) +def test_fully_resolve(tmp_path: Path, test_case_1_catalog: Catalog) -> None: + test_case_1_catalog.save(dest_href=str(tmp_path / "before")) assert len(list((tmp_path / "before").glob("**/*.json"))) == 1 - label_catalog.fully_resolve() - label_catalog.save(dest_href=str(tmp_path / "after")) + test_case_1_catalog.fully_resolve() + test_case_1_catalog.save(dest_href=str(tmp_path / "after")) assert len(list((tmp_path / "after").glob("**/*.json"))) == 15 diff --git a/tests/test_collection.py b/tests/test_collection.py index 8751bcb29..99a0c93f2 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -533,8 +533,10 @@ def from_dict( @pytest.mark.parametrize("add_canonical", (True, False)) -def test_remove_hierarchical_links(label_catalog: Catalog, add_canonical: bool) -> None: - collection = list(label_catalog.get_all_collections())[0] +def test_remove_hierarchical_links( + test_case_1_catalog: Catalog, add_canonical: bool +) -> None: + collection = list(test_case_1_catalog.get_all_collections())[0] collection.remove_hierarchical_links(add_canonical=add_canonical) for link in collection.links: assert not link.is_hierarchical() diff --git a/tests/test_item.py b/tests/test_item.py index 2ac7a8d2c..62d24c567 100644 --- a/tests/test_item.py +++ b/tests/test_item.py @@ -458,8 +458,10 @@ def test_item_from_dict_with_missing_type_raises_useful_error() -> None: @pytest.mark.parametrize("add_canonical", (True, False)) -def test_remove_hierarchical_links(label_catalog: Catalog, add_canonical: bool) -> None: - item = list(label_catalog.get_all_items())[0] +def test_remove_hierarchical_links( + test_case_1_catalog: Catalog, add_canonical: bool +) -> None: + item = list(test_case_1_catalog.get_all_items())[0] item.remove_hierarchical_links(add_canonical=add_canonical) for link in item.links: assert not link.is_hierarchical()