Merge pull request #166 from p1c2u/feature/wrappers-restructure

OpenAPI request/response factories introduction
This commit is contained in:
A 2019-10-19 14:13:33 +01:00 committed by GitHub
commit 9be404ebfc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 310 additions and 304 deletions

View file

@ -66,8 +66,10 @@ and unmarshal request data from validation result
.. code-block:: python .. code-block:: python
# get parameters dictionary with path, query, cookies and headers parameters # get parameters object with path, query, cookies and headers parameters
validated_params = result.parameters validated_params = result.parameters
# or specific parameters
validated_path_params = result.parameters.path
# get body # get body
validated_body = result.body validated_body = result.body
@ -81,27 +83,27 @@ or use shortcuts for simple validation
validated_params = validate_parameters(spec, request) validated_params = validate_parameters(spec, request)
validated_body = validate_body(spec, request) validated_body = validate_body(spec, request)
Request object should implement BaseOpenAPIRequest interface. You can use FlaskOpenAPIRequest a Flask/Werkzeug request wrapper implementation: Request object should be instance of OpenAPIRequest class. You can use FlaskOpenAPIRequest a Flask/Werkzeug request factory:
.. code-block:: python .. code-block:: python
from openapi_core.shortcuts import RequestValidator from openapi_core.shortcuts import RequestValidator
from openapi_core.wrappers.flask import FlaskOpenAPIRequest from openapi_core.contrib.flask import FlaskOpenAPIRequest
openapi_request = FlaskOpenAPIRequest(flask_request) openapi_request = FlaskOpenAPIRequest(flask_request)
validator = RequestValidator(spec) validator = RequestValidator(spec)
result = validator.validate(openapi_request) result = validator.validate(openapi_request)
or specify request wrapper class for shortcuts or simply specify request factory for shortcuts
.. code-block:: python .. code-block:: python
from openapi_core import validate_parameters, validate_body from openapi_core import validate_parameters, validate_body
validated_params = validate_parameters( validated_params = validate_parameters(
spec, request, wrapper_class=FlaskOpenAPIRequest) spec, request, request_factory=FlaskOpenAPIRequest)
validated_body = validate_body( validated_body = validate_body(
spec, request, wrapper_class=FlaskOpenAPIRequest) spec, request, request_factory=FlaskOpenAPIRequest)
You can also validate responses You can also validate responses
@ -136,25 +138,27 @@ or use shortcuts for simple validation
validated_data = validate_data(spec, request, response) validated_data = validate_data(spec, request, response)
Response object should implement BaseOpenAPIResponse interface. You can use FlaskOpenAPIResponse a Flask/Werkzeug response wrapper implementation: Response object should be instance of OpenAPIResponse class. You can use FlaskOpenAPIResponse a Flask/Werkzeug response factory:
.. code-block:: python .. code-block:: python
from openapi_core.shortcuts import ResponseValidator from openapi_core.shortcuts import ResponseValidator
from openapi_core.wrappers.flask import FlaskOpenAPIResponse from openapi_core.contrib.flask import FlaskOpenAPIResponse
openapi_response = FlaskOpenAPIResponse(flask_response) openapi_response = FlaskOpenAPIResponse(flask_response)
validator = ResponseValidator(spec) validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response) result = validator.validate(openapi_request, openapi_response)
or specify response wrapper class for shortcuts or simply specify response factory for shortcuts
.. code-block:: python .. code-block:: python
from openapi_core import validate_parameters, validate_body from openapi_core import validate_parameters, validate_body
validated_data = validate_data( validated_data = validate_data(
spec, request, response, response_wrapper_class=FlaskOpenAPIResponse) spec, request, response,
request_factory=FlaskOpenAPIRequest,
response_factory=FlaskOpenAPIResponse)
Related projects Related projects
================ ================

View file

@ -0,0 +1,11 @@
from openapi_core.contrib.flask.requests import FlaskOpenAPIRequestFactory
from openapi_core.contrib.flask.responses import FlaskOpenAPIResponseFactory
# backward compatibility
FlaskOpenAPIRequest = FlaskOpenAPIRequestFactory.create
FlaskOpenAPIResponse = FlaskOpenAPIResponseFactory.create
__all__ = [
'FlaskOpenAPIRequestFactory', 'FlaskOpenAPIResponseFactory',
'FlaskOpenAPIRequest', 'FlaskOpenAPIResponse',
]

View file

