Skip to content

Commit df1f1e1

Browse files
authored
Merge pull request #691 from python-openapi/feature/use-openapi-spec-validator-spec-version-finder
Use openapi-spec-validator spec version finder
2 parents 0f5ac8e + 860ca0a commit df1f1e1

File tree

4 files changed

+105
-24
lines changed

4 files changed

+105
-24
lines changed

openapi_core/shortcuts.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
from typing import Union
66

77
from jsonschema_path import SchemaPath
8+
from openapi_spec_validator.versions import consts as versions
9+
from openapi_spec_validator.versions.datatypes import SpecVersion
10+
from openapi_spec_validator.versions.exceptions import OpenAPIVersionNotFound
11+
from openapi_spec_validator.versions.shortcuts import get_spec_version
812

913
from openapi_core.exceptions import SpecError
10-
from openapi_core.finders import SpecClasses
11-
from openapi_core.finders import SpecFinder
12-
from openapi_core.finders import SpecVersion
1314
from openapi_core.protocols import Request
1415
from openapi_core.protocols import Response
1516
from openapi_core.protocols import WebhookRequest
1617
from openapi_core.spec import Spec
18+
from openapi_core.types import SpecClasses
1719
from openapi_core.unmarshalling.request import V30RequestUnmarshaller
1820
from openapi_core.unmarshalling.request import V31RequestUnmarshaller
1921
from openapi_core.unmarshalling.request import V31WebhookRequestUnmarshaller
@@ -63,8 +65,8 @@
6365

6466
AnyRequest = Union[Request, WebhookRequest]
6567

