Skip to content

Commit 19bdf61

Browse files
committed
Three more exception-related deprecations.
* RefResolutionError is deprecated entirely. Use referencing.Registry-based APIs, and catch referencing.exceptions.Unresolvable if you really want to ignore referencing related issues. * FormatError should now be imported from jsonschema.exceptions only, not from the package root. * ErrorTree should now be imported from jsonschema.exceptions only, not from the package root.
1 parent 3801d9a commit 19bdf61

File tree

8 files changed

+107
-19
lines changed

8 files changed

+107
-19
lines changed

docs/errors.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ error objects.
273273

274274
.. testcode::
275275

276+
from jsonschema.exceptions import ErrorTree
276277
tree = ErrorTree(v.iter_errors(instance))
277278

278279
As you can see, `jsonschema.exceptions.ErrorTree` takes an

jsonschema/__init__.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,7 @@
1212

1313
from jsonschema._format import FormatChecker
1414
from jsonschema._types import TypeChecker
15-
from jsonschema.exceptions import (
16-
ErrorTree,
17-
FormatError,
18-
RefResolutionError,
19-
SchemaError,
20-
ValidationError,
21-
)
15+
from jsonschema.exceptions import SchemaError, ValidationError
2216
from jsonschema.protocols import Validator
2317
from jsonschema.validators import (
2418
Draft3Validator,
@@ -55,6 +49,34 @@ def __getattr__(name):
5549
stacklevel=2,
5650
)
5751
return _RefResolver
52+
elif name == "ErrorTree":
53+
warnings.warn(
54+
"Importing ErrorTree directly from the jsonschema package "
55+
"is deprecated and will become an ImportError. Import it from "
56+
"jsonschema.exceptions instead.",
57+
DeprecationWarning,
58+
stacklevel=2,
59+
)
60+
from jsonschema.exceptions import ErrorTree
61+
return ErrorTree
62+
elif name == "FormatError":
63+
warnings.warn(
64+
"Importing FormatError directly from the jsonschema package "
65+
"is deprecated and will become an ImportError. Import it from "
66+
"jsonschema.exceptions instead.",
67+
DeprecationWarning,
68+
stacklevel=2,
69+
)
70+
from jsonschema.exceptions import FormatError
71+
return FormatError
72+
elif name == "RefResolutionError":
73+
from jsonschema.exceptions import _RefResolutionError
74+
warnings.warn(
75+
_RefResolutionError._DEPRECATION_MESSAGE,
76+
DeprecationWarning,
77+
stacklevel=2,
78+
)
79+
return _RefResolutionError
5880