@ -0,0 +1,39 @@
"""OpenAPI core contrib flask requests module"""
import re
from openapi_core.validation.request.datatypes import (
RequestParameters, OpenAPIRequest,
)
# http://flask.pocoo.org/docs/1.0/quickstart/#variable-rules
PATH_PARAMETER_PATTERN = r'<(?:(?:string|int|float|path|uuid):)?(\w+)>'
class FlaskOpenAPIRequestFactory(object):
path_regex = re.compile(PATH_PARAMETER_PATTERN)
@classmethod
def create(cls, request):
method = request.method.lower()
if request.url_rule is None:
path_pattern = request.path
else:
path_pattern = cls.path_regex.sub(r'{\1}', request.url_rule.rule)
parameters = RequestParameters(
path=request.view_args,
query=request.args,
header=request.headers,
cookie=request.cookies,
)
return OpenAPIRequest(
host_url=request.host_url,
path=request.path,
path_pattern=path_pattern,
method=method,
parameters=parameters,
body=request.data,
mimetype=request.mimetype,
)

View file

@ -0,0 +1,15 @@
"""OpenAPI core contrib flask responses module"""
import re
from openapi_core.validation.response.datatypes import OpenAPIResponse
class FlaskOpenAPIResponseFactory(object):
@classmethod
def create(cls, response):
return OpenAPIResponse(
data=response.data,
status_code=response._status_code,
mimetype=response.mimetype,
)

View file

@ -20,9 +20,9 @@ def create_spec(spec_dict, spec_url=''):
return spec_factory.create(spec_dict, spec_url=spec_url) return spec_factory.create(spec_dict, spec_url=spec_url)
def validate_parameters(spec, request, wrapper_class=None): def validate_parameters(spec, request, request_factory=None):
if wrapper_class is not None: if request_factory is not None:
request = wrapper_class(request) request = request_factory(request)
validator = RequestValidator(spec) validator = RequestValidator(spec)
result = validator.validate(request) result = validator.validate(request)
@ -38,9 +38,9 @@ def validate_parameters(spec, request, wrapper_class=None):
return result.parameters return result.parameters
def validate_body(spec, request, wrapper_class=None): def validate_body(spec, request, request_factory=None):
if wrapper_class is not None: if request_factory is not None:
request = wrapper_class(request) request = request_factory(request)
validator = RequestValidator(spec) validator = RequestValidator(spec)
result = validator.validate(request) result = validator.validate(request)
@ -55,13 +55,13 @@ def validate_body(spec, request, wrapper_class=None):
def validate_data( def validate_data(
spec, request, response, spec, request, response,
request_wrapper_class=None, request_factory=None,
response_wrapper_class=None): response_factory=None):
if request_wrapper_class is not None: if request_factory is not None:
request = request_wrapper_class(request) request = request_factory(request)
if response_wrapper_class is not None: if response_factory is not None:
response = response_wrapper_class(response) response = response_factory(response)
validator = ResponseValidator(spec) validator = ResponseValidator(spec)
result = validator.validate(request, response) result = validator.validate(request, response)

View file

@ -0,0 +1,10 @@
"""OpenAPI core testing module"""
from openapi_core.testing.mock import MockRequestFactory, MockResponseFactory
# backward compatibility
MockRequest = MockRequestFactory.create
MockResponse = MockResponseFactory.create
__all__ = [
'MockRequestFactory', 'MockResponseFactory', 'MockRequest', 'MockResponse',
]

View file

@ -0,0 +1,45 @@
"""OpenAPI core testing mock module"""
from werkzeug.datastructures import ImmutableMultiDict
from openapi_core.validation.request.datatypes import (
RequestParameters, OpenAPIRequest,
)
from openapi_core.validation.response.datatypes import OpenAPIResponse
class MockRequestFactory(object):
@classmethod
def create(
cls, host_url, method, path, path_pattern=None, args=None,
view_args=None, headers=None, cookies=None, data=None,
mimetype='application/json'):
parameters = RequestParameters(
path=view_args or {},
query=ImmutableMultiDict(args or []),
header=headers or {},
cookie=cookies or {},
)
path_pattern = path_pattern or path
method = method.lower()
body = data or ''
return OpenAPIRequest(
host_url=host_url,
path=path,
path_pattern=path_pattern,
method=method,
parameters=parameters,
body=body,
mimetype=mimetype,
)
class MockResponseFactory(object):
@classmethod
def create(cls, data, status_code=200, mimetype='application/json'):
return OpenAPIResponse(
data=data,
status_code=status_code,
mimetype=mimetype,
)

View file

