Skip to content

Commit 32f1624

Browse files
committed
Narrow validation exceptions
1 parent de159cc commit 32f1624

File tree

8 files changed

+83
-50
lines changed

8 files changed

+83
-50
lines changed

openapi_core/schema/media_types/models.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
from json import loads
55

66
from openapi_core.schema.media_types.exceptions import InvalidMediaTypeValue
7-
from openapi_core.schema.schemas.exceptions import OpenAPISchemaError
7+
from openapi_core.schema.schemas.exceptions import (
8+
CastError, ValidateError, UnmarshalError,
9+
)
810

911

1012
MEDIA_TYPE_DESERIALIZERS = {
@@ -37,20 +39,25 @@ def cast(self, value):
3739
return value
3840

3941
try:
40-
return self.deserialize(value)
42+
deserialized = self.deserialize(value)
4143
except ValueError as exc:
4244
raise InvalidMediaTypeValue(exc)
4345

46+
try:
47+
return self.schema.cast(deserialized)
48+
except CastError as exc:
49+
raise InvalidMediaTypeValue(exc)
50+
4451
def unmarshal(self, value, custom_formatters=None, resolver=None):
4552
if not self.schema:
4653
return value
4754

4855
try:
4956
self.schema.validate(value, resolver=resolver)
50-
except OpenAPISchemaError as exc:
57+
except ValidateError as exc:
5158
raise InvalidMediaTypeValue(exc)
5259

5360
try:
5461
return self.schema.unmarshal(value, custom_formatters=custom_formatters)
55-
except OpenAPISchemaError as exc:
62+
except UnmarshalError as exc:
5663
raise InvalidMediaTypeValue(exc)

openapi_core/schema/parameters/exceptions.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,21 @@ class OpenAPIParameterError(OpenAPIMappingError):
77
pass
88

99

10+
class MissingParameterError(OpenAPIParameterError):
11+
"""Missing parameter error"""
12+
pass
13+
14+
1015
@attr.s(hash=True)
11-
class MissingParameter(OpenAPIParameterError):
16+
class MissingParameter(MissingParameterError):
1217
name = attr.ib()
1318

1419
def __str__(self):
1520
return "Missing parameter (without default value): {0}".format(self.name)
1621

1722

1823
@attr.s(hash=True)
19-
class MissingRequiredParameter(OpenAPIParameterError):
24+
class MissingRequiredParameter(MissingParameterError):
2025
name = attr.ib()
2126

2227
def __str__(self):

openapi_core/schema/parameters/models.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
EmptyParameterValue,
1111
)
1212
from openapi_core.schema.schemas.enums import SchemaType
13-
from openapi_core.schema.schemas.exceptions import OpenAPISchemaError
13+
from openapi_core.schema.schemas.exceptions import (
14+
CastError, ValidateError, UnmarshalError,
15+
)
1416

1517
log = logging.getLogger(__name__)
1618

@@ -110,7 +112,7 @@ def cast(self, value):
110112

111113
try:
112114
return self.schema.cast(deserialized)
113-
except OpenAPISchemaError as exc:
115+
except CastError as exc:
114116
raise InvalidParameterValue(self.name, exc)
115117

116118
def unmarshal(self, value, custom_formatters=None, resolver=None):
@@ -119,7 +121,7 @@ def unmarshal(self, value, custom_formatters=None, resolver=None):
119121

120122
try:
121123
self.schema.validate(value, resolver=resolver)
122-
except OpenAPISchemaError as exc:
124+
except ValidateError as exc:
123125
raise InvalidParameterValue(self.name, exc)
124126

125127
try:
@@ -128,5 +130,5 @@ def unmarshal(self, value, custom_formatters=None, resolver=None):
128130
custom_formatters=custom_formatters,
129131
strict=True,
130132
)
131-
except OpenAPISchemaError as exc:
133+
except UnmarshalError as exc:
132134
raise InvalidParameterValue(self.name, exc)

openapi_core/schema/schemas/exceptions.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ class ValidateError(OpenAPISchemaError):
2323
pass
2424

2525

26-
class UnmarshallError(OpenAPISchemaError):
27-
"""Schema unmarshall operation error"""
26+
class UnmarshalError(OpenAPISchemaError):
27+
"""Schema unmarshal operation error"""
2828
pass
2929

3030

3131
@attr.s(hash=True)
32-
class UnmarshallValueError(UnmarshallError):
32+
class UnmarshalValueError(UnmarshalError):
3333
"""Failed to unmarshal value to type"""
3434
value = attr.ib()
3535
type = attr.ib()
@@ -57,7 +57,7 @@ def __str__(self):
5757
).format(value=self.value, type=self.type, errors=errors)
5858

5959

