From 54b8011603828e985cb8de85341d74b47a9e5d3b Mon Sep 17 00:00:00 2001 From: Artur Maciag Date: Wed, 30 May 2018 14:46:54 +0100 Subject: [PATCH] Mimetype wildcards support --- openapi_core/schema/content/__init__.py | 0 openapi_core/schema/content/exceptions.py | 9 ++++++ openapi_core/schema/content/models.py | 21 ++++++++++++ openapi_core/schema/request_bodies/models.py | 7 ++-- openapi_core/schema/responses/models.py | 6 ++-- tests/integration/data/v3.0/petstore.yaml | 4 +++ tests/integration/test_petstore.py | 34 +++++++++++++++++++- 7 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 openapi_core/schema/content/__init__.py create mode 100644 openapi_core/schema/content/exceptions.py create mode 100644 openapi_core/schema/content/models.py diff --git a/openapi_core/schema/content/__init__.py b/openapi_core/schema/content/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/openapi_core/schema/content/exceptions.py b/openapi_core/schema/content/exceptions.py new file mode 100644 index 0000000..88ca440 --- /dev/null +++ b/openapi_core/schema/content/exceptions.py @@ -0,0 +1,9 @@ +from openapi_core.schema.exceptions import OpenAPIMappingError + + +class OpenAPIContentError(OpenAPIMappingError): + pass + + +class MimeTypeNotFound(OpenAPIContentError): + pass diff --git a/openapi_core/schema/content/models.py b/openapi_core/schema/content/models.py new file mode 100644 index 0000000..1173671 --- /dev/null +++ b/openapi_core/schema/content/models.py @@ -0,0 +1,21 @@ +"""OpenAPI core content models module""" +import fnmatch + +from six import iteritems + +from openapi_core.schema.content.exceptions import MimeTypeNotFound + + +class Content(dict): + + def __getitem__(self, mimetype): + try: + return super(Content, self).__getitem__(mimetype) + except KeyError: + pass + + for key, value in iteritems(self): + if fnmatch.fnmatch(mimetype, key): + return value + + raise MimeTypeNotFound("{0} mimetype not found") diff --git a/openapi_core/schema/request_bodies/models.py b/openapi_core/schema/request_bodies/models.py index 9aff295..c8f775c 100644 --- a/openapi_core/schema/request_bodies/models.py +++ b/openapi_core/schema/request_bodies/models.py @@ -1,5 +1,6 @@ """OpenAPI core request bodies models module""" - +from openapi_core.schema.content.exceptions import MimeTypeNotFound +from openapi_core.schema.content.models import Content from openapi_core.schema.media_types.exceptions import InvalidContentType from openapi_core.schema.request_bodies.exceptions import MissingRequestBody @@ -8,13 +9,13 @@ class RequestBody(object): """Represents an OpenAPI RequestBody.""" def __init__(self, content, required=False): - self.content = dict(content) + self.content = Content(content) self.required = required def __getitem__(self, mimetype): try: return self.content[mimetype] - except KeyError: + except MimeTypeNotFound: raise InvalidContentType( "Invalid mime type `{0}`".format(mimetype)) diff --git a/openapi_core/schema/responses/models.py b/openapi_core/schema/responses/models.py index daf5b7e..476797f 100644 --- a/openapi_core/schema/responses/models.py +++ b/openapi_core/schema/responses/models.py @@ -1,4 +1,6 @@ """OpenAPI core responses models module""" +from openapi_core.schema.content.exceptions import MimeTypeNotFound +from openapi_core.schema.content.models import Content from openapi_core.schema.media_types.exceptions import InvalidContentType from openapi_core.schema.responses.exceptions import MissingResponseContent @@ -11,13 +13,13 @@ class Response(object): self.http_status = http_status self.description = description self.headers = headers and dict(headers) or {} - self.content = content and dict(content) or {} + self.content = content and Content(content) or Content() self.links = links and dict(links) or {} def __getitem__(self, mimetype): try: return self.content[mimetype] - except KeyError: + except MimeTypeNotFound: raise InvalidContentType( "Invalid mime type `{0}`".format(mimetype)) diff --git a/tests/integration/data/v3.0/petstore.yaml b/tests/integration/data/v3.0/petstore.yaml index 0e837e4..4f6c807 100644 --- a/tests/integration/data/v3.0/petstore.yaml +++ b/tests/integration/data/v3.0/petstore.yaml @@ -106,6 +106,10 @@ paths: application/json: schema: $ref: "#/components/schemas/PetData" + image/*: + schema: + type: string + format: binary default: $ref: "#/components/responses/ErrorResponse" /tags: diff --git a/tests/integration/test_petstore.py b/tests/integration/test_petstore.py index 9b41617..1b2aa77 100644 --- a/tests/integration/test_petstore.py +++ b/tests/integration/test_petstore.py @@ -112,7 +112,8 @@ class TestPetstore(object): continue assert type(media_type.schema) == Schema - assert media_type.schema.type == schema_spec['type'] + assert media_type.schema.type.value ==\ + schema_spec['type'] assert media_type.schema.required == schema_spec.get( 'required', []) @@ -675,6 +676,37 @@ class TestPetstore(object): assert response_result.errors == [] assert response_result.data == data_json + def test_get_pet_wildcard(self, spec, response_validator): + host_url = 'http://petstore.swagger.io/v1' + path_pattern = '/v1/pets/{petId}' + view_args = { + 'petId': '1', + } + request = MockRequest( + host_url, 'GET', '/pets/1', + path_pattern=path_pattern, view_args=view_args, + ) + + parameters = request.get_parameters(spec) + + assert parameters == { + 'path': { + 'petId': 1, + } + } + + body = request.get_body(spec) + + assert body is None + + data = b'imagedata' + response = MockResponse(data, mimetype='image/png') + + response_result = response_validator.validate(request, response) + + assert response_result.errors == [] + assert response_result.data == data + def test_get_tags(self, spec, response_validator): host_url = 'http://petstore.swagger.io/v1' path_pattern = '/v1/tags'