@ -1,13 +1,17 @@
"""OpenAPI core validation request datatypes module""" """OpenAPI core validation request datatypes module"""
import attr import attr
from werkzeug.datastructures import ImmutableMultiDict
from openapi_core.validation.datatypes import BaseValidationResult from openapi_core.validation.datatypes import BaseValidationResult
from six.moves.urllib.parse import urljoin
@attr.s @attr.s
class RequestParameters(object): class RequestParameters(object):
path = attr.ib(factory=dict) path = attr.ib(factory=dict)
query = attr.ib(factory=dict) query = attr.ib(factory=ImmutableMultiDict)
header = attr.ib(factory=dict) header = attr.ib(factory=dict)
cookie = attr.ib(factory=dict) cookie = attr.ib(factory=dict)
@ -15,6 +19,25 @@ class RequestParameters(object):
return getattr(self, location) return getattr(self, location)
@attr.s
class OpenAPIRequest(object):
host_url = attr.ib()
path = attr.ib()
path_pattern = attr.ib()
method = attr.ib()
body = attr.ib()
mimetype = attr.ib()
parameters = attr.ib(factory=RequestParameters)
@property
def full_url_pattern(self):
return urljoin(self.host_url, self.path_pattern)
@attr.s @attr.s
class RequestValidationResult(BaseValidationResult): class RequestValidationResult(BaseValidationResult):
body = attr.ib(default=None) body = attr.ib(default=None)

View file

@ -50,7 +50,7 @@ class RequestValidator(object):
def _get_parameters(self, request, params): def _get_parameters(self, request, params):
errors = [] errors = []
seen = set() seen = set()
parameters = RequestParameters() locations = {}
for param_name, param in params: for param_name, param in params:
if (param_name, param.location.value) in seen: if (param_name, param.location.value) in seen:
# skip parameter already seen # skip parameter already seen
@ -79,9 +79,10 @@ class RequestValidator(object):
except OpenAPIMappingError as exc: except OpenAPIMappingError as exc:
errors.append(exc) errors.append(exc)
else: else:
parameters[param.location.value][param_name] = unmarshalled locations.setdefault(param.location.value, {})
locations[param.location.value][param_name] = unmarshalled
return parameters, errors return RequestParameters(**locations), errors
def _get_body(self, request, operation): def _get_body(self, request, operation):
errors = [] errors = []

View file

@ -4,6 +4,15 @@ import attr
from openapi_core.validation.datatypes import BaseValidationResult from openapi_core.validation.datatypes import BaseValidationResult
@attr.s
class OpenAPIResponse(object):
data = attr.ib()
status_code = attr.ib()
mimetype = attr.ib()
@attr.s @attr.s
class ResponseValidationResult(BaseValidationResult): class ResponseValidationResult(BaseValidationResult):
data = attr.ib(default=None) data = attr.ib(default=None)

View file

@ -1,49 +0,0 @@
"""OpenAPI core wrappers module"""
import warnings
from six.moves.urllib.parse import urljoin
class BaseOpenAPIRequest(object):
host_url = NotImplemented
path = NotImplemented
path_pattern = NotImplemented
method = NotImplemented
parameters = NotImplemented
body = NotImplemented
mimetype = NotImplemented
@property
def full_url_pattern(self):
return urljoin(self.host_url, self.path_pattern)
def get_body(self, spec):
warnings.warn(
"`get_body` method is deprecated. "
"Use RequestValidator instead.",
DeprecationWarning,
)
# backward compatibility
from openapi_core.shortcuts import validate_body
return validate_body(spec, self, wrapper_class=None)
def get_parameters(self, spec):
warnings.warn(
"`get_parameters` method is deprecated. "
"Use RequestValidator instead.",
DeprecationWarning,
)
# backward compatibility
from openapi_core.shortcuts import validate_parameters
return validate_parameters(spec, self, wrapper_class=None)
class BaseOpenAPIResponse(object):
body = NotImplemented
status_code = NotImplemented
mimetype = NotImplemented

View file

@ -1,69 +0,0 @@
"""OpenAPI core wrappers module"""
import re
from openapi_core.wrappers.base import BaseOpenAPIRequest, BaseOpenAPIResponse
# http://flask.pocoo.org/docs/1.0/quickstart/#variable-rules
PATH_PARAMETER_PATTERN = r'<(?:(?:string|int|float|path|uuid):)?(\w+)>'
class FlaskOpenAPIRequest(BaseOpenAPIRequest):
path_regex = re.compile(PATH_PARAMETER_PATTERN)
def __init__(self, request):
self.request = request
@property
def host_url(self):
return self.request.host_url
@property
def path(self):
return self.request.path
@property
def method(self):
return self.request.method.lower()
@property
def path_pattern(self):
if self.request.url_rule is None:
return self.path
return self.path_regex.sub(r'{\1}', self.request.url_rule.rule)
@property
def parameters(self):
return {
'path': self.request.view_args,
'query': self.request.args,
'header': self.request.headers,
'cookie': self.request.cookies,
}
@property
def body(self):
return self.request.data
@property
def mimetype(self):
return self.request.mimetype
class FlaskOpenAPIResponse(BaseOpenAPIResponse):
def __init__(self, response):
self.response = response
@property
def data(self):
return self.response.data
@property
def status_code(self):
return self.response._status_code
@property
def mimetype(self):
return self.response.mimetype

View file