60-
class UnmarshallerError(UnmarshallError):
60+
class UnmarshallerError(UnmarshalError):
6161
"""Unmarshaller error"""
6262
pass
6363

openapi_core/schema/schemas/models.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType
1717
from openapi_core.schema.schemas.exceptions import (
1818
CastError, InvalidSchemaValue,
19-
UnmarshallerError, UnmarshallValueError, UnmarshallError,
19+
UnmarshallerError, UnmarshalValueError, UnmarshalError,
2020
)
2121
from openapi_core.schema.schemas.util import (
2222
forcebool, format_date, format_datetime, format_byte, format_uuid,
@@ -202,12 +202,12 @@ def unmarshal(self, value, custom_formatters=None, strict=True):
202202
warnings.warn("The schema is deprecated", DeprecationWarning)
203203
if value is None:
204204
if not self.nullable:
205-
raise UnmarshallError(
205+
raise UnmarshalError(
206206
"Null value for non-nullable schema", value, self.type)
207207
return self.default
208208

209209
if self.enum and value not in self.enum:
210-
raise UnmarshallError("Invalid value for enum: {0}".format(value))
210+
raise UnmarshalError("Invalid value for enum: {0}".format(value))
211211

212212
unmarshal_mapping = self.get_unmarshal_mapping(
213213
custom_formatters=custom_formatters, strict=strict)
@@ -219,7 +219,7 @@ def unmarshal(self, value, custom_formatters=None, strict=True):
219219
try:
220220
unmarshalled = unmarshal_callable(value)
221221
except ValueError as exc:
222-
raise UnmarshallValueError(value, self.type, exc)
222+
raise UnmarshalValueError(value, self.type, exc)
223223

224224
return unmarshalled
225225

@@ -254,7 +254,7 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
254254
for subschema in self.one_of:
255255
try:
256256
unmarshalled = subschema.unmarshal(value, custom_formatters)
257-
except UnmarshallError:
257+
except UnmarshalError:
258258
continue
259259
else:
260260
if result is not None:
@@ -271,7 +271,7 @@ def _unmarshal_any(self, value, custom_formatters=None, strict=True):
271271
unmarshal_callable = unmarshal_mapping[schema_type]
272272
try:
273273
return unmarshal_callable(value)
274-
except (UnmarshallError, ValueError):
274+
except (UnmarshalError, ValueError):
275275
continue
276276

277277
log.warning("failed to unmarshal any type")
@@ -300,7 +300,7 @@ def _unmarshal_object(self, value, model_factory=None,
300300
try:
301301
unmarshalled = self._unmarshal_properties(
302302
value, one_of_schema, custom_formatters=custom_formatters)
303-
except (UnmarshallError, ValueError):
303+
except (UnmarshalError, ValueError):
304304
pass
305305
else:
306306
if properties is not None:

openapi_core/validation/request/validators.py

+25-13
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22
from itertools import chain
33
from six import iteritems
44

5-
from openapi_core.schema.exceptions import OpenAPIMappingError
6-
from openapi_core.schema.parameters.exceptions import MissingParameter
5+
from openapi_core.schema.media_types.exceptions import (
6+
InvalidMediaTypeValue, InvalidContentType,
7+
)
8+
from openapi_core.schema.operations.exceptions import InvalidOperation
9+
from openapi_core.schema.parameters.exceptions import (
10+
OpenAPIParameterError, MissingRequiredParameter,
11+
)
12+
from openapi_core.schema.paths.exceptions import InvalidPath
13+
from openapi_core.schema.request_bodies.exceptions import MissingRequestBody
14+
from openapi_core.schema.servers.exceptions import InvalidServer
715
from openapi_core.validation.request.datatypes import (
816
RequestParameters, RequestValidationResult,
917
)
@@ -20,7 +28,7 @@ def validate(self, request):
2028
try:
2129
server = self.spec.get_server(request.full_url_pattern)
2230
# don't process if server errors
23-
except OpenAPIMappingError as exc:
31+
except InvalidServer as exc:
2432
return RequestValidationResult([exc, ], None, None)
2533

2634
operation_pattern = get_operation_pattern(
@@ -29,10 +37,14 @@ def validate(self, request):
2937

3038
try:
3139
path = self.spec[operation_pattern]
40+
except InvalidPath as exc:
41+
return RequestValidationResult([exc, ], None, None)
42+
43+
try:
3244
operation = self.spec.get_operation(
3345
operation_pattern, request.method)
3446
# don't process if operation errors
35-
except OpenAPIMappingError as exc:
47+
except InvalidOperation as exc:
3648
return RequestValidationResult([exc, ], None, None)
3749

3850
params, params_errors = self._get_parameters(
@@ -59,15 +71,15 @@ def _get_parameters(self, request, params):
5971
seen.add((param_name, param.location.value))
6072
try:
6173
raw_value = param.get_raw_value(request)
62-
except MissingParameter:
63-
continue
64-
except OpenAPIMappingError as exc:
74+
except MissingRequiredParameter as exc:
6575
errors.append(exc)
6676
continue
77+
except OpenAPIParameterError:
78+
continue
6779

6880
try:
6981
casted = param.cast(raw_value)
70-
except OpenAPIMappingError as exc:
82+
except OpenAPIParameterError as exc:
7183
errors.append(exc)
7284
continue
7385

@@ -76,7 +88,7 @@ def _get_parameters(self, request, params):
7688
casted, self.custom_formatters,
7789
resolver=self.spec._resolver,
7890
)
79-
except OpenAPIMappingError as exc:
91+
except OpenAPIParameterError as exc:
8092
errors.append(exc)
8193
else:
8294
locations.setdefault(param.location.value, {})
@@ -93,25 +105,25 @@ def _get_body(self, request, operation):
93105
body = None
94106
try:
95107
media_type = operation.request_body[request.mimetype]
96-
except OpenAPIMappingError as exc:
108+
except InvalidContentType as exc:
97109
errors.append(exc)
98110
else:
99111
try:
100112
raw_body = operation.request_body.get_value(request)
101-
except OpenAPIMappingError as exc:
113+
except MissingRequestBody as exc:
102114
errors.append(exc)
103115
else:
104116
try:
105117
casted = media_type.cast(raw_body)
106-
except OpenAPIMappingError as exc:
118+
except InvalidMediaTypeValue as exc:
107119
errors.append(exc)
108120
else:
109121
try:
110122
body = media_type.unmarshal(
111123
casted, self.custom_formatters,
112124
resolver=self.spec._resolver,
113125
)
114-
except OpenAPIMappingError as exc:
126+
except InvalidMediaTypeValue as exc:
115127
errors.append(exc)
116128

117129
return body, errors

openapi_core/validation/response/validators.py

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
"""OpenAPI core validation response validators module"""
2-
from openapi_core.schema.exceptions import OpenAPIMappingError
2+
from openapi_core.schema.operations.exceptions import InvalidOperation
3+
from openapi_core.schema.media_types.exceptions import (
4+
InvalidMediaTypeValue, InvalidContentType,
5+
)
6+
from openapi_core.schema.responses.exceptions import (
7+
InvalidResponse, MissingResponseContent,
8+
)
9+
from openapi_core.schema.servers.exceptions import InvalidServer
310
from openapi_core.validation.response.datatypes import ResponseValidationResult
411
from openapi_core.validation.util import get_operation_pattern
512

@@ -14,7 +21,7 @@ def validate(self, request, response):
1421
try:
1522
server = self.spec.get_server(request.full_url_pattern)
1623
# don't process if server errors
17-
except OpenAPIMappingError as exc:
24+
except InvalidServer as exc:
1825
return ResponseValidationResult([exc, ], None, None)
1926

2027
operation_pattern = get_operation_pattern(
@@ -25,14 +32,14 @@ def validate(self, request, response):
2532
operation = self.spec.get_operation(
2633
operation_pattern, request.method)
2734
# don't process if operation errors
28-
except OpenAPIMappingError as exc:
35+
except InvalidOperation as exc:
2936
return ResponseValidationResult([exc, ], None, None)
3037

3138
try:
3239
operation_response = operation.get_response(
3340
str(response.status_code))
3441
# don't process if operation response errors
35-
except OpenAPIMappingError as exc:
42+
except InvalidResponse as exc:
3643
return ResponseValidationResult([exc, ], None, None)
3744

3845
data, data_errors = self._get_data(response, operation_response)
@@ -52,25 +59,25 @@ def _get_data(self, response, operation_response):
5259
data = None
5360
try:
5461
media_type = operation_response[response.mimetype]
55-
except OpenAPIMappingError as exc:
62+
except InvalidContentType as exc:
5663
errors.append(exc)
5764
else:
5865
try:
5966
raw_data = operation_response.get_value(response)
60-
except OpenAPIMappingError as exc:
67+
except MissingResponseContent as exc:
6168
errors.append(exc)
6269
else:
6370
try:
6471
casted = media_type.cast(raw_data)
65-
except OpenAPIMappingError as exc:
72+
except InvalidMediaTypeValue as exc:
6673
errors.append(exc)
6774
else:
6875
try:
6976
data = media_type.unmarshal(
7077
casted, self.custom_formatters,
7178
resolver=self.spec._resolver,
7279
)
73-
except OpenAPIMappingError as exc:
80+
except InvalidMediaTypeValue as exc:
7481
errors.append(exc)
7582

7683
return data, errors

0 commit comments

Comments
 (0)