Skip to content

Commit aae4963

Browse files
committed
ValidationErrorWrapper wrapper
1 parent 7fd1a72 commit aae4963

File tree

3 files changed

+41
-16
lines changed

3 files changed

+41
-16
lines changed

openapi_spec_validator/decorators.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""OpenAPI spec validator decorators module."""
2+
from functools import wraps
23
import logging
34

45
from openapi_spec_validator.managers import VisitingManager
@@ -43,3 +44,21 @@ def _attach_scope(self, instance):
4344
return
4445

4546
instance['x-scope'] = list(self.instance_resolver._scopes_stack)
47+
48+
49+
class ValidationErrorWrapper(object):
50+
51+
def __init__(self, error_class):
52+
self.error_class = error_class
53+
54+
def __call__(self, f):
55+
@wraps(f)
56+
def wrapper(*args, **kwds):
57+
errors = f(*args, **kwds)
58+
for err in errors:
59+
if not isinstance(err, self.error_class):
60+
# wrap other exceptions with library specific version
61+
yield self.error_class.create_from(err)
62+
else:
63+
yield err
64+
return wrapper

openapi_spec_validator/validators.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@
22
import string
33

44
from jsonschema.validators import RefResolver
5-
from jsonschema.exceptions import ValidationError
6-
from six import iteritems, raise_from
5+
from six import iteritems
76

87
from openapi_spec_validator.exceptions import (
98
ParameterDuplicateError, ExtraParametersError, UnresolvableParameterError,
109
OpenAPIValidationError
1110
)
11+
from openapi_spec_validator.decorators import ValidationErrorWrapper
1212
from openapi_spec_validator.factories import Draft4ExtendedValidatorFactory
1313
from openapi_spec_validator.managers import ResolverManager
1414

1515
log = logging.getLogger(__name__)
1616

17+
wraps_errors = ValidationErrorWrapper(OpenAPIValidationError)
18+
1719

1820
def is_ref(spec):
1921
return isinstance(spec, dict) and '$ref' in spec
@@ -43,12 +45,9 @@ def __init__(self, validator_factory, resolver_handlers):
4345

4446
def validate(self, spec, spec_url=''):
4547
for err in self.iter_errors(spec, spec_url=spec_url):
46-
if isinstance(err, ValidationError):
47-
# wrap jsonschema exceptions with library specific version
48-
raise raise_from(OpenAPIValidationError.create_from(err), err)
49-
else:
50-
raise err
48+
raise err
5149

50+
@wraps_errors
5251
def iter_errors(self, spec, spec_url=''):
5352
spec_resolver = self._get_resolver(spec_url, spec)
5453
dereferencer = self._get_dereferencer(spec_resolver)
@@ -87,6 +86,7 @@ class ComponentsValidator(object):
8786
def __init__(self, dereferencer):
8887
self.dereferencer = dereferencer
8988

89+
@wraps_errors
9090
def iter_errors(self, components):
9191
components_deref = self.dereferencer.dereference(components)
9292

@@ -103,6 +103,7 @@ class SchemasValidator(object):
103103
def __init__(self, dereferencer):
104104
self.dereferencer = dereferencer
105105

106+
@wraps_errors
106107
def iter_errors(self, schemas):
107108
schemas_deref = self.dereferencer.dereference(schemas)
108109
for name, schema in iteritems(schemas_deref):
@@ -118,6 +119,7 @@ class SchemaValidator(object):
118119
def __init__(self, dereferencer):
119120
self.dereferencer = dereferencer
120121

122+
@wraps_errors
121123
def iter_errors(self, schema, require_properties=True):
122124
schema_deref = self.dereferencer.dereference(schema)
123125

@@ -158,6 +160,7 @@ class PathsValidator(object):
158160
def __init__(self, dereferencer):
159161
self.dereferencer = dereferencer
160162

163+
@wraps_errors
161164
def iter_errors(self, paths):
162165
paths_deref = self.dereferencer.dereference(paths)
163166
for url, path_item in iteritems(paths_deref):
@@ -173,6 +176,7 @@ class PathValidator(object):
173176
def __init__(self, dereferencer):
174177
self.dereferencer = dereferencer
175178

179+
@wraps_errors
176180
def iter_errors(self, url, path_item):
177181
path_item_deref = self.dereferencer.dereference(path_item)
178182

@@ -192,6 +196,7 @@ class PathItemValidator(object):
192196
def __init__(self, dereferencer):
193197
self.dereferencer = dereferencer
194198

199+
@wraps_errors
195200
def iter_errors(self, url, path_item):
196201
path_item_deref = self.dereferencer.dereference(path_item)
197202

@@ -220,6 +225,7 @@ class OperationValidator(object):
220225
def __init__(self, dereferencer):
221226
self.dereferencer = dereferencer
222227

228+
@wraps_errors
223229
def iter_errors(self, url, name, operation, path_parameters=None):
224230
path_parameters = path_parameters or []
225231
operation_deref = self.dereferencer.dereference(operation)
@@ -261,6 +267,7 @@ class ParametersValidator(object):
261267
def __init__(self, dereferencer):
262268
self.dereferencer = dereferencer
263269

270+
@wraps_errors
264271
def iter_errors(self, parameters):
265272
seen = set()
266273
for parameter in parameters:
@@ -284,6 +291,7 @@ class ParameterValidator(object):
284291
def __init__(self, dereferencer):
285292
self.dereferencer = dereferencer
286293

294+
@wraps_errors
287295
def iter_errors(self, parameter):
288296
if 'schema' in parameter:
289297
schema = parameter['schema']

tests/integration/test_validators.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
from jsonschema.exceptions import ValidationError
2-
31
from openapi_spec_validator.exceptions import (
4-
ExtraParametersError, UnresolvableParameterError,
2+
ExtraParametersError, UnresolvableParameterError, OpenAPIValidationError,
53
)
64

75

@@ -13,11 +11,11 @@ def test_empty(self, validator):
1311
errors = validator.iter_errors(spec)
1412

1513
errors_list = list(errors)
16-
assert errors_list[0].__class__ == ValidationError
14+
assert errors_list[0].__class__ == OpenAPIValidationError
1715
assert errors_list[0].message == "'openapi' is a required property"
18-
assert errors_list[1].__class__ == ValidationError
16+
assert errors_list[1].__class__ == OpenAPIValidationError
1917
assert errors_list[1].message == "'info' is a required property"
20-
assert errors_list[2].__class__ == ValidationError
18+
assert errors_list[2].__class__ == OpenAPIValidationError
2119
assert errors_list[2].message == "'paths' is a required property"
2220

2321
def test_info_empty(self, validator):
@@ -30,7 +28,7 @@ def test_info_empty(self, validator):
3028
errors = validator.iter_errors(spec)
3129

3230
errors_list = list(errors)
33-
assert errors_list[0].__class__ == ValidationError
31+
assert errors_list[0].__class__ == OpenAPIValidationError
3432
assert errors_list[0].message == "'title' is a required property"
3533

3634
def test_minimalistic(self, validator):
@@ -200,7 +198,7 @@ def test_default_value_wrong_type(self, validator):
200198

201199
errors_list = list(errors)
202200
assert len(errors_list) == 1
203-
assert errors_list[0].__class__ == ValidationError
201+
assert errors_list[0].__class__ == OpenAPIValidationError
204202
assert errors_list[0].message == (
205203
"'invaldtype' is not of type 'integer'"
206204
)
@@ -235,7 +233,7 @@ def test_parameter_default_value_wrong_type(self, validator):
235233

236234
errors_list = list(errors)
237235
assert len(errors_list) == 1
238-
assert errors_list[0].__class__ == ValidationError
236+
assert errors_list[0].__class__ == OpenAPIValidationError
239237
assert errors_list[0].message == (
240238
"'invaldtype' is not of type 'integer'"
241239
)

0 commit comments

Comments
 (0)