Skip to content

Commit 3b35731

Browse files
committed
Wrap raised referencing exceptions in a RefResolutionError subclass.
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
1 parent 6f271fc commit 3b35731

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

jsonschema/exceptions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import itertools
1212
import warnings
1313

14+
from referencing.exceptions import Unresolvable as _Unresolvable
1415
import attr
1516

1617
from jsonschema import _utils
@@ -210,6 +211,15 @@ def __str__(self):
210211
return str(self._cause)
211212

212213

214+
class _WrappedReferencingError(_RefResolutionError, _Unresolvable):
215+
def __init__(self, cause: _Unresolvable):
216+
object.__setattr__(self, "_cause", cause)
217+
218+
def __getattribute__(self, attr):
219+
cause = object.__getattribute__(self, "_cause")
220+
return getattr(cause, attr)
221+
222+
213223
class UndefinedTypeCheck(Exception):
214224
"""
215225
A type checker was asked to check a type it did not have registered.

jsonschema/tests/test_deprecations.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import subprocess
44
import sys
55

6+
import referencing.exceptions
7+
68
from jsonschema import FormatChecker, exceptions, validators
79

810

@@ -169,6 +171,38 @@ def test_RefResolutionError(self):
169171
self.assertEqual(RefResolutionError, exceptions._RefResolutionError)
170172
self.assertEqual(w.filename, __file__)
171173

174+
def test_catching_Unresolvable_directly(self):
175+
"""
176+
This behavior is the intended behavior (i.e. it's not deprecated), but
177+
given we do "tricksy" things in the iterim to wrap exceptions in a
178+
multiple inheritance subclass, we need to be extra sure it works and
179+
stays working.
180+
"""
181+
validator = validators.Draft202012Validator({"$ref": "http://foo.com"})
182+
183+
with self.assertRaises(referencing.exceptions.Unresolvable) as e:
184+
validator.validate(12)
185+
186+
expected = referencing.exceptions.Unresolvable(ref="http://foo.com")
187+
self.assertEqual(e.exception, expected)
188+
189+
def test_catching_Unresolvable_via_RefResolutionError(self):
190+
"""
191+
Until RefResolutionError is removed, it is still possible to catch
192+
exceptions from reference resolution using it, even though they may
193+
have been raised by referencing.
194+
"""
195+
with self.assertWarns(DeprecationWarning):
196+
from jsonschema import RefResolutionError
197+
198+
validator = validators.Draft202012Validator({"$ref": "http://foo.com"})
199+
200+
with self.assertRaises(referencing.exceptions.Unresolvable):
201+
validator.validate(12)
202+
203+
with self.assertRaises(RefResolutionError):
204+
validator.validate(12)
205+
172206
def test_Validator_subclassing(self):
173207
"""
174208
As of v4.12.0, subclassing a validator class produces an explicit

jsonschema/validators.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from jsonschema_specifications import REGISTRY as SPECIFICATIONS
2020
from referencing import Specification
2121
from rpds import HashTrieMap
22+
import referencing.exceptions
2223
import referencing.jsonschema
2324

2425
from jsonschema import (
@@ -401,7 +402,11 @@ def is_type(self, instance, type):
401402

402403
def _validate_reference(self, ref, instance):
403404
if self._ref_resolver is None:
404-
resolved = self._resolver.lookup(ref)
405+
try:
406+
resolved = self._resolver.lookup(ref)
407+
except referencing.exceptions.Unresolvable as err:
408+
raise exceptions._WrappedReferencingError(err)
409+
405410
return self.descend(
406411
instance,
407412
resolved.contents,

0 commit comments

Comments
 (0)