mirror of
https://github.com/correl/openapi-core.git
synced 2024-11-22 03:00:10 +00:00
Merge pull request #152 from phrfpeixoto/read_only_write_only
Yet another readOnly and writeOnly support
This commit is contained in:
commit
778b4a51a5
13 changed files with 279 additions and 19 deletions
|
@ -46,6 +46,8 @@ class SchemaFactory(object):
|
||||||
exclusive_maximum = schema_deref.get('exclusiveMaximum', False)
|
exclusive_maximum = schema_deref.get('exclusiveMaximum', False)
|
||||||
min_properties = schema_deref.get('minProperties', None)
|
min_properties = schema_deref.get('minProperties', None)
|
||||||
max_properties = schema_deref.get('maxProperties', None)
|
max_properties = schema_deref.get('maxProperties', None)
|
||||||
|
read_only = schema_deref.get('readOnly', False)
|
||||||
|
write_only = schema_deref.get('writeOnly', False)
|
||||||
|
|
||||||
extensions = self.extensions_generator.generate(schema_deref)
|
extensions = self.extensions_generator.generate(schema_deref)
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ class SchemaFactory(object):
|
||||||
exclusive_maximum=exclusive_maximum,
|
exclusive_maximum=exclusive_maximum,
|
||||||
exclusive_minimum=exclusive_minimum,
|
exclusive_minimum=exclusive_minimum,
|
||||||
min_properties=min_properties, max_properties=max_properties,
|
min_properties=min_properties, max_properties=max_properties,
|
||||||
extensions=extensions,
|
read_only=read_only, write_only=write_only, extensions=extensions,
|
||||||
_source=schema_deref,
|
_source=schema_deref,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ class Schema(object):
|
||||||
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,
|
||||||
min_properties=None, max_properties=None, extensions=None,
|
min_properties=None, max_properties=None,
|
||||||
|
read_only=False, write_only=False, extensions=None,
|
||||||
_source=None):
|
_source=None):
|
||||||
self.type = SchemaType(schema_type)
|
self.type = SchemaType(schema_type)
|
||||||
self.properties = properties and dict(properties) or {}
|
self.properties = properties and dict(properties) or {}
|
||||||
|
@ -56,6 +57,8 @@ class Schema(object):
|
||||||
if min_properties is not None else None
|
if min_properties is not None else None
|
||||||
self.max_properties = int(max_properties)\
|
self.max_properties = int(max_properties)\
|
||||||
if max_properties is not None else None
|
if max_properties is not None else None
|
||||||
|
self.read_only = read_only
|
||||||
|
self.write_only = write_only
|
||||||
|
|
||||||
self.extensions = extensions and dict(extensions) or {}
|
self.extensions = extensions and dict(extensions) or {}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,19 @@ def nullable(validator, is_nullable, instance, schema):
|
||||||
yield ValidationError("None for not nullable")
|
yield ValidationError("None for not nullable")
|
||||||
|
|
||||||
|
|
||||||
|
def required(validator, required, instance, schema):
|
||||||
|
if not validator.is_type(instance, "object"):
|
||||||
|
return
|
||||||
|
for property in required:
|
||||||
|
if property not in instance:
|
||||||
|
prop_schema = schema['properties'][property]
|
||||||
|
read_only = prop_schema.get('readOnly', False)
|
||||||
|
write_only = prop_schema.get('writeOnly', False)
|
||||||
|
if validator.write and read_only or validator.read and write_only:
|
||||||
|
continue
|
||||||
|
yield ValidationError("%r is a required property" % property)
|
||||||
|
|
||||||
|
|
||||||
def additionalProperties(validator, aP, instance, schema):
|
def additionalProperties(validator, aP, instance, schema):
|
||||||
if not validator.is_type(instance, "object"):
|
if not validator.is_type(instance, "object"):
|
||||||
return
|
return
|
||||||
|
@ -54,5 +67,21 @@ def additionalProperties(validator, aP, instance, schema):
|
||||||
yield ValidationError(error % extras_msg(extras))
|
yield ValidationError(error % extras_msg(extras))
|
||||||
|
|
||||||
|
|
||||||
|
def readOnly(validator, ro, instance, schema):
|
||||||
|
if not validator.write or not ro:
|
||||||
|
return
|
||||||
|
|
||||||
|
yield ValidationError(
|
||||||
|
"Tried to write read-only proparty with %s" % (instance))
|
||||||
|
|
||||||
|
|
||||||
|
def writeOnly(validator, wo, instance, schema):
|
||||||
|
if not validator.read or not wo:
|
||||||
|
return
|
||||||
|
|
||||||
|
yield ValidationError(
|
||||||
|
"Tried to read write-only proparty with %s" % (instance))
|
||||||
|
|
||||||
|
|
||||||
def not_implemented(validator, value, instance, schema):
|
def not_implemented(validator, value, instance, schema):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -21,7 +21,6 @@ BaseOAS30Validator = create(
|
||||||
u"uniqueItems": _validators.uniqueItems,
|
u"uniqueItems": _validators.uniqueItems,
|
||||||
u"maxProperties": _validators.maxProperties,
|
u"maxProperties": _validators.maxProperties,
|
||||||
u"minProperties": _validators.minProperties,
|
u"minProperties": _validators.minProperties,
|
||||||
u"required": _validators.required,
|
|
||||||
u"enum": _validators.enum,
|
u"enum": _validators.enum,
|
||||||
# adjusted to OAS
|
# adjusted to OAS
|
||||||
u"type": oas_validators.type,
|
u"type": oas_validators.type,
|
||||||
|
@ -31,6 +30,7 @@ BaseOAS30Validator = create(
|
||||||
u"not": _validators.not_,
|
u"not": _validators.not_,
|
||||||
u"items": oas_validators.items,
|
u"items": oas_validators.items,
|
||||||
u"properties": _validators.properties,
|
u"properties": _validators.properties,
|
||||||
|
u"required": oas_validators.required,
|
||||||
u"additionalProperties": oas_validators.additionalProperties,
|
u"additionalProperties": oas_validators.additionalProperties,
|
||||||
# TODO: adjust description
|
# TODO: adjust description
|
||||||
u"format": oas_validators.format,
|
u"format": oas_validators.format,
|
||||||
|
@ -39,8 +39,8 @@ BaseOAS30Validator = create(
|
||||||
# fixed OAS fields
|
# fixed OAS fields
|
||||||
u"nullable": oas_validators.nullable,
|
u"nullable": oas_validators.nullable,
|
||||||
u"discriminator": oas_validators.not_implemented,
|
u"discriminator": oas_validators.not_implemented,
|
||||||
u"readOnly": oas_validators.not_implemented,
|
u"readOnly": oas_validators.readOnly,
|
||||||
u"writeOnly": oas_validators.not_implemented,
|
u"writeOnly": oas_validators.writeOnly,
|
||||||
u"xml": oas_validators.not_implemented,
|
u"xml": oas_validators.not_implemented,
|
||||||
u"externalDocs": oas_validators.not_implemented,
|
u"externalDocs": oas_validators.not_implemented,
|
||||||
u"example": oas_validators.not_implemented,
|
u"example": oas_validators.not_implemented,
|
||||||
|
@ -54,6 +54,11 @@ BaseOAS30Validator = create(
|
||||||
|
|
||||||
class OAS30Validator(BaseOAS30Validator):
|
class OAS30Validator(BaseOAS30Validator):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.read = kwargs.pop('read', None)
|
||||||
|
self.write = kwargs.pop('write', None)
|
||||||
|
super(OAS30Validator, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def iter_errors(self, instance, _schema=None):
|
def iter_errors(self, instance, _schema=None):
|
||||||
if _schema is None:
|
if _schema is None:
|
||||||
_schema = self.schema
|
_schema = self.schema
|
||||||
|
|
7
openapi_core/unmarshalling/schemas/enums.py
Normal file
7
openapi_core/unmarshalling/schemas/enums.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
"""OpenAPI core unmarshalling schemas enums module"""
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class UnmarshalContext(Enum):
|
||||||
|
REQUEST = 'request'
|
||||||
|
RESPONSE = 'response'
|
|
@ -5,6 +5,7 @@ from openapi_core.schema.schemas.enums import SchemaType, SchemaFormat
|
||||||
from openapi_core.schema.schemas.models import Schema
|
from openapi_core.schema.schemas.models import Schema
|
||||||
from openapi_core.schema_validator import OAS30Validator
|
from openapi_core.schema_validator import OAS30Validator
|
||||||
from openapi_core.schema_validator import oas30_format_checker
|
from openapi_core.schema_validator import oas30_format_checker
|
||||||
|
from openapi_core.unmarshalling.schemas.enums import UnmarshalContext
|
||||||
from openapi_core.unmarshalling.schemas.exceptions import (
|
from openapi_core.unmarshalling.schemas.exceptions import (
|
||||||
FormatterNotFoundError,
|
FormatterNotFoundError,
|
||||||
)
|
)
|
||||||
|
@ -29,11 +30,17 @@ class SchemaUnmarshallersFactory(object):
|
||||||
SchemaType.ANY: AnyUnmarshaller,
|
SchemaType.ANY: AnyUnmarshaller,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, resolver=None, custom_formatters=None):
|
CONTEXT_VALIDATION = {
|
||||||
|
UnmarshalContext.REQUEST: 'write',
|
||||||
|
UnmarshalContext.RESPONSE: 'read',
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, resolver=None, custom_formatters=None, context=None):
|
||||||
self.resolver = resolver
|
self.resolver = resolver
|
||||||
if custom_formatters is None:
|
if custom_formatters is None:
|
||||||
custom_formatters = {}
|
custom_formatters = {}
|
||||||
self.custom_formatters = custom_formatters
|
self.custom_formatters = custom_formatters
|
||||||
|
self.context = context
|
||||||
|
|
||||||
def create(self, schema, type_override=None):
|
def create(self, schema, type_override=None):
|
||||||
"""Create unmarshaller from the schema."""
|
"""Create unmarshaller from the schema."""
|
||||||
|
@ -50,7 +57,9 @@ class SchemaUnmarshallersFactory(object):
|
||||||
elif schema_type in self.COMPLEX_UNMARSHALLERS:
|
elif schema_type in self.COMPLEX_UNMARSHALLERS:
|
||||||
klass = self.COMPLEX_UNMARSHALLERS[schema_type]
|
klass = self.COMPLEX_UNMARSHALLERS[schema_type]
|
||||||
kwargs = dict(
|
kwargs = dict(
|
||||||
schema=schema, unmarshallers_factory=self)
|
schema=schema, unmarshallers_factory=self,
|
||||||
|
context=self.context,
|
||||||
|
)
|
||||||
|
|
||||||
formatter = self.get_formatter(klass.FORMATTERS, schema.format)
|
formatter = self.get_formatter(klass.FORMATTERS, schema.format)
|
||||||
|
|
||||||
|
@ -70,10 +79,17 @@ class SchemaUnmarshallersFactory(object):
|
||||||
return default_formatters.get(schema_format)
|
return default_formatters.get(schema_format)
|
||||||
|
|
||||||
def get_validator(self, schema):
|
def get_validator(self, schema):
|
||||||
format_checker = deepcopy(oas30_format_checker)
|
format_checker = self._get_format_checker()
|
||||||
|
kwargs = {
|
||||||
|
'resolver': self.resolver,
|
||||||
|
'format_checker': format_checker,
|
||||||
|
}
|
||||||
|
if self.context is not None:
|
||||||
|
kwargs[self.CONTEXT_VALIDATION[self.context]] = True
|
||||||
|
return OAS30Validator(schema.__dict__, **kwargs)
|
||||||
|
|
||||||
|
def _get_format_checker(self):
|
||||||
|
fc = deepcopy(oas30_format_checker)
|
||||||
for name, formatter in self.custom_formatters.items():
|
for name, formatter in self.custom_formatters.items():
|
||||||
format_checker.checks(name)(formatter.validate)
|
fc.checks(name)(formatter.validate)
|
||||||
return OAS30Validator(
|
return fc
|
||||||
schema.__dict__,
|
|
||||||
resolver=self.resolver, format_checker=format_checker,
|
|
||||||
)
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ from openapi_core.schema_validator._types import (
|
||||||
is_object, is_number, is_string,
|
is_object, is_number, is_string,
|
||||||
)
|
)
|
||||||
from openapi_core.schema_validator._format import oas30_format_checker
|
from openapi_core.schema_validator._format import oas30_format_checker
|
||||||
|
from openapi_core.unmarshalling.schemas.enums import UnmarshalContext
|
||||||
from openapi_core.unmarshalling.schemas.exceptions import (
|
from openapi_core.unmarshalling.schemas.exceptions import (
|
||||||
UnmarshalError, ValidateError, InvalidSchemaValue,
|
UnmarshalError, ValidateError, InvalidSchemaValue,
|
||||||
InvalidSchemaFormatValue,
|
InvalidSchemaFormatValue,
|
||||||
|
@ -120,9 +121,12 @@ class BooleanUnmarshaller(PrimitiveTypeUnmarshaller):
|
||||||
|
|
||||||
class ComplexUnmarshaller(PrimitiveTypeUnmarshaller):
|
class ComplexUnmarshaller(PrimitiveTypeUnmarshaller):
|
||||||
|
|
||||||
def __init__(self, formatter, validator, schema, unmarshallers_factory):
|
def __init__(
|
||||||
|
self, formatter, validator, schema, unmarshallers_factory,
|
||||||
|
context=None):
|
||||||
super(ComplexUnmarshaller, self).__init__(formatter, validator, schema)
|
super(ComplexUnmarshaller, self).__init__(formatter, validator, schema)
|
||||||
self.unmarshallers_factory = unmarshallers_factory
|
self.unmarshallers_factory = unmarshallers_factory
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
|
||||||
class ArrayUnmarshaller(ComplexUnmarshaller):
|
class ArrayUnmarshaller(ComplexUnmarshaller):
|
||||||
|
@ -206,6 +210,10 @@ class ObjectUnmarshaller(ComplexUnmarshaller):
|
||||||
properties[prop_name] = prop_value
|
properties[prop_name] = prop_value
|
||||||
|
|
||||||
for prop_name, prop in iteritems(all_props):
|
for prop_name, prop in iteritems(all_props):
|
||||||
|
if self.context == UnmarshalContext.REQUEST and prop.read_only:
|
||||||
|
continue
|
||||||
|
if self.context == UnmarshalContext.RESPONSE and prop.write_only:
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
prop_value = value[prop_name]
|
prop_value = value[prop_name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
|
@ -13,6 +13,7 @@ from openapi_core.schema.paths.exceptions import InvalidPath
|
||||||
from openapi_core.schema.request_bodies.exceptions import MissingRequestBody
|
from openapi_core.schema.request_bodies.exceptions import MissingRequestBody
|
||||||
from openapi_core.schema.servers.exceptions import InvalidServer
|
from openapi_core.schema.servers.exceptions import InvalidServer
|
||||||
from openapi_core.security.exceptions import SecurityError
|
from openapi_core.security.exceptions import SecurityError
|
||||||
|
from openapi_core.unmarshalling.schemas.enums import UnmarshalContext
|
||||||
from openapi_core.unmarshalling.schemas.exceptions import (
|
from openapi_core.unmarshalling.schemas.exceptions import (
|
||||||
UnmarshalError, ValidateError,
|
UnmarshalError, ValidateError,
|
||||||
)
|
)
|
||||||
|
@ -256,7 +257,9 @@ class RequestValidator(object):
|
||||||
SchemaUnmarshallersFactory,
|
SchemaUnmarshallersFactory,
|
||||||
)
|
)
|
||||||
unmarshallers_factory = SchemaUnmarshallersFactory(
|
unmarshallers_factory = SchemaUnmarshallersFactory(
|
||||||
self.spec._resolver, self.custom_formatters)
|
self.spec._resolver, self.custom_formatters,
|
||||||
|
context=UnmarshalContext.REQUEST,
|
||||||
|
)
|
||||||
unmarshaller = unmarshallers_factory.create(
|
unmarshaller = unmarshallers_factory.create(
|
||||||
param_or_media_type.schema)
|
param_or_media_type.schema)
|
||||||
return unmarshaller(value)
|
return unmarshaller(value)
|
||||||
|
|
|
@ -7,6 +7,7 @@ from openapi_core.schema.responses.exceptions import (
|
||||||
InvalidResponse, MissingResponseContent,
|
InvalidResponse, MissingResponseContent,
|
||||||
)
|
)
|
||||||
from openapi_core.schema.servers.exceptions import InvalidServer
|
from openapi_core.schema.servers.exceptions import InvalidServer
|
||||||
|
from openapi_core.unmarshalling.schemas.enums import UnmarshalContext
|
||||||
from openapi_core.unmarshalling.schemas.exceptions import (
|
from openapi_core.unmarshalling.schemas.exceptions import (
|
||||||
UnmarshalError, ValidateError,
|
UnmarshalError, ValidateError,
|
||||||
)
|
)
|
||||||
|
@ -139,7 +140,9 @@ class ResponseValidator(object):
|
||||||
SchemaUnmarshallersFactory,
|
SchemaUnmarshallersFactory,
|
||||||
)
|
)
|
||||||
unmarshallers_factory = SchemaUnmarshallersFactory(
|
unmarshallers_factory = SchemaUnmarshallersFactory(
|
||||||
self.spec._resolver, self.custom_formatters)
|
self.spec._resolver, self.custom_formatters,
|
||||||
|
context=UnmarshalContext.RESPONSE,
|
||||||
|
)
|
||||||
unmarshaller = unmarshallers_factory.create(
|
unmarshaller = unmarshallers_factory.create(
|
||||||
param_or_media_type.schema)
|
param_or_media_type.schema)
|
||||||
return unmarshaller(value)
|
return unmarshaller(value)
|
||||||
|
|
39
tests/integration/data/v3.0/read_only_write_only.yaml
Normal file
39
tests/integration/data/v3.0/read_only_write_only.yaml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
openapi: "3.0.0"
|
||||||
|
info:
|
||||||
|
title: Specification Containing readOnly
|
||||||
|
version: "0.1"
|
||||||
|
paths:
|
||||||
|
/users:
|
||||||
|
post:
|
||||||
|
operationId: createUser
|
||||||
|
requestBody:
|
||||||
|
description: Post data for creating a user
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
responses:
|
||||||
|
default:
|
||||||
|
description: Create a user
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int32
|
||||||
|
readOnly: true
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
hidden:
|
||||||
|
type: boolean
|
||||||
|
writeOnly: true
|
|
@ -268,5 +268,9 @@ class TestPetstore(object):
|
||||||
if not spec.components:
|
if not spec.components:
|
||||||
return
|
return
|
||||||
|
|
||||||
for _, schema in iteritems(spec.components.schemas):
|
for schema_name, schema in iteritems(spec.components.schemas):
|
||||||
assert type(schema) == Schema
|
assert type(schema) == Schema
|
||||||
|
|
||||||
|
schema_spec = spec_dict['components']['schemas'][schema_name]
|
||||||
|
assert schema.read_only == schema_spec.get('readOnly', False)
|
||||||
|
assert schema.write_only == schema_spec.get('writeOnly', False)
|
||||||
|
|
97
tests/integration/validation/test_read_only_write_only.py
Normal file
97
tests/integration/validation/test_read_only_write_only.py
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from openapi_core.shortcuts import create_spec
|
||||||
|
from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue
|
||||||
|
from openapi_core.validation.response.validators import ResponseValidator
|
||||||
|
from openapi_core.validation.request.validators import RequestValidator
|
||||||
|
from openapi_core.testing import MockRequest, MockResponse
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def response_validator(spec):
|
||||||
|
return ResponseValidator(spec)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def request_validator(spec):
|
||||||
|
return RequestValidator(spec)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture('class')
|
||||||
|
def spec(factory):
|
||||||
|
spec_dict = factory.spec_from_file("data/v3.0/read_only_write_only.yaml")
|
||||||
|
return create_spec(spec_dict)
|
||||||
|
|
||||||
|
|
||||||
|
class TestReadOnly(object):
|
||||||
|
|
||||||
|
def test_write_a_read_only_property(self, request_validator):
|
||||||
|
data = json.dumps({
|
||||||
|
'id': 10,
|
||||||
|
'name': "Pedro",
|
||||||
|
})
|
||||||
|
|
||||||
|
request = MockRequest(host_url='', method='POST',
|
||||||
|
path='/users', data=data)
|
||||||
|
|
||||||
|
result = request_validator.validate(request)
|
||||||
|
|
||||||
|
assert type(result.errors[0]) == InvalidSchemaValue
|
||||||
|
assert result.body is None
|
||||||
|
|
||||||
|
def test_read_only_property_response(self, response_validator):
|
||||||
|
data = json.dumps({
|
||||||
|
'id': 10,
|
||||||
|
'name': "Pedro",
|
||||||
|
})
|
||||||
|
|
||||||
|
request = MockRequest(host_url='', method='POST',
|
||||||
|
path='/users')
|
||||||
|
|
||||||
|
response = MockResponse(data)
|
||||||
|
|
||||||
|
result = response_validator.validate(request, response)
|
||||||
|
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == {
|
||||||
|
'id': 10,
|
||||||
|
'name': "Pedro",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestWriteOnly(object):
|
||||||
|
|
||||||
|
def test_write_only_property(self, request_validator):
|
||||||
|
data = json.dumps({
|
||||||
|
'name': "Pedro",
|
||||||
|
'hidden': False,
|
||||||
|
})
|
||||||
|
|
||||||
|
request = MockRequest(host_url='', method='POST',
|
||||||
|
path='/users', data=data)
|
||||||
|
|
||||||
|
result = request_validator.validate(request)
|
||||||
|
|
||||||
|
assert not result.errors
|
||||||
|
assert result.body == {
|
||||||
|
'name': "Pedro",
|
||||||
|
'hidden': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_read_a_write_only_property(self, response_validator):
|
||||||
|
data = json.dumps({
|
||||||
|
'id': 10,
|
||||||
|
'name': "Pedro",
|
||||||
|
'hidden': True,
|
||||||
|
})
|
||||||
|
|
||||||
|
request = MockRequest(host_url='', method='POST',
|
||||||
|
path='/users')
|
||||||
|
response = MockResponse(data)
|
||||||
|
|
||||||
|
result = response_validator.validate(request, response)
|
||||||
|
|
||||||
|
assert type(result.errors[0]) == InvalidSchemaValue
|
||||||
|
assert result.data is None
|
|
@ -8,6 +8,7 @@ from openapi_core.schema.parameters.models import Parameter
|
||||||
from openapi_core.schema.schemas.enums import SchemaType
|
from openapi_core.schema.schemas.enums import SchemaType
|
||||||
from openapi_core.schema.schemas.models import Schema
|
from openapi_core.schema.schemas.models import Schema
|
||||||
from openapi_core.schema.schemas.types import NoValue
|
from openapi_core.schema.schemas.types import NoValue
|
||||||
|
from openapi_core.unmarshalling.schemas.enums import UnmarshalContext
|
||||||
from openapi_core.unmarshalling.schemas.exceptions import (
|
from openapi_core.unmarshalling.schemas.exceptions import (
|
||||||
InvalidSchemaFormatValue, InvalidSchemaValue, UnmarshalError,
|
InvalidSchemaFormatValue, InvalidSchemaValue, UnmarshalError,
|
||||||
FormatterNotFoundError,
|
FormatterNotFoundError,
|
||||||
|
@ -20,9 +21,10 @@ from openapi_core.unmarshalling.schemas.formatters import Formatter
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def unmarshaller_factory():
|
def unmarshaller_factory():
|
||||||
def create_unmarshaller(schema, custom_formatters=None):
|
def create_unmarshaller(schema, custom_formatters=None, context=None):
|
||||||
return SchemaUnmarshallersFactory(
|
return SchemaUnmarshallersFactory(
|
||||||
custom_formatters=custom_formatters).create(schema)
|
custom_formatters=custom_formatters, context=context).create(
|
||||||
|
schema)
|
||||||
return create_unmarshaller
|
return create_unmarshaller
|
||||||
|
|
||||||
|
|
||||||
|
@ -429,3 +431,45 @@ class TestSchemaUnmarshallerCall(object):
|
||||||
|
|
||||||
result = unmarshaller_factory(schema)(value)
|
result = unmarshaller_factory(schema)(value)
|
||||||
assert result == value
|
assert result == value
|
||||||
|
|
||||||
|
def test_read_only_properties(self, unmarshaller_factory):
|
||||||
|
id_property = Schema('integer', read_only=True)
|
||||||
|
|
||||||
|
def properties():
|
||||||
|
yield ('id', id_property)
|
||||||
|
|
||||||
|
obj_schema = Schema('object', properties=properties(), required=['id'])
|
||||||
|
|
||||||
|
# readOnly properties may be admitted in a Response context
|
||||||
|
result = unmarshaller_factory(
|
||||||
|
obj_schema, context=UnmarshalContext.RESPONSE)({"id": 10})
|
||||||
|
assert result == {
|
||||||
|
'id': 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
# readOnly properties are not admitted on a Request context
|
||||||
|
result = unmarshaller_factory(
|
||||||
|
obj_schema, context=UnmarshalContext.REQUEST)({"id": 10})
|
||||||
|
|
||||||
|
assert result == {}
|
||||||
|
|
||||||
|
def test_write_only_properties(self, unmarshaller_factory):
|
||||||
|
id_property = Schema('integer', write_only=True)
|
||||||
|
|
||||||
|
def properties():
|
||||||
|
yield ('id', id_property)
|
||||||
|
|
||||||
|
obj_schema = Schema('object', properties=properties(), required=['id'])
|
||||||
|
|
||||||
|
# readOnly properties may be admitted in a Response context
|
||||||
|
result = unmarshaller_factory(
|
||||||
|
obj_schema, context=UnmarshalContext.REQUEST)({"id": 10})
|
||||||
|
assert result == {
|
||||||
|
'id': 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
# readOnly properties are not admitted on a Request context
|
||||||
|
result = unmarshaller_factory(
|
||||||
|
obj_schema, context=UnmarshalContext.RESPONSE)({"id": 10})
|
||||||
|
|
||||||
|
assert result == {}
|
||||||
|
|
Loading…
Reference in a new issue