[Git][debian-gis-team/stac-validator][master] 6 commits: New upstream version 3.10.1

Antonio Valentino (@antonio.valentino) gitlab at salsa.debian.org
Sun Nov 16 07:42:15 GMT 2025



Antonio Valentino pushed to branch master at Debian GIS Project / stac-validator


Commits:
b2c8fa9e by Antonio Valentino at 2025-08-09T15:35:53+00:00
New upstream version 3.10.1
- - - - -
4d8844e4 by Antonio Valentino at 2025-11-16T07:33:47+00:00
New upstream version 3.10.2
- - - - -
50c386ac by Antonio Valentino at 2025-11-16T07:34:01+00:00
Update upstream source from tag 'upstream/3.10.2'

Update to upstream version '3.10.2'
with Debian dir bac6b15a0cc59c48a21e228f0007e3ffe451dfd3
- - - - -
01cd6171 by Antonio Valentino at 2025-11-16T07:34:46+00:00
New upstream release

- - - - -
1c063358 by Antonio Valentino at 2025-11-16T07:39:24+00:00
Mark python3-pytest as "<!nocheck>"

- - - - -
8b97bc61 by Antonio Valentino at 2025-11-16T07:40:07+00:00
Set distribution to unstable

- - - - -


12 changed files:

- .github/workflows/publish.yml
- .github/workflows/test-runner.yml
- CHANGELOG.md
- README.md
- debian/changelog
- debian/control
- pyproject.toml
- − requirements-dev.txt
- − setup.py
- stac_validator/utilities.py
- stac_validator/validate.py
- tests/test_default.py


Changes:

=====================================
.github/workflows/publish.yml
=====================================
@@ -21,11 +21,11 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install setuptools wheel twine
+          pip install setuptools wheel twine build
 
       - name: Build package
         run: |
-          python setup.py sdist bdist_wheel
+          python -m build
 
       - name: Publish package to PyPI
         env:


=====================================
.github/workflows/test-runner.yml
=====================================
@@ -29,7 +29,7 @@ jobs:
         if: matrix.python-version == '3.12'
         run: |
           pip install .
-          pip install -r requirements-dev.txt
+          pip install -e .[dev]
           mypy stac_validator/
 
       - name: Run pre-commit


