Skip to content

Commit c0bb06e

Browse files
committed
stac-pydantic optional
1 parent 7111c1c commit c0bb06e

File tree

5 files changed

+76
-14
lines changed

5 files changed

+76
-14
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ The format is (loosely) based on [Keep a Changelog](http://keepachangelog.com/)
88

99
### Changed
1010

11+
- Made `stac-pydantic` an optional dependency ([#XXX](https://github.com/stac-utils/stac-check/pull/XXX))
12+
- `stac-validator` is now installed without the `[pydantic]` extra by default
13+
- Added `stac-check[pydantic]` extra for users who need pydantic validation
14+
- Added graceful fallback to JSONSchema validation when pydantic is not available
15+
- Updated tests to handle both scenarios (with and without pydantic installed)
16+
- Added helpful warning messages when pydantic is requested but not installed
17+
1118
- Migrated documentation from Read the Docs to GitHub Pages ([#128](https://github.com/stac-utils/stac-check/pull/128))
1219
- Updated documentation build system to use Sphinx with sphinx_rtd_theme
1320
- Added support for Markdown content in documentation using myst-parser

setup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"requests>=2.32.3",
2121
"jsonschema>=4.23.0",
2222
"click>=8.1.8",
23-
"stac-validator[pydantic]>=3.7.0",
23+
"stac-validator>=3.7.0",
2424
"PyYAML",
2525
"python-dotenv",
2626
],
@@ -29,13 +29,15 @@
2929
"pytest",
3030
"requests-mock",
3131
"types-setuptools",
32+
"stac-validator[pydantic]",
3233
],
3334
"docs": [
3435
"sphinx>=4.0.0",
3536
"sphinx_rtd_theme>=1.0.0",
3637
"myst-parser>=0.18.0",
3738
"sphinx-autodoc-typehints>=1.18.0",
3839
],
40+
"pydantic": ["stac-validator[pydantic]"],
3941
},
4042
entry_points={"console_scripts": ["stac-check=stac_check.cli:main"]},
4143
author="Jonathan Healy",

stac_check/cli.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,24 @@ def cli_message(linter: Linter) -> None:
223223
@click.option(
224224
"--pydantic",
225225
is_flag=True,
226-
help="Use stac-pydantic for enhanced validation with Pydantic models.",
226+
help="Use pydantic validation (requires stac-pydantic to be installed).",
227227
)
228228
@click.command()
229229
@click.argument("file")
230230
@click.version_option(version=importlib.metadata.distribution("stac-check").version)
231231
def main(file, recursive, max_depth, assets, links, no_assets_urls, header, pydantic):
232+
# Check if pydantic validation is requested but not installed
233+
if pydantic:
234+
try:
235+
importlib.import_module("stac_pydantic")
236+
except ImportError:
237+
click.secho(
238+
"Warning: stac-pydantic is not installed. Pydantic validation will be disabled.\n"
239+
"To enable pydantic validation, install it with: pip install stac-check[pydantic]",
240+
fg="yellow",
241+
)
242+
pydantic = False
243+
232244
linter = Linter(
233245
file,
234246
assets=assets,

stac_check/lint.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,21 @@ def check_summaries(self) -> bool:
141141
pydantic: bool = False
142142

143143
def __post_init__(self):
144+
# Check if pydantic validation is requested but not installed
145+
if self.pydantic:
146+
try:
147+
importlib.import_module("stac_pydantic")
148+
except ImportError:
149+
import warnings
150+
151+
warnings.warn(
152+
"stac-pydantic is not installed. Pydantic validation will be disabled. "
153+
"Install it with: pip install stac-check[pydantic]",
154+
UserWarning,
155+
stacklevel=2,
156+
)
157+
self.pydantic = False
158+
144159
self.data = self.load_data(self.item)
145160
self.message = self.validate_file(self.item)
146161
self.config = self.parse_config(self.config_file)

tests/test_lint.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -923,34 +923,60 @@ def test_bbox_antimeridian():
923923
assert linter.check_bbox_antimeridian() == True
924924

925925

926+
# Check if stac-pydantic is available
927+
try:
928+
import importlib
929+
930+
importlib.import_module("stac_pydantic")
931+
PYDANTIC_AVAILABLE = True
932+
except ImportError:
933+
PYDANTIC_AVAILABLE = False
934+
935+
# Test decorator for pydantic tests
936+
pytest.mark.pydantic = pytest.mark.skipif(
937+
not PYDANTIC_AVAILABLE,
938+
reason="stac-pydantic is not installed. Run 'pip install -e .[dev]' to install test dependencies.",
939+
)
940+
941+
942+
@pytest.mark.pydantic
926943
def test_lint_pydantic_validation_valid():
927944
"""Test pydantic validation with a valid STAC item."""
928945
file = "sample_files/1.0.0/core-item.json"
929946
linter = Linter(file, pydantic=True)
930947

931-
assert linter.valid_stac == True
948+
assert linter.valid_stac is True
932949
assert linter.asset_type == "ITEM"
933-
assert "stac-pydantic Item model" in linter.message["schema"]
950+
assert any("stac-pydantic" in schema for schema in linter.message["schema"])
934951
assert linter.message["validation_method"] == "pydantic"
935952

936953

954+
@pytest.mark.pydantic
937955
def test_lint_pydantic_validation_invalid():
938956
"""Test pydantic validation with an invalid STAC item (missing required fields)."""
939957
file = "sample_files/1.0.0/bad-item.json"
940958
linter = Linter(file, pydantic=True)
941959

942-
assert linter.valid_stac == False
960+
assert linter.valid_stac is False
943961
assert "PydanticValidationError" in linter.message["error_type"]
944962
assert "id: Field required" in linter.message["error_message"]
945-
assert linter.message["validation_method"] == "pydantic"
946963

947964

948-
def test_lint_pydantic_validation_recursive():
949-
"""Test pydantic validation with recursive option."""
950-
file = "sample_files/1.0.0/collection.json"
951-
linter = Linter(file, recursive=True, max_depth=1, pydantic=True)
965+
def test_pydantic_fallback_without_import(monkeypatch):
966+
"""Test that pydantic validation falls back to JSONSchema when stac-pydantic is not available."""
967+
# Skip this test if stac-pydantic is actually installed
968+
if PYDANTIC_AVAILABLE:
969+
pytest.skip("stac-pydantic is installed, skipping fallback test")
952970

953-
assert linter.valid_stac == True
954-
assert linter.asset_type == "COLLECTION"
955-
assert "stac-pydantic Collection model" in linter.message["schema"]
956-
assert linter.message["validation_method"] == "pydantic"
971+
# Test that pydantic=False works without stac-pydantic
972+
file = "sample_files/1.0.0/core-item.json"
973+
linter = Linter(file, pydantic=False)
974+
assert linter.valid_stac is True
975+
assert linter.asset_type == "ITEM"
976+
assert linter.message["validation_method"] == "default"
977+
978+
# Test that pydantic=True falls back to JSONSchema when stac-pydantic is not available
979+
linter = Linter(file, pydantic=True)
980+
assert linter.valid_stac is True
981+
assert linter.asset_type == "ITEM"
982+
assert linter.message["validation_method"] == "default"

0 commit comments

Comments
 (0)