summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Berman <Julian@GrayVines.com>2023-04-17 11:29:08 -0400
committerJulian Berman <Julian@GrayVines.com>2023-04-17 11:29:10 -0400
commit3b35731082e75d686024342e2507ea50f2ef7657 (patch)
tree04ea118b780a70b0b362d9d180010f692c3a1e5e
parent6f271fccd937d1ae8b99fd42daefa804cedf3b7d (diff)
downloadjsonschema-3b35731082e75d686024342e2507ea50f2ef7657.tar.gz
Wrap raised referencing exceptions in a RefResolutionError subclass.v4.18.0a4
Even though RefResolutionError is deprecated (and already raises a suitable warning), this should make some additional code warn rather than blow up (i.e. if someone is catching RefResolutionError, that code should continue to work though it will raise a warning). Users can transition to non-deprecated APIs by directly catching referencing.exceptions.Unresolvable. Closes: #1069
-rw-r--r--jsonschema/exceptions.py10
-rw-r--r--jsonschema/tests/test_deprecations.py34
-rw-r--r--jsonschema/validators.py7
3 files changed, 50 insertions, 1 deletions
diff --git a/jsonschema/exceptions.py b/jsonschema/exceptions.py
index d1ee50a..2ad9d3c 100644
--- a/jsonschema/exceptions.py
+++ b/jsonschema/exceptions.py
@@ -11,6 +11,7 @@ import heapq
import itertools
import warnings
+from referencing.exceptions import Unresolvable as _Unresolvable
import attr
from jsonschema import _utils
@@ -210,6 +211,15 @@ class _RefResolutionError(Exception):
return str(self._cause)
+class _WrappedReferencingError(_RefResolutionError, _Unresolvable):
+ def __init__(self, cause: _Unresolvable):
+ object.__setattr__(self, "_cause", cause)
+
+ def __getattribute__(self, attr):
+ cause = object.__getattribute__(self, "_cause")
+ return getattr(cause, attr)
+
+
class UndefinedTypeCheck(Exception):
"""
A type checker was asked to check a type it did not have registered.
diff --git a/jsonschema/tests/test_deprecations.py b/jsonschema/tests/test_deprecations.py
index 2beb02f..cf5538f 100644
--- a/jsonschema/tests/test_deprecations.py
+++ b/jsonschema/tests/test_deprecations.py
@@ -3,6 +3,8 @@ import importlib
import subprocess
import sys
+import referencing.exceptions
+
from jsonschema import FormatChecker, exceptions, validators
@@ -169,6 +171,38 @@ class TestDeprecations(TestCase):
self.assertEqual(RefResolutionError, exceptions._RefResolutionError)
self.assertEqual(w.filename, __file__)
+ def test_catching_Unresolvable_directly(self):
+ """
+ This behavior is the intended behavior (i.e. it's not deprecated), but
+ given we do "tricksy" things in the iterim to wrap exceptions in a
+ multiple inheritance subclass, we need to be extra sure it works and
+ stays working.
+ """
+ validator = validators.Draft202012Validator({"$ref": "http://foo.com"})
+
+ with self.assertRaises(referencing.exceptions.Unresolvable) as e:
+ validator.validate(12)
+
+ expected = referencing.exceptions.Unresolvable(ref="http://foo.com")
+ self.assertEqual(e.exception, expected)
+
+ def test_catching_Unresolvable_via_RefResolutionError(self):
+ """
+ Until RefResolutionError is removed, it is still possible to catch
+ exceptions from reference resolution using it, even though they may
+ have been raised by referencing.
+ """
+ with self.assertWarns(DeprecationWarning):
+ from jsonschema import RefResolutionError
+
+ validator = validators.Draft202012Validator({"$ref": "http://foo.com"})
+
+ with self.assertRaises(referencing.exceptions.Unresolvable):
+ validator.validate(12)
+
+ with self.assertRaises(RefResolutionError):
+ validator.validate(12)
+
def test_Validator_subclassing(self):
"""
As of v4.12.0, subclassing a validator class produces an explicit
diff --git a/jsonschema/validators.py b/jsonschema/validators.py
index 23ea17c..72af8fc 100644
--- a/jsonschema/validators.py
+++ b/jsonschema/validators.py
@@ -19,6 +19,7 @@ from attrs import define, field, fields
from jsonschema_specifications import REGISTRY as SPECIFICATIONS
from referencing import Specification
from rpds import HashTrieMap
+import referencing.exceptions
import referencing.jsonschema
from jsonschema import (
@@ -401,7 +402,11 @@ def create(
def _validate_reference(self, ref, instance):
if self._ref_resolver is None:
- resolved = self._resolver.lookup(ref)
+ try:
+ resolved = self._resolver.lookup(ref)
+ except referencing.exceptions.Unresolvable as err:
+ raise exceptions._WrappedReferencingError(err)
+
return self.descend(
instance,
resolved.contents,