=====================================
CHANGELOG.md
=====================================
@@ -6,6 +6,14 @@ The format is (loosely) based on [Keep a Changelog](http://keepachangelog.com/)
 
 ## [Unreleased]
 
+## [v3.10.2] - 2025-11-16
+
+### Fixed
+- Added validation for STAC version format to provide clear error messages when stac_version field is missing, empty, or incorrectly formatted (e.g., "1.1" instead of "1.1.0"). [#268](https://github.com/stac-utils/stac-validator/pull/268)
+
+### Changed
+- Migrated from `setup.py` to modern `pyproject.toml` packaging (PEP 621), removing legacy `requirements-dev.txt` file. [#268](https://github.com/stac-utils/stac-validator/pull/268)
+
 ## [v3.10.1] - 2025-07-26
 
 ### Fixed
@@ -302,7 +310,8 @@ The format is (loosely) based on [Keep a Changelog](http://keepachangelog.com/)
 - With the newest version - 1.0.0-beta.2 - items will run through jsonchema validation before the PySTAC validation. The reason for this is that jsonschema will give more informative error messages. This should be addressed better in the future. This is not the case with the --recursive option as time can be a concern here with larger collections.
 - Logging. Various additions were made here depending on the options selected. This was done to help assist people to update their STAC collections.
 
-[Unreleased]: https://github.com/sparkgeo/stac-validator/compare/v3.10.1..main
+[Unreleased]: https://github.com/sparkgeo/stac-validator/compare/v3.10.2..main
+[v3.10.2]: https://github.com/sparkgeo/stac-validator/compare/v3.10.1..v3.10.2
 [v3.10.1]: https://github.com/sparkgeo/stac-validator/compare/v3.10.0..v3.10.1
 [v3.10.0]: https://github.com/sparkgeo/stac-validator/compare/v3.9.3..v3.10.0
 [v3.9.3]: https://github.com/sparkgeo/stac-validator/compare/v3.9.2..v3.9.3


=====================================
README.md
=====================================
@@ -6,7 +6,7 @@
   <img src="https://raw.githubusercontent.com/stac-utils/stac-validator/main/assets/stac-validator.png" width=560>
 </p>
 
-[![PyPI Downloads](https://static.pepy.tech/badge/stac-validator/month)](https://pepy.tech/projects/stac-validator)
+[![PyPI Downloads](https://static.pepy.tech/personalized-badge/stac-validator?period=total&units=NONE&left_color=GREY&right_color=BLUE&left_text=downloads)](https://pepy.tech/projects/stac-validator)
   [![GitHub contributors](https://img.shields.io/github/contributors/stac-utils/stac-validator?color=blue)](https://github.com/stac-utils/stac-validator/graphs/contributors)
   [![GitHub stars](https://img.shields.io/github/stars/stac-utils/stac-validator.svg?color=blue)](https://github.com/stac-utils/stac-validator/stargazers)
   [![GitHub forks](https://img.shields.io/github/forks/stac-utils/stac-validator.svg?color=blue)](https://github.com/stac-utils/stac-validator/network/members)


=====================================
debian/changelog
=====================================
@@ -1,11 +1,16 @@
-stac-validator (3.10.1-3) UNRELEASED; urgency=medium
+stac-validator (3.10.2-1) unstable; urgency=medium
 
-  * Team upload.
+  [ Bas Couwenberg ]
   * Update lintian overrides.
   * Drop Rules-Requires-Root: no, default since dpkg 1.22.13.
   * Use test-build-validate-cleanup instead of test-build-twice.
 
- -- Bas Couwenberg <sebastic at debian.org>  Fri, 12 Sep 2025 17:50:59 +0200
+  [ Antonio Valentino ]
+  * New upstream release.
+  * debian/control:
+    - Mark python3-pytest dependency as '<!nocheck>'.
+
+ -- Antonio Valentino <antonio.valentino at tiscali.it>  Sun, 16 Nov 2025 07:39:47 +0000
 
 stac-validator (3.10.1-2) unstable; urgency=medium
 


=====================================
debian/control
=====================================
@@ -9,7 +9,7 @@ Build-Depends: debhelper-compat (= 13),
                python3-all,
                python3-click,
                python3-jsonschema,
-               python3-pytest,
+               python3-pytest <!nocheck>,
                python3-requests,
                python3-requests-mock <!nocheck>,
                python3-referencing,


=====================================
pyproject.toml
=====================================
@@ -1,8 +1,62 @@
 [build-system]
-requires = [
-    "requests",
-    "jsonschema",
-    "click",
-    "setuptools"
+requires = ["setuptools>=61.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "stac_validator"
+version = "3.10.2"
+description = "A package to validate STAC files"
+authors = [
+    {name = "James Banting"},
+    {name = "Jonathan Healy", email = "jonathan.d.healy at gmail.com"}
 ]
-build-backend = "setuptools.build_meta"
\ No newline at end of file
+license = {text = "Apache-2.0"}
+classifiers = [
+    "Intended Audience :: Information Technology",
+    "Intended Audience :: Science/Research",
+    "License :: OSI Approved :: Apache Software License",
+    "Programming Language :: Python :: 3.8",
+    "Topic :: Scientific/Engineering :: GIS",
+]
+keywords = ["STAC", "validation", "raster"]
+requires-python = ">=3.8"
+dependencies = [
+    "requests>=2.32.3",
+    "jsonschema>=4.23.0",
+    "click>=8.1.8",
+    "referencing>=0.35.1",
+    "pyYAML>=6.0.1",
+]
+optional-dependencies.dev = [
+    "black",
+    "pytest",
+    "pytest-mypy",
+    "pre-commit",
+    "requests-mock",
+    "types-setuptools",
+    "stac-pydantic>=3.3.0",
+    "mypy",
+    "types-attrs",
+    "types-requests",
+    "types-jsonschema"
+]
+optional-dependencies.pydantic = [
+    "stac-pydantic>=3.3.0"
+]
+
+[project.urls]
+Homepage = "https://github.com/stac-utils/stac-validator"
+Repository = "https://github.com/stac-utils/stac-validator"
+
+[project.readme]
+file = "README.md"
+content-type = "text/markdown"
+
+[tool.setuptools]
+packages = ["stac_validator"]
+
+[project.scripts]
+stac-validator = "stac_validator.stac_validator:main"
+
+[tool.setuptools.package-data]
+stac_validator = ["*.yaml"]
\ No newline at end of file


=====================================
requirements-dev.txt deleted
=====================================
@@ -1,6 +0,0 @@
-black
-pytest
-pytest-mypy
-pre-commit
-requests-mock
-types-jsonschema


=====================================
setup.py deleted
=====================================
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-
-from setuptools import setup
-
-__version__ = "3.10.1"
-
-with open("README.md", "r") as fh:
-    long_description = fh.read()
-
-setup(
-    name="stac_validator",
-    version=__version__,
-    author="James Banting, Jonathan Healy",
-    author_email="jonathan.d.healy at gmail.com",
-    description="A package to validate STAC files",
-    license="Apache-2.0",
-    classifiers=[
-        "Intended Audience :: Information Technology",
-        "Intended Audience :: Science/Research",
-        "License :: OSI Approved :: Apache Software License",
-        "Programming Language :: Python :: 3.8",
-        "Topic :: Scientific/Engineering :: GIS",
-    ],
-    keywords="STAC validation raster",
-    long_description=long_description,
-    long_description_content_type="text/markdown",
-    url="https://github.com/stac-utils/stac-validator",
-    install_requires=[
-        "requests>=2.32.3",
-        "jsonschema>=4.23.0",
-        "click>=8.1.8",
-        "referencing>=0.35.1",
-        "pyYAML>=6.0.1",
-    ],
-    extras_require={
-        "dev": ["pytest", "requests-mock", "types-setuptools", "stac-pydantic>=3.3.0"],
-        "pydantic": [
-            "stac-pydantic>=3.3.0",
-        ],
-    },
-    packages=["stac_validator"],
-    entry_points={
-        "console_scripts": ["stac-validator = stac_validator.stac_validator:main"]
-    },
-    python_requires=">=3.8",
-    tests_require=["pytest", "requests-mock"],
-)


=====================================
stac_validator/utilities.py
=====================================
@@ -2,7 +2,7 @@ import functools
 import json
 import os
 import ssl
-from typing import Dict, Optional
+from typing import Dict, Optional, Tuple
 from urllib.parse import urlparse
 from urllib.request import Request, urlopen
 
@@ -25,6 +25,71 @@ NEW_VERSIONS = [
 ]
 
 
+def validate_stac_version_field(stac_content: Dict) -> Tuple[bool, str, str]:
+    """Validate the stac_version field in STAC content.
+
+    Args:
+        stac_content (dict): The STAC content dictionary.
+
+    Returns:
+        Tuple[bool, str, str]: (is_valid, error_type, error_message)
+            - is_valid: True if the version is valid
+            - error_type: Error type string if invalid, empty string if valid
+            - error_message: Error message if invalid, empty string if valid
+    """
+    version = stac_content.get("stac_version", "")
+
+    # Check if version is present and not empty
+    if not version or not isinstance(version, str) or version.strip() == "":
+        error_type = "MissingSTACVersion"
+        error_msg = (
+            "The 'stac_version' field is missing or empty. "
+            "Please ensure your STAC object includes a valid 'stac_version' field "
+            "(e.g., '1.0.0', '1.1.0'). This field is required for proper schema validation."
+        )
+        return False, error_type, error_msg
+
+    # Validate version format
+    format_valid, format_error = validate_version_format(version)
+    if not format_valid:
+        return False, "InvalidSTACVersionFormat", format_error
+
+    return True, "", ""
+
+
+def validate_version_format(version: str) -> Tuple[bool, str]:
+    """Validate that a STAC version string has the correct format.
+
+    Args:
+        version (str): The version string to validate.
+
+    Returns:
+        Tuple[bool, str]: (is_valid, error_message)
+            - is_valid: True if the version format is valid
+            - error_message: Description of the issue if invalid, empty string if valid
+
+    Valid formats:
+        - Standard semver: "1.0.0", "1.1.0", "0.9.0"
+        - Pre-release versions: "1.0.0-beta.1", "1.0.0-rc.1"
+    """
+    if not version:
+        return False, "Version is empty"
+
+    import re
+
+    # Regex for semantic versioning: major.minor.patch with optional pre-release
+    semver_pattern = r"^\d+\.\d+\.\d+(-[\w\.\-]+)?$"
+
+    if not re.match(semver_pattern, version):
+        return False, (
+            f"Version '{version}' does not match expected format. "
+            "STAC versions should be in semantic versioning format (e.g., '1.0.0', '1.1.0', '1.0.0-beta.1'). "
+            "Please check your 'stac_version' field."
+        )
+
+    return True, ""
+
+
 def is_url(url: str) -> bool:
     """Checks whether the input string is a valid URL.
 


=====================================
stac_validator/validate.py
=====================================
@@ -18,6 +18,7 @@ from .utilities import (
     link_request,
     load_schema_config,
     set_schema_addr,
+    validate_stac_version_field,
     validate_with_ref_resolver,
 )
 
@@ -247,6 +248,7 @@ class StacValidate:
         err_msg: str,
         error_obj: Optional[Exception] = None,
         schema_uri: str = "",
+        version: Optional[str] = None,
     ) -> Dict[str, Union[str, bool, List[str], Dict[str, Any]]]:
         """
         Create a standardized error message dictionary and mark validation as failed.
@@ -256,6 +258,7 @@ class StacValidate:
             err_msg (str): The error message.
             error_obj (Optional[Exception]): The raw exception object for verbose details.
             schema_uri (str, optional): The URI of the schema that failed validation.
+            version (Optional[str]): Override version to use in the error message.
 
         Returns:
             dict: Dictionary containing error information.
@@ -268,9 +271,16 @@ class StacValidate:
         if not isinstance(err_msg, str):
             err_msg = str(err_msg)
 
+        # Use provided version or fall back to self.version
+        version_to_use = (
+            version
+            if version is not None
+            else (str(self.version) if hasattr(self, "version") else "")
+        )
+
         # Initialize the message with common fields
         message: Dict[str, Any] = {
-            "version": str(self.version) if hasattr(self, "version") else "",
+            "version": version_to_use,
             "path": str(self.stac_file) if hasattr(self, "stac_file") else "",
             "schema": (
                 [self._original_schema_paths.get(self.schema, self.schema)]
@@ -306,7 +316,7 @@ class StacValidate:
 
         # Initialize the error message with common fields
         error_message: Dict[str, Union[str, bool, List[str], Dict[str, Any]]] = {
-            "version": str(self.version) if self.version is not None else "",
+            "version": version_to_use,
             "path": str(self.stac_file) if self.stac_file is not None else "",
             "schema": schema_field,  # All schemas that were checked
             "valid_stac": False,
@@ -950,7 +960,25 @@ class StacValidate:
                 self.stac_content = fetch_and_parse_file(self.stac_file, self.headers)
 
             stac_type = get_stac_type(self.stac_content).upper()
-            self.version = self.stac_content["stac_version"]
+            version = self.stac_content.get("stac_version", "")
+
+            # Validate stac_version field comprehensively
+            version_valid, version_error_type, version_error_msg = (
+                validate_stac_version_field(self.stac_content)
+            )
+            if not version_valid:
+                message.update(
+                    self.create_err_msg(
+                        err_type=version_error_type,
+                        err_msg=version_error_msg,
+                        schema_uri="",
+                        version=version,  # Pass the version we extracted
+                    )
+                )
+                self.message.append(message)
+                return self.valid
+
+            self.version = version
 
             if self.core:
                 message = self.create_message(stac_type, "core")


=====================================
tests/test_default.py
=====================================
@@ -180,3 +180,105 @@ def test_default_collection_validates_extensions():
             "validation_method": "default",
         }
     ]
+
+
+def test_missing_stac_version():
+    """Test that missing or empty stac_version provides a clear error message."""
+    import json
+    import tempfile
+
+    # Create a test STAC object with empty stac_version
+    test_stac = {
+        "type": "Collection",
+        "id": "test-collection",
+        "stac_version": "",  # Empty stac_version
+        "description": "Test collection",
+        "license": "MIT",
+        "extent": {
+            "spatial": {"bbox": [[-180, -90, 180, 90]]},
+            "temporal": {"interval": [["2020-01-01T00:00:00Z", None]]},
+        },
+        "links": [{"rel": "self", "href": "test.json", "type": "application/json"}],
+    }
+
+    # Write to temp file
+    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
+        json.dump(test_stac, f)
+        temp_file = f.name
+
+    try:
+        stac = stac_validator.StacValidate(temp_file)
+        stac.run()
+        assert stac.message == [
+            {
+                "version": "",
+                "path": temp_file,
+                "schema": [],
+                "valid_stac": False,
+                "error_type": "MissingSTACVersion",
+                "error_message": (
+                    "The 'stac_version' field is missing or empty. "
+                    "Please ensure your STAC object includes a valid 'stac_version' field "
+                    "(e.g., '1.0.0', '1.1.0'). This field is required for proper schema validation."
+                ),
+                "failed_schema": "",
+                "recommendation": "For more accurate error information, rerun with --verbose.",
+            }
+        ]
+    finally:
+        import os
+
+        os.unlink(temp_file)
+
+
+def test_invalid_stac_version_format():
+    """Test that invalid stac_version format provides a clear error message."""
+    import json
+    import tempfile
+
+    # Test cases for invalid formats
+    invalid_versions = ["1.1", "1", "1.0", "abc", "1.0.0.0"]
+
+    for invalid_version in invalid_versions:
+        # Create a test STAC object with invalid stac_version format
+        test_stac = {
+            "type": "Collection",
+            "id": "test-collection",
+            "stac_version": invalid_version,  # Invalid format
+            "description": "Test collection",
+            "license": "MIT",
+            "extent": {
+                "spatial": {"bbox": [[-180, -90, 180, 90]]},
+                "temporal": {"interval": [["2020-01-01T00:00:00Z", None]]},
+            },
+            "links": [{"rel": "self", "href": "test.json", "type": "application/json"}],
+        }
+
+        # Write to temp file
+        with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
+            json.dump(test_stac, f)
+            temp_file = f.name
+
+        try:
+            stac = stac_validator.StacValidate(temp_file)
+            stac.run()
+            assert stac.message == [
+                {
+                    "version": invalid_version,
+                    "path": temp_file,
+                    "schema": [],
+                    "valid_stac": False,
+                    "error_type": "InvalidSTACVersionFormat",
+                    "error_message": (
+                        f"Version '{invalid_version}' does not match expected format. "
+                        "STAC versions should be in semantic versioning format (e.g., '1.0.0', '1.1.0', '1.0.0-beta.1'). "
+                        "Please check your 'stac_version' field."
+                    ),
+                    "failed_schema": "",
+                    "recommendation": "For more accurate error information, rerun with --verbose.",
+                }
+            ]
+        finally:
+            import os
+
+            os.unlink(temp_file)



View it on GitLab: https://salsa.debian.org/debian-gis-team/stac-validator/-/compare/d9481ece21e62574815cb5444b037780e2628a94...8b97bc61837c6a8a5c706544311e85c6b21c7fbb

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/stac-validator/-/compare/d9481ece21e62574815cb5444b037780e2628a94...8b97bc61837c6a8a5c706544311e85c6b21c7fbb
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20251116/43b03d05/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list