diff options
author | Julian Berman <Julian@GrayVines.com> | 2023-04-17 11:29:08 -0400 |
---|---|---|
committer | Julian Berman <Julian@GrayVines.com> | 2023-04-17 11:29:10 -0400 |
commit | 3b35731082e75d686024342e2507ea50f2ef7657 (patch) | |
tree | 04ea118b780a70b0b362d9d180010f692c3a1e5e | |
parent | 6f271fccd937d1ae8b99fd42daefa804cedf3b7d (diff) | |
download | jsonschema-4.18.0a4.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.py | 10 | ||||
-rw-r--r-- | jsonschema/tests/test_deprecations.py | 34 | ||||
-rw-r--r-- | jsonschema/validators.py | 7 |
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, |