Repository: python-jsonschema/check-jsonschema

Issue:
FailedDownloadError
In order to check files in config/*.yaml I am using:

```
    - repo: https://github.com/python-jsonschema/check-jsonschema
      rev: 0.23.3
      hooks:
        - id: check-github-workflows
        - id: check-jsonschema
          name: Check test configs
          files: ^config/[^/]+$
          types: [yaml]
          args: ["--schemafile", "https://raw.githubusercontent.com/EVerest/everest-framework/main/schemas/config.yaml"]
```

But it fails with:

```
Check test configs.......................................................Failed
- hook id: check-jsonschema
- duration: 0.56s
- exit code: 1

Error: Unexpected Error building schema validator
FailedDownloadError: got responses with status=200, retries exhausted
  in "/Users/hendry/.cache/pre-commit/repoircq8841/py_env-python3.10/lib/python3.10/site-packages/check_jsonschema/checker.py", line 52
  >>> return self._schema_loader.get_validator(

make: *** [run] Error 1
```

I don't understand why it fails with status 200 success?

Comments:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a8df1f5..0214083 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -20,6 +20,9 @@ Unreleased
   non-JSON format supported by `check-jsonschema`. The file type is inferred
   only from the file extension in these cases and defaults to JSON if there is
   no recognizable extension.
+- Remote schemafiles (http/s) now support YAML, TOML, and JSON5 formats, if the
+  URL ends with the appropriate extension and the matching parser is available.
+  Extensionless URLs are treated as JSON.
 
 0.23.3
 ------
diff --git a/src/check_jsonschema/checker.py b/src/check_jsonschema/checker.py
index bf1aea0..28931d5 100644
--- a/src/check_jsonschema/checker.py
+++ b/src/check_jsonschema/checker.py
@@ -48,7 +48,7 @@ class SchemaChecker:
 
     def get_validator(
         self, path: pathlib.Path, doc: dict[str, t.Any]
-    ) -> jsonschema.Validator:
+    ) -> jsonschema.protocols.Validator:
         try:
             return self._schema_loader.get_validator(
                 path, doc, self._format_opts, self._fill_defaults
diff --git a/src/check_jsonschema/schema_loader/main.py b/src/check_jsonschema/schema_loader/main.py
index c8c9045..4fa1c57 100644
--- a/src/check_jsonschema/schema_loader/main.py
+++ b/src/check_jsonschema/schema_loader/main.py
@@ -17,7 +17,7 @@ from .resolver import make_reference_registry
 
 
 def _extend_with_default(
-    validator_class: type[jsonschema.Validator],
+    validator_class: type[jsonschema.protocols.Validator],
 ) -> type[jsonschema.Validator]:
     validate_properties = validator_class.VALIDATORS["properties"]
 
@@ -51,7 +51,7 @@ class SchemaLoaderBase:
         instance_doc: dict[str, t.Any],
         format_opts: FormatOptions,
         fill_defaults: bool,
-    ) -> jsonschema.Validator:
+    ) -> jsonschema.protocols.Validator:
         raise NotImplementedError
 
 
@@ -112,7 +112,7 @@ class SchemaLoader(SchemaLoaderBase):
         instance_doc: dict[str, t.Any],
         format_opts: FormatOptions,
         fill_defaults: bool,
-    ) -> jsonschema.Validator:
+    ) -> jsonschema.protocols.Validator:
         retrieval_uri = self.get_schema_retrieval_uri()
         schema = self.get_schema()
 
@@ -141,7 +141,7 @@ class SchemaLoader(SchemaLoaderBase):
             registry=reference_registry,
             format_checker=format_checker,
         )
-        return t.cast(jsonschema.Validator, validator)
+        return t.cast(jsonschema.protocols.Validator, validator)
 
 
 class BuiltinSchemaLoader(SchemaLoader):
@@ -163,7 +163,7 @@ class MetaSchemaLoader(SchemaLoaderBase):
         instance_doc: dict[str, t.Any],
         format_opts: FormatOptions,
         fill_defaults: bool,
-    ) -> jsonschema.Validator:
+    ) -> jsonschema.protocols.Validator:
         schema_validator = jsonschema.validators.validator_for(instance_doc)
         meta_validator_class = jsonschema.validators.validator_for(
             schema_validator.META_SCHEMA, default=schema_validator
diff --git a/src/check_jsonschema/schema_loader/readers.py b/src/check_jsonschema/schema_loader/readers.py
index c2e4697..4c362dc 100644
--- a/src/check_jsonschema/schema_loader/readers.py
+++ b/src/check_jsonschema/schema_loader/readers.py
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-import json
+import io
 import typing as t
 
 import ruamel.yaml
@@ -48,19 +48,28 @@ class HttpSchemaReader:
         disable_cache: bool,
     ) -> None:
         self.url = url
+        self.parsers = ParserSet()
         self.downloader = CacheDownloader(
             url,
             cache_filename,
             disable_cache=disable_cache,
-            validation_callback=json.loads,
+            validation_callback=self._parse,
         )
+        self._parsed_schema: t.Any | None = None
+
+    def _parse(self, schema_bytes: bytes) -> t.Any:
+        if self._parsed_schema is None:
+            self._parsed_schema = self.parsers.parse_data_with_path(
+                io.BytesIO(schema_bytes), self.url, default_filetype="json"
+            )
+        return self._parsed_schema
 
     def get_retrieval_uri(self) -> str:
         return self.url
 
     def _read_impl(self) -> t.Any:
         with self.downloader.open() as fp:
-            return json.load(fp)
+            return self._parse(fp.read())
 
     def read_schema(self) -> dict:
         return _run_load_callback(self.url, self._read_impl)


Test patch:
diff --git a/tests/unit/test_schema_loader.py b/tests/unit/test_schema_loader.py
index b6938cb..ddc487f 100644
--- a/tests/unit/test_schema_loader.py
+++ b/tests/unit/test_schema_loader.py
@@ -2,6 +2,7 @@ import os
 import pathlib
 
 import pytest
+import responses
 
 from check_jsonschema.schema_loader import SchemaLoader, SchemaParseError
 from check_jsonschema.schema_loader.readers import HttpSchemaReader, LocalSchemaReader
@@ -40,12 +41,12 @@ def test_schemaloader_path_handling_relative_local_path(in_tmp_dir, filename):
     [
         "schema.yaml",
         "schema.yml",
+        "https://foo.example.com/schema.yaml",
+        "https://foo.example.com/schema.yml",
     ],
 )
-def test_schemaloader_local_yaml_data(tmp_path, filename):
-    f = tmp_path / filename
-    f.write_text(
-        """
+def test_schemaloader_yaml_data(tmp_path, filename):
+    schema_text = """
 ---
 "$schema": https://json-schema.org/draft/2020-12/schema
 type: object
@@ -60,8 +61,14 @@ properties:
       c:
         type: string
 """
-    )
-    sl = SchemaLoader(str(f))
+    if filename.startswith("http"):
+        responses.add("GET", filename, body=schema_text)
+        path = filename
+    else:
+        f = tmp_path / filename
+        f.write_text(schema_text)
+        path = str(f)
+    sl = SchemaLoader(path)
     schema = sl.get_schema()
     assert schema == {
         "$schema": "https://json-schema.org/draft/2020-12/schema",