5981
format_checkers = {
6082
"draft3_format_checker": Draft3Validator,

jsonschema/exceptions.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import ClassVar
1010
import heapq
1111
import itertools
12+
import warnings
1213

1314
import attr
1415

@@ -20,6 +21,17 @@
2021
_unset = _utils.Unset()
2122

2223

24+
def __getattr__(name):
25+
if name == "RefResolutionError":
26+
warnings.warn(
27+
_RefResolutionError._DEPRECATION_MESSAGE,
28+
DeprecationWarning,
29+
stacklevel=2,
30+
)
31+
return _RefResolutionError
32+
raise AttributeError(f"module {__name__} has no attribute {name}")
33+
34+
2335
class _Error(Exception):
2436

2537
_word_for_schema_in_error_message: ClassVar[str]
@@ -181,11 +193,17 @@ class SchemaError(_Error):
181193

182194

183195
@attr.s(hash=True)
184-
class RefResolutionError(Exception):
196+
class _RefResolutionError(Exception):
185197
"""
186198
A ref could not be resolved.
187199
"""
188200

201+
_DEPRECATION_MESSAGE = (
202+
"jsonschema.exceptions.RefResolutionError is deprecated as of version "
203+
"4.18.0. If you wish to catch potential reference resolution errors, "
204+
"directly catch referencing.exceptions.Unresolvable."
205+
)
206+
189207
_cause = attr.ib()
190208

191209
def __str__(self):

jsonschema/tests/test_cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
from jsonschema import Draft4Validator, Draft202012Validator
2222
from jsonschema.exceptions import (
23-
RefResolutionError,
2423
SchemaError,
2524
ValidationError,
25+
_RefResolutionError,
2626
)
2727
from jsonschema.validators import _LATEST_VERSION, validate
2828

@@ -747,7 +747,7 @@ def test_nonexistent_file_with_explicit_base_uri(self):
747747
schema = '{"$ref": "someNonexistentFile.json#definitions/num"}'
748748
instance = "1"
749749

750-
with self.assertRaises(RefResolutionError) as e:
750+
with self.assertRaises(_RefResolutionError) as e:
751751
self.assertOutputs(
752752
files=dict(
753753
some_schema=schema,
@@ -766,7 +766,7 @@ def test_invalid_explicit_base_uri(self):
766766
schema = '{"$ref": "foo.json#definitions/num"}'
767767
instance = "1"
768768

769-
with self.assertRaises(RefResolutionError) as e:
769+
with self.assertRaises(_RefResolutionError) as e:
770770
self.assertOutputs(
771771
files=dict(
772772
some_schema=schema,

jsonschema/tests/test_deprecations.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import subprocess
44
import sys
55

6-
from jsonschema import FormatChecker, validators
6+
from jsonschema import FormatChecker, exceptions, validators
77

88

99
class TestDeprecations(TestCase):
@@ -28,6 +28,33 @@ def test_validators_ErrorTree(self):
2828
with self.assertWarnsRegex(DeprecationWarning, message) as w:
2929
from jsonschema.validators import ErrorTree # noqa
3030

31+
self.assertEqual(ErrorTree, exceptions.ErrorTree)
32+
self.assertEqual(w.filename, __file__)
33+
34+
def test_import_ErrorTree(self):
35+
"""
36+
As of v4.18.0, importing ErrorTree from the package root is
37+
deprecated in favor of doing so from jsonschema.exceptions.
38+
"""
39+
40+
message = "Importing ErrorTree directly from the jsonschema package "
41+
with self.assertWarnsRegex(DeprecationWarning, message) as w:
42+
from jsonschema import ErrorTree # noqa
43+
44+
self.assertEqual(ErrorTree, exceptions.ErrorTree)
45+
self.assertEqual(w.filename, __file__)
46+
47+
def test_import_FormatError(self):
48+
"""
49+
As of v4.18.0, importing FormatError from the package root is
50+
deprecated in favor of doing so from jsonschema.exceptions.
51+
"""
52+
53+
message = "Importing FormatError directly from the jsonschema package "
54+
with self.assertWarnsRegex(DeprecationWarning, message) as w:
55+
from jsonschema import FormatError # noqa
56+
57+
self.assertEqual(FormatError, exceptions.FormatError)
3158
self.assertEqual(w.filename, __file__)
3259

3360
def test_validators_validators(self):
@@ -123,6 +150,25 @@ def test_RefResolver(self):
123150
from jsonschema.validators import RefResolver # noqa: F401, F811
124151
self.assertEqual(w.filename, __file__)
125152

153+
def test_RefResolutionError(self):
154+
"""
155+
As of v4.18.0, RefResolutionError is deprecated in favor of directly
156+
catching errors from the referencing library.
157+
"""
158+
159+
message = "jsonschema.exceptions.RefResolutionError is deprecated"
160+
with self.assertWarnsRegex(DeprecationWarning, message) as w:
161+
from jsonschema import RefResolutionError # noqa: F401
162+
163+
self.assertEqual(RefResolutionError, exceptions._RefResolutionError)
164+
self.assertEqual(w.filename, __file__)
165+
166+
with self.assertWarnsRegex(DeprecationWarning, message) as w:
167+
from jsonschema.exceptions import RefResolutionError # noqa
168+
169+
self.assertEqual(RefResolutionError, exceptions._RefResolutionError)
170+
self.assertEqual(w.filename, __file__)
171+
126172
def test_Validator_subclassing(self):
127173
"""
128174
As of v4.12.0, subclassing a validator class produces an explicit

jsonschema/tests/test_format.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
from unittest import TestCase
66

7-
from jsonschema import FormatChecker, FormatError, ValidationError
7+
from jsonschema import FormatChecker, ValidationError
8+
from jsonschema.exceptions import FormatError
89
from jsonschema.validators import Draft4Validator
910

1011
BOOM = ValueError("Boom!")

jsonschema/tests/test_validators.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,15 +2285,15 @@ def handler(url):
22852285

22862286
ref = "foo://bar"
22872287
resolver = validators._RefResolver("", {}, handlers={"foo": handler})
2288-
with self.assertRaises(exceptions.RefResolutionError) as err:
2288+
with self.assertRaises(exceptions._RefResolutionError) as err:
22892289
with resolver.resolving(ref):
22902290
self.fail("Shouldn't get this far!") # pragma: no cover
2291-
self.assertEqual(err.exception, exceptions.RefResolutionError(error))
2291+
self.assertEqual(err.exception, exceptions._RefResolutionError(error))
22922292

22932293
def test_helpful_error_message_on_failed_pop_scope(self):
22942294
resolver = validators._RefResolver("", {})
22952295
resolver.pop_scope()
2296-
with self.assertRaises(exceptions.RefResolutionError) as exc:
2296+
with self.assertRaises(exceptions._RefResolutionError) as exc:
22972297
resolver.pop_scope()
22982298
self.assertIn("Failed to pop the scope", str(exc.exception))
22992299

jsonschema/validators.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ def pop_scope(self):
884884
try:
885885
self._scopes_stack.pop()
886886
except IndexError:
887-
raise exceptions.RefResolutionError(
887+
raise exceptions._RefResolutionError(
888888
"Failed to pop the scope from an empty stack. "
889889
"`pop_scope()` should only be called once for every "
890890
"`push_scope()`",
@@ -1000,7 +1000,7 @@ def resolve_from_url(self, url):
10001000
try:
10011001
document = self.resolve_remote(url)
10021002
except Exception as exc:
1003-
raise exceptions.RefResolutionError(exc)
1003+
raise exceptions._RefResolutionError(exc)
10041004

10051005
return self.resolve_fragment(document, fragment)
10061006

@@ -1054,7 +1054,7 @@ def find(key):
10541054
try:
10551055
document = document[part]
10561056
except (TypeError, LookupError):
1057-
raise exceptions.RefResolutionError(
1057+
raise exceptions._RefResolutionError(
10581058
f"Unresolvable JSON pointer: {fragment!r}",
10591059
)
10601060

0 commit comments

Comments
 (0)