Skip to content

Commit 99fb081

Browse files
authored
Merge pull request #482 from p1c2u/feature/make-shortcuts-backward-compatible
Shortcuts backward compatible
2 parents 82fce49 + ffbd2ef commit 99fb081

File tree

3 files changed

+132
-67
lines changed

3 files changed

+132
-67
lines changed

openapi_core/validation/shortcuts.py

+32-6
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,19 @@ def validate_request(
8383
cls: Optional[AnyRequestValidatorType] = None,
8484
**validator_kwargs: Any,
8585
) -> RequestValidationResult:
86+
if isinstance(spec, (Request, WebhookRequest)) and isinstance(
87+
request, Spec
88+
):
89+
warnings.warn(
90+
"spec parameter as a first argument is deprecated. "
91+
"Move it to second argument instead.",
92+
DeprecationWarning,
93+
)
94+
request, spec = spec, request
8695
if not isinstance(request, (Request, WebhookRequest)):
87-
raise TypeError("'request' is not (Webhook)Request")
96+
raise TypeError("'request' argument is not type of (Webhook)Request")
97+
if not isinstance(spec, Spec):
98+
raise TypeError("'spec' argument is not type of Spec")
8899
if validator is not None and isinstance(request, Request):
89100
warnings.warn(
90101
"validator parameter is deprecated. Use cls instead.",
@@ -113,18 +124,33 @@ def validate_request(
113124

114125

115126
def validate_response(
116-
request: AnyRequest,
117-
response: Response,
118-
spec: Spec,
127+
request: Union[Request, WebhookRequest, Spec],
128+
response: Union[Response, Request, WebhookRequest],
129+
spec: Union[Spec, Response],
119130
base_url: Optional[str] = None,
120131
validator: Optional[SpecResponseValidatorProxy] = None,
121132
cls: Optional[AnyResponseValidatorType] = None,
122133
**validator_kwargs: Any,
123134
) -> ResponseValidationResult:
135+
if (
136+
isinstance(request, Spec)
137+
and isinstance(response, (Request, WebhookRequest))
138+
and isinstance(spec, Response)
139+
):
140+
warnings.warn(
141+
"spec parameter as a first argument is deprecated. "
142+
"Move it to third argument instead.",
143+
DeprecationWarning,
144+
)
145+
args = request, response, spec
146+
spec, request, response = args
147+
124148
if not isinstance(request, (Request, WebhookRequest)):
125-
raise TypeError("'request' is not (Webhook)Request")
149+
raise TypeError("'request' argument is not type of (Webhook)Request")
126150
if not isinstance(response, Response):
127-
raise TypeError("'response' is not Response")
151+
raise TypeError("'response' argument is not type of Response")
152+
if not isinstance(spec, Spec):
153+
raise TypeError("'spec' argument is not type of Spec")
128154
if validator is not None and isinstance(request, Request):
129155
warnings.warn(
130156
"validator parameter is deprecated. Use cls instead.",

tests/unit/validation/conftest.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest
2+
3+
from openapi_core import Spec
4+
5+
6+
@pytest.fixture
7+
def spec_v30():
8+
return Spec.from_dict({"openapi": "3.0"}, validator=None)
9+
10+
11+
@pytest.fixture
12+
def spec_v31():
13+
return Spec.from_dict({"openapi": "3.1"}, validator=None)
14+
15+
16+
@pytest.fixture
17+
def spec_invalid():
18+
return Spec.from_dict({}, validator=None)

tests/unit/validation/test_shortcuts.py

+82-61
Original file line numberDiff line numberDiff line change
@@ -18,62 +18,77 @@
1818

1919

2020
class TestValidateRequest:
21-
def test_spec_not_detected(self):
22-
spec = {}
21+
def test_spec_not_detected(self, spec_invalid):
2322
request = mock.Mock(spec=Request)
2423

2524
with pytest.raises(ValidatorDetectError):
26-
validate_request(request, spec=spec)
25+
validate_request(request, spec=spec_invalid)
2726

28-
def test_request_type_error(self):
29-
spec = {"openapi": "3.1"}
27+
def test_request_type_error(self, spec_v31):
3028
request = mock.sentinel.request
3129

30+
with pytest.raises(TypeError):
31+
validate_request(request, spec=spec_v31)
32+
33+
def test_spec_type_error(self):
34+
request = mock.Mock(spec=Request)
35+
spec = mock.sentinel.spec
36+
3237
with pytest.raises(TypeError):
3338
validate_request(request, spec=spec)
3439

3540
@mock.patch(
3641
"openapi_core.validation.request.validators.RequestValidator.validate",
3742
)
38-
def test_request(self, mock_validate):
39-
spec = {"openapi": "3.1"}
43+
def test_request(self, mock_validate, spec_v31):
44+
request = mock.Mock(spec=Request)
45+
46+
result = validate_request(request, spec=spec_v31)
47+
48+
assert result == mock_validate.return_value
49+
mock_validate.validate.aasert_called_once_with(request)
50+
51+
@mock.patch(
52+
"openapi_core.validation.request.validators.RequestValidator.validate",
53+
)
54+
def test_spec_as_first_arg_deprecated(self, mock_validate, spec_v31):
4055
request = mock.Mock(spec=Request)
4156

42-
result = validate_request(request, spec=spec)
57+
with pytest.warns(DeprecationWarning):
58+
result = validate_request(spec_v31, request)
4359

4460
assert result == mock_validate.return_value
4561
mock_validate.validate.aasert_called_once_with(request)
4662

4763
@mock.patch(
4864
"openapi_core.validation.request.validators.RequestValidator.validate",
4965
)
50-
def test_request_error(self, mock_validate):
51-
spec = {"openapi": "3.1"}
66+
def test_request_error(self, mock_validate, spec_v31):
5267
request = mock.Mock(spec=Request)
5368
mock_validate.return_value = ResultMock(error_to_raise=ValueError)
5469

5570
with pytest.raises(ValueError):
56-
validate_request(request, spec=spec)
71+
validate_request(request, spec=spec_v31)
5772

5873
mock_validate.aasert_called_once_with(request)
5974

60-
def test_validator(self):
61-
spec = mock.sentinel.spec
75+
def test_validator(self, spec_v31):
6276
request = mock.Mock(spec=Request)
6377
validator = mock.Mock(spec=RequestValidator)
6478

6579
with pytest.warns(DeprecationWarning):
66-
result = validate_request(request, spec=spec, validator=validator)
80+
result = validate_request(
81+
request, spec=spec_v31, validator=validator
82+
)
6783

6884
assert result == validator.validate.return_value
6985
validator.validate.aasert_called_once_with(request)
7086

71-
def test_validator_cls(self):
72-
spec = mock.sentinel.spec
87+
def test_validator_cls(self, spec_v31):
7388
request = mock.Mock(spec=Request)
7489
validator_cls = mock.Mock(spec=RequestValidator)
7590

76-
result = validate_request(request, spec=spec, cls=validator_cls)
91+
result = validate_request(request, spec=spec_v31, cls=validator_cls)
7792

7893
assert result == validator_cls().validate.return_value
7994
validator_cls().validate.aasert_called_once_with(request)
@@ -82,82 +97,95 @@ def test_validator_cls(self):
8297
"openapi_core.validation.request.validators.WebhookRequestValidator."
8398
"validate",
8499
)
85-
def test_webhook_request(self, mock_validate):
86-
spec = {"openapi": "3.1"}
100+
def test_webhook_request(self, mock_validate, spec_v31):
87101
request = mock.Mock(spec=WebhookRequest)
88102

89-
result = validate_request(request, spec=spec)
103+
result = validate_request(request, spec=spec_v31)
90104

91105
assert result == mock_validate.return_value
92106
mock_validate.validate.aasert_called_once_with(request)
93107

94-
def test_webhook_request_validator_not_found(self):
95-
spec = {"openapi": "3.0"}
108+
def test_webhook_request_validator_not_found(self, spec_v30):
96109
request = mock.Mock(spec=WebhookRequest)
97110

98111
with pytest.raises(ValidatorDetectError):
99-
validate_request(request, spec=spec)
112+
validate_request(request, spec=spec_v30)
100113

101114
@mock.patch(
102115
"openapi_core.validation.request.validators.WebhookRequestValidator."
103116
"validate",
104117
)
105-
def test_webhook_request_error(self, mock_validate):
106-
spec = {"openapi": "3.1"}
118+
def test_webhook_request_error(self, mock_validate, spec_v31):
107119
request = mock.Mock(spec=WebhookRequest)
108120
mock_validate.return_value = ResultMock(error_to_raise=ValueError)
109121

110122
with pytest.raises(ValueError):
111-
validate_request(request, spec=spec)
123+
validate_request(request, spec=spec_v31)
112124

113125
mock_validate.aasert_called_once_with(request)
114126

115-
def test_webhook_validator_cls(self):
116-
spec = mock.sentinel.spec
127+
def test_webhook_validator_cls(self, spec_v31):
117128
request = mock.Mock(spec=WebhookRequest)
118129
validator_cls = mock.Mock(spec=WebhookRequestValidator)
119130

120-
result = validate_request(request, spec=spec, cls=validator_cls)
131+
result = validate_request(request, spec=spec_v31, cls=validator_cls)
121132

122133
assert result == validator_cls().validate.return_value
123134
validator_cls().validate.aasert_called_once_with(request)
124135

125136

126137
class TestValidateResponse:
127-
def test_spec_not_detected(self):
128-
spec = {}
138+
def test_spec_not_detected(self, spec_invalid):
129139
request = mock.Mock(spec=Request)
130140
response = mock.Mock(spec=Response)
131141

132142
with pytest.raises(ValidatorDetectError):
133-
validate_response(request, response, spec=spec)
143+
validate_response(request, response, spec=spec_invalid)
134144

135-
def test_request_type_error(self):
136-
spec = {"openapi": "3.1"}
145+
def test_request_type_error(self, spec_v31):
137146
request = mock.sentinel.request
138147
response = mock.Mock(spec=Response)
139148

140149
with pytest.raises(TypeError):
141-
validate_response(request, response, spec=spec)
150+
validate_response(request, response, spec=spec_v31)
142151

143-
def test_response_type_error(self):
144-
spec = {"openapi": "3.1"}
152+
def test_response_type_error(self, spec_v31):
145153
request = mock.Mock(spec=Request)
146154
response = mock.sentinel.response
147155

156+
with pytest.raises(TypeError):
157+
validate_response(request, response, spec=spec_v31)
158+
159+
def test_spec_type_error(self):
160+
request = mock.Mock(spec=Request)
161+
response = mock.Mock(spec=Response)
162+
spec = mock.sentinel.spec
163+
148164
with pytest.raises(TypeError):
149165
validate_response(request, response, spec=spec)
150166

151167
@mock.patch(
152168
"openapi_core.validation.response.validators.ResponseValidator."
153169
"validate",
154170
)
155-
def test_request_response(self, mock_validate):
156-
spec = {"openapi": "3.1"}
171+
def test_request_response(self, mock_validate, spec_v31):
172+
request = mock.Mock(spec=Request)
173+
response = mock.Mock(spec=Response)
174+
175+
result = validate_response(request, response, spec=spec_v31)
176+
177+
assert result == mock_validate.return_value
178+
mock_validate.aasert_called_once_with(request, response)
179+
180+
@mock.patch(
181+
"openapi_core.validation.response.validators.ResponseValidator."
182+
"validate",
183+
)
184+
def test_spec_as_first_arg_deprecated(self, mock_validate, spec_v31):
157185
request = mock.Mock(spec=Request)
158186
response = mock.Mock(spec=Response)
159187

160-
result = validate_response(request, response, spec=spec)
188+
result = validate_response(spec_v31, request, response)
161189

162190
assert result == mock_validate.return_value
163191
mock_validate.aasert_called_once_with(request, response)
@@ -166,62 +194,57 @@ def test_request_response(self, mock_validate):
166194
"openapi_core.validation.response.validators.ResponseValidator."
167195
"validate",
168196
)
169-
def test_request_response_error(self, mock_validate):
170-
spec = {"openapi": "3.1"}
197+
def test_request_response_error(self, mock_validate, spec_v31):
171198
request = mock.Mock(spec=Request)
172199
response = mock.Mock(spec=Response)
173200
mock_validate.return_value = ResultMock(error_to_raise=ValueError)
174201

175202
with pytest.raises(ValueError):
176-
validate_response(request, response, spec=spec)
203+
validate_response(request, response, spec=spec_v31)
177204

178205
mock_validate.aasert_called_once_with(request, response)
179206

180-
def test_validator(self):
181-
spec = mock.sentinel.spec
207+
def test_validator(self, spec_v31):
182208
request = mock.Mock(spec=Request)
183209
response = mock.Mock(spec=Response)
184210
validator = mock.Mock(spec=ResponseValidator)
185211

186212
with pytest.warns(DeprecationWarning):
187213
result = validate_response(
188-
request, response, spec=spec, validator=validator
214+
request, response, spec=spec_v31, validator=validator
189215
)
190216

191217
assert result == validator.validate.return_value
192218
validator.validate.aasert_called_once_with(request)
193219

194-
def test_validator_cls(self):
195-
spec = mock.sentinel.spec
220+
def test_validator_cls(self, spec_v31):
196221
request = mock.Mock(spec=Request)
197222
response = mock.Mock(spec=Response)
198223
validator_cls = mock.Mock(spec=ResponseValidator)
199224

200225
result = validate_response(
201-
request, response, spec=spec, cls=validator_cls
226+
request, response, spec=spec_v31, cls=validator_cls
202227
)
203228

204229
assert result == validator_cls().validate.return_value
205230
validator_cls().validate.aasert_called_once_with(request)
206231

207-
def test_webhook_response_validator_not_found(self):
208-
spec = {"openapi": "3.0"}
232+
def test_webhook_response_validator_not_found(self, spec_v30):
209233
request = mock.Mock(spec=WebhookRequest)
210234
response = mock.Mock(spec=Response)
211235

212236
with pytest.raises(ValidatorDetectError):
213-
validate_response(request, response, spec=spec)
237+
validate_response(request, response, spec=spec_v30)
214238

215239
@mock.patch(
216240
"openapi_core.validation.response.validators.WebhookResponseValidator."
217241
"validate",
218242
)
219-
def test_webhook_request(self, mock_validate):
220-
spec = {"openapi": "3.1"}
243+
def test_webhook_request(self, mock_validate, spec_v31):
221244
request = mock.Mock(spec=WebhookRequest)
222245
response = mock.Mock(spec=Response)
223246

224-
result = validate_response(request, response, spec=spec)
247+
result = validate_response(request, response, spec=spec_v31)
225248

226249
assert result == mock_validate.return_value
227250
mock_validate.aasert_called_once_with(request, response)
@@ -230,25 +253,23 @@ def test_webhook_request(self, mock_validate):
230253
"openapi_core.validation.response.validators.WebhookResponseValidator."
231254
"validate",
232255
)
233-
def test_webhook_request_error(self, mock_validate):
234-
spec = {"openapi": "3.1"}
256+
def test_webhook_request_error(self, mock_validate, spec_v31):
235257
request = mock.Mock(spec=WebhookRequest)
236258
response = mock.Mock(spec=Response)
237259
mock_validate.return_value = ResultMock(error_to_raise=ValueError)
238260

239261
with pytest.raises(ValueError):
240-
validate_response(request, response, spec=spec)
262+
validate_response(request, response, spec=spec_v31)
241263

242264
mock_validate.aasert_called_once_with(request, response)
243265

244-
def test_webhook_response_cls(self):
245-
spec = mock.sentinel.spec
266+
def test_webhook_response_cls(self, spec_v31):
246267
request = mock.Mock(spec=WebhookRequest)
247268
response = mock.Mock(spec=Response)
248269
validator_cls = mock.Mock(spec=WebhookResponseValidator)
249270

250271
result = validate_response(
251-
request, response, spec=spec, cls=validator_cls
272+
request, response, spec=spec_v31, cls=validator_cls
252273
)
253274

254275
assert result == validator_cls().validate.return_value

0 commit comments

Comments
 (0)