bazarr/libs/flask_restx/schemas/__init__.py

119 lines
3.3 KiB
Python

"""
This module give access to OpenAPI specifications schemas
and allows to validate specs against them.
.. versionadded:: 0.12.1
"""
import io
import json
import pkg_resources
from collections.abc import Mapping
from jsonschema import Draft4Validator
from flask_restx import errors
class SchemaValidationError(errors.ValidationError):
"""
Raised when specification is not valid
.. versionadded:: 0.12.1
"""
def __init__(self, msg, errors=None):
super(SchemaValidationError, self).__init__(msg)
self.errors = errors
def __str__(self):
msg = [self.msg]
for error in sorted(self.errors, key=lambda e: e.path):
path = ".".join(error.path)
msg.append("- {}: {}".format(path, error.message))
for suberror in sorted(error.context, key=lambda e: e.schema_path):
path = ".".join(suberror.schema_path)
msg.append(" - {}: {}".format(path, suberror.message))
return "\n".join(msg)
__unicode__ = __str__
class LazySchema(Mapping):
"""
A thin wrapper around schema file lazy loading the data on first access
:param filename str: The package relative json schema filename
:param validator: The jsonschema validator class version
.. versionadded:: 0.12.1
"""
def __init__(self, filename, validator=Draft4Validator):
super(LazySchema, self).__init__()
self.filename = filename
self._schema = None
self._validator = validator
def _load(self):
if not self._schema:
filename = pkg_resources.resource_filename(__name__, self.filename)
with io.open(filename) as infile:
self._schema = json.load(infile)
def __getitem__(self, key):
self._load()
return self._schema.__getitem__(key)
def __iter__(self):
self._load()
return self._schema.__iter__()
def __len__(self):
self._load()
return self._schema.__len__()
@property
def validator(self):
"""The jsonschema validator to validate against"""
return self._validator(self)
#: OpenAPI 2.0 specification schema
OAS_20 = LazySchema("oas-2.0.json")
#: Map supported OpenAPI versions to their JSON schema
VERSIONS = {
"2.0": OAS_20,
}
def validate(data):
"""
Validate an OpenAPI specification.
Supported OpenAPI versions: 2.0
:param data dict: The specification to validate
:returns boolean: True if the specification is valid
:raises SchemaValidationError: when the specification is invalid
:raises flask_restx.errors.SpecsError: when it's not possible to determinate
the schema to validate against
.. versionadded:: 0.12.1
"""
if "swagger" not in data:
raise errors.SpecsError("Unable to determinate OpenAPI schema version")
version = data["swagger"]
if version not in VERSIONS:
raise errors.SpecsError('Unknown OpenAPI schema version "{}"'.format(version))
validator = VERSIONS[version].validator
validation_errors = list(validator.iter_errors(data))
if validation_errors:
raise SchemaValidationError(
"OpenAPI {} validation failed".format(version), errors=validation_errors
)
return True