mirror of
https://github.com/correl/openapi-core.git
synced 2025-01-04 03:00:15 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
beaa08a9c0
7 changed files with 356 additions and 56 deletions
|
@ -109,7 +109,11 @@ class Parameter(object):
|
||||||
raise InvalidParameterValue(self.name, exc)
|
raise InvalidParameterValue(self.name, exc)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
unmarshalled = self.schema.unmarshal(deserialized, custom_formatters=custom_formatters)
|
unmarshalled = self.schema.unmarshal(
|
||||||
|
deserialized,
|
||||||
|
custom_formatters=custom_formatters,
|
||||||
|
strict=False,
|
||||||
|
)
|
||||||
except OpenAPISchemaError as exc:
|
except OpenAPISchemaError as exc:
|
||||||
raise InvalidParameterValue(self.name, exc)
|
raise InvalidParameterValue(self.name, exc)
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ class SchemaFactory(object):
|
||||||
deprecated = schema_deref.get('deprecated', False)
|
deprecated = schema_deref.get('deprecated', False)
|
||||||
all_of_spec = schema_deref.get('allOf', None)
|
all_of_spec = schema_deref.get('allOf', None)
|
||||||
one_of_spec = schema_deref.get('oneOf', None)
|
one_of_spec = schema_deref.get('oneOf', None)
|
||||||
additional_properties_spec = schema_deref.get('additionalProperties')
|
additional_properties_spec = schema_deref.get('additionalProperties',
|
||||||
|
True)
|
||||||
min_items = schema_deref.get('minItems', None)
|
min_items = schema_deref.get('minItems', None)
|
||||||
max_items = schema_deref.get('maxItems', None)
|
max_items = schema_deref.get('maxItems', None)
|
||||||
min_length = schema_deref.get('minLength', None)
|
min_length = schema_deref.get('minLength', None)
|
||||||
|
@ -59,8 +60,8 @@ class SchemaFactory(object):
|
||||||
if items_spec:
|
if items_spec:
|
||||||
items = self._create_items(items_spec)
|
items = self._create_items(items_spec)
|
||||||
|
|
||||||
additional_properties = None
|
additional_properties = additional_properties_spec
|
||||||
if additional_properties_spec:
|
if isinstance(additional_properties_spec, dict):
|
||||||
additional_properties = self.create(additional_properties_spec)
|
additional_properties = self.create(additional_properties_spec)
|
||||||
|
|
||||||
return Schema(
|
return Schema(
|
||||||
|
|
|
@ -39,9 +39,6 @@ class Schema(object):
|
||||||
"""Represents an OpenAPI Schema."""
|
"""Represents an OpenAPI Schema."""
|
||||||
|
|
||||||
DEFAULT_CAST_CALLABLE_GETTER = {
|
DEFAULT_CAST_CALLABLE_GETTER = {
|
||||||
SchemaType.INTEGER: int,
|
|
||||||
SchemaType.NUMBER: float,
|
|
||||||
SchemaType.BOOLEAN: forcebool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STRING_FORMAT_CALLABLE_GETTER = {
|
STRING_FORMAT_CALLABLE_GETTER = {
|
||||||
|
@ -69,7 +66,7 @@ class Schema(object):
|
||||||
self, schema_type=None, model=None, properties=None, items=None,
|
self, schema_type=None, model=None, properties=None, items=None,
|
||||||
schema_format=None, required=None, default=None, nullable=False,
|
schema_format=None, required=None, default=None, nullable=False,
|
||||||
enum=None, deprecated=False, all_of=None, one_of=None,
|
enum=None, deprecated=False, all_of=None, one_of=None,
|
||||||
additional_properties=None, min_items=None, max_items=None,
|
additional_properties=True, min_items=None, max_items=None,
|
||||||
min_length=None, max_length=None, pattern=None, unique_items=False,
|
min_length=None, max_length=None, pattern=None, unique_items=False,
|
||||||
minimum=None, maximum=None, multiple_of=None,
|
minimum=None, maximum=None, multiple_of=None,
|
||||||
exclusive_minimum=False, exclusive_maximum=False,
|
exclusive_minimum=False, exclusive_maximum=False,
|
||||||
|
@ -149,12 +146,15 @@ class Schema(object):
|
||||||
|
|
||||||
return set(required)
|
return set(required)
|
||||||
|
|
||||||
def get_cast_mapping(self, custom_formatters=None):
|
def get_cast_mapping(self, custom_formatters=None, strict=True):
|
||||||
pass_defaults = lambda f: functools.partial(
|
pass_defaults = lambda f: functools.partial(
|
||||||
f, custom_formatters=custom_formatters)
|
f, custom_formatters=custom_formatters, strict=strict)
|
||||||
mapping = self.DEFAULT_CAST_CALLABLE_GETTER.copy()
|
mapping = self.DEFAULT_CAST_CALLABLE_GETTER.copy()
|
||||||
mapping.update({
|
mapping.update({
|
||||||
SchemaType.STRING: pass_defaults(self._unmarshal_string),
|
SchemaType.STRING: pass_defaults(self._unmarshal_string),
|
||||||
|
SchemaType.BOOLEAN: pass_defaults(self._unmarshal_boolean),
|
||||||
|
SchemaType.INTEGER: pass_defaults(self._unmarshal_integer),
|
||||||
|
SchemaType.NUMBER: pass_defaults(self._unmarshal_number),
|
||||||
SchemaType.ANY: pass_defaults(self._unmarshal_any),
|
SchemaType.ANY: pass_defaults(self._unmarshal_any),
|
||||||
SchemaType.ARRAY: pass_defaults(self._unmarshal_collection),
|
SchemaType.ARRAY: pass_defaults(self._unmarshal_collection),
|
||||||
SchemaType.OBJECT: pass_defaults(self._unmarshal_object),
|
SchemaType.OBJECT: pass_defaults(self._unmarshal_object),
|
||||||
|
@ -162,14 +162,15 @@ class Schema(object):
|
||||||
|
|
||||||
return defaultdict(lambda: lambda x: x, mapping)
|
return defaultdict(lambda: lambda x: x, mapping)
|
||||||
|
|
||||||
def cast(self, value, custom_formatters=None):
|
def cast(self, value, custom_formatters=None, strict=True):
|
||||||
"""Cast value to schema type"""
|
"""Cast value to schema type"""
|
||||||
if value is None:
|
if value is None:
|
||||||
if not self.nullable:
|
if not self.nullable:
|
||||||
raise InvalidSchemaValue("Null value for non-nullable schema", value, self.type)
|
raise InvalidSchemaValue("Null value for non-nullable schema", value, self.type)
|
||||||
return self.default
|
return self.default
|
||||||
|
|
||||||
cast_mapping = self.get_cast_mapping(custom_formatters=custom_formatters)
|
cast_mapping = self.get_cast_mapping(
|
||||||
|
custom_formatters=custom_formatters, strict=strict)
|
||||||
|
|
||||||
if self.type is not SchemaType.STRING and value == '':
|
if self.type is not SchemaType.STRING and value == '':
|
||||||
return None
|
return None
|
||||||
|
@ -181,12 +182,12 @@ class Schema(object):
|
||||||
raise InvalidSchemaValue(
|
raise InvalidSchemaValue(
|
||||||
"Failed to cast value {value} to type {type}", value, self.type)
|
"Failed to cast value {value} to type {type}", value, self.type)
|
||||||
|
|
||||||
def unmarshal(self, value, custom_formatters=None):
|
def unmarshal(self, value, custom_formatters=None, strict=True):
|
||||||
"""Unmarshal parameter from the value."""
|
"""Unmarshal parameter from the value."""
|
||||||
if self.deprecated:
|
if self.deprecated:
|
||||||
warnings.warn("The schema is deprecated", DeprecationWarning)
|
warnings.warn("The schema is deprecated", DeprecationWarning)
|
||||||
|
|
||||||
casted = self.cast(value, custom_formatters=custom_formatters)
|
casted = self.cast(value, custom_formatters=custom_formatters, strict=strict)
|
||||||
|
|
||||||
if casted is None and not self.required:
|
if casted is None and not self.required:
|
||||||
return None
|
return None
|
||||||
|
@ -197,7 +198,10 @@ class Schema(object):
|
||||||
|
|
||||||
return casted
|
return casted
|
||||||
|
|
||||||
def _unmarshal_string(self, value, custom_formatters=None):
|
def _unmarshal_string(self, value, custom_formatters=None, strict=True):
|
||||||
|
if strict and not isinstance(value, (text_type, binary_type)):
|
||||||
|
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
schema_format = SchemaFormat(self.format)
|
schema_format = SchemaFormat(self.format)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -217,7 +221,25 @@ class Schema(object):
|
||||||
raise InvalidCustomFormatSchemaValue(
|
raise InvalidCustomFormatSchemaValue(
|
||||||
"Failed to format value {value} to format {type}: {exception}", value, self.format, exc)
|
"Failed to format value {value} to format {type}: {exception}", value, self.format, exc)
|
||||||
|
|
||||||
def _unmarshal_any(self, value, custom_formatters=None):
|
def _unmarshal_integer(self, value, custom_formatters=None, strict=True):
|
||||||
|
if strict and not isinstance(value, (integer_types, )):
|
||||||
|
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
||||||
|
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
def _unmarshal_number(self, value, custom_formatters=None, strict=True):
|
||||||
|
if strict and not isinstance(value, (float, )):
|
||||||
|
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
||||||
|
|
||||||
|
return float(value)
|
||||||
|
|
||||||
|
def _unmarshal_boolean(self, value, custom_formatters=None, strict=True):
|
||||||
|
if strict and not isinstance(value, (bool, )):
|
||||||
|
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
||||||
|
|
||||||
|
return forcebool(value)
|
||||||
|
|
||||||
|
def _unmarshal_any(self, value, custom_formatters=None, strict=True):
|
||||||
types_resolve_order = [
|
types_resolve_order = [
|
||||||
SchemaType.OBJECT, SchemaType.ARRAY, SchemaType.BOOLEAN,
|
SchemaType.OBJECT, SchemaType.ARRAY, SchemaType.BOOLEAN,
|
||||||
SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING,
|
SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING,
|
||||||
|
@ -233,16 +255,21 @@ class Schema(object):
|
||||||
|
|
||||||
raise NoValidSchema(value)
|
raise NoValidSchema(value)
|
||||||
|
|
||||||
def _unmarshal_collection(self, value, custom_formatters=None):
|
def _unmarshal_collection(self, value, custom_formatters=None, strict=True):
|
||||||
|
if not isinstance(value, (list, tuple)):
|
||||||
|
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
||||||
|
|
||||||
if self.items is None:
|
if self.items is None:
|
||||||
raise UndefinedItemsSchema(self.type)
|
raise UndefinedItemsSchema(self.type)
|
||||||
|
|
||||||
f = functools.partial(self.items.unmarshal,
|
f = functools.partial(
|
||||||
custom_formatters=custom_formatters)
|
self.items.unmarshal,
|
||||||
|
custom_formatters=custom_formatters, strict=strict,
|
||||||
|
)
|
||||||
return list(map(f, value))
|
return list(map(f, value))
|
||||||
|
|
||||||
def _unmarshal_object(self, value, model_factory=None,
|
def _unmarshal_object(self, value, model_factory=None,
|
||||||
custom_formatters=None):
|
custom_formatters=None, strict=True):
|
||||||
if not isinstance(value, (dict, )):
|
if not isinstance(value, (dict, )):
|
||||||
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)
|
||||||
|
|
||||||
|
@ -271,7 +298,7 @@ class Schema(object):
|
||||||
return model_factory.create(properties, name=self.model)
|
return model_factory.create(properties, name=self.model)
|
||||||
|
|
||||||
def _unmarshal_properties(self, value, one_of_schema=None,
|
def _unmarshal_properties(self, value, one_of_schema=None,
|
||||||
custom_formatters=None):
|
custom_formatters=None, strict=True):
|
||||||
all_props = self.get_all_properties()
|
all_props = self.get_all_properties()
|
||||||
all_props_names = self.get_all_properties_names()
|
all_props_names = self.get_all_properties_names()
|
||||||
all_req_props_names = self.get_all_required_properties_names()
|
all_req_props_names = self.get_all_required_properties_names()
|
||||||
|
@ -285,14 +312,15 @@ class Schema(object):
|
||||||
|
|
||||||
value_props_names = value.keys()
|
value_props_names = value.keys()
|
||||||
extra_props = set(value_props_names) - set(all_props_names)
|
extra_props = set(value_props_names) - set(all_props_names)
|
||||||
if extra_props and self.additional_properties is None:
|
if extra_props and self.additional_properties is False:
|
||||||
raise UndefinedSchemaProperty(extra_props)
|
raise UndefinedSchemaProperty(extra_props)
|
||||||
|
|
||||||
properties = {}
|
properties = {}
|
||||||
for prop_name in extra_props:
|
if self.additional_properties is not True:
|
||||||
prop_value = value[prop_name]
|
for prop_name in extra_props:
|
||||||
properties[prop_name] = self.additional_properties.unmarshal(
|
prop_value = value[prop_name]
|
||||||
prop_value, custom_formatters=custom_formatters)
|
properties[prop_name] = self.additional_properties.unmarshal(
|
||||||
|
prop_value, custom_formatters=custom_formatters)
|
||||||
|
|
||||||
for prop_name, prop in iteritems(all_props):
|
for prop_name, prop in iteritems(all_props):
|
||||||
try:
|
try:
|
||||||
|
@ -516,13 +544,14 @@ class Schema(object):
|
||||||
|
|
||||||
value_props_names = value.keys()
|
value_props_names = value.keys()
|
||||||
extra_props = set(value_props_names) - set(all_props_names)
|
extra_props = set(value_props_names) - set(all_props_names)
|
||||||
if extra_props and self.additional_properties is None:
|
if extra_props and self.additional_properties is False:
|
||||||
raise UndefinedSchemaProperty(extra_props)
|
raise UndefinedSchemaProperty(extra_props)
|
||||||
|
|
||||||
for prop_name in extra_props:
|
if self.additional_properties is not True:
|
||||||
prop_value = value[prop_name]
|
for prop_name in extra_props:
|
||||||
self.additional_properties.validate(
|
prop_value = value[prop_name]
|
||||||
prop_value, custom_formatters=custom_formatters)
|
self.additional_properties.validate(
|
||||||
|
prop_value, custom_formatters=custom_formatters)
|
||||||
|
|
||||||
for prop_name, prop in iteritems(all_props):
|
for prop_name, prop in iteritems(all_props):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -59,16 +59,7 @@ paths:
|
||||||
explode: false
|
explode: false
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: An paged array of pets
|
$ref: "#/components/responses/PetsResponse"
|
||||||
headers:
|
|
||||||
x-next:
|
|
||||||
description: A link to the next page of responses
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/PetsData"
|
|
||||||
post:
|
post:
|
||||||
summary: Create a pet
|
summary: Create a pet
|
||||||
operationId: createPets
|
operationId: createPets
|
||||||
|
@ -295,6 +286,7 @@ components:
|
||||||
$ref: "#/components/schemas/Utctime"
|
$ref: "#/components/schemas/Utctime"
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
additionalProperties: false
|
||||||
TagList:
|
TagList:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@ -327,9 +319,20 @@ components:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
responses:
|
responses:
|
||||||
ErrorResponse:
|
ErrorResponse:
|
||||||
description: unexpected error
|
description: unexpected error
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/ExtendedError"
|
$ref: "#/components/schemas/ExtendedError"
|
||||||
|
PetsResponse:
|
||||||
|
description: An paged array of pets
|
||||||
|
headers:
|
||||||
|
x-next:
|
||||||
|
description: A link to the next page of responses
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/PetsData"
|
||||||
|
|
|
@ -17,8 +17,9 @@ from openapi_core.schema.parameters.models import Parameter
|
||||||
from openapi_core.schema.paths.models import Path
|
from openapi_core.schema.paths.models import Path
|
||||||
from openapi_core.schema.request_bodies.models import RequestBody
|
from openapi_core.schema.request_bodies.models import RequestBody
|
||||||
from openapi_core.schema.responses.models import Response
|
from openapi_core.schema.responses.models import Response
|
||||||
|
from openapi_core.schema.schemas.enums import SchemaType
|
||||||
from openapi_core.schema.schemas.exceptions import (
|
from openapi_core.schema.schemas.exceptions import (
|
||||||
NoValidSchema,
|
NoValidSchema, InvalidSchemaProperty, InvalidSchemaValue,
|
||||||
)
|
)
|
||||||
from openapi_core.schema.schemas.models import Schema
|
from openapi_core.schema.schemas.models import Schema
|
||||||
from openapi_core.schema.servers.exceptions import InvalidServer
|
from openapi_core.schema.servers.exceptions import InvalidServer
|
||||||
|
@ -234,6 +235,105 @@ class TestPetstore(object):
|
||||||
assert isinstance(response_result.data, BaseModel)
|
assert isinstance(response_result.data, BaseModel)
|
||||||
assert response_result.data.data == []
|
assert response_result.data.data == []
|
||||||
|
|
||||||
|
def test_get_pets_response(self, spec, response_validator):
|
||||||
|
host_url = 'http://petstore.swagger.io/v1'
|
||||||
|
path_pattern = '/v1/pets'
|
||||||
|
query_params = {
|
||||||
|
'limit': '20',
|
||||||
|
}
|
||||||
|
|
||||||
|
request = MockRequest(
|
||||||
|
host_url, 'GET', '/pets',
|
||||||
|
path_pattern=path_pattern, args=query_params,
|
||||||
|
)
|
||||||
|
|
||||||
|
parameters = request.get_parameters(spec)
|
||||||
|
body = request.get_body(spec)
|
||||||
|
|
||||||
|
assert parameters == {
|
||||||
|
'query': {
|
||||||
|
'limit': 20,
|
||||||
|
'page': 1,
|
||||||
|
'search': '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert body is None
|
||||||
|
|
||||||
|
data_json = {
|
||||||
|
'data': [
|
||||||
|
{
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Cat',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
data = json.dumps(data_json)
|
||||||
|
response = MockResponse(data)
|
||||||
|
|
||||||
|
response_result = response_validator.validate(request, response)
|
||||||
|
|
||||||
|
assert response_result.errors == []
|
||||||
|
assert isinstance(response_result.data, BaseModel)
|
||||||
|
assert len(response_result.data.data) == 1
|
||||||
|
assert response_result.data.data[0].id == 1
|
||||||
|
assert response_result.data.data[0].name == 'Cat'
|
||||||
|
|
||||||
|
def test_get_pets_invalid_response(self, spec, response_validator):
|
||||||
|
host_url = 'http://petstore.swagger.io/v1'
|
||||||
|
path_pattern = '/v1/pets'
|
||||||
|
query_params = {
|
||||||
|
'limit': '20',
|
||||||
|
}
|
||||||
|
|
||||||
|
request = MockRequest(
|
||||||
|
host_url, 'GET', '/pets',
|
||||||
|
path_pattern=path_pattern, args=query_params,
|
||||||
|
)
|
||||||
|
|
||||||
|
parameters = request.get_parameters(spec)
|
||||||
|
body = request.get_body(spec)
|
||||||
|
|
||||||
|
assert parameters == {
|
||||||
|
'query': {
|
||||||
|
'limit': 20,
|
||||||
|
'page': 1,
|
||||||
|
'search': '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert body is None
|
||||||
|
|
||||||
|
data_json = {
|
||||||
|
'data': [
|
||||||
|
{
|
||||||
|
'id': 1,
|
||||||
|
'name': {
|
||||||
|
'first_name': 'Cat',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
data = json.dumps(data_json)
|
||||||
|
response = MockResponse(data)
|
||||||
|
|
||||||
|
response_result = response_validator.validate(request, response)
|
||||||
|
|
||||||
|
assert response_result.errors == [
|
||||||
|
InvalidMediaTypeValue(
|
||||||
|
original_exception=InvalidSchemaProperty(
|
||||||
|
property_name='data',
|
||||||
|
original_exception=InvalidSchemaProperty(
|
||||||
|
property_name='name',
|
||||||
|
original_exception=InvalidSchemaValue(
|
||||||
|
msg="Value {value} is not of type {type}",
|
||||||
|
type=SchemaType.STRING,
|
||||||
|
value={'first_name': 'Cat'},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
assert response_result.data is None
|
||||||
|
|
||||||
def test_get_pets_ids_param(self, spec, response_validator):
|
def test_get_pets_ids_param(self, spec, response_validator):
|
||||||
host_url = 'http://petstore.swagger.io/v1'
|
host_url = 'http://petstore.swagger.io/v1'
|
||||||
path_pattern = '/v1/pets'
|
path_pattern = '/v1/pets'
|
||||||
|
@ -419,7 +519,7 @@ class TestPetstore(object):
|
||||||
data_json = {
|
data_json = {
|
||||||
'name': pet_name,
|
'name': pet_name,
|
||||||
'tag': pet_tag,
|
'tag': pet_tag,
|
||||||
'position': '2',
|
'position': 2,
|
||||||
'address': {
|
'address': {
|
||||||
'street': pet_street,
|
'street': pet_street,
|
||||||
'city': pet_city,
|
'city': pet_city,
|
||||||
|
@ -479,7 +579,7 @@ class TestPetstore(object):
|
||||||
data_json = {
|
data_json = {
|
||||||
'name': pet_name,
|
'name': pet_name,
|
||||||
'tag': pet_tag,
|
'tag': pet_tag,
|
||||||
'position': '2',
|
'position': 2,
|
||||||
'address': {
|
'address': {
|
||||||
'street': pet_street,
|
'street': pet_street,
|
||||||
'city': pet_city,
|
'city': pet_city,
|
||||||
|
@ -535,11 +635,11 @@ class TestPetstore(object):
|
||||||
pet_tag = 'cats'
|
pet_tag = 'cats'
|
||||||
pet_street = 'Piekna'
|
pet_street = 'Piekna'
|
||||||
pet_city = 'Warsaw'
|
pet_city = 'Warsaw'
|
||||||
pet_healthy = 'false'
|
pet_healthy = False
|
||||||
data_json = {
|
data_json = {
|
||||||
'name': pet_name,
|
'name': pet_name,
|
||||||
'tag': pet_tag,
|
'tag': pet_tag,
|
||||||
'position': '2',
|
'position': 2,
|
||||||
'address': {
|
'address': {
|
||||||
'street': pet_street,
|
'street': pet_street,
|
||||||
'city': pet_city,
|
'city': pet_city,
|
||||||
|
|
|
@ -155,7 +155,7 @@ class TestRequestValidator(object):
|
||||||
data_json = {
|
data_json = {
|
||||||
'name': pet_name,
|
'name': pet_name,
|
||||||
'tag': pet_tag,
|
'tag': pet_tag,
|
||||||
'position': '2',
|
'position': 2,
|
||||||
'address': {
|
'address': {
|
||||||
'street': pet_street,
|
'street': pet_street,
|
||||||
'city': pet_city,
|
'city': pet_city,
|
||||||
|
|
|
@ -8,6 +8,7 @@ from openapi_core.extensions.models.models import Model
|
||||||
from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType
|
from openapi_core.schema.schemas.enums import SchemaFormat, SchemaType
|
||||||
from openapi_core.schema.schemas.exceptions import (
|
from openapi_core.schema.schemas.exceptions import (
|
||||||
InvalidSchemaValue, MultipleOneOfSchema, NoOneOfSchema, OpenAPISchemaError,
|
InvalidSchemaValue, MultipleOneOfSchema, NoOneOfSchema, OpenAPISchemaError,
|
||||||
|
UndefinedSchemaProperty
|
||||||
)
|
)
|
||||||
from openapi_core.schema.schemas.models import Schema
|
from openapi_core.schema.schemas.models import Schema
|
||||||
|
|
||||||
|
@ -65,6 +66,13 @@ class TestSchemaUnmarshal(object):
|
||||||
|
|
||||||
assert result == value
|
assert result == value
|
||||||
|
|
||||||
|
def test_string_float_invalid(self):
|
||||||
|
schema = Schema('string')
|
||||||
|
value = 1.23
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
def test_string_none(self):
|
def test_string_none(self):
|
||||||
schema = Schema('string')
|
schema = Schema('string')
|
||||||
value = None
|
value = None
|
||||||
|
@ -134,7 +142,7 @@ class TestSchemaUnmarshal(object):
|
||||||
value = 'x'
|
value = 'x'
|
||||||
|
|
||||||
with mock.patch.dict(
|
with mock.patch.dict(
|
||||||
Schema.STRING_FORMAT_CAST_CALLABLE_GETTER,
|
Schema.STRING_FORMAT_CALLABLE_GETTER,
|
||||||
{custom_format: mock.Mock(side_effect=ValueError())},
|
{custom_format: mock.Mock(side_effect=ValueError())},
|
||||||
), pytest.raises(
|
), pytest.raises(
|
||||||
InvalidSchemaValue, message='Failed to format value'
|
InvalidSchemaValue, message='Failed to format value'
|
||||||
|
@ -143,12 +151,19 @@ class TestSchemaUnmarshal(object):
|
||||||
|
|
||||||
def test_integer_valid(self):
|
def test_integer_valid(self):
|
||||||
schema = Schema('integer')
|
schema = Schema('integer')
|
||||||
value = '123'
|
value = 123
|
||||||
|
|
||||||
result = schema.unmarshal(value)
|
result = schema.unmarshal(value)
|
||||||
|
|
||||||
assert result == int(value)
|
assert result == int(value)
|
||||||
|
|
||||||
|
def test_integer_string_invalid(self):
|
||||||
|
schema = Schema('integer')
|
||||||
|
value = '123'
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
def test_integer_enum_invalid(self):
|
def test_integer_enum_invalid(self):
|
||||||
schema = Schema('integer', enum=[1, 2, 3])
|
schema = Schema('integer', enum=[1, 2, 3])
|
||||||
value = '123'
|
value = '123'
|
||||||
|
@ -158,12 +173,19 @@ class TestSchemaUnmarshal(object):
|
||||||
|
|
||||||
def test_integer_enum(self):
|
def test_integer_enum(self):
|
||||||
schema = Schema('integer', enum=[1, 2, 3])
|
schema = Schema('integer', enum=[1, 2, 3])
|
||||||
value = '2'
|
value = 2
|
||||||
|
|
||||||
result = schema.unmarshal(value)
|
result = schema.unmarshal(value)
|
||||||
|
|
||||||
assert result == int(value)
|
assert result == int(value)
|
||||||
|
|
||||||
|
def test_integer_enum_string_invalid(self):
|
||||||
|
schema = Schema('integer', enum=[1, 2, 3])
|
||||||
|
value = '2'
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
def test_integer_default(self):
|
def test_integer_default(self):
|
||||||
default_value = '123'
|
default_value = '123'
|
||||||
schema = Schema('integer', default=default_value)
|
schema = Schema('integer', default=default_value)
|
||||||
|
@ -188,6 +210,65 @@ class TestSchemaUnmarshal(object):
|
||||||
with pytest.raises(InvalidSchemaValue):
|
with pytest.raises(InvalidSchemaValue):
|
||||||
schema.unmarshal(value)
|
schema.unmarshal(value)
|
||||||
|
|
||||||
|
def test_array_valid(self):
|
||||||
|
schema = Schema('array', items=Schema('integer'))
|
||||||
|
value = [1, 2, 3]
|
||||||
|
|
||||||
|
result = schema.unmarshal(value)
|
||||||
|
|
||||||
|
assert result == value
|
||||||
|
|
||||||
|
def test_array_of_string_string_invalid(self):
|
||||||
|
schema = Schema('array', items=Schema('string'))
|
||||||
|
value = '123'
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
|
def test_array_of_integer_string_invalid(self):
|
||||||
|
schema = Schema('array', items=Schema('integer'))
|
||||||
|
value = '123'
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
|
def test_boolean_valid(self):
|
||||||
|
schema = Schema('boolean')
|
||||||
|
value = True
|
||||||
|
|
||||||
|
result = schema.unmarshal(value)
|
||||||
|
|
||||||
|
assert result == value
|
||||||
|
|
||||||
|
def test_boolean_string_invalid(self):
|
||||||
|
schema = Schema('boolean')
|
||||||
|
value = 'True'
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
|
def test_number_valid(self):
|
||||||
|
schema = Schema('number')
|
||||||
|
value = 1.23
|
||||||
|
|
||||||
|
result = schema.unmarshal(value)
|
||||||
|
|
||||||
|
assert result == value
|
||||||
|
|
||||||
|
def test_number_string_invalid(self):
|
||||||
|
schema = Schema('number')
|
||||||
|
value = '1.23'
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
|
def test_number_int_invalid(self):
|
||||||
|
schema = Schema('number')
|
||||||
|
value = 1
|
||||||
|
|
||||||
|
with pytest.raises(InvalidSchemaValue):
|
||||||
|
schema.unmarshal(value)
|
||||||
|
|
||||||
|
|
||||||
class TestSchemaValidate(object):
|
class TestSchemaValidate(object):
|
||||||
|
|
||||||
|
@ -714,6 +795,26 @@ class TestSchemaValidate(object):
|
||||||
|
|
||||||
assert result == value
|
assert result == value
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('value', [Model({'additional': 1}), ])
|
||||||
|
def test_object_additional_propetries(self, value):
|
||||||
|
schema = Schema('object')
|
||||||
|
|
||||||
|
schema.validate(value)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('value', [Model({'additional': 1}), ])
|
||||||
|
def test_object_additional_propetries_false(self, value):
|
||||||
|
schema = Schema('object', additional_properties=False)
|
||||||
|
|
||||||
|
with pytest.raises(UndefinedSchemaProperty):
|
||||||
|
schema.validate(value)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('value', [Model({'additional': 1}), ])
|
||||||
|
def test_object_additional_propetries_object(self, value):
|
||||||
|
additional_properties = Schema('integer')
|
||||||
|
schema = Schema('object', additional_properties=additional_properties)
|
||||||
|
|
||||||
|
schema.validate(value)
|
||||||
|
|
||||||
@pytest.mark.parametrize('value', [[], ])
|
@pytest.mark.parametrize('value', [[], ])
|
||||||
def test_list_min_items_invalid_schema(self, value):
|
def test_list_min_items_invalid_schema(self, value):
|
||||||
schema = Schema(
|
schema = Schema(
|
||||||
|
@ -780,3 +881,65 @@ class TestSchemaValidate(object):
|
||||||
|
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
schema.validate(value)
|
schema.validate(value)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('value', [
|
||||||
|
Model({
|
||||||
|
'someint': 123,
|
||||||
|
}),
|
||||||
|
Model({
|
||||||
|
'somestr': u('content'),
|
||||||
|
}),
|
||||||
|
Model({
|
||||||
|
'somestr': u('content'),
|
||||||
|
'someint': 123,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
def test_object_with_properties(self, value):
|
||||||
|
schema = Schema(
|
||||||
|
'object',
|
||||||
|
properties={
|
||||||
|
'somestr': Schema('string'),
|
||||||
|
'someint': Schema('integer'),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
result = schema.validate(value)
|
||||||
|
|
||||||
|
assert result == value
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('value', [
|
||||||
|
Model({
|
||||||
|
'somestr': Model(),
|
||||||
|
'someint': 123,
|
||||||
|
}),
|
||||||
|
Model({
|
||||||
|
'somestr': {},
|
||||||
|
'someint': 123,
|
||||||
|
}),
|
||||||
|
Model({
|
||||||
|
'somestr': [
|
||||||
|
'content1', 'content2'
|
||||||
|
],
|
||||||
|
'someint': 123,
|
||||||
|
}),
|
||||||
|
Model({
|
||||||
|
'somestr': 123,
|
||||||
|
'someint': 123,
|
||||||
|
}),
|
||||||
|
Model({
|
||||||
|
'somestr': 'content',
|
||||||
|
'someint': 123,
|
||||||
|
'not_in_scheme_prop': 123,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
def test_object_with_invalid_properties(self, value):
|
||||||
|
schema = Schema(
|
||||||
|
'object',
|
||||||
|
properties={
|
||||||
|
'somestr': Schema('string'),
|
||||||
|
'someint': Schema('integer'),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
schema.validate(value)
|
||||||
|
|
Loading…
Reference in a new issue