2018-04-17 12:18:40 +00:00
|
|
|
"""OpenAPI core schemas models module"""
|
2018-08-24 14:57:41 +00:00
|
|
|
import attr
|
2017-09-21 11:51:37 +00:00
|
|
|
import logging
|
2018-09-07 20:40:10 +00:00
|
|
|
import re
|
2017-10-17 13:23:26 +00:00
|
|
|
|
2019-09-03 00:38:19 +00:00
|
|
|
from jsonschema.exceptions import ValidationError
|
2017-09-21 11:51:37 +00:00
|
|
|
|
2020-01-28 09:51:09 +00:00
|
|
|
from openapi_core.schema_validator import OAS30Validator
|
|
|
|
from openapi_core.schema_validator import oas30_format_checker
|
2020-01-17 14:36:14 +00:00
|
|
|
from openapi_core.schema.schemas.enums import SchemaType
|
2020-01-23 22:48:34 +00:00
|
|
|
from openapi_core.schema.schemas.exceptions import InvalidSchemaValue
|
2019-10-25 23:34:42 +00:00
|
|
|
from openapi_core.schema.schemas.types import NoValue
|
|
|
|
from openapi_core.unmarshalling.schemas.exceptions import (
|
|
|
|
UnmarshalValueError,
|
|
|
|
)
|
2017-09-22 08:14:07 +00:00
|
|
|
|
2017-09-21 11:51:37 +00:00
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2018-09-05 11:39:10 +00:00
|
|
|
|
2018-08-24 14:57:41 +00:00
|
|
|
@attr.s
|
2018-09-05 11:39:10 +00:00
|
|
|
class Format(object):
|
|
|
|
unmarshal = attr.ib()
|
2018-08-24 14:57:41 +00:00
|
|
|
validate = attr.ib()
|
|
|
|
|
2018-02-28 12:01:05 +00:00
|
|
|
|
2017-09-21 11:51:37 +00:00
|
|
|
class Schema(object):
|
|
|
|
"""Represents an OpenAPI Schema."""
|
|
|
|
|
|
|
|
def __init__(
|
2019-10-25 23:34:42 +00:00
|
|
|
self, schema_type=None, properties=None, items=None,
|
|
|
|
schema_format=None, required=None, default=NoValue, nullable=False,
|
2018-05-30 10:15:17 +00:00
|
|
|
enum=None, deprecated=False, all_of=None, one_of=None,
|
2019-03-12 15:01:16 +00:00
|
|
|
additional_properties=True, min_items=None, max_items=None,
|
2018-09-07 20:40:10 +00:00
|
|
|
min_length=None, max_length=None, pattern=None, unique_items=False,
|
|
|
|
minimum=None, maximum=None, multiple_of=None,
|
|
|
|
exclusive_minimum=False, exclusive_maximum=False,
|
2019-10-25 23:34:42 +00:00
|
|
|
min_properties=None, max_properties=None, extensions=None,
|
|
|
|
_source=None):
|
2018-08-02 18:30:51 +00:00
|
|
|
self.type = SchemaType(schema_type)
|
2017-09-21 11:51:37 +00:00
|
|
|
self.properties = properties and dict(properties) or {}
|
|
|
|
self.items = items
|
2018-05-30 08:41:34 +00:00
|
|
|
self.format = schema_format
|
2017-11-06 16:50:00 +00:00
|
|
|
self.required = required or []
|
2017-09-25 14:15:00 +00:00
|
|
|
self.default = default
|
2017-10-17 13:02:21 +00:00
|
|
|
self.nullable = nullable
|
2017-10-17 13:23:26 +00:00
|
|
|
self.enum = enum
|
2017-10-17 13:33:46 +00:00
|
|
|
self.deprecated = deprecated
|
2017-11-06 16:50:00 +00:00
|
|
|
self.all_of = all_of and list(all_of) or []
|
2018-05-25 15:32:09 +00:00
|
|
|
self.one_of = one_of and list(one_of) or []
|
2018-05-30 10:15:17 +00:00
|
|
|
self.additional_properties = additional_properties
|
2018-09-07 20:40:10 +00:00
|
|
|
self.min_items = int(min_items) if min_items is not None else None
|
|
|
|
self.max_items = int(max_items) if max_items is not None else None
|
|
|
|
self.min_length = int(min_length) if min_length is not None else None
|
|
|
|
self.max_length = int(max_length) if max_length is not None else None
|
|
|
|
self.pattern = pattern and re.compile(pattern) or None
|
|
|
|
self.unique_items = unique_items
|
|
|
|
self.minimum = int(minimum) if minimum is not None else None
|
|
|
|
self.maximum = int(maximum) if maximum is not None else None
|
|
|
|
self.multiple_of = int(multiple_of)\
|
|
|
|
if multiple_of is not None else None
|
|
|
|
self.exclusive_minimum = exclusive_minimum
|
|
|
|
self.exclusive_maximum = exclusive_maximum
|
|
|
|
self.min_properties = int(min_properties)\
|
|
|
|
if min_properties is not None else None
|
|
|
|
self.max_properties = int(max_properties)\
|
|
|
|
if max_properties is not None else None
|
2018-05-25 15:32:09 +00:00
|
|
|
|
2019-10-25 23:34:42 +00:00
|
|
|
self.extensions = extensions and dict(extensions) or {}
|
|
|
|
|
2018-05-25 15:32:09 +00:00
|
|
|
self._all_required_properties_cache = None
|
|
|
|
self._all_optional_properties_cache = None
|
2017-09-21 11:51:37 +00:00
|
|
|
|
2019-09-03 00:38:19 +00:00
|
|
|
self._source = _source
|
|
|
|
|
2019-09-11 21:47:16 +00:00
|
|
|
@property
|
|
|
|
def __dict__(self):
|
|
|
|
return self._source or self.to_dict()
|
|
|
|
|
|
|
|
def to_dict(self):
|
|
|
|
from openapi_core.schema.schemas.factories import SchemaDictFactory
|
|
|
|
return SchemaDictFactory().create(self)
|
|
|
|
|
2017-09-21 11:51:37 +00:00
|
|
|
def __getitem__(self, name):
|
|
|
|
return self.properties[name]
|
|
|
|
|
2019-10-25 23:34:42 +00:00
|
|
|
def has_default(self):
|
|
|
|
return self.default is not NoValue
|
|
|
|
|
2017-11-06 16:50:00 +00:00
|
|
|
def get_all_properties(self):
|
|
|
|
properties = self.properties.copy()
|
|
|
|
|
|
|
|
for subschema in self.all_of:
|
|
|
|
subschema_props = subschema.get_all_properties()
|
|
|
|
properties.update(subschema_props)
|
|
|
|
|
|
|
|
return properties
|
|
|
|
|
2018-05-25 15:32:09 +00:00
|
|
|
def get_all_properties_names(self):
|
|
|
|
all_properties = self.get_all_properties()
|
|
|
|
return set(all_properties.keys())
|
|
|
|
|
2019-09-02 22:14:37 +00:00
|
|
|
def cast(self, value):
|
|
|
|
"""Cast value from string to schema type"""
|
2020-01-23 22:48:34 +00:00
|
|
|
from openapi_core.casting.schemas.exceptions import CastError
|
|
|
|
from openapi_core.casting.schemas.factories import SchemaCastersFactory
|
|
|
|
casters_factory = SchemaCastersFactory()
|
|
|
|
caster = casters_factory.create(self)
|
2019-09-02 22:14:37 +00:00
|
|
|
try:
|
2020-01-23 22:48:34 +00:00
|
|
|
return caster(value)
|
|
|
|
except (ValueError, TypeError):
|
2019-10-20 12:25:21 +00:00
|
|
|
raise CastError(value, self.type)
|
2019-09-02 22:14:37 +00:00
|
|
|
|
2019-09-03 00:38:19 +00:00
|
|
|
def get_validator(self, resolver=None):
|
|
|
|
return OAS30Validator(
|
2020-01-17 14:36:14 +00:00
|
|
|
self.__dict__,
|
|
|
|
resolver=resolver, format_checker=oas30_format_checker,
|
|
|
|
)
|
2019-09-03 00:38:19 +00:00
|
|
|
|
|
|
|
def validate(self, value, resolver=None):
|
|
|
|
validator = self.get_validator(resolver=resolver)
|
|
|
|
try:
|
|
|
|
return validator.validate(value)
|
|
|
|
except ValidationError:
|
2019-10-20 12:55:50 +00:00
|
|
|
errors_iter = validator.iter_errors(value)
|
2019-10-22 21:01:17 +00:00
|
|
|
raise InvalidSchemaValue(
|
|
|
|
value, self.type, schema_errors_iter=errors_iter)
|
2019-09-03 00:38:19 +00:00
|
|
|
|
2019-09-02 22:14:37 +00:00
|
|
|
def unmarshal(self, value, custom_formatters=None, strict=True):
|
|
|
|
"""Unmarshal parameter from the value."""
|
2019-10-25 23:34:42 +00:00
|
|
|
from openapi_core.unmarshalling.schemas.factories import (
|
|
|
|
SchemaUnmarshallersFactory,
|
|
|
|
)
|
|
|
|
unmarshallers_factory = SchemaUnmarshallersFactory(
|
|
|
|
custom_formatters)
|
|
|
|
unmarshaller = unmarshallers_factory.create(self)
|
2017-09-21 11:51:37 +00:00
|
|
|
try:
|
2019-10-25 23:34:42 +00:00
|
|
|
return unmarshaller(value, strict=strict)
|
2019-10-20 12:00:14 +00:00
|
|
|
except ValueError as exc:
|
2019-10-20 13:38:41 +00:00
|
|
|
raise UnmarshalValueError(value, self.type, exc)
|