@ -1,36 +0,0 @@
"""OpenAPI core wrappers module"""
from werkzeug.datastructures import ImmutableMultiDict
from openapi_core.wrappers.base import BaseOpenAPIRequest, BaseOpenAPIResponse
class MockRequest(BaseOpenAPIRequest):
def __init__(
self, host_url, method, path, path_pattern=None, args=None,
view_args=None, headers=None, cookies=None, data=None,
mimetype='application/json'):
self.host_url = host_url
self.path = path
self.path_pattern = path_pattern or path
self.method = method.lower()
self.parameters = {
'path': view_args or {},
'query': ImmutableMultiDict(args or []),
'header': headers or {},
'cookie': cookies or {},
}
self.body = data or ''
self.mimetype = mimetype
class MockResponse(BaseOpenAPIResponse):
def __init__(self, data, status_code=200, mimetype='application/json'):
self.data = data
self.status_code = status_code
self.mimetype = mimetype

View file

@ -1,14 +1,16 @@
from flask.wrappers import Request, Response from flask.wrappers import Request, Response
import pytest
from werkzeug.datastructures import EnvironHeaders, ImmutableMultiDict from werkzeug.datastructures import EnvironHeaders, ImmutableMultiDict
from werkzeug.routing import Map, Rule, Subdomain from werkzeug.routing import Map, Rule, Subdomain
from werkzeug.test import create_environ from werkzeug.test import create_environ
import pytest from openapi_core.contrib.flask import (
FlaskOpenAPIRequest, FlaskOpenAPIResponse,
)
from openapi_core.shortcuts import create_spec from openapi_core.shortcuts import create_spec
from openapi_core.validation.response.validators import ResponseValidator from openapi_core.validation.request.datatypes import RequestParameters
from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.request.validators import RequestValidator
from openapi_core.wrappers.flask import (FlaskOpenAPIRequest, from openapi_core.validation.response.validators import ResponseValidator
FlaskOpenAPIResponse)
@pytest.fixture @pytest.fixture
@ -66,12 +68,12 @@ class TestFlaskOpenAPIRequest(object):
query = ImmutableMultiDict([]) query = ImmutableMultiDict([])
headers = EnvironHeaders(request.environ) headers = EnvironHeaders(request.environ)
cookies = {} cookies = {}
assert openapi_request.parameters == { assert openapi_request.parameters == RequestParameters(
'path': path, path=path,
'query': query, query=query,
'header': headers, header=headers,
'cookie': cookies, cookie=cookies,
} )
assert openapi_request.host_url == request.host_url assert openapi_request.host_url == request.host_url
assert openapi_request.path == request.path assert openapi_request.path == request.path
assert openapi_request.method == request.method.lower() assert openapi_request.method == request.method.lower()
@ -91,12 +93,12 @@ class TestFlaskOpenAPIRequest(object):
]) ])
headers = EnvironHeaders(request.environ) headers = EnvironHeaders(request.environ)
cookies = {} cookies = {}
assert openapi_request.parameters == { assert openapi_request.parameters == RequestParameters(
'path': path, path=path,
'query': query, query=query,
'header': headers, header=headers,
'cookie': cookies, cookie=cookies,
} )
assert openapi_request.host_url == request.host_url assert openapi_request.host_url == request.host_url
assert openapi_request.path == request.path assert openapi_request.path == request.path
assert openapi_request.method == request.method.lower() assert openapi_request.method == request.method.lower()
@ -113,12 +115,12 @@ class TestFlaskOpenAPIRequest(object):
query = ImmutableMultiDict([]) query = ImmutableMultiDict([])
headers = EnvironHeaders(request.environ) headers = EnvironHeaders(request.environ)
cookies = {} cookies = {}
assert openapi_request.parameters == { assert openapi_request.parameters == RequestParameters(
'path': path, path=path,
'query': query, query=query,
'header': headers, header=headers,
'cookie': cookies, cookie=cookies,
} )
assert openapi_request.host_url == request.host_url assert openapi_request.host_url == request.host_url
assert openapi_request.path == request.path assert openapi_request.path == request.path
assert openapi_request.method == request.method.lower() assert openapi_request.method == request.method.lower()
@ -134,7 +136,6 @@ class TestFlaskOpenAPIResponse(object):
openapi_response = FlaskOpenAPIResponse(response) openapi_response = FlaskOpenAPIResponse(response)
assert openapi_response.response == response
assert openapi_response.data == response.data assert openapi_response.data == response.data
assert openapi_response.status_code == response._status_code assert openapi_response.status_code == response._status_code
assert openapi_response.mimetype == response.mimetype assert openapi_response.mimetype == response.mimetype
@ -144,7 +145,7 @@ class TestFlaskOpenAPIValidation(object):
@pytest.fixture @pytest.fixture
def flask_spec(self, factory): def flask_spec(self, factory):
specfile = 'data/v3.0/flask_wrapper.yaml' specfile = 'data/v3.0/flask_factory.yaml'
return create_spec(factory.spec_from_file(specfile)) return create_spec(factory.spec_from_file(specfile))
def test_response_validator_path_pattern(self, def test_response_validator_path_pattern(self,

View file

@ -1,6 +1,6 @@
openapi: "3.0.0" openapi: "3.0.0"
info: info:
title: Basic OpenAPI specification used with test_wrappers.TestFlaskOpenAPIIValidation title: Basic OpenAPI specification used with test_flask.TestFlaskOpenAPIIValidation
version: "0.1" version: "0.1"
servers: servers:
- url: 'http://localhost' - url: 'http://localhost'

View file

@ -3,8 +3,8 @@ import pytest
from openapi_core.schema.operations.exceptions import InvalidOperation from openapi_core.schema.operations.exceptions import InvalidOperation
from openapi_core.schema.paths.exceptions import InvalidPath from openapi_core.schema.paths.exceptions import InvalidPath
from openapi_core.shortcuts import create_spec from openapi_core.shortcuts import create_spec
from openapi_core.testing import MockRequest
from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.request.validators import RequestValidator
from openapi_core.wrappers.mock import MockRequest
class TestMinimal(object): class TestMinimal(object):

View file

@ -15,11 +15,13 @@ from openapi_core.schema.parameters.exceptions import (
from openapi_core.schema.schemas.enums import SchemaType from openapi_core.schema.schemas.enums import SchemaType
from openapi_core.schema.schemas.exceptions import InvalidSchemaValue from openapi_core.schema.schemas.exceptions import InvalidSchemaValue
from openapi_core.schema.servers.exceptions import InvalidServer from openapi_core.schema.servers.exceptions import InvalidServer
from openapi_core.shortcuts import create_spec from openapi_core.shortcuts import (
create_spec, validate_parameters, validate_body,
)
from openapi_core.testing import MockRequest, MockResponse
from openapi_core.validation.request.datatypes import RequestParameters from openapi_core.validation.request.datatypes import RequestParameters
from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.wrappers.mock import MockRequest, MockResponse
class TestPetstore(object): class TestPetstore(object):
@ -64,8 +66,8 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params, path_pattern=path_pattern, args=query_params,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
query={ query={
@ -100,8 +102,8 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params, path_pattern=path_pattern, args=query_params,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
query={ query={
@ -146,8 +148,8 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params, path_pattern=path_pattern, args=query_params,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
query={ query={
@ -197,8 +199,8 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params, path_pattern=path_pattern, args=query_params,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
query={ query={
@ -235,8 +237,8 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params, path_pattern=path_pattern, args=query_params,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
query={ query={
@ -274,9 +276,9 @@ class TestPetstore(object):
) )
with pytest.raises(InvalidParameterValue): with pytest.raises(InvalidParameterValue):
request.get_parameters(spec) validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -293,9 +295,9 @@ class TestPetstore(object):
) )
with pytest.raises(InvalidParameterValue): with pytest.raises(InvalidParameterValue):
request.get_parameters(spec) validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -308,9 +310,9 @@ class TestPetstore(object):
) )
with pytest.raises(MissingRequiredParameter): with pytest.raises(MissingRequiredParameter):
request.get_parameters(spec) validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -327,8 +329,8 @@ class TestPetstore(object):
) )
with pytest.raises(EmptyParameterValue): with pytest.raises(EmptyParameterValue):
request.get_parameters(spec) validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -344,7 +346,7 @@ class TestPetstore(object):
path_pattern=path_pattern, args=query_params, path_pattern=path_pattern, args=query_params,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
query={ query={
@ -354,7 +356,7 @@ class TestPetstore(object):
} }
) )
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -393,7 +395,7 @@ class TestPetstore(object):
headers=headers, cookies=cookies, headers=headers, cookies=cookies,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
header={ header={
@ -404,7 +406,7 @@ class TestPetstore(object):
}, },
) )
body = request.get_body(spec) body = validate_body(spec, request)
schemas = spec_dict['components']['schemas'] schemas = spec_dict['components']['schemas']
pet_model = schemas['PetCreate']['x-model'] pet_model = schemas['PetCreate']['x-model']
@ -453,7 +455,7 @@ class TestPetstore(object):
headers=headers, cookies=cookies, headers=headers, cookies=cookies,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
header={ header={
@ -464,7 +466,7 @@ class TestPetstore(object):
}, },
) )
body = request.get_body(spec) body = validate_body(spec, request)
schemas = spec_dict['components']['schemas'] schemas = spec_dict['components']['schemas']
pet_model = schemas['PetCreate']['x-model'] pet_model = schemas['PetCreate']['x-model']
@ -513,7 +515,7 @@ class TestPetstore(object):
headers=headers, cookies=cookies, headers=headers, cookies=cookies,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
header={ header={
@ -524,7 +526,7 @@ class TestPetstore(object):
}, },
) )
body = request.get_body(spec) body = validate_body(spec, request)
schemas = spec_dict['components']['schemas'] schemas = spec_dict['components']['schemas']
pet_model = schemas['PetCreate']['x-model'] pet_model = schemas['PetCreate']['x-model']
@ -561,7 +563,7 @@ class TestPetstore(object):
headers=headers, cookies=cookies, headers=headers, cookies=cookies,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
header={ header={
@ -573,7 +575,7 @@ class TestPetstore(object):
) )
with pytest.raises(InvalidMediaTypeValue): with pytest.raises(InvalidMediaTypeValue):
request.get_body(spec) validate_body(spec, request)
def test_post_cats_only_required_body(self, spec, spec_dict): def test_post_cats_only_required_body(self, spec, spec_dict):
host_url = 'http://petstore.swagger.io/v1' host_url = 'http://petstore.swagger.io/v1'
@ -600,7 +602,7 @@ class TestPetstore(object):
headers=headers, cookies=cookies, headers=headers, cookies=cookies,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
header={ header={
@ -611,7 +613,7 @@ class TestPetstore(object):
}, },
) )
body = request.get_body(spec) body = validate_body(spec, request)
schemas = spec_dict['components']['schemas'] schemas = spec_dict['components']['schemas']
pet_model = schemas['PetCreate']['x-model'] pet_model = schemas['PetCreate']['x-model']
@ -641,7 +643,7 @@ class TestPetstore(object):
headers=headers, cookies=cookies, headers=headers, cookies=cookies,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
header={ header={
@ -653,7 +655,7 @@ class TestPetstore(object):
) )
with pytest.raises(InvalidContentType): with pytest.raises(InvalidContentType):
request.get_body(spec) validate_body(spec, request)
def test_post_pets_missing_cookie(self, spec, spec_dict): def test_post_pets_missing_cookie(self, spec, spec_dict):
host_url = 'http://petstore.swagger.io/v1' host_url = 'http://petstore.swagger.io/v1'
@ -678,9 +680,9 @@ class TestPetstore(object):
) )
with pytest.raises(MissingRequiredParameter): with pytest.raises(MissingRequiredParameter):
request.get_parameters(spec) validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
schemas = spec_dict['components']['schemas'] schemas = spec_dict['components']['schemas']
pet_model = schemas['PetCreate']['x-model'] pet_model = schemas['PetCreate']['x-model']
@ -712,9 +714,9 @@ class TestPetstore(object):
) )
with pytest.raises(MissingRequiredParameter): with pytest.raises(MissingRequiredParameter):
request.get_parameters(spec) validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
schemas = spec_dict['components']['schemas'] schemas = spec_dict['components']['schemas']
pet_model = schemas['PetCreate']['x-model'] pet_model = schemas['PetCreate']['x-model']
@ -745,10 +747,10 @@ class TestPetstore(object):
) )
with pytest.raises(InvalidServer): with pytest.raises(InvalidServer):
request.get_parameters(spec) validate_parameters(spec, request)
with pytest.raises(InvalidServer): with pytest.raises(InvalidServer):
request.get_body(spec) validate_body(spec, request)
def test_get_pet(self, spec, response_validator): def test_get_pet(self, spec, response_validator):
host_url = 'http://petstore.swagger.io/v1' host_url = 'http://petstore.swagger.io/v1'
@ -761,7 +763,7 @@ class TestPetstore(object):
path_pattern=path_pattern, view_args=view_args, path_pattern=path_pattern, view_args=view_args,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
path={ path={
@ -769,7 +771,7 @@ class TestPetstore(object):
} }
) )
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -806,7 +808,7 @@ class TestPetstore(object):
path_pattern=path_pattern, view_args=view_args, path_pattern=path_pattern, view_args=view_args,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
path={ path={
@ -814,7 +816,7 @@ class TestPetstore(object):
} }
) )
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -848,7 +850,7 @@ class TestPetstore(object):
path_pattern=path_pattern, view_args=view_args, path_pattern=path_pattern, view_args=view_args,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters( assert parameters == RequestParameters(
path={ path={
@ -856,7 +858,7 @@ class TestPetstore(object):
} }
) )
body = request.get_body(spec) body = validate_body(spec, request)
assert body is None assert body is None
@ -877,8 +879,8 @@ class TestPetstore(object):
path_pattern=path_pattern, path_pattern=path_pattern,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
assert body is None assert body is None
@ -908,12 +910,12 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
with pytest.raises(InvalidMediaTypeValue): with pytest.raises(InvalidMediaTypeValue):
request.get_body(spec) validate_body(spec, request)
def test_post_tags_empty_body(self, spec, spec_dict): def test_post_tags_empty_body(self, spec, spec_dict):
host_url = 'http://petstore.swagger.io/v1' host_url = 'http://petstore.swagger.io/v1'
@ -926,12 +928,12 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
with pytest.raises(InvalidMediaTypeValue): with pytest.raises(InvalidMediaTypeValue):
request.get_body(spec) validate_body(spec, request)
def test_post_tags_wrong_property_type(self, spec): def test_post_tags_wrong_property_type(self, spec):
host_url = 'http://petstore.swagger.io/v1' host_url = 'http://petstore.swagger.io/v1'
@ -944,12 +946,12 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
with pytest.raises(InvalidMediaTypeValue): with pytest.raises(InvalidMediaTypeValue):
request.get_body(spec) validate_body(spec, request)
def test_post_tags_additional_properties( def test_post_tags_additional_properties(
self, spec, response_validator): self, spec, response_validator):
@ -966,8 +968,8 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
assert isinstance(body, BaseModel) assert isinstance(body, BaseModel)
@ -1012,8 +1014,8 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
assert isinstance(body, BaseModel) assert isinstance(body, BaseModel)
@ -1059,8 +1061,8 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
body = request.get_body(spec) body = validate_body(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()
assert isinstance(body, BaseModel) assert isinstance(body, BaseModel)
@ -1106,9 +1108,9 @@ class TestPetstore(object):
path_pattern=path_pattern, data=data, path_pattern=path_pattern, data=data,
) )
parameters = request.get_parameters(spec) parameters = validate_parameters(spec, request)
with pytest.raises(InvalidMediaTypeValue): with pytest.raises(InvalidMediaTypeValue):
request.get_body(spec) validate_body(spec, request)
assert parameters == RequestParameters() assert parameters == RequestParameters()

