Skip to content

Commit 59e9e6c

Browse files
committed
Validators refactor
1 parent ff01252 commit 59e9e6c

File tree

13 files changed

+726
-347
lines changed

13 files changed

+726
-347
lines changed

openapi_spec_validator/__main__.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010
from openapi_spec_validator.readers import read_from_filename
1111
from openapi_spec_validator.readers import read_from_stdin
12-
from openapi_spec_validator.validation import openapi_spec_validator_proxy
13-
from openapi_spec_validator.validation import openapi_v2_spec_validator
14-
from openapi_spec_validator.validation import openapi_v30_spec_validator
15-
from openapi_spec_validator.validation import openapi_v31_spec_validator
12+
from openapi_spec_validator.shortcuts import get_validator_cls
13+
from openapi_spec_validator.validation import OpenAPIV2SpecValidator
14+
from openapi_spec_validator.validation import OpenAPIV30SpecValidator
15+
from openapi_spec_validator.validation import OpenAPIV31SpecValidator
1616

1717
logger = logging.getLogger(__name__)
1818
logging.basicConfig(
@@ -91,19 +91,22 @@ def main(args: Optional[Sequence[str]] = None) -> None:
9191

9292
# choose the validator
9393
validators = {
94-
"detect": openapi_spec_validator_proxy,
95-
"2.0": openapi_v2_spec_validator,
96-
"3.0": openapi_v30_spec_validator,
97-
"3.1": openapi_v31_spec_validator,
94+
"2.0": OpenAPIV2SpecValidator,
95+
"3.0": OpenAPIV30SpecValidator,
96+
"3.1": OpenAPIV31SpecValidator,
9897
# backward compatibility
99-
"3.0.0": openapi_v30_spec_validator,
100-
"3.1.0": openapi_v31_spec_validator,
98+
"3.0.0": OpenAPIV30SpecValidator,
99+
"3.1.0": OpenAPIV31SpecValidator,
101100
}
102-
validator = validators[args_parsed.schema]
101+
if args_parsed.schema == "detect":
102+
validator_cls = get_validator_cls(spec)
103+
else:
104+
validator_cls = validators[args_parsed.schema]
103105

106+
validator = validator_cls(spec, base_uri=base_uri)
104107
# validate
105108
try:
106-
validator.validate(spec, base_uri=base_uri)
109+
validator.validate()
107110
except ValidationError as exc:
108111
print_validationerror(filename, exc, args_parsed.errors)
109112
sys.exit(1)

openapi_spec_validator/exceptions.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
class OpenAPISpecValidatorError(Exception):
1+
class OpenAPIError(Exception):
2+
pass
3+
4+
5+
class OpenAPISpecValidatorError(OpenAPIError):
26
pass

openapi_spec_validator/schemas/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""OpenAIP spec validator schemas module."""
22
from functools import partial
33

4+
from jsonschema.validators import Draft4Validator
5+
from jsonschema.validators import Draft202012Validator
46
from lazy_object_proxy import Proxy
57

68
from openapi_spec_validator.schemas.utils import get_schema_content
@@ -17,3 +19,11 @@
1719

1820
# alias to the latest v3 version
1921
schema_v3 = schema_v31
22+
23+
get_openapi_v2_schema_validator = partial(Draft4Validator, schema_v2)
24+
get_openapi_v30_schema_validator = partial(Draft4Validator, schema_v30)
25+
get_openapi_v31_schema_validator = partial(Draft202012Validator, schema_v31)
26+
27+
openapi_v2_schema_validator = Proxy(get_openapi_v2_schema_validator)
28+
openapi_v30_schema_validator = Proxy(get_openapi_v30_schema_validator)
29+
openapi_v31_schema_validator = Proxy(get_openapi_v31_schema_validator)

openapi_spec_validator/shortcuts.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,57 @@
11
"""OpenAPI spec validator shortcuts module."""
2+
import warnings
23
from typing import Any
34
from typing import Hashable
45
from typing import Mapping
56
from typing import Optional
7+
from typing import Type
68

79
from jsonschema_spec.handlers import all_urls_handler
10+
from jsonschema_spec.typing import Schema
811

9-
from openapi_spec_validator.validation import openapi_spec_validator_proxy
12+
from openapi_spec_validator.validation import OpenAPIV2SpecValidator
13+
from openapi_spec_validator.validation import OpenAPIV30SpecValidator
14+
from openapi_spec_validator.validation import OpenAPIV31SpecValidator
15+
from openapi_spec_validator.validation.finders import SpecFinder
16+
from openapi_spec_validator.validation.finders import SpecVersion
1017
from openapi_spec_validator.validation.protocols import SupportsValidation
18+
from openapi_spec_validator.validation.types import SpecValidatorType
19+
from openapi_spec_validator.validation.validators import SpecValidator
20+
21+
SPECS: Mapping[SpecVersion, SpecValidatorType] = {
22+
SpecVersion("swagger", "2.0"): OpenAPIV2SpecValidator,
23+
SpecVersion("openapi", "3.0"): OpenAPIV30SpecValidator,
24+
SpecVersion("openapi", "3.1"): OpenAPIV31SpecValidator,
25+
}
26+
27+
28+
def get_validator_cls(spec: Schema) -> SpecValidatorType:
29+
return SpecFinder(SPECS).find(spec)
1130

1231

1332
def validate_spec(
14-
spec: Mapping[Hashable, Any],
33+
spec: Schema,
1534
base_uri: str = "",
16-
validator: SupportsValidation = openapi_spec_validator_proxy,
35+
validator: Optional[SupportsValidation] = None,
36+
cls: Optional[SpecValidatorType] = None,
1737
spec_url: Optional[str] = None,
1838
) -> None:
19-
return validator.validate(spec, base_uri=base_uri, spec_url=spec_url)
39+
if validator is not None:
40+
warnings.warn(
41+
"validator parameter is deprecated. Use cls instead.",
42+
DeprecationWarning,
43+
)
44+
return validator.validate(spec, base_uri=base_uri, spec_url=spec_url)
45+
if cls is None:
46+
cls = get_validator_cls(spec)
47+
v = cls(spec)
48+
return v.validate()
2049

2150

2251
def validate_spec_url(
2352
spec_url: str,
24-
validator: SupportsValidation = openapi_spec_validator_proxy,
53+
validator: Optional[SupportsValidation] = None,
54+
cls: Optional[Type[SpecValidator]] = None,
2555
) -> None:
2656
spec = all_urls_handler(spec_url)
27-
return validator.validate(spec, base_uri=spec_url)
57+
return validate_spec(spec, base_uri=spec_url)

openapi_spec_validator/validation/__init__.py

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from functools import partial
22

3-
from jsonschema.validators import Draft4Validator
4-
from jsonschema.validators import Draft202012Validator
53
from jsonschema_spec.handlers import default_handlers
64
from lazy_object_proxy import Proxy
75
from openapi_schema_validator import oas30_format_checker
@@ -13,51 +11,46 @@
1311
from openapi_spec_validator.schemas import schema_v30
1412
from openapi_spec_validator.schemas import schema_v31
1513
from openapi_spec_validator.validation.proxies import DetectValidatorProxy
16-
from openapi_spec_validator.validation.validators import SpecValidator
14+
from openapi_spec_validator.validation.proxies import SpecValidatorProxy
15+
from openapi_spec_validator.validation.validators import OpenAPIV2SpecValidator
16+
from openapi_spec_validator.validation.validators import (
17+
OpenAPIV30SpecValidator,
18+
)
19+
from openapi_spec_validator.validation.validators import (
20+
OpenAPIV31SpecValidator,
21+
)
1722

1823
__all__ = [
1924
"openapi_v2_spec_validator",
2025
"openapi_v3_spec_validator",
2126
"openapi_v30_spec_validator",
2227
"openapi_v31_spec_validator",
2328
"openapi_spec_validator_proxy",
29+
"OpenAPIV2SpecValidator",
30+
"OpenAPIV30SpecValidator",
31+
"OpenAPIV31SpecValidator",
2432
]
2533

2634
# v2.0 spec
27-
get_openapi_v2_schema_validator = partial(Draft4Validator, schema_v2)
28-
openapi_v2_schema_validator = Proxy(get_openapi_v2_schema_validator)
29-
get_openapi_v2_spec_validator = partial(
30-
SpecValidator,
31-
openapi_v2_schema_validator,
32-
OAS30Validator,
33-
oas30_format_checker,
34-
resolver_handlers=default_handlers,
35+
openapi_v2_spec_validator = SpecValidatorProxy(
36+
OpenAPIV2SpecValidator,
37+
deprecated="openapi_v2_spec_validator",
38+
use="OpenAPIV2SpecValidator",
3539
)
36-
openapi_v2_spec_validator = Proxy(get_openapi_v2_spec_validator)
3740

3841
# v3.0 spec
39-
get_openapi_v30_schema_validator = partial(Draft4Validator, schema_v30)
40-
openapi_v30_schema_validator = Proxy(get_openapi_v30_schema_validator)
41-
get_openapi_v30_spec_validator = partial(
42-
SpecValidator,
43-
openapi_v30_schema_validator,
44-
OAS30Validator,
45-
oas30_format_checker,
46-
resolver_handlers=default_handlers,
42+
openapi_v30_spec_validator = SpecValidatorProxy(
43+
OpenAPIV30SpecValidator,
44+
deprecated="openapi_v30_spec_validator",
45+
use="OpenAPIV30SpecValidator",
4746
)
48-
openapi_v30_spec_validator = Proxy(get_openapi_v30_spec_validator)
4947

5048
# v3.1 spec
51-
get_openapi_v31_schema_validator = partial(Draft202012Validator, schema_v31)
52-
openapi_v31_schema_validator = Proxy(get_openapi_v31_schema_validator)
53-
get_openapi_v31_spec_validator = partial(
54-
SpecValidator,
55-
openapi_v31_schema_validator,
56-
OAS31Validator,
57-
oas31_format_checker,
58-
resolver_handlers=default_handlers,
49+
openapi_v31_spec_validator = SpecValidatorProxy(
50+
OpenAPIV31SpecValidator,
51+
deprecated="openapi_v31_spec_validator",
52+
use="OpenAPIV31SpecValidator",
5953
)
60-
openapi_v31_spec_validator = Proxy(get_openapi_v31_spec_validator)
6154

6255
# alias to the latest v3 version
6356
openapi_v3_spec_validator = openapi_v31_spec_validator

openapi_spec_validator/validation/decorators.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ class ValidationErrorWrapper:
1515
def __init__(self, error_class: Type[ValidationError]):
1616
self.error_class = error_class
1717

18-
def __call__(self, f: Callable[..., Any]) -> Callable[..., Any]:
18+
def __call__(
19+
self, f: Callable[..., Any]
20+
) -> Callable[..., Iterator[ValidationError]]:
1921
@wraps(f)
2022
def wrapper(*args: Any, **kwds: Any) -> Iterator[ValidationError]:
2123
errors = f(*args, **kwds)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from typing import Mapping
2+
from typing import NamedTuple
3+
from typing import Optional
4+
from typing import Type
5+
6+
from jsonschema_spec.typing import Schema
7+
8+
from openapi_spec_validator.validation.exceptions import ValidatorDetectError
9+
from openapi_spec_validator.validation.types import SpecValidatorType
10+
11+
12+
class SpecVersion(NamedTuple):
13+
name: str
14+
version: str
15+
16+
17+
class SpecFinder:
18+
def __init__(self, specs: Mapping[SpecVersion, SpecValidatorType]) -> None:
19+
self.specs = specs
20+
21+
def find(self, spec: Schema) -> SpecValidatorType:
22+
for v, classes in self.specs.items():
23+
if v.name in spec and spec[v.name].startswith(v.version):
24+
return classes
25+
raise ValidatorDetectError("Spec schema version not detected")

0 commit comments

Comments
 (0)