66-
SPECS: Dict[SpecVersion, SpecClasses] = {
67-
SpecVersion("openapi", "3.0"): SpecClasses(
68+
SPEC2CLASSES: Dict[SpecVersion, SpecClasses] = {
69+
versions.OPENAPIV30: SpecClasses(
6870
V30RequestValidator,
6971
V30ResponseValidator,
7072
None,
@@ -74,7 +76,7 @@
7476
None,
7577
None,
7678
),
77-
SpecVersion("openapi", "3.1"): SpecClasses(
79+
versions.OPENAPIV31: SpecClasses(
7880
V31RequestValidator,
7981
V31ResponseValidator,
8082
V31WebhookRequestValidator,
@@ -88,7 +90,15 @@
8890

8991

9092
def get_classes(spec: SchemaPath) -> SpecClasses:
91-
return SpecFinder(SPECS).get_classes(spec)
93+
try:
94+
spec_version = get_spec_version(spec.contents())
95+
# backward compatibility
96+
except OpenAPIVersionNotFound:
97+
raise SpecError("Spec schema version not detected")
98+
try:
99+
return SPEC2CLASSES[spec_version]
100+
except KeyError:
101+
raise SpecError("Spec schema version not supported")
92102

93103

94104
def unmarshal_apicall_request(

openapi_core/finders.py renamed to openapi_core/types.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from dataclasses import dataclass
12
from typing import Mapping
23
from typing import NamedTuple
34
from typing import Optional
@@ -21,12 +22,8 @@
2122
from openapi_core.validation.validators import BaseValidator
2223

2324

24-
class SpecVersion(NamedTuple):
25-
name: str
26-
version: str
27-
28-
29-
class SpecClasses(NamedTuple):
25+
@dataclass
26+
class SpecClasses:
3027
request_validator_cls: RequestValidatorType
3128
response_validator_cls: ResponseValidatorType
3229
webhook_request_validator_cls: Optional[WebhookRequestValidatorType]
@@ -37,14 +34,3 @@ class SpecClasses(NamedTuple):
3734
webhook_response_unmarshaller_cls: Optional[
3835
WebhookResponseUnmarshallerType
3936
]
40-
41-
42-
class SpecFinder:
43-
def __init__(self, specs: Mapping[SpecVersion, SpecClasses]) -> None:
44-
self.specs = specs
45-
46-
def get_classes(self, spec: SchemaPath) -> SpecClasses:
47-
for v, classes in self.specs.items():
48-
if v.name in spec and spec[v.name].startswith(v.version):
49-
return classes
50-
raise SpecError("Spec schema version not detected")

tests/unit/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
from jsonschema_path import SchemaPath
33

44

5+
@pytest.fixture
6+
def spec_v20():
7+
return SchemaPath.from_dict({"swagger": "2.0"})
8+
9+
510
@pytest.fixture
611
def spec_v30():
712
return SchemaPath.from_dict({"openapi": "3.0.0"})

tests/unit/test_shortcuts.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ def test_spec_not_detected(self, spec_invalid):
9797
with pytest.raises(SpecError):
9898
unmarshal_apicall_request(request, spec=spec_invalid)
9999

100+
def test_spec_not_supported(self, spec_v20):
101+
request = mock.Mock(spec=Request)
102+
103+
with pytest.raises(SpecError):
104+
unmarshal_apicall_request(request, spec=spec_v20)
105+
100106
def test_request_type_invalid(self, spec_v31):
101107
request = mock.sentinel.request
102108

@@ -124,6 +130,12 @@ def test_spec_not_detected(self, spec_invalid):
124130
with pytest.raises(SpecError):
125131
unmarshal_webhook_request(request, spec=spec_invalid)
126132

133+
def test_spec_not_supported(self, spec_v20):
134+
request = mock.Mock(spec=WebhookRequest)
135+
136+
with pytest.raises(SpecError):
137+
unmarshal_webhook_request(request, spec=spec_v20)
138+
127139
def test_request_type_invalid(self, spec_v31):
128140
request = mock.sentinel.request
129141

@@ -169,6 +181,12 @@ def test_spec_not_detected(self, spec_invalid):
169181
with pytest.raises(SpecError):
170182
unmarshal_request(request, spec=spec_invalid)
171183

184+
def test_spec_not_supported(self, spec_v20):
185+
request = mock.Mock(spec=Request)
186+
187+
with pytest.raises(SpecError):
188+
unmarshal_request(request, spec=spec_v20)
189+
172190
def test_request_type_invalid(self, spec_v31):
173191
request = mock.sentinel.request
174192

@@ -257,6 +275,13 @@ def test_spec_not_detected(self, spec_invalid):
257275
with pytest.raises(SpecError):
258276
unmarshal_apicall_response(request, response, spec=spec_invalid)
259277

278+
def test_spec_not_supported(self, spec_v20):
279+
request = mock.Mock(spec=Request)
280+
response = mock.Mock(spec=Response)
281+
282+
with pytest.raises(SpecError):
283+
unmarshal_apicall_response(request, response, spec=spec_v20)
284+
260285
def test_request_type_invalid(self, spec_v31):
261286
request = mock.sentinel.request
262287
response = mock.Mock(spec=Response)
@@ -297,6 +322,13 @@ def test_spec_not_detected(self, spec_invalid):
297322
with pytest.raises(SpecError):
298323
unmarshal_response(request, response, spec=spec_invalid)
299324

325+
def test_spec_not_supported(self, spec_v20):
326+
request = mock.Mock(spec=Request)
327+
response = mock.Mock(spec=Response)
328+
329+
with pytest.raises(SpecError):
330+
unmarshal_response(request, response, spec=spec_v20)
331+
300332
def test_request_type_invalid(self, spec_v31):
301333
request = mock.sentinel.request
302334
response = mock.Mock(spec=Response)
@@ -404,6 +436,13 @@ def test_spec_not_detected(self, spec_invalid):
404436
with pytest.raises(SpecError):
405437
unmarshal_webhook_response(request, response, spec=spec_invalid)
406438

439+
def test_spec_not_supported(self, spec_v20):
440+
request = mock.Mock(spec=WebhookRequest)
441+
response = mock.Mock(spec=Response)
442+
443+
with pytest.raises(SpecError):
444+
unmarshal_webhook_response(request, response, spec=spec_v20)
445+
407446
def test_request_type_invalid(self, spec_v31):
408447
request = mock.sentinel.request
409448
response = mock.Mock(spec=Response)
@@ -463,6 +502,12 @@ def test_spec_not_detected(self, spec_invalid):
463502
with pytest.raises(SpecError):
464503
validate_apicall_request(request, spec=spec_invalid)
465504

505+
def test_spec_not_supported(self, spec_v20):
506+
request = mock.Mock(spec=Request)
507+
508+
with pytest.raises(SpecError):
509+
validate_apicall_request(request, spec=spec_v20)
510+
466511
def test_request_type_invalid(self, spec_v31):
467512
request = mock.sentinel.request
468513

@@ -502,6 +547,12 @@ def test_spec_not_detected(self, spec_invalid):
502547
with pytest.raises(SpecError):
503548
validate_webhook_request(request, spec=spec_invalid)
504549

550+
def test_spec_not_supported(self, spec_v20):
551+
request = mock.Mock(spec=WebhookRequest)
552+
553+
with pytest.raises(SpecError):
554+
validate_webhook_request(request, spec=spec_v20)
555+
505556
def test_request_type_invalid(self, spec_v31):
506557
request = mock.sentinel.request
507558

@@ -548,6 +599,13 @@ def test_spec_not_detected(self, spec_invalid):
548599
with pytest.warns(DeprecationWarning):
549600
validate_request(request, spec=spec_invalid)
550601

602+
def test_spec_not_detected(self, spec_v20):
603+
request = mock.Mock(spec=Request)
604+
605+
with pytest.raises(SpecError):
606+
with pytest.warns(DeprecationWarning):
607+
validate_request(request, spec=spec_v20)
608+
551609
def test_request_type_invalid(self, spec_v31):
552610
request = mock.sentinel.request
553611

@@ -705,6 +763,13 @@ def test_spec_not_detected(self, spec_invalid):
705763
with pytest.raises(SpecError):
706764
validate_apicall_response(request, response, spec=spec_invalid)
707765

766+
def test_spec_not_supported(self, spec_v20):
767+
request = mock.Mock(spec=Request)
768+
response = mock.Mock(spec=Response)
769+
770+
with pytest.raises(SpecError):
771+
validate_apicall_response(request, response, spec=spec_v20)
772+
708773
def test_request_type_invalid(self, spec_v31):
709774
request = mock.sentinel.request
710775
response = mock.Mock(spec=Response)
@@ -758,6 +823,13 @@ def test_spec_not_detected(self, spec_invalid):
758823
with pytest.raises(SpecError):
759824
validate_webhook_response(request, response, spec=spec_invalid)
760825

826+
def test_spec_not_supported(self, spec_v20):
827+
request = mock.Mock(spec=WebhookRequest)
828+
response = mock.Mock(spec=Response)
829+
830+
with pytest.raises(SpecError):
831+
validate_webhook_response(request, response, spec=spec_v20)
832+
761833
def test_request_type_invalid(self, spec_v31):
762834
request = mock.sentinel.request
763835
response = mock.Mock(spec=Response)
@@ -819,6 +891,14 @@ def test_spec_not_detected(self, spec_invalid):
819891
with pytest.warns(DeprecationWarning):
820892
validate_response(request, response, spec=spec_invalid)
821893

894+
def test_spec_not_supported(self, spec_v20):
895+
request = mock.Mock(spec=Request)
896+
response = mock.Mock(spec=Response)
897+
898+
with pytest.raises(SpecError):
899+
with pytest.warns(DeprecationWarning):
900+
validate_response(request, response, spec=spec_v20)
901+
822902
def test_request_type_invalid(self, spec_v31):
823903
request = mock.sentinel.request
824904
response = mock.Mock(spec=Response)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy