From e1f31376b7a43fe777104f8e57296a6a8605dfb1 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Fri, 31 Jan 2025 11:01:29 -0500 Subject: [PATCH] Cope with the suite permuting of remotes. This new-but-similarly-messy logic comes modified from Bowtie (which itself may need to be modified there, we'll see). `jsonschema_suite remotes` is somewhat semantically broken (as it doesn't really help with not emitting schemas which aren't valid under the version under test), so it's time to give up and use the other filesystem mechanism of walking the remotes directory. Refs: json-schema-org/JSON-Schema-Test-Suite#753 --- jsonschema/tests/_suite.py | 75 +++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/jsonschema/tests/_suite.py b/jsonschema/tests/_suite.py index 0da6503c..d61d3827 100644 --- a/jsonschema/tests/_suite.py +++ b/jsonschema/tests/_suite.py @@ -10,7 +10,6 @@ import json import os import re -import subprocess import sys import unittest @@ -21,11 +20,14 @@ if TYPE_CHECKING: from collections.abc import Iterable, Mapping, Sequence + from referencing.jsonschema import Schema import pyperf from jsonschema.validators import _VALIDATORS import jsonschema +MAGIC_REMOTE_URL = "http://localhost:1234" + _DELIMITERS = re.compile(r"[\W\- ]+") @@ -51,38 +53,7 @@ def _find_suite(): class Suite: _root: Path = field(factory=_find_suite) - _remotes: referencing.jsonschema.SchemaRegistry = field(init=False) - - def __attrs_post_init__(self): - jsonschema_suite = self._root.joinpath("bin", "jsonschema_suite") - argv = [sys.executable, str(jsonschema_suite), "remotes"] - remotes = subprocess.check_output(argv).decode("utf-8") - - resources = json.loads(remotes) - li = "http://localhost:1234/locationIndependentIdentifierPre2019.json" - li4 = "http://localhost:1234/locationIndependentIdentifierDraft4.json" - - registry = Registry().with_resources( - [ - ( - li, - referencing.jsonschema.DRAFT7.create_resource( - contents=resources.pop(li), - ), - ), - ( - li4, - referencing.jsonschema.DRAFT4.create_resource( - contents=resources.pop(li4), - ), - ), - ], - ).with_contents( - resources.items(), - default_specification=referencing.jsonschema.DRAFT202012, - ) - object.__setattr__(self, "_remotes", registry) def benchmark(self, runner: pyperf.Runner): # pragma: no cover for name, Validator in _VALIDATORS.items(): @@ -92,10 +63,18 @@ def benchmark(self, runner: pyperf.Runner): # pragma: no cover ) def version(self, name) -> Version: + Validator = _VALIDATORS[name] + uri: str = Validator.ID_OF(Validator.META_SCHEMA) # type: ignore[assignment] + specification = referencing.jsonschema.specification_with(uri) + + registry = Registry().with_contents( + remotes_in(root=self._root / "remotes", name=name, uri=uri), + default_specification=specification, + ) return Version( name=name, path=self._root / "tests" / name, - remotes=self._remotes, + remotes=registry, ) @@ -187,6 +166,36 @@ def benchmark(self, runner: pyperf.Runner, **kwargs): # pragma: no cover ) +def remotes_in( + root: Path, + name: str, + uri: str, +) -> Iterable[tuple[str, Schema]]: + # This messy logic is because the test suite is terrible at indicating + # what remotes are needed for what drafts, and mixes in schemas which + # have no $schema and which are invalid under earlier versions, in with + # other schemas which are needed for tests. + + for each in root.rglob("*.json"): + schema = json.loads(each.read_text()) + + relative = str(each.relative_to(root)).replace("\\", "/") + + if ( + ( # invalid boolean schema + name in {"draft3", "draft4"} + and each.stem == "tree" + ) or + ( # draft/*.json + "$schema" not in schema + and relative.startswith("draft") + and not relative.startswith(name) + ) + ): + continue + yield f"{MAGIC_REMOTE_URL}/{relative}", schema + + @frozen(repr=False) class _Test: