Skip to content

Versions submodule #291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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