Skip to content

Commit

Permalink
Merge pull request #291 from python-openapi/feature/versions-submodule
Browse files Browse the repository at this point in the history
Versions submodule
  • Loading branch information
p1c2u committed Oct 11, 2023
2 parents 74a6c5f + db016fa commit 45bbe0a
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 31 deletions.
24 changes: 16 additions & 8 deletions openapi_spec_validator/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,29 @@
from openapi_spec_validator.validation import OpenAPIV2SpecValidator
from openapi_spec_validator.validation import OpenAPIV30SpecValidator
from openapi_spec_validator.validation import OpenAPIV31SpecValidator
from openapi_spec_validator.validation.finders import SpecFinder
from openapi_spec_validator.validation.finders import SpecVersion
from openapi_spec_validator.validation.exceptions import ValidatorDetectError
from openapi_spec_validator.validation.protocols import SupportsValidation
from openapi_spec_validator.validation.types import SpecValidatorType
from openapi_spec_validator.validation.validators import SpecValidator

SPECS: Mapping[SpecVersion, SpecValidatorType] = {
SpecVersion("swagger", "2.0"): OpenAPIV2SpecValidator,
SpecVersion("openapi", "3.0"): OpenAPIV30SpecValidator,
SpecVersion("openapi", "3.1"): OpenAPIV31SpecValidator,
from openapi_spec_validator.versions import consts as versions
from openapi_spec_validator.versions.datatypes import SpecVersion
from openapi_spec_validator.versions.exceptions import OpenAPIVersionNotFound
from openapi_spec_validator.versions.shortcuts import get_spec_version

SPEC2VALIDATOR: Mapping[SpecVersion, SpecValidatorType] = {
versions.OPENAPIV2: OpenAPIV2SpecValidator,
versions.OPENAPIV30: OpenAPIV30SpecValidator,
versions.OPENAPIV31: OpenAPIV31SpecValidator,
}


def get_validator_cls(spec: Schema) -> SpecValidatorType:
return SpecFinder(SPECS).find(spec)
try:
spec_version = get_spec_version(spec)
# backward compatibility
except OpenAPIVersionNotFound:
raise ValidatorDetectError
return SPEC2VALIDATOR[spec_version]


def validate_spec(
Expand Down
23 changes: 0 additions & 23 deletions openapi_spec_validator/validation/finders.py

This file was deleted.

13 changes: 13 additions & 0 deletions openapi_spec_validator/versions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from openapi_spec_validator.versions.consts import OPENAPIV2
from openapi_spec_validator.versions.consts import OPENAPIV30
from openapi_spec_validator.versions.consts import OPENAPIV31
from openapi_spec_validator.versions.datatypes import SpecVersion
from openapi_spec_validator.versions.shortcuts import get_spec_version

__all__ = [
"OPENAPIV2",
"OPENAPIV30",
"OPENAPIV31",
"SpecVersion",
"get_spec_version",
]
23 changes: 23 additions & 0 deletions openapi_spec_validator/versions/consts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import List

from openapi_spec_validator.versions.datatypes import SpecVersion

OPENAPIV2 = SpecVersion(
keyword="swagger",
major="2",
minor="0",
)

OPENAPIV30 = SpecVersion(
keyword="openapi",
major="3",
minor="0",
)

OPENAPIV31 = SpecVersion(
keyword="openapi",
major="3",
minor="1",
)

VERSIONS: List[SpecVersion] = [OPENAPIV2, OPENAPIV30, OPENAPIV31]
15 changes: 15 additions & 0 deletions openapi_spec_validator/versions/datatypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from dataclasses import dataclass


@dataclass(frozen=True)
class SpecVersion:
"""
Spec version designates the OAS feature set.
"""

keyword: str
major: str
minor: str

def __str__(self) -> str:
return f"OpenAPIV{self.major}.{self.minor}"
6 changes: 6 additions & 0 deletions openapi_spec_validator/versions/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from openapi_spec_validator.exceptions import OpenAPIError


class OpenAPIVersionNotFound(OpenAPIError):
def __str__(self) -> str:
return "Specification version not found"
26 changes: 26 additions & 0 deletions openapi_spec_validator/versions/finders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from re import compile
from typing import List

from jsonschema_spec.typing import Schema

from openapi_spec_validator.versions.datatypes import SpecVersion
from openapi_spec_validator.versions.exceptions import OpenAPIVersionNotFound


class SpecVersionFinder:
pattern = compile(r"(?P<major>\d+)\.(?P<minor>\d+)(\..*)?")

def __init__(self, versions: List[SpecVersion]) -> None:
self.versions = versions

def find(self, spec: Schema) -> SpecVersion:
for v in self.versions:
if v.keyword in spec:
version_str = spec[v.keyword]
m = self.pattern.match(version_str)
if m:
version = SpecVersion(**m.groupdict(), keyword=v.keyword)
if v == version:
return v

raise OpenAPIVersionNotFound
10 changes: 10 additions & 0 deletions openapi_spec_validator/versions/shortcuts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from jsonschema_spec.typing import Schema

from openapi_spec_validator.versions.consts import VERSIONS
from openapi_spec_validator.versions.datatypes import SpecVersion
from openapi_spec_validator.versions.finders import SpecVersionFinder


def get_spec_version(spec: Schema) -> SpecVersion:
finder = SpecVersionFinder(VERSIONS)
return finder.find(spec)
43 changes: 43 additions & 0 deletions tests/integration/test_versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import pytest

from openapi_spec_validator.versions import consts as versions
from openapi_spec_validator.versions.exceptions import OpenAPIVersionNotFound
from openapi_spec_validator.versions.shortcuts import get_spec_version


class TestGetSpecVersion:
def test_no_keyword(self):
spec = {}

with pytest.raises(OpenAPIVersionNotFound):
get_spec_version(spec)

@pytest.mark.parametrize("keyword", ["swagger", "openapi"])
@pytest.mark.parametrize("version", ["x.y.z", "xyz2.0.0", "2.xyz0.0"])
def test_invalid(self, keyword, version):
spec = {
keyword: version,
}

with pytest.raises(OpenAPIVersionNotFound):
get_spec_version(spec)

@pytest.mark.parametrize(
"keyword,version,expected",
[
("swagger", "2.0", versions.OPENAPIV2),
("openapi", "3.0.0", versions.OPENAPIV30),
("openapi", "3.0.1", versions.OPENAPIV30),
("openapi", "3.0.2", versions.OPENAPIV30),
("openapi", "3.0.3", versions.OPENAPIV30),
("openapi", "3.1.0", versions.OPENAPIV31),
],
)
def test_valid(self, keyword, version, expected):
spec = {
keyword: version,
}

result = get_spec_version(spec)

assert result == expected

0 comments on commit 45bbe0a

Please sign in to comment.