View file

@ -17,10 +17,10 @@ from openapi_core.schema.responses.exceptions import (
) )
from openapi_core.schema.servers.exceptions import InvalidServer from openapi_core.schema.servers.exceptions import InvalidServer
from openapi_core.shortcuts import create_spec from openapi_core.shortcuts import create_spec
from openapi_core.testing import MockRequest, MockResponse
from openapi_core.validation.request.datatypes import RequestParameters from openapi_core.validation.request.datatypes import RequestParameters
from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.wrappers.mock import MockRequest, MockResponse
class TestRequestValidator(object): class TestRequestValidator(object):

View file

@ -27,7 +27,7 @@ class ResultMock(object):
return self.data return self.data
class WrapperClassMock(object): class FactoryClassMock(object):
_instances = {} _instances = {}
@ -43,7 +43,7 @@ class WrapperClassMock(object):
class TestValidateParameters(object): class TestValidateParameters(object):
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_no_wrapper(self, mock_validate): def test_no_request_factory(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
parameters = mock.sentinel.parameters parameters = mock.sentinel.parameters
@ -55,7 +55,7 @@ class TestValidateParameters(object):
mock_validate.aasert_called_once_with(request) mock_validate.aasert_called_once_with(request)
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_no_wrapper_error(self, mock_validate): def test_no_request_factory_error(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
mock_validate.return_value = ResultMock(error_to_raise=ValueError) mock_validate.return_value = ResultMock(error_to_raise=ValueError)
@ -66,39 +66,39 @@ class TestValidateParameters(object):
mock_validate.aasert_called_once_with(request) mock_validate.aasert_called_once_with(request)
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_wrapper(self, mock_validate): def test_request_factory(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
parameters = mock.sentinel.parameters parameters = mock.sentinel.parameters
mock_validate.return_value = ResultMock(parameters=parameters) mock_validate.return_value = ResultMock(parameters=parameters)
request_wrapper_class = WrapperClassMock request_factory = FactoryClassMock
result = validate_parameters(spec, request, request_wrapper_class) result = validate_parameters(spec, request, request_factory)
assert result == parameters assert result == parameters
mock_validate.assert_called_once_with( mock_validate.assert_called_once_with(
WrapperClassMock(request), FactoryClassMock(request),
) )
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_wrapper_error(self, mock_validate): def test_request_factory_error(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
mock_validate.return_value = ResultMock(error_to_raise=ValueError) mock_validate.return_value = ResultMock(error_to_raise=ValueError)
request_wrapper_class = WrapperClassMock request_factory = FactoryClassMock
with pytest.raises(ValueError): with pytest.raises(ValueError):
validate_parameters(spec, request, request_wrapper_class) validate_parameters(spec, request, request_factory)
mock_validate.assert_called_once_with( mock_validate.assert_called_once_with(
WrapperClassMock(request), FactoryClassMock(request),
) )
class TestValidateBody(object): class TestValidateBody(object):
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_no_wrapper(self, mock_validate): def test_no_request_factory(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
body = mock.sentinel.body body = mock.sentinel.body
@ -110,7 +110,7 @@ class TestValidateBody(object):
mock_validate.aasert_called_once_with(request) mock_validate.aasert_called_once_with(request)
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_no_wrapper_error(self, mock_validate): def test_no_request_factory_error(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
mock_validate.return_value = ResultMock(error_to_raise=ValueError) mock_validate.return_value = ResultMock(error_to_raise=ValueError)
@ -121,39 +121,39 @@ class TestValidateBody(object):
mock_validate.aasert_called_once_with(request) mock_validate.aasert_called_once_with(request)
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_wrapper(self, mock_validate): def test_request_factory(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
body = mock.sentinel.body body = mock.sentinel.body
mock_validate.return_value = ResultMock(body=body) mock_validate.return_value = ResultMock(body=body)
request_wrapper_class = WrapperClassMock request_factory = FactoryClassMock
result = validate_body(spec, request, request_wrapper_class) result = validate_body(spec, request, request_factory)
assert result == body assert result == body
mock_validate.assert_called_once_with( mock_validate.assert_called_once_with(
WrapperClassMock(request), FactoryClassMock(request),
) )
@mock.patch('openapi_core.shortcuts.RequestValidator.validate') @mock.patch('openapi_core.shortcuts.RequestValidator.validate')
def test_wrapper_error(self, mock_validate): def test_request_factory_error(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
mock_validate.return_value = ResultMock(error_to_raise=ValueError) mock_validate.return_value = ResultMock(error_to_raise=ValueError)
request_wrapper_class = WrapperClassMock request_factory = FactoryClassMock
with pytest.raises(ValueError): with pytest.raises(ValueError):
validate_body(spec, request, request_wrapper_class) validate_body(spec, request, request_factory)
mock_validate.assert_called_once_with( mock_validate.assert_called_once_with(
WrapperClassMock(request), FactoryClassMock(request),
) )
class TestvalidateData(object): class TestvalidateData(object):
@mock.patch('openapi_core.shortcuts.ResponseValidator.validate') @mock.patch('openapi_core.shortcuts.ResponseValidator.validate')
def test_no_wrappers(self, mock_validate): def test_no_factories(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
response = mock.sentinel.response response = mock.sentinel.response
@ -166,7 +166,7 @@ class TestvalidateData(object):
mock_validate.aasert_called_once_with(request, response) mock_validate.aasert_called_once_with(request, response)
@mock.patch('openapi_core.shortcuts.ResponseValidator.validate') @mock.patch('openapi_core.shortcuts.ResponseValidator.validate')
def test_no_wrappers_error(self, mock_validate): def test_no_factories_error(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
response = mock.sentinel.response response = mock.sentinel.response
@ -178,42 +178,42 @@ class TestvalidateData(object):
mock_validate.aasert_called_once_with(request, response) mock_validate.aasert_called_once_with(request, response)
@mock.patch('openapi_core.shortcuts.ResponseValidator.validate') @mock.patch('openapi_core.shortcuts.ResponseValidator.validate')
def test_wrappers(self, mock_validate): def test_factories(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
response = mock.sentinel.response response = mock.sentinel.response
data = mock.sentinel.data data = mock.sentinel.data
mock_validate.return_value = ResultMock(data=data) mock_validate.return_value = ResultMock(data=data)
request_wrapper_class = WrapperClassMock request_factory = FactoryClassMock
response_wrapper_class = WrapperClassMock response_factory = FactoryClassMock
result = validate_data( result = validate_data(
spec, request, response, spec, request, response,
request_wrapper_class, response_wrapper_class, request_factory, response_factory,
) )
assert result == data assert result == data
mock_validate.assert_called_once_with( mock_validate.assert_called_once_with(
WrapperClassMock(request), FactoryClassMock(request),
WrapperClassMock(response), FactoryClassMock(response),
) )
@mock.patch('openapi_core.shortcuts.ResponseValidator.validate') @mock.patch('openapi_core.shortcuts.ResponseValidator.validate')
def test_wrappers_error(self, mock_validate): def test_factories_error(self, mock_validate):
spec = mock.sentinel.spec spec = mock.sentinel.spec
request = mock.sentinel.request request = mock.sentinel.request
response = mock.sentinel.response response = mock.sentinel.response
mock_validate.return_value = ResultMock(error_to_raise=ValueError) mock_validate.return_value = ResultMock(error_to_raise=ValueError)
request_wrapper_class = WrapperClassMock request_factory = FactoryClassMock
response_wrapper_class = WrapperClassMock response_factory = FactoryClassMock
with pytest.raises(ValueError): with pytest.raises(ValueError):
validate_data( validate_data(
spec, request, response, spec, request, response,
request_wrapper_class, response_wrapper_class, request_factory, response_factory,
) )
mock_validate.assert_called_once_with( mock_validate.assert_called_once_with(
WrapperClassMock(request), FactoryClassMock(request),
WrapperClassMock(response), FactoryClassMock(response),
) )