fix: require the jsonschema format checkers

This commit is contained in:
Abdessamad Derraz committed 2026-10-06 09:45:25 +02:00
1 parent 892cff38bc
commit e9653069a2
7 files changed
+59 -5

No files matched your search

+1 -1
View File
@@ -84,7 +84,7 @@ jobs:
# mkdocs-material >= 9.7.5 caps mkdocs < 2; the upper bound keeps a major # mkdocs-material >= 9.7.5 caps mkdocs < 2; the upper bound keeps a major
# theme release from changing the site without a deliberate bump here. # theme release from changing the site without a deliberate bump here.
- run: pip install pyyaml jsonschema==4.26.0 "mkdocs-material>=9.7.5,<10" "pymdown-extensions>=10.14" - run: pip install pyyaml "jsonschema[format-nongpl]==4.26.0" "mkdocs-material>=9.7.5,<10" "pymdown-extensions>=10.14"
- name: Validate data contracts - name: Validate data contracts
run: python scripts/validate_schemas.py run: python scripts/validate_schemas.py
+2 -2
View File
@@ -112,7 +112,7 @@ jobs:
python-version: "3.12" python-version: "3.12"
- name: Install dependencies - name: Install dependencies
run: pip install pyyaml jsonschema==4.26.0 run: pip install pyyaml "jsonschema[format-nongpl]==4.26.0"
- name: Validate platform configs and emulator profiles - name: Validate platform configs and emulator profiles
run: python scripts/validate_schemas.py --source-only run: python scripts/validate_schemas.py --source-only
@@ -127,7 +127,7 @@ jobs:
python-version: "3.12" python-version: "3.12"
- name: Install dependencies - name: Install dependencies
run: pip install pyyaml jsonschema==4.26.0 run: pip install pyyaml "jsonschema[format-nongpl]==4.26.0"
# The exporter fidelity cases compare what we hand back against the # The exporter fidelity cases compare what we hand back against the
# file each platform publishes, so they need those files. They skip # file each platform publishes, so they need those files. They skip
+1 -1
View File
@@ -16,7 +16,7 @@ dependencies = [
# and the CI contract check are the only callers, and no user path imports it. # and the CI contract check are the only callers, and no user path imports it.
[project.optional-dependencies] [project.optional-dependencies]
dev = [ dev = [
"jsonschema>=4.23", "jsonschema[format-nongpl]>=4.23",
] ]
# The site build the repo generates and documents. Both were hard # The site build the repo generates and documents. Both were hard
# requirements of deploy-site.yml and of wiki/release-process.md while being # requirements of deploy-site.yml and of wiki/release-process.md while being
+3 -1
View File
@@ -804,7 +804,9 @@ def _check_fbneo(cache_dir: str, offline: bool) -> Finding:
# --- CI toolchain ----------------------------------------------------------- # --- CI toolchain -----------------------------------------------------------
_PIN_RE = re.compile(r'"?([A-Za-z0-9_.\-]+)((?:[<>=!~]=?[^,"\s]+)(?:,[<>=!~]=?[^,"\s]+)*)?"?') _PIN_RE = re.compile(
r'"?([A-Za-z0-9_.\-]+)(?:\[[^\]]*\])?((?:[<>=!~]=?[^,"\s]+)(?:,[<>=!~]=?[^,"\s]+)*)?"?'
)
_USES_RE = re.compile(r"uses:\s*([\w.\-]+/[\w.\-]+)@([0-9a-f]{40})\s*(?:#\s*(\S+))?") _USES_RE = re.compile(r"uses:\s*([\w.\-]+/[\w.\-]+)@([0-9a-f]{40})\s*(?:#\s*(\S+))?")
+24
View File
@@ -254,6 +254,20 @@ def _semantic_install_checks(path: Path, manifest: dict) -> list[str]:
return out return out
def unchecked_formats() -> list[str]:
"""Formats the schemas declare that this jsonschema install cannot check.
date-time and uri need the format extras; without them the ten format
constraints of the published schemas were accepted unread.
"""
used = {
match
for path in SCHEMAS.glob("*.json")
for match in re.findall(r'"format"\s*:\s*"([^"]+)"', path.read_text(encoding="utf-8"))
}
return sorted(used - set(FormatChecker().checkers))
def main() -> int: def main() -> int:
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument( parser.add_argument(
@@ -263,6 +277,16 @@ def main() -> int:
) )
args = parser.parse_args() args = parser.parse_args()
unchecked = unchecked_formats()
if unchecked:
# jsonschema skips a format it has no checker for, silently.
print(
f"ERROR no checker for format(s) {', '.join(unchecked)}: "
'install "jsonschema[format-nongpl]"',
file=sys.stderr,
)
return 1
errors: list[str] = [] errors: list[str] = []
errors.extend( errors.extend(
_validate_yaml_directory(ROOT / "emulators", "emulator.schema.json") _validate_yaml_directory(ROOT / "emulators", "emulator.schema.json")
+20
View File
@@ -570,6 +570,26 @@ class PipelineRegressions(unittest.TestCase):
self.assertTrue(full_models, truth_runs) self.assertTrue(full_models, truth_runs)
class SchemaFormatsAreChecked(unittest.TestCase):
"""date-time and uri need jsonschema's format extras; without them the
published format constraints were accepted unread."""
@unittest.skipUnless(HAS_JSONSCHEMA, "validating a schema needs jsonschema")
def test_a_missing_checker_is_named(self):
import validate_schemas
empty = mock.Mock(checkers={})
with mock.patch.object(validate_schemas, "FormatChecker", return_value=empty):
self.assertEqual(validate_schemas.unchecked_formats(), ["date-time", "uri"])
def test_every_install_asks_for_the_extras(self):
for path in (".github/workflows/validate.yml", ".github/workflows/deploy-site.yml",
"pyproject.toml"):
text = (ROOT / path).read_text(encoding="utf-8")
with self.subTest(path=path):
self.assertNotRegex(text, r"jsonschema(?!\[format)[=>]")
class ResolverRegressions(unittest.TestCase): class ResolverRegressions(unittest.TestCase):
def _database(self, entries: dict[str, Path], suffix: str | None = None) -> dict: def _database(self, entries: dict[str, Path], suffix: str | None = None) -> dict:
files = {} files = {}
+8
View File
@@ -318,5 +318,13 @@ class RepeatedDestinations(unittest.TestCase):
self.assertEqual(diff.files_changed, ["pce/syscard3.pce"]) self.assertEqual(diff.files_changed, ["pce/syscard3.pce"])
class PinsWithExtras(unittest.TestCase):
def test_an_extras_bracket_keeps_its_pin(self):
from check_freshness import parse_pip_pins # noqa: PLC0415
pins = parse_pip_pins(' run: pip install pyyaml "jsonschema[format-nongpl]==4.26.0"')
self.assertEqual(pins["jsonschema"], "==4.26.0")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()