From f6415ed867b97708944abe65feafb5fc404b8e4d Mon Sep 17 00:00:00 2001 From: Sigurd Spieckermann Date: Sat, 3 Jul 2021 14:24:44 +0200 Subject: [PATCH] Use Black and isort for code formatting --- .github/workflows/python-test.yml | 30 +- .pre-commit-config.yaml | 17 + docs/conf.py | 12 +- openapi_core/__init__.py | 54 +- openapi_core/casting/schemas/casters.py | 11 +- openapi_core/casting/schemas/exceptions.py | 1 + openapi_core/casting/schemas/factories.py | 20 +- openapi_core/contrib/django/__init__.py | 6 +- openapi_core/contrib/django/handlers.py | 23 +- openapi_core/contrib/django/middlewares.py | 14 +- openapi_core/contrib/django/requests.py | 15 +- openapi_core/contrib/django/responses.py | 1 - openapi_core/contrib/falcon/__init__.py | 1 - openapi_core/contrib/falcon/handlers.py | 24 +- openapi_core/contrib/falcon/middlewares.py | 18 +- openapi_core/contrib/falcon/requests.py | 13 +- openapi_core/contrib/falcon/responses.py | 2 +- openapi_core/contrib/flask/__init__.py | 6 +- openapi_core/contrib/flask/decorators.py | 39 +- openapi_core/contrib/flask/handlers.py | 27 +- openapi_core/contrib/flask/providers.py | 1 - openapi_core/contrib/flask/requests.py | 9 +- openapi_core/contrib/flask/responses.py | 1 - openapi_core/contrib/requests/__init__.py | 6 +- openapi_core/contrib/requests/requests.py | 17 +- openapi_core/contrib/requests/responses.py | 3 +- .../media_types/deserializers.py | 3 - .../deserializing/media_types/exceptions.py | 1 + .../deserializing/media_types/factories.py | 21 +- .../deserializing/media_types/util.py | 7 +- .../deserializing/parameters/deserializers.py | 18 +- .../deserializing/parameters/exceptions.py | 4 +- .../deserializing/parameters/factories.py | 16 +- openapi_core/deserializing/parameters/util.py | 2 +- openapi_core/exceptions.py | 3 - openapi_core/extensions/models/factories.py | 5 +- openapi_core/schema/parameters.py | 28 +- openapi_core/schema/schemas.py | 6 +- openapi_core/schema/servers.py | 10 +- openapi_core/schema/specs.py | 2 +- openapi_core/security/factories.py | 16 +- openapi_core/security/providers.py | 23 +- openapi_core/shortcuts.py | 27 +- openapi_core/spec/accessors.py | 6 +- openapi_core/spec/paths.py | 5 +- openapi_core/spec/shortcuts.py | 12 +- openapi_core/templating/datatypes.py | 4 +- .../templating/media_types/exceptions.py | 3 +- .../templating/media_types/finders.py | 1 - openapi_core/templating/paths/exceptions.py | 3 + openapi_core/templating/paths/finders.py | 59 +- .../templating/responses/exceptions.py | 7 +- openapi_core/templating/responses/finders.py | 9 +- openapi_core/templating/util.py | 4 +- openapi_core/testing/__init__.py | 8 +- openapi_core/testing/datatypes.py | 4 +- openapi_core/testing/mock.py | 2 +- openapi_core/testing/requests.py | 26 +- openapi_core/testing/responses.py | 5 +- openapi_core/unmarshalling/schemas/enums.py | 4 +- .../unmarshalling/schemas/exceptions.py | 12 +- .../unmarshalling/schemas/factories.py | 50 +- .../unmarshalling/schemas/formatters.py | 7 +- .../unmarshalling/schemas/unmarshallers.py | 179 +-- openapi_core/unmarshalling/schemas/util.py | 6 +- openapi_core/validation/datatypes.py | 3 +- openapi_core/validation/decorators.py | 22 +- openapi_core/validation/exceptions.py | 1 - openapi_core/validation/processors.py | 1 - openapi_core/validation/request/datatypes.py | 10 +- openapi_core/validation/request/shortcuts.py | 23 +- openapi_core/validation/request/validators.py | 115 +- openapi_core/validation/response/datatypes.py | 8 +- openapi_core/validation/response/shortcuts.py | 18 +- .../validation/response/validators.py | 90 +- openapi_core/validation/validators.py | 32 +- poetry.lock | 162 ++- pyproject.toml | 12 +- tests/integration/conftest.py | 4 +- .../django/data/v3.0/djangoproject/auth.py | 4 +- .../data/v3.0/djangoproject/pets/views.py | 45 +- .../data/v3.0/djangoproject/settings.py | 75 +- .../django/data/v3.0/djangoproject/urls.py | 17 +- .../contrib/django/test_django_project.py | 264 ++--- tests/integration/contrib/falcon/conftest.py | 32 +- .../data/v3.0/falconproject/__main__.py | 4 +- .../falcon/data/v3.0/falconproject/openapi.py | 3 +- .../data/v3.0/falconproject/pets/resources.py | 45 +- .../contrib/falcon/test_falcon_project.py | 255 ++-- tests/integration/contrib/flask/conftest.py | 60 +- .../contrib/flask/test_flask_decorator.py | 112 +- .../contrib/flask/test_flask_requests.py | 37 +- .../contrib/flask/test_flask_responses.py | 3 +- .../contrib/flask/test_flask_validation.py | 22 +- .../contrib/flask/test_flask_views.py | 107 +- .../integration/contrib/requests/conftest.py | 31 +- .../requests/test_requests_requests.py | 44 +- .../requests/test_requests_responses.py | 5 +- .../requests/test_requests_validation.py | 44 +- tests/integration/schema/test_empty.py | 1 - tests/integration/schema/test_link_spec.py | 33 +- tests/integration/schema/test_path_params.py | 14 +- tests/integration/schema/test_spec.py | 276 ++--- tests/integration/validation/test_minimal.py | 9 +- tests/integration/validation/test_petstore.py | 1026 +++++++++-------- .../validation/test_read_only_write_only.py | 77 +- .../validation/test_security_override.py | 36 +- .../integration/validation/test_validators.py | 359 +++--- tests/unit/casting/test_schema_casters.py | 16 +- tests/unit/contrib/django/test_django.py | 124 +- .../test_media_types_deserializers.py | 51 +- .../test_parameters_deserializers.py | 28 +- tests/unit/extensions/test_models.py | 13 +- tests/unit/schema/test_schema_parameters.py | 131 ++- tests/unit/security/test_providers.py | 21 +- tests/unit/templating/test_paths_finders.py | 445 ++++--- .../unit/templating/test_responses_finders.py | 25 +- tests/unit/templating/test_util.py | 13 +- tests/unit/unmarshalling/test_unmarshal.py | 463 ++++---- tests/unit/unmarshalling/test_validate.py | 914 +++++++++------ .../unit/validation/test_request_shortcuts.py | 39 +- .../validation/test_response_shortcuts.py | 31 +- 122 files changed, 3836 insertions(+), 2998 deletions(-) diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 6ec87c60..0abf925a 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -68,5 +68,31 @@ jobs: with: python-version: 3.9 - - name: "Run static checks" - uses: pre-commit/action@v2.0.3 + - name: Get full Python version + id: full-python-version + run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") + + - name: Bootstrap poetry + run: | + curl -sL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python - -y + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Configure poetry + run: poetry config virtualenvs.in-project true + + - name: Set up cache + uses: actions/cache@v2 + id: cache + with: + path: .venv + key: venv-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Ensure cache is healthy + if: steps.cache.outputs.cache-hit == 'true' + run: timeout 10s poetry run pip --version || rm -rf .venv + + - name: Install dependencies + run: poetry install + + - name: Run static checks + run: poetry run pre-commit run -a diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85ea3f48..385f970b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,11 +8,13 @@ repos: - repo: meta hooks: - id: check-hooks-apply + - repo: https://github.com/asottile/pyupgrade rev: v2.19.0 hooks: - id: pyupgrade args: ["--py36-plus"] + - repo: local hooks: - id: flynt @@ -20,3 +22,18 @@ repos: entry: flynt language: python additional_dependencies: ['flynt==0.64'] + + - id: black + name: black + entry: black + language: system + require_serial: true + types: [python] + + - id: isort + name: isort + entry: isort + args: ['--filter-files'] + language: system + require_serial: true + types: [python] diff --git a/docs/conf.py b/docs/conf.py index 5c299e15..8436deb5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,9 +18,9 @@ # -- Project information ----------------------------------------------------- -project = 'openapi-core' -copyright = '2021, Artur Maciag' -author = 'Artur Maciag' +project = "openapi-core" +copyright = "2021, Artur Maciag" +author = "Artur Maciag" # The full version, including alpha/beta/rc tags release = openapi_core.__version__ @@ -40,12 +40,12 @@ ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- @@ -53,7 +53,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/openapi_core/__init__.py b/openapi_core/__init__.py index 0803b960..8c806231 100644 --- a/openapi_core/__init__.py +++ b/openapi_core/__init__.py @@ -1,32 +1,44 @@ """OpenAPI core module""" -from openapi_core.shortcuts import ( - create_spec, validate_request, validate_response, - spec_validate_body, spec_validate_parameters, spec_validate_security, - spec_validate_data, spec_validate_headers, -) +from openapi_core.shortcuts import create_spec +from openapi_core.shortcuts import spec_validate_body +from openapi_core.shortcuts import spec_validate_data +from openapi_core.shortcuts import spec_validate_headers +from openapi_core.shortcuts import spec_validate_parameters +from openapi_core.shortcuts import spec_validate_security +from openapi_core.shortcuts import validate_request +from openapi_core.shortcuts import validate_response +from openapi_core.validation.request.validators import RequestBodyValidator from openapi_core.validation.request.validators import ( - RequestValidator, - RequestBodyValidator, RequestParametersValidator, - RequestSecurityValidator, ) +from openapi_core.validation.request.validators import RequestSecurityValidator +from openapi_core.validation.request.validators import RequestValidator +from openapi_core.validation.response.validators import ResponseDataValidator from openapi_core.validation.response.validators import ( - ResponseValidator, - ResponseDataValidator, ResponseHeadersValidator, ) +from openapi_core.validation.response.validators import ResponseValidator -__author__ = 'Artur Maciag' -__email__ = 'maciag.artur@gmail.com' -__version__ = '0.14.2' -__url__ = 'https://github.com/p1c2u/openapi-core' -__license__ = 'BSD 3-Clause License' +__author__ = "Artur Maciag" +__email__ = "maciag.artur@gmail.com" +__version__ = "0.14.2" +__url__ = "https://github.com/p1c2u/openapi-core" +__license__ = "BSD 3-Clause License" __all__ = [ - 'create_spec', 'validate_request', 'validate_response', - 'spec_validate_body', 'spec_validate_parameters', 'spec_validate_security', - 'spec_validate_data', 'spec_validate_headers', - 'RequestValidator', 'ResponseValidator', 'RequestBodyValidator', - 'RequestParametersValidator', 'RequestSecurityValidator', - 'ResponseDataValidator', 'ResponseHeadersValidator', + "create_spec", + "validate_request", + "validate_response", + "spec_validate_body", + "spec_validate_parameters", + "spec_validate_security", + "spec_validate_data", + "spec_validate_headers", + "RequestValidator", + "ResponseValidator", + "RequestBodyValidator", + "RequestParametersValidator", + "RequestSecurityValidator", + "ResponseDataValidator", + "ResponseHeadersValidator", ] diff --git a/openapi_core/casting/schemas/casters.py b/openapi_core/casting/schemas/casters.py index 530e9b10..f6e912b9 100644 --- a/openapi_core/casting/schemas/casters.py +++ b/openapi_core/casting/schemas/casters.py @@ -2,7 +2,6 @@ class BaseSchemaCaster: - def __init__(self, schema): self.schema = schema @@ -17,7 +16,6 @@ def cast(self, value): class CallableSchemaCaster(BaseSchemaCaster): - def __init__(self, schema, caster_callable): super().__init__(schema) self.caster_callable = caster_callable @@ -26,30 +24,27 @@ def cast(self, value): try: return self.caster_callable(value) except (ValueError, TypeError): - raise CastError(value, self.schema['type']) + raise CastError(value, self.schema["type"]) class DummyCaster(BaseSchemaCaster): - def cast(self, value): return value class ComplexCaster(BaseSchemaCaster): - def __init__(self, schema, casters_factory): super().__init__(schema) self.casters_factory = casters_factory class ArrayCaster(ComplexCaster): - @property def items_caster(self): - return self.casters_factory.create(self.schema / 'items') + return self.casters_factory.create(self.schema / "items") def cast(self, value): try: return list(map(self.items_caster, value)) except (ValueError, TypeError): - raise CastError(value, self.schema['type']) + raise CastError(value, self.schema["type"]) diff --git a/openapi_core/casting/schemas/exceptions.py b/openapi_core/casting/schemas/exceptions.py index d271d130..1f3f8bc4 100644 --- a/openapi_core/casting/schemas/exceptions.py +++ b/openapi_core/casting/schemas/exceptions.py @@ -6,6 +6,7 @@ @dataclass class CastError(OpenAPIError): """Schema cast operation error""" + value: str type: str diff --git a/openapi_core/casting/schemas/factories.py b/openapi_core/casting/schemas/factories.py index dfce8746..7240fcc5 100644 --- a/openapi_core/casting/schemas/factories.py +++ b/openapi_core/casting/schemas/factories.py @@ -1,25 +1,27 @@ -from openapi_core.casting.schemas.casters import ( - ArrayCaster, CallableSchemaCaster, DummyCaster, -) +from openapi_core.casting.schemas.casters import ArrayCaster +from openapi_core.casting.schemas.casters import CallableSchemaCaster +from openapi_core.casting.schemas.casters import DummyCaster from openapi_core.casting.schemas.util import forcebool class SchemaCastersFactory: DUMMY_CASTERS = [ - 'string', 'object', 'any', + "string", + "object", + "any", ] PRIMITIVE_CASTERS = { - 'integer': int, - 'number': float, - 'boolean': forcebool, + "integer": int, + "number": float, + "boolean": forcebool, } COMPLEX_CASTERS = { - 'array': ArrayCaster, + "array": ArrayCaster, } def create(self, schema): - schema_type = schema.getkey('type', 'any') + schema_type = schema.getkey("type", "any") if schema_type in self.DUMMY_CASTERS: return DummyCaster(schema) diff --git a/openapi_core/contrib/django/__init__.py b/openapi_core/contrib/django/__init__.py index 93ef7cfc..ed5dcd37 100644 --- a/openapi_core/contrib/django/__init__.py +++ b/openapi_core/contrib/django/__init__.py @@ -6,6 +6,8 @@ DjangoOpenAPIResponse = DjangoOpenAPIResponseFactory().create __all__ = [ - 'DjangoOpenAPIRequestFactory', 'DjangoOpenAPIResponseFactory', - 'DjangoOpenAPIRequest', 'DjangoOpenAPIResponse', + "DjangoOpenAPIRequestFactory", + "DjangoOpenAPIResponseFactory", + "DjangoOpenAPIRequest", + "DjangoOpenAPIResponse", ] diff --git a/openapi_core/contrib/django/handlers.py b/openapi_core/contrib/django/handlers.py index 664ae6a1..9dd808e5 100644 --- a/openapi_core/contrib/django/handlers.py +++ b/openapi_core/contrib/django/handlers.py @@ -3,9 +3,9 @@ from openapi_core.exceptions import MissingRequiredParameter from openapi_core.templating.media_types.exceptions import MediaTypeNotFound -from openapi_core.templating.paths.exceptions import ( - ServerNotFound, OperationNotFound, PathNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound +from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.validation.exceptions import InvalidSecurity @@ -22,24 +22,21 @@ class DjangoOpenAPIErrorsHandler: @classmethod def handle(cls, errors, req, resp=None): - data_errors = [ - cls.format_openapi_error(err) - for err in errors - ] + data_errors = [cls.format_openapi_error(err) for err in errors] data = { - 'errors': data_errors, + "errors": data_errors, } data_error_max = max(data_errors, key=cls.get_error_status) - return JsonResponse(data, status=data_error_max['status']) + return JsonResponse(data, status=data_error_max["status"]) @classmethod def format_openapi_error(cls, error): return { - 'title': str(error), - 'status': cls.OPENAPI_ERROR_STATUS.get(error.__class__, 400), - 'class': str(type(error)), + "title": str(error), + "status": cls.OPENAPI_ERROR_STATUS.get(error.__class__, 400), + "class": str(type(error)), } @classmethod def get_error_status(cls, error): - return error['status'] + return error["status"] diff --git a/openapi_core/contrib/django/middlewares.py b/openapi_core/contrib/django/middlewares.py index cd1356ff..42216b14 100644 --- a/openapi_core/contrib/django/middlewares.py +++ b/openapi_core/contrib/django/middlewares.py @@ -19,13 +19,14 @@ class DjangoOpenAPIMiddleware: def __init__(self, get_response): self.get_response = get_response - if not hasattr(settings, 'OPENAPI_SPEC'): + if not hasattr(settings, "OPENAPI_SPEC"): raise ImproperlyConfigured("OPENAPI_SPEC not defined in settings") request_validator = RequestValidator(settings.OPENAPI_SPEC) response_validator = ResponseValidator(settings.OPENAPI_SPEC) self.validation_processor = OpenAPIProcessor( - request_validator, response_validator) + request_validator, response_validator + ) def __call__(self, request): openapi_request = self._get_openapi_request(request) @@ -38,19 +39,18 @@ def __call__(self, request): openapi_response = self._get_openapi_response(response) resp_result = self.validation_processor.process_response( - openapi_request, openapi_response) + openapi_request, openapi_response + ) if resp_result.errors: return self._handle_response_errors(resp_result, request, response) return response def _handle_request_errors(self, request_result, req): - return self.errors_handler.handle( - request_result.errors, req, None) + return self.errors_handler.handle(request_result.errors, req, None) def _handle_response_errors(self, response_result, req, resp): - return self.errors_handler.handle( - response_result.errors, req, resp) + return self.errors_handler.handle(response_result.errors, req, resp) def _get_openapi_request(self, request): return self.request_factory.create(request) diff --git a/openapi_core/contrib/django/requests.py b/openapi_core/contrib/django/requests.py index 7cc59152..2398996d 100644 --- a/openapi_core/contrib/django/requests.py +++ b/openapi_core/contrib/django/requests.py @@ -2,11 +2,11 @@ import re from urllib.parse import urljoin -from werkzeug.datastructures import ImmutableMultiDict, Headers +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableMultiDict -from openapi_core.validation.request.datatypes import ( - RequestParameters, OpenAPIRequest, -) +from openapi_core.validation.request.datatypes import OpenAPIRequest +from openapi_core.validation.request.datatypes import RequestParameters # https://docs.djangoproject.com/en/2.2/topics/http/urls/ # @@ -18,7 +18,7 @@ # # The regex matches everything, except a "/" until "<". Than only the name # is exported, after which it matches ">" and everything until a "/". -PATH_PARAMETER_PATTERN = r'(?:[^\/]*?)<(?:(?:.*?:))*?(\w+)>(?:[^\/]*)' +PATH_PARAMETER_PATTERN = r"(?:[^\/]*?)<(?:(?:.*?:))*?(\w+)>(?:[^\/]*)" class DjangoOpenAPIRequestFactory: @@ -58,14 +58,13 @@ def _get_full_url_pattern(self, request): if request.resolver_match is None: path_pattern = request.path else: - route = self.path_regex.sub( - r'{\1}', request.resolver_match.route) + route = self.path_regex.sub(r"{\1}", request.resolver_match.route) # Delete start and end marker to allow concatenation. if route[:1] == "^": route = route[1:] if route[-1:] == "$": route = route[:-1] - path_pattern = '/' + route + path_pattern = "/" + route current_scheme_host = request._current_scheme_host return urljoin(current_scheme_host, path_pattern) diff --git a/openapi_core/contrib/django/responses.py b/openapi_core/contrib/django/responses.py index 9dbb448a..48ebb854 100644 --- a/openapi_core/contrib/django/responses.py +++ b/openapi_core/contrib/django/responses.py @@ -5,7 +5,6 @@ class DjangoOpenAPIResponseFactory: - def create(self, response): return OpenAPIResponse( data=self._get_data(response), diff --git a/openapi_core/contrib/falcon/__init__.py b/openapi_core/contrib/falcon/__init__.py index 3183150f..4f4a9093 100644 --- a/openapi_core/contrib/falcon/__init__.py +++ b/openapi_core/contrib/falcon/__init__.py @@ -1,5 +1,4 @@ from openapi_core.contrib.falcon.requests import FalconOpenAPIRequestFactory from openapi_core.contrib.falcon.responses import FalconOpenAPIResponseFactory - __all__ = ["FalconOpenAPIRequestFactory", "FalconOpenAPIResponseFactory"] diff --git a/openapi_core/contrib/falcon/handlers.py b/openapi_core/contrib/falcon/handlers.py index 2711f304..a01e70dc 100644 --- a/openapi_core/contrib/falcon/handlers.py +++ b/openapi_core/contrib/falcon/handlers.py @@ -6,9 +6,9 @@ from openapi_core.exceptions import MissingRequiredParameter from openapi_core.templating.media_types.exceptions import MediaTypeNotFound -from openapi_core.templating.paths.exceptions import ( - ServerNotFound, OperationNotFound, PathNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound +from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.validation.exceptions import InvalidSecurity @@ -25,18 +25,16 @@ class FalconOpenAPIErrorsHandler: @classmethod def handle(cls, req, resp, errors): - data_errors = [ - cls.format_openapi_error(err) - for err in errors - ] + data_errors = [cls.format_openapi_error(err) for err in errors] data = { - 'errors': data_errors, + "errors": data_errors, } data_str = dumps(data) data_error_max = max(data_errors, key=cls.get_error_status) resp.content_type = MEDIA_JSON resp.status = getattr( - status_codes, f"HTTP_{data_error_max['status']}", + status_codes, + f"HTTP_{data_error_max['status']}", status_codes.HTTP_400, ) resp.text = data_str @@ -45,11 +43,11 @@ def handle(cls, req, resp, errors): @classmethod def format_openapi_error(cls, error): return { - 'title': str(error), - 'status': cls.OPENAPI_ERROR_STATUS.get(error.__class__, 400), - 'class': str(type(error)), + "title": str(error), + "status": cls.OPENAPI_ERROR_STATUS.get(error.__class__, 400), + "class": str(type(error)), } @classmethod def get_error_status(cls, error): - return error['status'] + return error["status"] diff --git a/openapi_core/contrib/falcon/middlewares.py b/openapi_core/contrib/falcon/middlewares.py index 1b3c4fa5..7c574ae4 100644 --- a/openapi_core/contrib/falcon/middlewares.py +++ b/openapi_core/contrib/falcon/middlewares.py @@ -37,7 +37,8 @@ def from_spec( request_validator = RequestValidator(spec) response_validator = ResponseValidator(spec) validation_processor = OpenAPIProcessor( - request_validator, response_validator) + request_validator, response_validator + ) return cls( validation_processor, request_factory=request_factory, @@ -55,18 +56,18 @@ def process_response(self, req, resp, resource, req_succeeded): openapi_req = self._get_openapi_request(req) openapi_resp = self._get_openapi_response(resp) resp.context.openapi = self._process_openapi_response( - openapi_req, openapi_resp) + openapi_req, openapi_resp + ) if resp.context.openapi.errors: return self._handle_response_errors( - req, resp, resp.context.openapi) + req, resp, resp.context.openapi + ) def _handle_request_errors(self, req, resp, request_result): - return self.errors_handler.handle( - req, resp, request_result.errors) + return self.errors_handler.handle(req, resp, request_result.errors) def _handle_response_errors(self, req, resp, response_result): - return self.errors_handler.handle( - req, resp, response_result.errors) + return self.errors_handler.handle(req, resp, response_result.errors) def _get_openapi_request(self, request): return self.request_factory.create(request) @@ -79,4 +80,5 @@ def _process_openapi_request(self, openapi_request): def _process_openapi_response(self, opneapi_request, openapi_response): return self.validation_processor.process_response( - opneapi_request, openapi_response) + opneapi_request, openapi_response + ) diff --git a/openapi_core/contrib/falcon/requests.py b/openapi_core/contrib/falcon/requests.py index 49fe2fe9..74210149 100644 --- a/openapi_core/contrib/falcon/requests.py +++ b/openapi_core/contrib/falcon/requests.py @@ -1,15 +1,14 @@ """OpenAPI core contrib falcon responses module""" from json import dumps -from werkzeug.datastructures import ImmutableMultiDict, Headers +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableMultiDict -from openapi_core.validation.request.datatypes import ( - OpenAPIRequest, RequestParameters, -) +from openapi_core.validation.request.datatypes import OpenAPIRequest +from openapi_core.validation.request.datatypes import RequestParameters class FalconOpenAPIRequestFactory: - def __init__(self, default_when_empty=None): if default_when_empty is None: default_when_empty = {} @@ -23,9 +22,7 @@ def create(self, request): media = request.get_media(default_when_empty=self.default_when_empty) # Support falcon-jsonify. - body = ( - dumps(getattr(request, "json", media)) - ) + body = dumps(getattr(request, "json", media)) mimetype = request.options.default_media_type if request.content_type: mimetype = request.content_type.partition(";")[0] diff --git a/openapi_core/contrib/falcon/responses.py b/openapi_core/contrib/falcon/responses.py index 9e90af43..f56e06b8 100644 --- a/openapi_core/contrib/falcon/responses.py +++ b/openapi_core/contrib/falcon/responses.py @@ -9,7 +9,7 @@ class FalconOpenAPIResponseFactory: def create(cls, response): status_code = int(response.status[:3]) - mimetype = '' + mimetype = "" if response.content_type: mimetype = response.content_type.partition(";")[0] else: diff --git a/openapi_core/contrib/flask/__init__.py b/openapi_core/contrib/flask/__init__.py index 415b74cf..f429c780 100644 --- a/openapi_core/contrib/flask/__init__.py +++ b/openapi_core/contrib/flask/__init__.py @@ -6,6 +6,8 @@ FlaskOpenAPIResponse = FlaskOpenAPIResponseFactory.create __all__ = [ - 'FlaskOpenAPIRequestFactory', 'FlaskOpenAPIResponseFactory', - 'FlaskOpenAPIRequest', 'FlaskOpenAPIResponse', + "FlaskOpenAPIRequestFactory", + "FlaskOpenAPIResponseFactory", + "FlaskOpenAPIRequest", + "FlaskOpenAPIResponse", ] diff --git a/openapi_core/contrib/flask/decorators.py b/openapi_core/contrib/flask/decorators.py index 93e528e9..7dc1aa6e 100644 --- a/openapi_core/contrib/flask/decorators.py +++ b/openapi_core/contrib/flask/decorators.py @@ -9,36 +9,39 @@ class FlaskOpenAPIViewDecorator(OpenAPIDecorator): - def __init__( - self, - request_validator, - response_validator, - request_factory=FlaskOpenAPIRequestFactory, - response_factory=FlaskOpenAPIResponseFactory, - request_provider=FlaskRequestProvider, - openapi_errors_handler=FlaskOpenAPIErrorsHandler, + self, + request_validator, + response_validator, + request_factory=FlaskOpenAPIRequestFactory, + response_factory=FlaskOpenAPIResponseFactory, + request_provider=FlaskRequestProvider, + openapi_errors_handler=FlaskOpenAPIErrorsHandler, ): super().__init__( - request_validator, response_validator, - request_factory, response_factory, - request_provider, openapi_errors_handler, + request_validator, + response_validator, + request_factory, + response_factory, + request_provider, + openapi_errors_handler, ) def _handle_request_view(self, request_result, view, *args, **kwargs): request = self._get_request(*args, **kwargs) request.openapi = request_result return super()._handle_request_view( - request_result, view, *args, **kwargs) + request_result, view, *args, **kwargs + ) @classmethod def from_spec( - cls, - spec, - request_factory=FlaskOpenAPIRequestFactory, - response_factory=FlaskOpenAPIResponseFactory, - request_provider=FlaskRequestProvider, - openapi_errors_handler=FlaskOpenAPIErrorsHandler, + cls, + spec, + request_factory=FlaskOpenAPIRequestFactory, + response_factory=FlaskOpenAPIResponseFactory, + request_provider=FlaskRequestProvider, + openapi_errors_handler=FlaskOpenAPIErrorsHandler, ): request_validator = RequestValidator(spec) response_validator = ResponseValidator(spec) diff --git a/openapi_core/contrib/flask/handlers.py b/openapi_core/contrib/flask/handlers.py index 5470fe07..1f15d2be 100644 --- a/openapi_core/contrib/flask/handlers.py +++ b/openapi_core/contrib/flask/handlers.py @@ -3,9 +3,9 @@ from flask.json import dumps from openapi_core.templating.media_types.exceptions import MediaTypeNotFound -from openapi_core.templating.paths.exceptions import ( - ServerNotFound, OperationNotFound, PathNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound +from openapi_core.templating.paths.exceptions import ServerNotFound class FlaskOpenAPIErrorsHandler: @@ -19,29 +19,24 @@ class FlaskOpenAPIErrorsHandler: @classmethod def handle(cls, errors): - data_errors = [ - cls.format_openapi_error(err) - for err in errors - ] + data_errors = [cls.format_openapi_error(err) for err in errors] data = { - 'errors': data_errors, + "errors": data_errors, } data_error_max = max(data_errors, key=cls.get_error_status) - status = data_error_max['status'] + status = data_error_max["status"] return current_app.response_class( - dumps(data), - status=status, - mimetype='application/json' + dumps(data), status=status, mimetype="application/json" ) @classmethod def format_openapi_error(cls, error): return { - 'title': str(error), - 'status': cls.OPENAPI_ERROR_STATUS.get(error.__class__, 400), - 'class': str(type(error)), + "title": str(error), + "status": cls.OPENAPI_ERROR_STATUS.get(error.__class__, 400), + "class": str(type(error)), } @classmethod def get_error_status(cls, error): - return error['status'] + return error["status"] diff --git a/openapi_core/contrib/flask/providers.py b/openapi_core/contrib/flask/providers.py index 29baace4..f45784ad 100644 --- a/openapi_core/contrib/flask/providers.py +++ b/openapi_core/contrib/flask/providers.py @@ -3,7 +3,6 @@ class FlaskRequestProvider: - @classmethod def provide(self, *args, **kwargs): return request diff --git a/openapi_core/contrib/flask/requests.py b/openapi_core/contrib/flask/requests.py index 6fb9f367..67dd327c 100644 --- a/openapi_core/contrib/flask/requests.py +++ b/openapi_core/contrib/flask/requests.py @@ -4,12 +4,11 @@ from werkzeug.datastructures import Headers -from openapi_core.validation.request.datatypes import ( - RequestParameters, OpenAPIRequest, -) +from openapi_core.validation.request.datatypes import OpenAPIRequest +from openapi_core.validation.request.datatypes import RequestParameters # http://flask.pocoo.org/docs/1.0/quickstart/#variable-rules -PATH_PARAMETER_PATTERN = r'<(?:(?:string|int|float|path|uuid):)?(\w+)>' +PATH_PARAMETER_PATTERN = r"<(?:(?:string|int|float|path|uuid):)?(\w+)>" class FlaskOpenAPIRequestFactory: @@ -23,7 +22,7 @@ def create(cls, request): if request.url_rule is None: path_pattern = request.path else: - path_pattern = cls.path_regex.sub(r'{\1}', request.url_rule.rule) + path_pattern = cls.path_regex.sub(r"{\1}", request.url_rule.rule) header = Headers(request.headers) parameters = RequestParameters( diff --git a/openapi_core/contrib/flask/responses.py b/openapi_core/contrib/flask/responses.py index a36a36ac..a6c6f7a1 100644 --- a/openapi_core/contrib/flask/responses.py +++ b/openapi_core/contrib/flask/responses.py @@ -5,7 +5,6 @@ class FlaskOpenAPIResponseFactory: - @classmethod def create(cls, response): header = Headers(response.headers) diff --git a/openapi_core/contrib/requests/__init__.py b/openapi_core/contrib/requests/__init__.py index a95180a1..4c0dcbe5 100644 --- a/openapi_core/contrib/requests/__init__.py +++ b/openapi_core/contrib/requests/__init__.py @@ -10,6 +10,8 @@ RequestsOpenAPIResponse = RequestsOpenAPIResponseFactory.create __all__ = [ - 'RequestsOpenAPIRequestFactory', 'RequestsOpenAPIResponseFactory', - 'RequestsOpenAPIRequest', 'RequestsOpenAPIResponse', + "RequestsOpenAPIRequestFactory", + "RequestsOpenAPIResponseFactory", + "RequestsOpenAPIRequest", + "RequestsOpenAPIResponse", ] diff --git a/openapi_core/contrib/requests/requests.py b/openapi_core/contrib/requests/requests.py index 7f20f2b9..9ca13bdd 100644 --- a/openapi_core/contrib/requests/requests.py +++ b/openapi_core/contrib/requests/requests.py @@ -1,17 +1,17 @@ """OpenAPI core contrib requests requests module""" -from urllib.parse import urlparse, parse_qs +from urllib.parse import parse_qs +from urllib.parse import urlparse -from werkzeug.datastructures import ImmutableMultiDict, Headers from requests import Request +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableMultiDict -from openapi_core.validation.request.datatypes import ( - RequestParameters, OpenAPIRequest, -) +from openapi_core.validation.request.datatypes import OpenAPIRequest +from openapi_core.validation.request.datatypes import RequestParameters class RequestsOpenAPIRequestFactory: - @classmethod def create(cls, request): """ @@ -40,8 +40,9 @@ def create(cls, request): # Order matters because all python requests issued from a session # include Accept */* which does not necessarily match the content type - mimetype = request.headers.get('Content-Type') or \ - request.headers.get('Accept') + mimetype = request.headers.get("Content-Type") or request.headers.get( + "Accept" + ) # Headers - request.headers is not an instance of Headers # which is expected diff --git a/openapi_core/contrib/requests/responses.py b/openapi_core/contrib/requests/responses.py index 47725a5e..ea3b6f86 100644 --- a/openapi_core/contrib/requests/responses.py +++ b/openapi_core/contrib/requests/responses.py @@ -5,10 +5,9 @@ class RequestsOpenAPIResponseFactory: - @classmethod def create(cls, response): - mimetype = response.headers.get('Content-Type') + mimetype = response.headers.get("Content-Type") headers = Headers(dict(response.headers)) return OpenAPIResponse( data=response.content, diff --git a/openapi_core/deserializing/media_types/deserializers.py b/openapi_core/deserializing/media_types/deserializers.py index a7d65f28..2d62cfcd 100644 --- a/openapi_core/deserializing/media_types/deserializers.py +++ b/openapi_core/deserializing/media_types/deserializers.py @@ -6,7 +6,6 @@ class BaseMediaTypeDeserializer: - def __init__(self, mimetype): self.mimetype = mimetype @@ -15,14 +14,12 @@ def __call__(self, value): class UnsupportedMimetypeDeserializer(BaseMediaTypeDeserializer): - def __call__(self, value): warnings.warn(f"Unsupported {self.mimetype} mimetype") return value class CallableMediaTypeDeserializer(BaseMediaTypeDeserializer): - def __init__(self, mimetype, deserializer_callable): self.mimetype = mimetype self.deserializer_callable = deserializer_callable diff --git a/openapi_core/deserializing/media_types/exceptions.py b/openapi_core/deserializing/media_types/exceptions.py index 45a16c7f..87def336 100644 --- a/openapi_core/deserializing/media_types/exceptions.py +++ b/openapi_core/deserializing/media_types/exceptions.py @@ -6,6 +6,7 @@ @dataclass class MediaTypeDeserializeError(DeserializeError): """Media type deserialize operation error""" + mimetype: str value: str diff --git a/openapi_core/deserializing/media_types/factories.py b/openapi_core/deserializing/media_types/factories.py index 8316c373..3b0aa547 100644 --- a/openapi_core/deserializing/media_types/factories.py +++ b/openapi_core/deserializing/media_types/factories.py @@ -1,20 +1,21 @@ from json import loads -from openapi_core.deserializing.media_types.util import ( - urlencoded_form_loads, data_form_loads, +from openapi_core.deserializing.media_types.deserializers import ( + CallableMediaTypeDeserializer, ) - from openapi_core.deserializing.media_types.deserializers import ( - CallableMediaTypeDeserializer, UnsupportedMimetypeDeserializer, + UnsupportedMimetypeDeserializer, ) +from openapi_core.deserializing.media_types.util import data_form_loads +from openapi_core.deserializing.media_types.util import urlencoded_form_loads class MediaTypeDeserializersFactory: MEDIA_TYPE_DESERIALIZERS = { - 'application/json': loads, - 'application/x-www-form-urlencoded': urlencoded_form_loads, - 'multipart/form-data': data_form_loads, + "application/json": loads, + "application/x-www-form-urlencoded": urlencoded_form_loads, + "multipart/form-data": data_form_loads, } def __init__(self, custom_deserializers=None): @@ -23,14 +24,12 @@ def __init__(self, custom_deserializers=None): self.custom_deserializers = custom_deserializers def create(self, mimetype): - deserialize_callable = self.get_deserializer_callable( - mimetype) + deserialize_callable = self.get_deserializer_callable(mimetype) if deserialize_callable is None: return UnsupportedMimetypeDeserializer(mimetype) - return CallableMediaTypeDeserializer( - mimetype, deserialize_callable) + return CallableMediaTypeDeserializer(mimetype, deserialize_callable) def get_deserializer_callable(self, mimetype): if mimetype in self.custom_deserializers: diff --git a/openapi_core/deserializing/media_types/util.py b/openapi_core/deserializing/media_types/util.py index eccc3ccf..22d9f345 100644 --- a/openapi_core/deserializing/media_types/util.py +++ b/openapi_core/deserializing/media_types/util.py @@ -8,11 +8,12 @@ def urlencoded_form_loads(value): def data_form_loads(value): if issubclass(type(value), bytes): - value = value.decode('ASCII', errors='surrogateescape') + value = value.decode("ASCII", errors="surrogateescape") parser = Parser() parts = parser.parsestr(value, headersonly=False) return { - part.get_param('name', header='content-disposition'): - part.get_payload(decode=True) + part.get_param("name", header="content-disposition"): part.get_payload( + decode=True + ) for part in parts.get_payload() } diff --git a/openapi_core/deserializing/parameters/deserializers.py b/openapi_core/deserializing/parameters/deserializers.py index e9c544ac..9565d02d 100644 --- a/openapi_core/deserializing/parameters/deserializers.py +++ b/openapi_core/deserializing/parameters/deserializers.py @@ -4,11 +4,11 @@ from openapi_core.deserializing.parameters.exceptions import ( EmptyQueryParameterValue, ) -from openapi_core.schema.parameters import get_aslist, get_explode +from openapi_core.schema.parameters import get_aslist +from openapi_core.schema.parameters import get_explode class BaseParameterDeserializer: - def __init__(self, param_or_header, style): self.param_or_header = param_or_header self.style = style @@ -18,14 +18,12 @@ def __call__(self, value): class UnsupportedStyleDeserializer(BaseParameterDeserializer): - def __call__(self, value): warnings.warn(f"Unsupported {self.style} style") return value class CallableParameterDeserializer(BaseParameterDeserializer): - def __init__(self, param_or_header, style, deserializer_callable): super().__init__(param_or_header, style) self.deserializer_callable = deserializer_callable @@ -35,17 +33,17 @@ def __init__(self, param_or_header, style, deserializer_callable): def __call__(self, value): # if "in" not defined then it's a Header - if 'allowEmptyValue' in self.param_or_header: + if "allowEmptyValue" in self.param_or_header: warnings.warn( "Use of allowEmptyValue property is deprecated", DeprecationWarning, ) allow_empty_values = self.param_or_header.getkey( - 'allowEmptyValue', False) - location_name = self.param_or_header.getkey('in', 'header') - if (location_name == 'query' and value == "" and - not allow_empty_values): - name = self.param_or_header['name'] + "allowEmptyValue", False + ) + location_name = self.param_or_header.getkey("in", "header") + if location_name == "query" and value == "" and not allow_empty_values: + name = self.param_or_header["name"] raise EmptyQueryParameterValue(name) if not self.aslist or self.explode: diff --git a/openapi_core/deserializing/parameters/exceptions.py b/openapi_core/deserializing/parameters/exceptions.py index 0009af29..64dbe910 100644 --- a/openapi_core/deserializing/parameters/exceptions.py +++ b/openapi_core/deserializing/parameters/exceptions.py @@ -6,12 +6,14 @@ @dataclass class BaseParameterDeserializeError(DeserializeError): """Base parameter deserialize operation error""" + location: str @dataclass class ParameterDeserializeError(BaseParameterDeserializeError): """Parameter deserialize operation error""" + style: str value: str @@ -27,7 +29,7 @@ class EmptyQueryParameterValue(BaseParameterDeserializeError): name: str def __init__(self, name): - super().__init__(location='query') + super().__init__(location="query") self.name = name def __str__(self): diff --git a/openapi_core/deserializing/parameters/factories.py b/openapi_core/deserializing/parameters/factories.py index b69c7985..f72825b2 100644 --- a/openapi_core/deserializing/parameters/factories.py +++ b/openapi_core/deserializing/parameters/factories.py @@ -1,7 +1,10 @@ from functools import partial from openapi_core.deserializing.parameters.deserializers import ( - CallableParameterDeserializer, UnsupportedStyleDeserializer, + CallableParameterDeserializer, +) +from openapi_core.deserializing.parameters.deserializers import ( + UnsupportedStyleDeserializer, ) from openapi_core.deserializing.parameters.util import split from openapi_core.schema.parameters import get_style @@ -10,10 +13,10 @@ class ParameterDeserializersFactory: PARAMETER_STYLE_DESERIALIZERS = { - 'form': partial(split, separator=','), - 'simple': partial(split, separator=','), - 'spaceDelimited': partial(split, separator=' '), - 'pipeDelimited': partial(split, separator='|'), + "form": partial(split, separator=","), + "simple": partial(split, separator=","), + "spaceDelimited": partial(split, separator=" "), + "pipeDelimited": partial(split, separator="|"), } def create(self, param_or_header): @@ -24,4 +27,5 @@ def create(self, param_or_header): deserialize_callable = self.PARAMETER_STYLE_DESERIALIZERS[style] return CallableParameterDeserializer( - param_or_header, style, deserialize_callable) + param_or_header, style, deserialize_callable + ) diff --git a/openapi_core/deserializing/parameters/util.py b/openapi_core/deserializing/parameters/util.py index c0d7e8a1..e9cc4db0 100644 --- a/openapi_core/deserializing/parameters/util.py +++ b/openapi_core/deserializing/parameters/util.py @@ -1,2 +1,2 @@ -def split(value, separator=','): +def split(value, separator=","): return value.split(separator) diff --git a/openapi_core/exceptions.py b/openapi_core/exceptions.py index 8fba2d04..59f32b11 100644 --- a/openapi_core/exceptions.py +++ b/openapi_core/exceptions.py @@ -15,7 +15,6 @@ class OpenAPIHeaderError(OpenAPIError): class MissingHeaderError(OpenAPIHeaderError): """Missing header error""" - pass @dataclass @@ -40,7 +39,6 @@ class OpenAPIParameterError(OpenAPIError): class MissingParameterError(OpenAPIParameterError): """Missing parameter error""" - pass @dataclass @@ -65,7 +63,6 @@ class OpenAPIRequestBodyError(OpenAPIError): class MissingRequestBodyError(OpenAPIRequestBodyError): """Missing request body error""" - pass @dataclass diff --git a/openapi_core/extensions/models/factories.py b/openapi_core/extensions/models/factories.py index 4573d59b..1e66c128 100644 --- a/openapi_core/extensions/models/factories.py +++ b/openapi_core/extensions/models/factories.py @@ -7,16 +7,15 @@ class ModelClassFactory: base_class = Model def create(self, name): - return type(name, (self.base_class, ), {}) + return type(name, (self.base_class,), {}) class ModelFactory: - def __init__(self, model_class_factory=None): self.model_class_factory = model_class_factory or ModelClassFactory() def create(self, properties, name=None): - name = name or 'Model' + name = name or "Model" model_class = self._create_class(name) return model_class(properties) diff --git a/openapi_core/schema/parameters.py b/openapi_core/schema/parameters.py index 79ead68b..c44dc2e3 100644 --- a/openapi_core/schema/parameters.py +++ b/openapi_core/schema/parameters.py @@ -4,42 +4,40 @@ def get_aslist(param_or_header): """Checks if parameter/header is described as list for simpler scenarios""" # if schema is not defined it's a complex scenario - if 'schema' not in param_or_header: + if "schema" not in param_or_header: return False - schema = param_or_header / 'schema' - schema_type = schema.getkey('type', 'any') + schema = param_or_header / "schema" + schema_type = schema.getkey("type", "any") # TODO: resolve for 'any' schema type - return schema_type in ['array', 'object'] + return schema_type in ["array", "object"] def get_style(param_or_header): """Checks parameter/header style for simpler scenarios""" - if 'style' in param_or_header: - return param_or_header['style'] + if "style" in param_or_header: + return param_or_header["style"] # if "in" not defined then it's a Header - location = param_or_header.getkey('in', 'header') + location = param_or_header.getkey("in", "header") # determine default - return ( - 'simple' if location in ['path', 'header'] else 'form' - ) + return "simple" if location in ["path", "header"] else "form" def get_explode(param_or_header): """Checks parameter/header explode for simpler scenarios""" - if 'explode' in param_or_header: - return param_or_header['explode'] + if "explode" in param_or_header: + return param_or_header["explode"] # determine default style = get_style(param_or_header) - return style == 'form' + return style == "form" def get_value(param_or_header, location, name=None): """Returns parameter/header value from specific location""" - name = name or param_or_header['name'] + name = name or param_or_header["name"] if name not in location: raise KeyError @@ -47,7 +45,7 @@ def get_value(param_or_header, location, name=None): aslist = get_aslist(param_or_header) explode = get_explode(param_or_header) if aslist and explode: - if hasattr(location, 'getall'): + if hasattr(location, "getall"): return location.getall(name) return location.getlist(name) diff --git a/openapi_core/schema/schemas.py b/openapi_core/schema/schemas.py index 43919cb3..a4f1bf1b 100644 --- a/openapi_core/schema/schemas.py +++ b/openapi_core/schema/schemas.py @@ -1,11 +1,11 @@ def get_all_properties(schema): - properties = schema.get('properties', {}) + properties = schema.get("properties", {}) properties_dict = dict(list(properties.items())) - if 'allOf'not in schema: + if "allOf" not in schema: return properties_dict - for subschema in schema / 'allOf': + for subschema in schema / "allOf": subschema_props = get_all_properties(subschema) properties_dict.update(subschema_props) diff --git a/openapi_core/schema/servers.py b/openapi_core/schema/servers.py index 3f7a1141..cabeabf4 100644 --- a/openapi_core/schema/servers.py +++ b/openapi_core/schema/servers.py @@ -1,19 +1,19 @@ def is_absolute(url): - return url.startswith('//') or '://' in url + return url.startswith("//") or "://" in url def get_server_default_variables(server): - if 'variables' not in server: + if "variables" not in server: return {} defaults = {} - variables = server / 'variables' + variables = server / "variables" for name, variable in list(variables.items()): - defaults[name] = variable['default'] + defaults[name] = variable["default"] return defaults def get_server_url(server, **variables): if not variables: variables = get_server_default_variables(server) - return server['url'].format(**variables) + return server["url"].format(**variables) diff --git a/openapi_core/schema/specs.py b/openapi_core/schema/specs.py index 45753074..ab275734 100644 --- a/openapi_core/schema/specs.py +++ b/openapi_core/schema/specs.py @@ -2,5 +2,5 @@ def get_spec_url(spec, index=0): - servers = spec / 'servers' + servers = spec / "servers" return get_server_url(servers / 0) diff --git a/openapi_core/security/factories.py b/openapi_core/security/factories.py index 1bc0ff28..65c1d91d 100644 --- a/openapi_core/security/factories.py +++ b/openapi_core/security/factories.py @@ -1,18 +1,18 @@ -from openapi_core.security.providers import ( - ApiKeyProvider, HttpProvider, UnsupportedProvider, -) +from openapi_core.security.providers import ApiKeyProvider +from openapi_core.security.providers import HttpProvider +from openapi_core.security.providers import UnsupportedProvider class SecurityProviderFactory: PROVIDERS = { - 'apiKey': ApiKeyProvider, - 'http': HttpProvider, - 'oauth2': UnsupportedProvider, - 'openIdConnect': UnsupportedProvider, + "apiKey": ApiKeyProvider, + "http": HttpProvider, + "oauth2": UnsupportedProvider, + "openIdConnect": UnsupportedProvider, } def create(self, scheme): - scheme_type = scheme['type'] + scheme_type = scheme["type"] provider_class = self.PROVIDERS[scheme_type] return provider_class(scheme) diff --git a/openapi_core/security/providers.py b/openapi_core/security/providers.py index e0613650..39403578 100644 --- a/openapi_core/security/providers.py +++ b/openapi_core/security/providers.py @@ -4,22 +4,19 @@ class BaseProvider: - def __init__(self, scheme): self.scheme = scheme class UnsupportedProvider(BaseProvider): - def __call__(self, request): warnings.warn("Unsupported scheme type") class ApiKeyProvider(BaseProvider): - def __call__(self, request): - name = self.scheme['name'] - location = self.scheme['in'] + name = self.scheme["name"] + location = self.scheme["in"] source = getattr(request.parameters, location) if name not in source: raise SecurityError("Missing api key parameter.") @@ -27,19 +24,17 @@ def __call__(self, request): class HttpProvider(BaseProvider): - def __call__(self, request): - if 'Authorization' not in request.parameters.header: - raise SecurityError('Missing authorization header.') - auth_header = request.parameters.header['Authorization'] + if "Authorization" not in request.parameters.header: + raise SecurityError("Missing authorization header.") + auth_header = request.parameters.header["Authorization"] try: - auth_type, encoded_credentials = auth_header.split(' ', 1) + auth_type, encoded_credentials = auth_header.split(" ", 1) except ValueError: - raise SecurityError('Could not parse authorization header.') + raise SecurityError("Could not parse authorization header.") - scheme = self.scheme['scheme'] + scheme = self.scheme["scheme"] if auth_type.lower() != scheme: - raise SecurityError( - f'Unknown authorization method {auth_type}') + raise SecurityError(f"Unknown authorization method {auth_type}") return encoded_credentials diff --git a/openapi_core/shortcuts.py b/openapi_core/shortcuts.py index 70e8617a..59c27269 100644 --- a/openapi_core/shortcuts.py +++ b/openapi_core/shortcuts.py @@ -1,18 +1,21 @@ """OpenAPI core shortcuts module""" # backward compatibility from openapi_core.spec.shortcuts import create_spec -from openapi_core.validation.request.shortcuts import ( - validate_request, - spec_validate_body, spec_validate_parameters, spec_validate_security, -) -from openapi_core.validation.response.shortcuts import ( - validate_response, - spec_validate_data, spec_validate_headers, -) +from openapi_core.validation.request.shortcuts import spec_validate_body +from openapi_core.validation.request.shortcuts import spec_validate_parameters +from openapi_core.validation.request.shortcuts import spec_validate_security +from openapi_core.validation.request.shortcuts import validate_request +from openapi_core.validation.response.shortcuts import spec_validate_data +from openapi_core.validation.response.shortcuts import spec_validate_headers +from openapi_core.validation.response.shortcuts import validate_response __all__ = [ - 'create_spec', - 'validate_request', 'validate_response', - 'spec_validate_body', 'spec_validate_parameters', 'spec_validate_security', - 'spec_validate_data', 'spec_validate_headers', + "create_spec", + "validate_request", + "validate_response", + "spec_validate_body", + "spec_validate_parameters", + "spec_validate_security", + "spec_validate_data", + "spec_validate_headers", ] diff --git a/openapi_core/spec/accessors.py b/openapi_core/spec/accessors.py index 76d2ca0d..2687d523 100644 --- a/openapi_core/spec/accessors.py +++ b/openapi_core/spec/accessors.py @@ -4,7 +4,6 @@ class SpecAccessor(DictOrListAccessor): - def __init__(self, dict_or_list, dereferencer): super().__init__(dict_or_list) self.dereferencer = dereferencer @@ -14,9 +13,8 @@ def open(self, parts): content = self.dict_or_list for part in parts: content = content[part] - if '$ref' in content: - content = self.dereferencer.dereference( - content) + if "$ref" in content: + content = self.dereferencer.dereference(content) try: yield content finally: diff --git a/openapi_core/spec/paths.py b/openapi_core/spec/paths.py index 8377aa0e..03bb8080 100644 --- a/openapi_core/spec/paths.py +++ b/openapi_core/spec/paths.py @@ -2,13 +2,12 @@ from openapi_core.spec.accessors import SpecAccessor -SPEC_SEPARATOR = '#' +SPEC_SEPARATOR = "#" class SpecPath(AccessorPath): - @classmethod def from_spec(cls, spec_dict, dereferencer=None, *args, **kwargs): - separator = kwargs.pop('separator', SPEC_SEPARATOR) + separator = kwargs.pop("separator", SPEC_SEPARATOR) accessor = SpecAccessor(spec_dict, dereferencer) return cls(accessor, *args, separator=separator) diff --git a/openapi_core/spec/shortcuts.py b/openapi_core/spec/shortcuts.py index 2df933d5..093c5ab3 100644 --- a/openapi_core/spec/shortcuts.py +++ b/openapi_core/spec/shortcuts.py @@ -1,21 +1,21 @@ """OpenAPI core spec shortcuts module""" from jsonschema.validators import RefResolver -from openapi_spec_validator import ( - default_handlers, openapi_v3_spec_validator, -) +from openapi_spec_validator import default_handlers +from openapi_spec_validator import openapi_v3_spec_validator from openapi_spec_validator.validators import Dereferencer from openapi_core.spec.paths import SpecPath def create_spec( - spec_dict, spec_url='', handlers=default_handlers, + spec_dict, + spec_url="", + handlers=default_handlers, validate_spec=True, ): if validate_spec: openapi_v3_spec_validator.validate(spec_dict, spec_url=spec_url) - spec_resolver = RefResolver( - spec_url, spec_dict, handlers=handlers) + spec_resolver = RefResolver(spec_url, spec_dict, handlers=handlers) dereferencer = Dereferencer(spec_resolver) return SpecPath.from_spec(spec_dict, dereferencer) diff --git a/openapi_core/templating/datatypes.py b/openapi_core/templating/datatypes.py index 5aa62d49..02d4424b 100644 --- a/openapi_core/templating/datatypes.py +++ b/openapi_core/templating/datatypes.py @@ -1,6 +1,6 @@ -from typing import Dict, Optional - from dataclasses import dataclass +from typing import Dict +from typing import Optional @dataclass diff --git a/openapi_core/templating/media_types/exceptions.py b/openapi_core/templating/media_types/exceptions.py index 0cc7a22e..26c46596 100644 --- a/openapi_core/templating/media_types/exceptions.py +++ b/openapi_core/templating/media_types/exceptions.py @@ -1,6 +1,5 @@ -from typing import List - from dataclasses import dataclass +from typing import List from openapi_core.exceptions import OpenAPIError diff --git a/openapi_core/templating/media_types/finders.py b/openapi_core/templating/media_types/finders.py index d10887bb..c9fa7d86 100644 --- a/openapi_core/templating/media_types/finders.py +++ b/openapi_core/templating/media_types/finders.py @@ -5,7 +5,6 @@ class MediaTypeFinder: - def __init__(self, content): self.content = content diff --git a/openapi_core/templating/paths/exceptions.py b/openapi_core/templating/paths/exceptions.py index ad720cc9..ec9fe4b3 100644 --- a/openapi_core/templating/paths/exceptions.py +++ b/openapi_core/templating/paths/exceptions.py @@ -10,6 +10,7 @@ class PathError(OpenAPIError): @dataclass class PathNotFound(PathError): """Find path error""" + url: str def __str__(self): @@ -19,6 +20,7 @@ def __str__(self): @dataclass class OperationNotFound(PathError): """Find path operation error""" + url: str method: str @@ -29,6 +31,7 @@ def __str__(self): @dataclass class ServerNotFound(PathError): """Find server error""" + url: str def __str__(self): diff --git a/openapi_core/templating/paths/finders.py b/openapi_core/templating/paths/finders.py index 5e05437c..bdeec72b 100644 --- a/openapi_core/templating/paths/finders.py +++ b/openapi_core/templating/paths/finders.py @@ -1,19 +1,20 @@ """OpenAPI core templating paths finders module""" -from urllib.parse import urljoin, urlparse +from urllib.parse import urljoin +from urllib.parse import urlparse from more_itertools import peekable from openapi_core.schema.servers import is_absolute from openapi_core.templating.datatypes import TemplateResult -from openapi_core.templating.util import parse, search -from openapi_core.templating.paths.exceptions import ( - PathNotFound, OperationNotFound, ServerNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound +from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.templating.paths.util import template_path_len +from openapi_core.templating.util import parse +from openapi_core.templating.util import search class PathFinder: - def __init__(self, spec, base_url=None): self.spec = spec self.base_url = base_url @@ -26,14 +27,16 @@ def find(self, request): raise PathNotFound(request.full_url_pattern) operations_iter = self._get_operations_iter( - request.method, paths_iter_peek) + request.method, paths_iter_peek + ) operations_iter_peek = peekable(operations_iter) if not operations_iter_peek: raise OperationNotFound(request.full_url_pattern, request.method) servers_iter = self._get_servers_iter( - request.full_url_pattern, operations_iter_peek) + request.full_url_pattern, operations_iter_peek + ) try: return next(servers_iter) @@ -42,7 +45,7 @@ def find(self, request): def _get_paths_iter(self, full_url_pattern): template_paths = [] - paths = self.spec / 'paths' + paths = self.spec / "paths" for path_pattern, path in list(paths.items()): # simple path. # Return right away since it is always the most concrete @@ -69,36 +72,46 @@ def _get_operations_iter(self, request_method, paths_iter): def _get_servers_iter(self, full_url_pattern, ooperations_iter): for path, operation, path_result in ooperations_iter: - servers = path.get('servers', None) or \ - operation.get('servers', None) or \ - self.spec.get('servers', [{'url': '/'}]) + servers = ( + path.get("servers", None) + or operation.get("servers", None) + or self.spec.get("servers", [{"url": "/"}]) + ) for server in servers: server_url_pattern = full_url_pattern.rsplit( - path_result.resolved, 1)[0] - server_url = server['url'] + path_result.resolved, 1 + )[0] + server_url = server["url"] if not is_absolute(server_url): # relative to absolute url if self.base_url is not None: - server_url = urljoin(self.base_url, server['url']) + server_url = urljoin(self.base_url, server["url"]) # if no base url check only path part else: server_url_pattern = urlparse(server_url_pattern).path - if server_url.endswith('/'): + if server_url.endswith("/"): server_url = server_url[:-1] # simple path if server_url_pattern == server_url: - server_result = TemplateResult(server['url'], {}) + server_result = TemplateResult(server["url"], {}) yield ( - path, operation, server, - path_result, server_result, + path, + operation, + server, + path_result, + server_result, ) # template path else: - result = parse(server['url'], server_url_pattern) + result = parse(server["url"], server_url_pattern) if result: server_result = TemplateResult( - server['url'], result.named) + server["url"], result.named + ) yield ( - path, operation, server, - path_result, server_result, + path, + operation, + server, + path_result, + server_result, ) diff --git a/openapi_core/templating/responses/exceptions.py b/openapi_core/templating/responses/exceptions.py index 71cade50..6ba282d0 100644 --- a/openapi_core/templating/responses/exceptions.py +++ b/openapi_core/templating/responses/exceptions.py @@ -1,6 +1,5 @@ -from typing import List - from dataclasses import dataclass +from typing import List from openapi_core.exceptions import OpenAPIError @@ -12,9 +11,9 @@ class ResponseFinderError(OpenAPIError): @dataclass class ResponseNotFound(ResponseFinderError): """Find response error""" + http_status: int availableresponses: List[str] def __str__(self): - return "Unknown response http status: {}".format( - str(self.http_status)) + return f"Unknown response http status: {str(self.http_status)}" diff --git a/openapi_core/templating/responses/finders.py b/openapi_core/templating/responses/finders.py index 3d3dfbd5..87446748 100644 --- a/openapi_core/templating/responses/finders.py +++ b/openapi_core/templating/responses/finders.py @@ -2,20 +2,19 @@ class ResponseFinder: - def __init__(self, responses): self.responses = responses - def find(self, http_status='default'): + def find(self, http_status="default"): if http_status in self.responses: return self.responses / http_status # try range - http_status_range = f'{http_status[0]}XX' + http_status_range = f"{http_status[0]}XX" if http_status_range in self.responses: return self.responses / http_status_range - if 'default' not in self.responses: + if "default" not in self.responses: raise ResponseNotFound(http_status, list(self.responses.keys())) - return self.responses / 'default' + return self.responses / "default" diff --git a/openapi_core/templating/util.py b/openapi_core/templating/util.py index a92c514a..d3d4fcc6 100644 --- a/openapi_core/templating/util.py +++ b/openapi_core/templating/util.py @@ -24,12 +24,12 @@ def __call__(self, text): def search(path_pattern, full_url_pattern): extra_types = {parse_path_parameter.name: parse_path_parameter} p = ExtendedParser(path_pattern, extra_types) - p._expression = p._expression + '$' + p._expression = p._expression + "$" return p.search(full_url_pattern) def parse(server_url, server_url_pattern): extra_types = {parse_path_parameter.name: parse_path_parameter} p = ExtendedParser(server_url, extra_types) - p._expression = '^' + p._expression + p._expression = "^" + p._expression return p.parse(server_url_pattern) diff --git a/openapi_core/testing/__init__.py b/openapi_core/testing/__init__.py index 28b50ca0..de7f631d 100644 --- a/openapi_core/testing/__init__.py +++ b/openapi_core/testing/__init__.py @@ -1,10 +1,14 @@ """OpenAPI core testing module""" -from openapi_core.testing.mock import MockRequestFactory, MockResponseFactory +from openapi_core.testing.mock import MockRequestFactory +from openapi_core.testing.mock import MockResponseFactory # backward compatibility MockRequest = MockRequestFactory.create MockResponse = MockResponseFactory.create __all__ = [ - 'MockRequestFactory', 'MockResponseFactory', 'MockRequest', 'MockResponse', + "MockRequestFactory", + "MockResponseFactory", + "MockRequest", + "MockResponse", ] diff --git a/openapi_core/testing/datatypes.py b/openapi_core/testing/datatypes.py index 75da8049..7bf38e8d 100644 --- a/openapi_core/testing/datatypes.py +++ b/openapi_core/testing/datatypes.py @@ -1,7 +1,7 @@ class ResultMock: - def __init__( - self, body=None, parameters=None, data=None, error_to_raise=None): + self, body=None, parameters=None, data=None, error_to_raise=None + ): self.body = body self.parameters = parameters self.data = data diff --git a/openapi_core/testing/mock.py b/openapi_core/testing/mock.py index d305f444..7871df13 100644 --- a/openapi_core/testing/mock.py +++ b/openapi_core/testing/mock.py @@ -3,4 +3,4 @@ from openapi_core.testing.requests import MockRequestFactory from openapi_core.testing.responses import MockResponseFactory -__all__ = ['MockRequestFactory', 'MockResponseFactory'] +__all__ = ["MockRequestFactory", "MockResponseFactory"] diff --git a/openapi_core/testing/requests.py b/openapi_core/testing/requests.py index d7af9495..93aeab7b 100644 --- a/openapi_core/testing/requests.py +++ b/openapi_core/testing/requests.py @@ -1,20 +1,28 @@ """OpenAPI core testing requests module""" from urllib.parse import urljoin -from werkzeug.datastructures import Headers, ImmutableMultiDict +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableMultiDict -from openapi_core.validation.request.datatypes import ( - RequestParameters, OpenAPIRequest, -) +from openapi_core.validation.request.datatypes import OpenAPIRequest +from openapi_core.validation.request.datatypes import RequestParameters class MockRequestFactory: - @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'): + cls, + host_url, + method, + path, + path_pattern=None, + args=None, + view_args=None, + headers=None, + cookies=None, + data=None, + mimetype="application/json", + ): path_pattern = path_pattern or path path = view_args or {} @@ -28,7 +36,7 @@ def create( cookie=cookie, ) method = method.lower() - body = data or '' + body = data or "" full_url_pattern = urljoin(host_url, path_pattern) return OpenAPIRequest( full_url_pattern=full_url_pattern, diff --git a/openapi_core/testing/responses.py b/openapi_core/testing/responses.py index 9eae17eb..228eba05 100644 --- a/openapi_core/testing/responses.py +++ b/openapi_core/testing/responses.py @@ -5,11 +5,10 @@ class MockResponseFactory: - @classmethod def create( - cls, data, status_code=200, headers=None, - mimetype='application/json'): + cls, data, status_code=200, headers=None, mimetype="application/json" + ): headers = Headers(headers or {}) return OpenAPIResponse( data=data, diff --git a/openapi_core/unmarshalling/schemas/enums.py b/openapi_core/unmarshalling/schemas/enums.py index ffe4ed55..cfe332e8 100644 --- a/openapi_core/unmarshalling/schemas/enums.py +++ b/openapi_core/unmarshalling/schemas/enums.py @@ -3,5 +3,5 @@ class UnmarshalContext(Enum): - REQUEST = 'request' - RESPONSE = 'response' + REQUEST = "request" + RESPONSE = "response" diff --git a/openapi_core/unmarshalling/schemas/exceptions.py b/openapi_core/unmarshalling/schemas/exceptions.py index e07b1dab..8df84c12 100644 --- a/openapi_core/unmarshalling/schemas/exceptions.py +++ b/openapi_core/unmarshalling/schemas/exceptions.py @@ -1,23 +1,20 @@ +from dataclasses import dataclass +from dataclasses import field from typing import List -from dataclasses import dataclass, field - from openapi_core.exceptions import OpenAPIError class UnmarshalError(OpenAPIError): """Schema unmarshal operation error""" - pass class ValidateError(UnmarshalError): """Schema validate operation error""" - pass class UnmarshallerError(UnmarshalError): """Unmarshaller error""" - pass @dataclass @@ -35,6 +32,7 @@ def __str__(self): @dataclass class InvalidSchemaFormatValue(UnmarshallerError): """Value failed to format with formatter""" + value: str type: str original_exception: Exception @@ -43,7 +41,8 @@ def __str__(self): return ( "Failed to format value {value} to format {type}: {exception}" ).format( - value=self.value, type=self.type, + value=self.value, + type=self.type, exception=self.original_exception, ) @@ -51,6 +50,7 @@ def __str__(self): @dataclass class FormatterNotFoundError(UnmarshallerError): """Formatter not found to unmarshal""" + type_format: str def __str__(self): diff --git a/openapi_core/unmarshalling/schemas/factories.py b/openapi_core/unmarshalling/schemas/factories.py index 59f1ac60..093215e1 100644 --- a/openapi_core/unmarshalling/schemas/factories.py +++ b/openapi_core/unmarshalling/schemas/factories.py @@ -6,35 +6,45 @@ from openapi_core.unmarshalling.schemas.exceptions import ( FormatterNotFoundError, ) +from openapi_core.unmarshalling.schemas.unmarshallers import AnyUnmarshaller +from openapi_core.unmarshalling.schemas.unmarshallers import ArrayUnmarshaller from openapi_core.unmarshalling.schemas.unmarshallers import ( - StringUnmarshaller, IntegerUnmarshaller, NumberUnmarshaller, - BooleanUnmarshaller, ArrayUnmarshaller, ObjectUnmarshaller, - AnyUnmarshaller, + BooleanUnmarshaller, ) +from openapi_core.unmarshalling.schemas.unmarshallers import ( + IntegerUnmarshaller, +) +from openapi_core.unmarshalling.schemas.unmarshallers import NumberUnmarshaller +from openapi_core.unmarshalling.schemas.unmarshallers import ObjectUnmarshaller +from openapi_core.unmarshalling.schemas.unmarshallers import StringUnmarshaller class SchemaUnmarshallersFactory: UNMARSHALLERS = { - 'string': StringUnmarshaller, - 'integer': IntegerUnmarshaller, - 'number': NumberUnmarshaller, - 'boolean': BooleanUnmarshaller, - 'array': ArrayUnmarshaller, - 'object': ObjectUnmarshaller, - 'any': AnyUnmarshaller, + "string": StringUnmarshaller, + "integer": IntegerUnmarshaller, + "number": NumberUnmarshaller, + "boolean": BooleanUnmarshaller, + "array": ArrayUnmarshaller, + "object": ObjectUnmarshaller, + "any": AnyUnmarshaller, } - COMPLEX_UNMARSHALLERS = ['array', 'object', 'any'] + COMPLEX_UNMARSHALLERS = ["array", "object", "any"] CONTEXT_VALIDATION = { - UnmarshalContext.REQUEST: 'write', - UnmarshalContext.RESPONSE: 'read', + UnmarshalContext.REQUEST: "write", + UnmarshalContext.RESPONSE: "read", } def __init__( - self, resolver=None, format_checker=None, - custom_formatters=None, context=None): + self, + resolver=None, + format_checker=None, + custom_formatters=None, + context=None, + ): self.resolver = resolver self.format_checker = format_checker if custom_formatters is None: @@ -47,11 +57,11 @@ def create(self, schema, type_override=None): if schema is None: raise TypeError("Invalid schema") - if schema.getkey('deprecated', False): + if schema.getkey("deprecated", False): warnings.warn("The schema is deprecated", DeprecationWarning) - schema_type = type_override or schema.getkey('type', 'any') - schema_format = schema.getkey('format') + schema_type = type_override or schema.getkey("type", "any") + schema_format = schema.getkey("format") klass = self.UNMARSHALLERS[schema_type] @@ -77,8 +87,8 @@ def get_formatter(self, type_format, default_formatters): def get_validator(self, schema): kwargs = { - 'resolver': self.resolver, - 'format_checker': self.format_checker, + "resolver": self.resolver, + "format_checker": self.format_checker, } if self.context is not None: kwargs[self.CONTEXT_VALIDATION[self.context]] = True diff --git a/openapi_core/unmarshalling/schemas/formatters.py b/openapi_core/unmarshalling/schemas/formatters.py index dc503bd5..cbb8776b 100644 --- a/openapi_core/unmarshalling/schemas/formatters.py +++ b/openapi_core/unmarshalling/schemas/formatters.py @@ -1,5 +1,4 @@ class Formatter: - def validate(self, value): return True @@ -10,9 +9,9 @@ def unmarshal(self, value): def from_callables(cls, validate=None, unmarshal=None): attrs = {} if validate is not None: - attrs['validate'] = staticmethod(validate) + attrs["validate"] = staticmethod(validate) if unmarshal is not None: - attrs['unmarshal'] = staticmethod(unmarshal) + attrs["unmarshal"] = staticmethod(unmarshal) - klass = type('Formatter', (cls, ), attrs) + klass = type("Formatter", (cls,), attrs) return klass() diff --git a/openapi_core/unmarshalling/schemas/unmarshallers.py b/openapi_core/unmarshalling/schemas/unmarshallers.py index ba02ef23..64a473cf 100644 --- a/openapi_core/unmarshalling/schemas/unmarshallers.py +++ b/openapi_core/unmarshalling/schemas/unmarshallers.py @@ -1,28 +1,31 @@ -from functools import partial import logging +from functools import partial from isodate.isodatetime import parse_datetime - -from openapi_schema_validator._types import ( - is_array, is_bool, is_integer, - is_object, is_number, is_string, -) from openapi_schema_validator._format import oas30_format_checker +from openapi_schema_validator._types import is_array +from openapi_schema_validator._types import is_bool +from openapi_schema_validator._types import is_integer +from openapi_schema_validator._types import is_number +from openapi_schema_validator._types import is_object +from openapi_schema_validator._types import is_string from openapi_core.extensions.models.factories import ModelFactory -from openapi_core.schema.schemas import ( - get_all_properties, get_all_properties_names -) +from openapi_core.schema.schemas import get_all_properties +from openapi_core.schema.schemas import get_all_properties_names from openapi_core.unmarshalling.schemas.enums import UnmarshalContext from openapi_core.unmarshalling.schemas.exceptions import ( - UnmarshalError, ValidateError, InvalidSchemaValue, InvalidSchemaFormatValue, ) +from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue +from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError +from openapi_core.unmarshalling.schemas.exceptions import ValidateError from openapi_core.unmarshalling.schemas.formatters import Formatter -from openapi_core.unmarshalling.schemas.util import ( - forcebool, format_date, format_byte, format_uuid, - format_number, -) +from openapi_core.unmarshalling.schemas.util import forcebool +from openapi_core.unmarshalling.schemas.util import format_byte +from openapi_core.unmarshalling.schemas.util import format_date +from openapi_core.unmarshalling.schemas.util import format_number +from openapi_core.unmarshalling.schemas.util import format_uuid log = logging.getLogger(__name__) @@ -52,7 +55,6 @@ def unmarshal(self, value): class PrimitiveTypeUnmarshaller(BaseSchemaUnmarshaller): - def __init__(self, schema, formatter, validator): super().__init__(schema) self.formatter = formatter @@ -61,56 +63,60 @@ def __init__(self, schema, formatter, validator): def _formatter_validate(self, value): result = self.formatter.validate(value) if not result: - schema_type = self.schema.getkey('type', 'any') + schema_type = self.schema.getkey("type", "any") raise InvalidSchemaValue(value, schema_type) def validate(self, value): errors_iter = self.validator.iter_errors(value) errors = tuple(errors_iter) if errors: - schema_type = self.schema.getkey('type', 'any') - raise InvalidSchemaValue( - value, schema_type, schema_errors=errors) + schema_type = self.schema.getkey("type", "any") + raise InvalidSchemaValue(value, schema_type, schema_errors=errors) def unmarshal(self, value): try: return self.formatter.unmarshal(value) except ValueError as exc: - schema_format = self.schema.getkey('format') - raise InvalidSchemaFormatValue( - value, schema_format, exc) + schema_format = self.schema.getkey("format") + raise InvalidSchemaFormatValue(value, schema_format, exc) class StringUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { - None: Formatter.from_callables( - partial(is_string, None), str), - 'password': Formatter.from_callables( - partial(oas30_format_checker.check, format='password'), str), - 'date': Formatter.from_callables( - partial(oas30_format_checker.check, format='date'), format_date), - 'date-time': Formatter.from_callables( - partial(oas30_format_checker.check, format='date-time'), - parse_datetime), - 'binary': Formatter.from_callables( - partial(oas30_format_checker.check, format='binary'), bytes), - 'uuid': Formatter.from_callables( - partial(oas30_format_checker.check, format='uuid'), format_uuid), - 'byte': Formatter.from_callables( - partial(oas30_format_checker.check, format='byte'), format_byte), + None: Formatter.from_callables(partial(is_string, None), str), + "password": Formatter.from_callables( + partial(oas30_format_checker.check, format="password"), str + ), + "date": Formatter.from_callables( + partial(oas30_format_checker.check, format="date"), format_date + ), + "date-time": Formatter.from_callables( + partial(oas30_format_checker.check, format="date-time"), + parse_datetime, + ), + "binary": Formatter.from_callables( + partial(oas30_format_checker.check, format="binary"), bytes + ), + "uuid": Formatter.from_callables( + partial(oas30_format_checker.check, format="uuid"), format_uuid + ), + "byte": Formatter.from_callables( + partial(oas30_format_checker.check, format="byte"), format_byte + ), } class IntegerUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { - None: Formatter.from_callables( - partial(is_integer, None), int), - 'int32': Formatter.from_callables( - partial(oas30_format_checker.check, format='int32'), int), - 'int64': Formatter.from_callables( - partial(oas30_format_checker.check, format='int64'), int), + None: Formatter.from_callables(partial(is_integer, None), int), + "int32": Formatter.from_callables( + partial(oas30_format_checker.check, format="int32"), int + ), + "int64": Formatter.from_callables( + partial(oas30_format_checker.check, format="int64"), int + ), } @@ -118,27 +124,28 @@ class NumberUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { None: Formatter.from_callables( - partial(is_number, None), format_number), - 'float': Formatter.from_callables( - partial(oas30_format_checker.check, format='float'), float), - 'double': Formatter.from_callables( - partial(oas30_format_checker.check, format='double'), float), + partial(is_number, None), format_number + ), + "float": Formatter.from_callables( + partial(oas30_format_checker.check, format="float"), float + ), + "double": Formatter.from_callables( + partial(oas30_format_checker.check, format="double"), float + ), } class BooleanUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { - None: Formatter.from_callables( - partial(is_bool, None), forcebool), + None: Formatter.from_callables(partial(is_bool, None), forcebool), } class ComplexUnmarshaller(PrimitiveTypeUnmarshaller): - def __init__( - self, schema, formatter, validator, unmarshallers_factory, - context=None): + self, schema, formatter, validator, unmarshallers_factory, context=None + ): super().__init__(schema, formatter, validator) self.unmarshallers_factory = unmarshallers_factory self.context = context @@ -147,17 +154,16 @@ def __init__( class ArrayUnmarshaller(ComplexUnmarshaller): FORMATTERS = { - None: Formatter.from_callables( - partial(is_array, None), list), + None: Formatter.from_callables(partial(is_array, None), list), } @property def items_unmarshaller(self): - return self.unmarshallers_factory.create(self.schema / 'items') + return self.unmarshallers_factory.create(self.schema / "items") def __call__(self, value): value = super().__call__(value) - if value is None and self.schema.getkey('nullable', False): + if value is None and self.schema.getkey("nullable", False): return None return list(map(self.items_unmarshaller, value)) @@ -165,8 +171,7 @@ def __call__(self, value): class ObjectUnmarshaller(ComplexUnmarshaller): FORMATTERS = { - None: Formatter.from_callables( - partial(is_object, None), dict), + None: Formatter.from_callables(partial(is_object, None), dict), } @property @@ -177,18 +182,18 @@ def unmarshal(self, value): try: value = self.formatter.unmarshal(value) except ValueError as exc: - raise InvalidSchemaFormatValue( - value, self.schema.format, exc) + raise InvalidSchemaFormatValue(value, self.schema.format, exc) else: return self._unmarshal_object(value) def _unmarshal_object(self, value): - if 'oneOf' in self.schema: + if "oneOf" in self.schema: properties = None - for one_of_schema in self.schema / 'oneOf': + for one_of_schema in self.schema / "oneOf": try: unmarshalled = self._unmarshal_properties( - value, one_of_schema) + value, one_of_schema + ) except (UnmarshalError, ValueError): pass else: @@ -203,8 +208,8 @@ def _unmarshal_object(self, value): else: properties = self._unmarshal_properties(value) - if 'x-model' in self.schema: - name = self.schema['x-model'] + if "x-model" in self.schema: + name = self.schema["x-model"] return self.model_factory.create(properties, name=name) return properties @@ -222,34 +227,37 @@ def _unmarshal_properties(self, value, one_of_schema=None): properties = {} additional_properties = self.schema.getkey( - 'additionalProperties', True) + "additionalProperties", True + ) if isinstance(additional_properties, dict): - additional_prop_schema = self.schema / 'additionalProperties' + additional_prop_schema = self.schema / "additionalProperties" for prop_name in extra_props: prop_value = value[prop_name] properties[prop_name] = self.unmarshallers_factory.create( - additional_prop_schema)(prop_value) + additional_prop_schema + )(prop_value) elif additional_properties is True: for prop_name in extra_props: prop_value = value[prop_name] properties[prop_name] = prop_value for prop_name, prop in list(all_props.items()): - read_only = prop.getkey('readOnly', False) + read_only = prop.getkey("readOnly", False) if self.context == UnmarshalContext.REQUEST and read_only: continue - write_only = prop.getkey('writeOnly', False) + write_only = prop.getkey("writeOnly", False) if self.context == UnmarshalContext.RESPONSE and write_only: continue try: prop_value = value[prop_name] except KeyError: - if 'default' not in prop: + if "default" not in prop: continue - prop_value = prop['default'] + prop_value = prop["default"] - properties[prop_name] = self.unmarshallers_factory.create( - prop)(prop_value) + properties[prop_name] = self.unmarshallers_factory.create(prop)( + prop_value + ) return properties @@ -257,8 +265,12 @@ def _unmarshal_properties(self, value, one_of_schema=None): class AnyUnmarshaller(ComplexUnmarshaller): SCHEMA_TYPES_ORDER = [ - 'object', 'array', 'boolean', - 'integer', 'number', 'string', + "object", + "array", + "boolean", + "integer", + "number", + "string", ] def unmarshal(self, value): @@ -272,7 +284,8 @@ def unmarshal(self, value): for schema_type in self.SCHEMA_TYPES_ORDER: unmarshaller = self.unmarshallers_factory.create( - self.schema, type_override=schema_type) + self.schema, type_override=schema_type + ) # validate with validator of formatter (usualy type validator) try: unmarshaller._formatter_validate(value) @@ -285,10 +298,10 @@ def unmarshal(self, value): return value def _get_one_of_schema(self, value): - if 'oneOf' not in self.schema: + if "oneOf" not in self.schema: return - one_of_schemas = self.schema / 'oneOf' + one_of_schemas = self.schema / "oneOf" for subschema in one_of_schemas: unmarshaller = self.unmarshallers_factory.create(subschema) try: @@ -299,12 +312,12 @@ def _get_one_of_schema(self, value): return subschema def _get_all_of_schema(self, value): - if 'allOf' not in self.schema: + if "allOf" not in self.schema: return - all_of_schemas = self.schema / 'allOf' + all_of_schemas = self.schema / "allOf" for subschema in all_of_schemas: - if 'type' not in subschema: + if "type" not in subschema: continue unmarshaller = self.unmarshallers_factory.create(subschema) try: diff --git a/openapi_core/unmarshalling/schemas/util.py b/openapi_core/unmarshalling/schemas/util.py index 3b4e9e40..58ce16d9 100644 --- a/openapi_core/unmarshalling/schemas/util.py +++ b/openapi_core/unmarshalling/schemas/util.py @@ -1,7 +1,7 @@ """OpenAPI core schemas util module""" +import datetime from base64 import b64decode from copy import copy -import datetime from distutils.util import strtobool from functools import lru_cache from uuid import UUID @@ -17,7 +17,7 @@ def forcebool(val): def format_date(value): - return datetime.datetime.strptime(value, '%Y-%m-%d').date() + return datetime.datetime.strptime(value, "%Y-%m-%d").date() def format_uuid(value): @@ -26,7 +26,7 @@ def format_uuid(value): return UUID(value) -def format_byte(value, encoding='utf8'): +def format_byte(value, encoding="utf8"): return str(b64decode(value), encoding) diff --git a/openapi_core/validation/datatypes.py b/openapi_core/validation/datatypes.py index 1eb58b9d..1c34ef0c 100644 --- a/openapi_core/validation/datatypes.py +++ b/openapi_core/validation/datatypes.py @@ -1,7 +1,6 @@ """OpenAPI core validation datatypes module""" -from typing import List - from dataclasses import dataclass +from typing import List @dataclass diff --git a/openapi_core/validation/decorators.py b/openapi_core/validation/decorators.py index 476502cf..2d94a42b 100644 --- a/openapi_core/validation/decorators.py +++ b/openapi_core/validation/decorators.py @@ -5,15 +5,14 @@ class OpenAPIDecorator(OpenAPIProcessor): - def __init__( - self, - request_validator, - response_validator, - request_factory, - response_factory, - request_provider, - openapi_errors_handler, + self, + request_validator, + response_validator, + request_factory, + response_factory, + request_provider, + openapi_errors_handler, ): super().__init__(request_validator, response_validator) self.request_factory = request_factory @@ -30,13 +29,16 @@ def decorated(*args, **kwargs): if request_result.errors: return self._handle_request_errors(request_result) response = self._handle_request_view( - request_result, view, *args, **kwargs) + request_result, view, *args, **kwargs + ) openapi_response = self._get_openapi_response(response) response_result = self.process_response( - openapi_request, openapi_response) + openapi_request, openapi_response + ) if response_result.errors: return self._handle_response_errors(response_result) return response + return decorated def _get_request(self, *args, **kwargs): diff --git a/openapi_core/validation/exceptions.py b/openapi_core/validation/exceptions.py index 004068f1..dab7aa24 100644 --- a/openapi_core/validation/exceptions.py +++ b/openapi_core/validation/exceptions.py @@ -10,6 +10,5 @@ class ValidationError(OpenAPIError): @dataclass class InvalidSecurity(ValidationError): - def __str__(self): return "Security not valid for any requirement" diff --git a/openapi_core/validation/processors.py b/openapi_core/validation/processors.py index f68ed571..587ebde8 100644 --- a/openapi_core/validation/processors.py +++ b/openapi_core/validation/processors.py @@ -2,7 +2,6 @@ class OpenAPIProcessor: - def __init__(self, request_validator, response_validator): self.request_validator = request_validator self.response_validator = response_validator diff --git a/openapi_core/validation/request/datatypes.py b/openapi_core/validation/request/datatypes.py index 7c9fb4c1..a47f9f50 100644 --- a/openapi_core/validation/request/datatypes.py +++ b/openapi_core/validation/request/datatypes.py @@ -1,8 +1,11 @@ """OpenAPI core validation request datatypes module""" -from typing import Dict, Optional +from dataclasses import dataclass +from dataclasses import field +from typing import Dict +from typing import Optional -from dataclasses import dataclass, field -from werkzeug.datastructures import ImmutableMultiDict, Headers +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableMultiDict from openapi_core.validation.datatypes import BaseValidationResult @@ -21,6 +24,7 @@ class RequestParameters: path Path parameters as dict. Gets resolved against spec if empty. """ + query: ImmutableMultiDict = field(default_factory=ImmutableMultiDict) header: Headers = field(default_factory=Headers) cookie: ImmutableMultiDict = field(default_factory=ImmutableMultiDict) diff --git a/openapi_core/validation/request/shortcuts.py b/openapi_core/validation/request/shortcuts.py index 6d881abc..e7185565 100644 --- a/openapi_core/validation/request/shortcuts.py +++ b/openapi_core/validation/request/shortcuts.py @@ -1,12 +1,12 @@ """OpenAPI core validation request shortcuts module""" from functools import partial +from openapi_core.validation.request.validators import RequestBodyValidator from openapi_core.validation.request.validators import ( - RequestValidator, - RequestBodyValidator, RequestParametersValidator, - RequestSecurityValidator, ) +from openapi_core.validation.request.validators import RequestSecurityValidator +from openapi_core.validation.request.validators import RequestValidator def validate_request(validator, request): @@ -16,7 +16,10 @@ def validate_request(validator, request): def spec_validate_request( - spec, request, request_factory=None, validator_class=RequestValidator, + spec, + request, + request_factory=None, + validator_class=RequestValidator, result_attribute=None, ): if request_factory is not None: @@ -34,14 +37,20 @@ def spec_validate_request( spec_validate_parameters = partial( spec_validate_request, - validator_class=RequestParametersValidator, result_attribute='parameters') + validator_class=RequestParametersValidator, + result_attribute="parameters", +) spec_validate_body = partial( spec_validate_request, - validator_class=RequestBodyValidator, result_attribute='body') + validator_class=RequestBodyValidator, + result_attribute="body", +) spec_validate_security = partial( spec_validate_request, - validator_class=RequestSecurityValidator, result_attribute='security') + validator_class=RequestSecurityValidator, + result_attribute="security", +) diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index f5c470ea..4b44016c 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -3,38 +3,38 @@ from openapi_core.casting.schemas.exceptions import CastError from openapi_core.deserializing.exceptions import DeserializeError -from openapi_core.exceptions import ( - MissingRequiredParameter, MissingParameter, - MissingRequiredRequestBody, MissingRequestBody, -) +from openapi_core.exceptions import MissingParameter +from openapi_core.exceptions import MissingRequestBody +from openapi_core.exceptions import MissingRequiredParameter +from openapi_core.exceptions import MissingRequiredRequestBody from openapi_core.schema.parameters import iter_params from openapi_core.security.exceptions import SecurityError from openapi_core.security.factories import SecurityProviderFactory from openapi_core.templating.media_types.exceptions import MediaTypeFinderError from openapi_core.templating.paths.exceptions import PathError from openapi_core.unmarshalling.schemas.enums import UnmarshalContext -from openapi_core.unmarshalling.schemas.exceptions import ( - UnmarshalError, ValidateError, -) +from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError +from openapi_core.unmarshalling.schemas.exceptions import ValidateError from openapi_core.unmarshalling.schemas.factories import ( SchemaUnmarshallersFactory, ) from openapi_core.validation.exceptions import InvalidSecurity -from openapi_core.validation.request.datatypes import ( - Parameters, RequestValidationResult, -) +from openapi_core.validation.request.datatypes import Parameters +from openapi_core.validation.request.datatypes import RequestValidationResult from openapi_core.validation.validators import BaseValidator class BaseRequestValidator(BaseValidator): - @property def schema_unmarshallers_factory(self): - spec_resolver = self.spec.accessor.dereferencer.resolver_manager.\ - resolver + spec_resolver = ( + self.spec.accessor.dereferencer.resolver_manager.resolver + ) return SchemaUnmarshallersFactory( - spec_resolver, self.format_checker, - self.custom_formatters, context=UnmarshalContext.REQUEST, + spec_resolver, + self.format_checker, + self.custom_formatters, + context=UnmarshalContext.REQUEST, ) @property @@ -42,16 +42,16 @@ def security_provider_factory(self): return SecurityProviderFactory() def _get_parameters(self, request, path, operation): - operation_params = operation.get('parameters', []) - path_params = path.get('parameters', []) + operation_params = operation.get("parameters", []) + path_params = path.get("parameters", []) errors = [] seen = set() parameters = Parameters() params_iter = iter_params(operation_params, path_params) for param in params_iter: - param_name = param['name'] - param_location = param['in'] + param_name = param["name"] + param_location = param["in"] if (param_name, param_location) in seen: # skip parameter already seen # e.g. overriden path item paremeter on operation @@ -62,8 +62,11 @@ def _get_parameters(self, request, path, operation): except MissingParameter: continue except ( - MissingRequiredParameter, DeserializeError, - CastError, ValidateError, UnmarshalError, + MissingRequiredParameter, + DeserializeError, + CastError, + ValidateError, + UnmarshalError, ) as exc: errors.append(exc) continue @@ -74,30 +77,30 @@ def _get_parameters(self, request, path, operation): return parameters, errors def _get_parameter(self, param, request): - name = param['name'] - deprecated = param.getkey('deprecated', False) + name = param["name"] + deprecated = param.getkey("deprecated", False) if deprecated: warnings.warn( f"{name} parameter is deprecated", DeprecationWarning, ) - param_location = param['in'] + param_location = param["in"] location = request.parameters[param_location] try: return self._get_param_or_header_value(param, location) except KeyError: - required = param.getkey('required', False) + required = param.getkey("required", False) if required: raise MissingRequiredParameter(name) raise MissingParameter(name) def _get_security(self, request, operation): security = None - if 'security' in self.spec: - security = self.spec / 'security' - if 'security' in operation: - security = operation / 'security' + if "security" in self.spec: + security = self.spec / "security" + if "security" in operation: + security = operation / "security" if not security: return {} @@ -105,8 +108,7 @@ def _get_security(self, request, operation): for security_requirement in security: try: return { - scheme_name: self._get_security_value( - scheme_name, request) + scheme_name: self._get_security_value(scheme_name, request) for scheme_name in list(security_requirement.keys()) } except SecurityError: @@ -115,7 +117,7 @@ def _get_security(self, request, operation): raise InvalidSecurity() def _get_security_value(self, scheme_name, request): - security_schemes = self.spec / 'components#securitySchemes' + security_schemes = self.spec / "components#securitySchemes" if scheme_name not in security_schemes: return scheme = security_schemes[scheme_name] @@ -123,63 +125,64 @@ def _get_security_value(self, scheme_name, request): return security_provider(request) def _get_body(self, request, operation): - if 'requestBody' not in operation: + if "requestBody" not in operation: return None, [] - request_body = operation / 'requestBody' + request_body = operation / "requestBody" try: raw_body = self._get_body_value(request_body, request) except MissingRequiredRequestBody as exc: - return None, [exc, ] + return None, [exc] except MissingRequestBody: return None, [] try: media_type, mimetype = self._get_media_type( - request_body / 'content', request) + request_body / "content", request + ) except MediaTypeFinderError as exc: - return None, [exc, ] + return None, [exc] try: deserialised = self._deserialise_data(mimetype, raw_body) except DeserializeError as exc: - return None, [exc, ] + return None, [exc] try: casted = self._cast(media_type, deserialised) except CastError as exc: - return None, [exc, ] + return None, [exc] - if 'schema' not in media_type: + if "schema" not in media_type: return casted, [] - schema = media_type / 'schema' + schema = media_type / "schema" try: body = self._unmarshal(schema, casted) except (ValidateError, UnmarshalError) as exc: - return None, [exc, ] + return None, [exc] return body, [] def _get_body_value(self, request_body, request): if not request.body: - if request_body.getkey('required', False): + if request_body.getkey("required", False): raise MissingRequiredRequestBody(request) raise MissingRequestBody(request) return request.body class RequestParametersValidator(BaseRequestValidator): - def validate(self, request): try: path, operation, _, path_result, _ = self._find_path(request) except PathError as exc: - return RequestValidationResult(errors=[exc, ]) + return RequestValidationResult(errors=[exc]) - request.parameters.path = request.parameters.path or \ - path_result.variables + request.parameters.path = ( + request.parameters.path or path_result.variables + ) params, params_errors = self._get_parameters(request, path, operation) @@ -190,12 +193,11 @@ def validate(self, request): class RequestBodyValidator(BaseRequestValidator): - def validate(self, request): try: _, operation, _, _, _ = self._find_path(request) except PathError as exc: - return RequestValidationResult(errors=[exc, ]) + return RequestValidationResult(errors=[exc]) body, body_errors = self._get_body(request, operation) @@ -206,17 +208,16 @@ def validate(self, request): class RequestSecurityValidator(BaseRequestValidator): - def validate(self, request): try: _, operation, _, _, _ = self._find_path(request) except PathError as exc: - return RequestValidationResult(errors=[exc, ]) + return RequestValidationResult(errors=[exc]) try: security = self._get_security(request, operation) except InvalidSecurity as exc: - return RequestValidationResult(errors=[exc, ]) + return RequestValidationResult(errors=[exc]) return RequestValidationResult( errors=[], @@ -225,21 +226,21 @@ def validate(self, request): class RequestValidator(BaseRequestValidator): - def validate(self, request): try: path, operation, _, path_result, _ = self._find_path(request) # don't process if operation errors except PathError as exc: - return RequestValidationResult(errors=[exc, ]) + return RequestValidationResult(errors=[exc]) try: security = self._get_security(request, operation) except InvalidSecurity as exc: - return RequestValidationResult(errors=[exc, ]) + return RequestValidationResult(errors=[exc]) - request.parameters.path = request.parameters.path or \ - path_result.variables + request.parameters.path = ( + request.parameters.path or path_result.variables + ) params, params_errors = self._get_parameters(request, path, operation) diff --git a/openapi_core/validation/response/datatypes.py b/openapi_core/validation/response/datatypes.py index 3fa06fa2..aaa6ba84 100644 --- a/openapi_core/validation/response/datatypes.py +++ b/openapi_core/validation/response/datatypes.py @@ -1,6 +1,9 @@ """OpenAPI core validation response datatypes module""" -from typing import Dict, Optional -from dataclasses import dataclass, field +from dataclasses import dataclass +from dataclasses import field +from typing import Dict +from typing import Optional + from werkzeug.datastructures import Headers from openapi_core.validation.datatypes import BaseValidationResult @@ -20,6 +23,7 @@ class OpenAPIResponse: mimetype Lowercase content type without charset. """ + data: str status_code: int mimetype: str diff --git a/openapi_core/validation/response/shortcuts.py b/openapi_core/validation/response/shortcuts.py index 27880bf8..09598fd3 100644 --- a/openapi_core/validation/response/shortcuts.py +++ b/openapi_core/validation/response/shortcuts.py @@ -1,11 +1,11 @@ """OpenAPI core validation response shortcuts module""" from functools import partial +from openapi_core.validation.response.validators import ResponseDataValidator from openapi_core.validation.response.validators import ( - ResponseValidator, - ResponseDataValidator, ResponseHeadersValidator, ) +from openapi_core.validation.response.validators import ResponseValidator def validate_response(validator, request, response): @@ -15,7 +15,11 @@ def validate_response(validator, request, response): def spec_validate_response( - spec, request, response, request_factory=None, response_factory=None, + spec, + request, + response, + request_factory=None, + response_factory=None, validator_class=ResponseValidator, result_attribute=None, ): @@ -36,9 +40,13 @@ def spec_validate_response( spec_validate_data = partial( spec_validate_response, - validator_class=ResponseDataValidator, result_attribute='data') + validator_class=ResponseDataValidator, + result_attribute="data", +) spec_validate_headers = partial( spec_validate_response, - validator_class=ResponseHeadersValidator, result_attribute='headers') + validator_class=ResponseHeadersValidator, + result_attribute="headers", +) diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py index a27adea2..897ca077 100644 --- a/openapi_core/validation/response/validators.py +++ b/openapi_core/validation/response/validators.py @@ -3,16 +3,15 @@ from openapi_core.casting.schemas.exceptions import CastError from openapi_core.deserializing.exceptions import DeserializeError -from openapi_core.exceptions import ( - MissingHeader, MissingRequiredHeader, MissingResponseContent, -) +from openapi_core.exceptions import MissingHeader +from openapi_core.exceptions import MissingRequiredHeader +from openapi_core.exceptions import MissingResponseContent from openapi_core.templating.media_types.exceptions import MediaTypeFinderError from openapi_core.templating.paths.exceptions import PathError from openapi_core.templating.responses.exceptions import ResponseFinderError from openapi_core.unmarshalling.schemas.enums import UnmarshalContext -from openapi_core.unmarshalling.schemas.exceptions import ( - UnmarshalError, ValidateError, -) +from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError +from openapi_core.unmarshalling.schemas.exceptions import ValidateError from openapi_core.unmarshalling.schemas.factories import ( SchemaUnmarshallersFactory, ) @@ -21,59 +20,62 @@ class BaseResponseValidator(BaseValidator): - @property def schema_unmarshallers_factory(self): - spec_resolver = self.spec.accessor.dereferencer.resolver_manager.\ - resolver + spec_resolver = ( + self.spec.accessor.dereferencer.resolver_manager.resolver + ) return SchemaUnmarshallersFactory( - spec_resolver, self.format_checker, - self.custom_formatters, context=UnmarshalContext.RESPONSE, + spec_resolver, + self.format_checker, + self.custom_formatters, + context=UnmarshalContext.RESPONSE, ) def _find_operation_response(self, request, response): _, operation, _, _, _ = self._find_path(request) - return self._get_operation_response( - operation, response) + return self._get_operation_response(operation, response) def _get_operation_response(self, operation, response): from openapi_core.templating.responses.finders import ResponseFinder - finder = ResponseFinder(operation / 'responses') + + finder = ResponseFinder(operation / "responses") return finder.find(str(response.status_code)) def _get_data(self, response, operation_response): - if 'content' not in operation_response: + if "content" not in operation_response: return None, [] try: media_type, mimetype = self._get_media_type( - operation_response / 'content', response) + operation_response / "content", response + ) except MediaTypeFinderError as exc: - return None, [exc, ] + return None, [exc] try: raw_data = self._get_data_value(response) except MissingResponseContent as exc: - return None, [exc, ] + return None, [exc] try: deserialised = self._deserialise_data(mimetype, raw_data) except DeserializeError as exc: - return None, [exc, ] + return None, [exc] try: casted = self._cast(media_type, deserialised) except CastError as exc: - return None, [exc, ] + return None, [exc] - if 'schema' not in media_type: + if "schema" not in media_type: return casted, [] - schema = media_type / 'schema' + schema = media_type / "schema" try: data = self._unmarshal(schema, casted) except (ValidateError, UnmarshalError) as exc: - return None, [exc, ] + return None, [exc] return data, [] @@ -84,10 +86,10 @@ def _get_data_value(self, response): return response.data def _get_headers(self, response, operation_response): - if 'headers' not in operation_response: + if "headers" not in operation_response: return {}, [] - headers = operation_response / 'headers' + headers = operation_response / "headers" errors = [] validated = {} @@ -100,8 +102,11 @@ def _get_headers(self, response, operation_response): except MissingHeader: continue except ( - MissingRequiredHeader, DeserializeError, - CastError, ValidateError, UnmarshalError, + MissingRequiredHeader, + DeserializeError, + CastError, + ValidateError, + UnmarshalError, ) as exc: errors.append(exc) continue @@ -111,7 +116,7 @@ def _get_headers(self, response, operation_response): return validated, errors def _get_header(self, name, header, response): - deprecated = header.getkey('deprecated', False) + deprecated = header.getkey("deprecated", False) if deprecated: warnings.warn( f"{name} header is deprecated", @@ -120,23 +125,24 @@ def _get_header(self, name, header, response): try: return self._get_param_or_header_value( - header, response.headers, name=name) + header, response.headers, name=name + ) except KeyError: - required = header.getkey('required', False) + required = header.getkey("required", False) if required: raise MissingRequiredHeader(name) raise MissingHeader(name) class ResponseDataValidator(BaseResponseValidator): - def validate(self, request, response): try: operation_response = self._find_operation_response( - request, response) + request, response + ) # don't process if operation errors except (PathError, ResponseFinderError) as exc: - return ResponseValidationResult(errors=[exc, ]) + return ResponseValidationResult(errors=[exc]) data, data_errors = self._get_data(response, operation_response) @@ -147,17 +153,18 @@ def validate(self, request, response): class ResponseHeadersValidator(BaseResponseValidator): - def validate(self, request, response): try: operation_response = self._find_operation_response( - request, response) + request, response + ) # don't process if operation errors except (PathError, ResponseFinderError) as exc: - return ResponseValidationResult(errors=[exc, ]) + return ResponseValidationResult(errors=[exc]) headers, headers_errors = self._get_headers( - response, operation_response) + response, operation_response + ) return ResponseValidationResult( errors=headers_errors, @@ -166,19 +173,20 @@ def validate(self, request, response): class ResponseValidator(BaseResponseValidator): - def validate(self, request, response): try: operation_response = self._find_operation_response( - request, response) + request, response + ) # don't process if operation errors except (PathError, ResponseFinderError) as exc: - return ResponseValidationResult(errors=[exc, ]) + return ResponseValidationResult(errors=[exc]) data, data_errors = self._get_data(response, operation_response) headers, headers_errors = self._get_headers( - response, operation_response) + response, operation_response + ) errors = data_errors + headers_errors return ResponseValidationResult( diff --git a/openapi_core/validation/validators.py b/openapi_core/validation/validators.py index f30b56a1..280ac82e 100644 --- a/openapi_core/validation/validators.py +++ b/openapi_core/validation/validators.py @@ -12,11 +12,12 @@ class BaseValidator: - def __init__( - self, spec, - base_url=None, - custom_formatters=None, custom_media_type_deserializers=None, + self, + spec, + base_url=None, + custom_formatters=None, + custom_media_type_deserializers=None, ): self.spec = spec self.base_url = base_url @@ -36,7 +37,8 @@ def schema_casters_factory(self): @property def media_type_deserializers_factory(self): return MediaTypeDeserializersFactory( - self.custom_media_type_deserializers) + self.custom_media_type_deserializers + ) @property def parameter_deserializers_factory(self): @@ -51,6 +53,7 @@ def _find_path(self, request): def _get_media_type(self, content, request_or_response): from openapi_core.templating.media_types.finders import MediaTypeFinder + finder = MediaTypeFinder(content) return finder.find(request_or_response) @@ -74,24 +77,25 @@ def _get_param_or_header_value(self, param_or_header, location, name=None): try: raw_value = get_value(param_or_header, location, name=name) except KeyError: - if 'schema' not in param_or_header: + if "schema" not in param_or_header: raise - schema = param_or_header / 'schema' - if 'default' not in schema: + schema = param_or_header / "schema" + if "default" not in schema: raise - casted = schema['default'] + casted = schema["default"] else: # Simple scenario - if 'content' not in param_or_header: + if "content" not in param_or_header: deserialised = self._deserialise_parameter( - param_or_header, raw_value) - schema = param_or_header / 'schema' + param_or_header, raw_value + ) + schema = param_or_header / "schema" # Complex scenario else: - content = param_or_header / 'content' + content = param_or_header / "content" mimetype, media_type = next(content.items()) deserialised = self._deserialise_data(mimetype, raw_value) - schema = media_type / 'schema' + schema = media_type / "schema" casted = self._cast(schema, deserialised) unmarshalled = self._unmarshal(schema, casted) return unmarshalled diff --git a/poetry.lock b/poetry.lock index 9adc2f08..b9f28052 100644 --- a/poetry.lock +++ b/poetry.lock @@ -61,6 +61,31 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pytz = ">=2015.7" +[[package]] +name = "black" +version = "21.6b0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +appdirs = "*" +click = ">=7.1.2" +dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} +mypy-extensions = ">=0.4.3" +pathspec = ">=0.8.1,<1" +regex = ">=2020.1.8" +toml = ">=0.10.1" +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "certifi" version = "2021.5.30" @@ -299,6 +324,20 @@ python-versions = "*" [package.dependencies] six = "*" +[[package]] +name = "isort" +version = "5.9.1" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6.1,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] + [[package]] name = "itsdangerous" version = "2.0.1" @@ -363,6 +402,14 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "nodeenv" version = "1.6.0" @@ -426,6 +473,14 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "pluggy" version = "0.13.1" @@ -571,6 +626,14 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +[[package]] +name = "regex" +version = "2021.7.1" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "requests" version = "2.25.1" @@ -761,6 +824,14 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "typed-ast" +version = "1.4.3" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "typing-extensions" version = "3.10.0.0" @@ -848,8 +919,8 @@ requests = ["requests"] [metadata] lock-version = "1.1" -python-versions = "^3.6" -content-hash = "2f8d8a5f472acbbd5cc53ad10f8a25f9e84480ff2e09c1e0a38e2c7bdf6ab47e" +python-versions = "^3.6.2" +content-hash = "68246028a2e99686d7115e542de8029213581626ac2e71b7d719eaafe293dd57" [metadata.files] alabaster = [ @@ -876,6 +947,10 @@ babel = [ {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] +black = [ + {file = "black-21.6b0-py3-none-any.whl", hash = "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7"}, + {file = "black-21.6b0.tar.gz", hash = "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04"}, +] certifi = [ {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, @@ -1032,6 +1107,10 @@ isodate = [ {file = "isodate-0.6.0-py2.py3-none-any.whl", hash = "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81"}, {file = "isodate-0.6.0.tar.gz", hash = "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8"}, ] +isort = [ + {file = "isort-5.9.1-py3-none-any.whl", hash = "sha256:8e2c107091cfec7286bc0f68a547d0ba4c094d460b732075b6fba674f1035c0c"}, + {file = "isort-5.9.1.tar.gz", hash = "sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56"}, +] itsdangerous = [ {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, @@ -1088,6 +1167,10 @@ more-itertools = [ {file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"}, {file = "more_itertools-8.8.0-py3-none-any.whl", hash = "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d"}, ] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] nodeenv = [ {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, @@ -1109,6 +1192,10 @@ packaging = [ parse = [ {file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"}, ] +pathspec = [ + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, @@ -1207,6 +1294,45 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] +regex = [ + {file = "regex-2021.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:494d0172774dc0beeea984b94c95389143db029575f7ca908edd74469321ea99"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8cf6728f89b071bd3ab37cb8a0e306f4de897553a0ed07442015ee65fbf53d62"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1806370b2bef4d4193eebe8ee59a9fd7547836a34917b7badbe6561a8594d9cb"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d0cf2651a8804f6325747c7e55e3be0f90ee2848e25d6b817aa2728d263f9abb"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:268fe9dd1deb4a30c8593cabd63f7a241dfdc5bd9dd0233906c718db22cdd49a"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:7743798dfb573d006f1143d745bf17efad39775a5190b347da5d83079646be56"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0e46c1191b2eb293a6912269ed08b4512e7e241bbf591f97e527492e04c77e93"}, + {file = "regex-2021.7.1-cp36-cp36m-win32.whl", hash = "sha256:b1dbeef938281f240347d50f28ae53c4b046a23389cd1fc4acec5ea0eae646a1"}, + {file = "regex-2021.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6c72ebb72e64e9bd195cb35a9b9bbfb955fd953b295255b8ae3e4ad4a146b615"}, + {file = "regex-2021.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf819c5b77ff44accc9a24e31f1f7ceaaf6c960816913ed3ef8443b9d20d81b6"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e80d2851109e56420b71f9702ad1646e2f0364528adbf6af85527bc61e49f394"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1b6a3f600d6aff97e3f28c34192c9ed93fee293bd96ef327b64adb51a74b2f6"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ed77b97896312bc2deafe137ca2626e8b63808f5bedb944f73665c68093688a7"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a548bb51c4476332ce4139df8e637386730f79a92652a907d12c696b6252b64d"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:210c359e6ee5b83f7d8c529ba3c75ba405481d50f35a420609b0db827e2e3bb5"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:1d386402ae7f3c9b107ae5863f7ecccb0167762c82a687ae6526b040feaa5ac6"}, + {file = "regex-2021.7.1-cp37-cp37m-win32.whl", hash = "sha256:5049d00dbb78f9d166d1c704e93934d42cce0570842bb1a61695123d6b01de09"}, + {file = "regex-2021.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:361be4d311ac995a8c7ad577025a3ae3a538531b1f2cf32efd8b7e5d33a13e5a"}, + {file = "regex-2021.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f32f47fb22c988c0b35756024b61d156e5c4011cb8004aa53d93b03323c45657"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b024ee43ee6b310fad5acaee23e6485b21468718cb792a9d1693eecacc3f0b7e"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b092754c06852e8a8b022004aff56c24b06310189186805800d09313c37ce1f8"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a8a5826d8a1b64e2ff9af488cc179e1a4d0f144d11ce486a9f34ea38ccedf4ef"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:444723ebaeb7fa8125f29c01a31101a3854ac3de293e317944022ae5effa53a4"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:fdad3122b69cdabdb3da4c2a4107875913ac78dab0117fc73f988ad589c66b66"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4b1999ef60c45357598935c12508abf56edbbb9c380df6f336de38a6c3a294ae"}, + {file = "regex-2021.7.1-cp38-cp38-win32.whl", hash = "sha256:e07e92935040c67f49571779d115ecb3e727016d42fb36ee0d8757db4ca12ee0"}, + {file = "regex-2021.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:6b8b629f93246e507287ee07e26744beaffb4c56ed520576deac8b615bd76012"}, + {file = "regex-2021.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56bef6b414949e2c9acf96cb5d78de8b529c7b99752619494e78dc76f99fd005"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:78a2a885345a2d60b5e68099e877757d5ed12e46ba1e87507175f14f80892af3"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3f7a92e60930f8fca2623d9e326c173b7cf2c8b7e4fdcf984b75a1d2fb08114d"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4fc86b729ab88fe8ac3ec92287df253c64aa71560d76da5acd8a2e245839c629"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:59845101de68fd5d3a1145df9ea022e85ecd1b49300ea68307ad4302320f6f61"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ce269e903b00d1ab4746793e9c50a57eec5d5388681abef074d7b9a65748fca5"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c11f2fca544b5e30a0e813023196a63b1cb9869106ef9a26e9dae28bce3e4e26"}, + {file = "regex-2021.7.1-cp39-cp39-win32.whl", hash = "sha256:1ccbd41dbee3a31e18938096510b7d4ee53aa9fce2ee3dcc8ec82ae264f6acfd"}, + {file = "regex-2021.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:18040755606b0c21281493ec309214bd61e41a170509e5014f41d6a5a586e161"}, + {file = "regex-2021.7.1.tar.gz", hash = "sha256:849802379a660206277675aa5a5c327f5c910c690649535863ddf329b0ba8c87"}, +] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, @@ -1266,6 +1392,38 @@ toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +typed-ast = [ + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, +] typing-extensions = [ {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, diff --git a/pyproject.toml b/pyproject.toml index adc17f71..da203e1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "^3.6" +python = "^3.6.2" dataclasses = {version = "*", python = "~3.6"} dictpath = "*" django = {version = ">=3.0", optional = true} @@ -54,10 +54,12 @@ flask = ["flask"] requests = ["requests"] [tool.poetry.dev-dependencies] +black = {version = "^21.6b0", allow-prereleases = true} django = ">=3.0" djangorestframework = "^3.11.2" falcon = ">=3.0" flask = "*" +isort = "^5.9.1" pre-commit = "*" pytest = "^6" pytest-flake8 = "*" @@ -79,3 +81,11 @@ addopts = """ --cov-report=term-missing --cov-report=xml """ + +[tool.black] +line-length = 79 + +[tool.isort] +profile = "black" +line_length = 79 +force_single_line = true diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index dfd769d3..64ec4b5a 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,8 +1,8 @@ from os import path from urllib import request -from openapi_spec_validator.schemas import read_yaml_file import pytest +from openapi_spec_validator.schemas import read_yaml_file from yaml import safe_load @@ -22,7 +22,7 @@ class Factory(dict): __setattr__ = dict.__setitem__ -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def factory(): return Factory( spec_from_file=spec_from_file, diff --git a/tests/integration/contrib/django/data/v3.0/djangoproject/auth.py b/tests/integration/contrib/django/data/v3.0/djangoproject/auth.py index b8dd0b0c..9359e7d1 100644 --- a/tests/integration/contrib/django/data/v3.0/djangoproject/auth.py +++ b/tests/integration/contrib/django/data/v3.0/djangoproject/auth.py @@ -5,13 +5,13 @@ class SimpleAuthentication(authentication.BaseAuthentication): def authenticate(self, request): - username = request.META.get('X_USERNAME') + username = request.META.get("X_USERNAME") if not username: return None try: user = User.objects.get(username=username) except User.DoesNotExist: - raise exceptions.AuthenticationFailed('No such user') + raise exceptions.AuthenticationFailed("No such user") return (user, None) diff --git a/tests/integration/contrib/django/data/v3.0/djangoproject/pets/views.py b/tests/integration/contrib/django/data/v3.0/djangoproject/pets/views.py index de62b00c..f46cb2eb 100644 --- a/tests/integration/contrib/django/data/v3.0/djangoproject/pets/views.py +++ b/tests/integration/contrib/django/data/v3.0/djangoproject/pets/views.py @@ -1,23 +1,23 @@ -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse +from django.http import JsonResponse from rest_framework.views import APIView class PetListView(APIView): - def get(self, request): assert request.openapi assert not request.openapi.errors assert request.openapi.parameters.query == { - 'page': 1, - 'limit': 12, - 'search': '', + "page": 1, + "limit": 12, + "search": "", } data = [ { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, }, ] @@ -25,7 +25,7 @@ def get(self, request): "data": data, } django_response = JsonResponse(response_dict) - django_response['X-Rate-Limit'] = '12' + django_response["X-Rate-Limit"] = "12" return django_response @@ -33,18 +33,18 @@ def post(self, request): assert request.openapi assert not request.openapi.errors assert request.openapi.parameters.cookie == { - 'user': 1, + "user": 1, } assert request.openapi.parameters.header == { - 'api-key': '12345', + "api-key": "12345", } - assert request.openapi.body.__class__.__name__ == 'PetCreate' - assert request.openapi.body.name == 'Cat' - assert request.openapi.body.ears.__class__.__name__ == 'Ears' + assert request.openapi.body.__class__.__name__ == "PetCreate" + assert request.openapi.body.name == "Cat" + assert request.openapi.body.ears.__class__.__name__ == "Ears" assert request.openapi.body.ears.healthy is True django_response = HttpResponse(status=201) - django_response['X-Rate-Limit'] = '12' + django_response["X-Rate-Limit"] = "12" return django_response @@ -54,25 +54,24 @@ def get_extra_actions(): class PetDetailView(APIView): - def get(self, request, petId): assert request.openapi assert not request.openapi.errors assert request.openapi.parameters.path == { - 'petId': 12, + "petId": 12, } data = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } response_dict = { "data": data, } django_response = JsonResponse(response_dict) - django_response['X-Rate-Limit'] = '12' + django_response["X-Rate-Limit"] = "12" return django_response diff --git a/tests/integration/contrib/django/data/v3.0/djangoproject/settings.py b/tests/integration/contrib/django/data/v3.0/djangoproject/settings.py index 1b231f58..e02e990b 100644 --- a/tests/integration/contrib/django/data/v3.0/djangoproject/settings.py +++ b/tests/integration/contrib/django/data/v3.0/djangoproject/settings.py @@ -10,8 +10,9 @@ https://docs.djangoproject.com/en/2.2/ref/settings/ """ -from pathlib import Path import os +from pathlib import Path + import yaml from openapi_core import create_spec @@ -24,65 +25,65 @@ # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '9=z^yj5yo%g_dyvgdzbceyph^nae)91lq(7^!qqmr1t9wi8b^=' +SECRET_KEY = "9=z^yj5yo%g_dyvgdzbceyph^nae)91lq(7^!qqmr1t9wi8b^=" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = ['petstore.swagger.io', 'staging.gigantic-server.com'] +ALLOWED_HOSTS = ["petstore.swagger.io", "staging.gigantic-server.com"] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "rest_framework", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'openapi_core.contrib.django.middlewares.DjangoOpenAPIMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "openapi_core.contrib.django.middlewares.DjangoOpenAPIMiddleware", ] -ROOT_URLCONF = 'djangoproject.urls' +ROOT_URLCONF = "djangoproject.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'djangoproject.wsgi.application' +WSGI_APPLICATION = "djangoproject.wsgi.application" # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3"), } } @@ -96,9 +97,9 @@ # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -110,11 +111,11 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'djangoproject.auth.SimpleAuthentication', + "DEFAULT_AUTHENTICATION_CLASSES": [ + "djangoproject.auth.SimpleAuthentication", ] } diff --git a/tests/integration/contrib/django/data/v3.0/djangoproject/urls.py b/tests/integration/contrib/django/data/v3.0/djangoproject/urls.py index 0661f5af..9a91da5c 100644 --- a/tests/integration/contrib/django/data/v3.0/djangoproject/urls.py +++ b/tests/integration/contrib/django/data/v3.0/djangoproject/urls.py @@ -14,23 +14,24 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import include, path +from django.urls import include +from django.urls import path from djangoproject.pets import views urlpatterns = [ - path('admin/', admin.site.urls), + path("admin/", admin.site.urls), path( - 'api-auth/', - include('rest_framework.urls', namespace='rest_framework'), + "api-auth/", + include("rest_framework.urls", namespace="rest_framework"), ), path( - 'v1/pets', + "v1/pets", views.PetListView.as_view(), - name='pet_list_view', + name="pet_list_view", ), path( - 'v1/pets/', + "v1/pets/", views.PetDetailView.as_view(), - name='pet_detail_view', + name="pet_detail_view", ), ] diff --git a/tests/integration/contrib/django/test_django_project.py b/tests/integration/contrib/django/test_django_project.py index 89f1b4a2..1c1de12c 100644 --- a/tests/integration/contrib/django/test_django_project.py +++ b/tests/integration/contrib/django/test_django_project.py @@ -1,7 +1,7 @@ -from base64 import b64encode -from json import dumps import os import sys +from base64 import b64encode +from json import dumps from unittest import mock import pytest @@ -9,26 +9,27 @@ class BaseTestDjangoProject: - api_key = '12345' + api_key = "12345" @property def api_key_encoded(self): - api_key_bytes = self.api_key.encode('utf8') + api_key_bytes = self.api_key.encode("utf8") api_key_bytes_enc = b64encode(api_key_bytes) - return str(api_key_bytes_enc, 'utf8') + return str(api_key_bytes_enc, "utf8") - @pytest.fixture(autouse=True, scope='module') + @pytest.fixture(autouse=True, scope="module") def django_setup(self): directory = os.path.abspath(os.path.dirname(__file__)) - django_project_dir = os.path.join(directory, 'data/v3.0') + django_project_dir = os.path.join(directory, "data/v3.0") sys.path.insert(0, django_project_dir) with mock.patch.dict( os.environ, { - 'DJANGO_SETTINGS_MODULE': 'djangoproject.settings', - } + "DJANGO_SETTINGS_MODULE": "djangoproject.settings", + }, ): import django + django.setup() yield sys.path.remove(django_project_dir) @@ -36,29 +37,29 @@ def django_setup(self): @pytest.fixture def client(self): from django.test import Client + return Client() class TestPetListView(BaseTestDjangoProject): - def test_get_no_required_param(self, client): headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'petstore.swagger.io', + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "petstore.swagger.io", } with pytest.warns(DeprecationWarning): - response = client.get('/v1/pets', **headers) + response = client.get("/v1/pets", **headers) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': 'Missing required parameter: limit', + "status": 400, + "title": "Missing required parameter: limit", } ] } @@ -67,23 +68,23 @@ def test_get_no_required_param(self, client): def test_get_valid(self, client): data_json = { - 'limit': 12, + "limit": 12, } headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'petstore.swagger.io', + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "petstore.swagger.io", } with pytest.warns(DeprecationWarning): - response = client.get('/v1/pets', data_json, **headers) + response = client.get("/v1/pets", data_json, **headers) expected_data = { - 'data': [ + "data": [ { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, }, ], @@ -93,21 +94,21 @@ def test_get_valid(self, client): def test_post_server_invalid(self, client): headers = { - 'HTTP_HOST': 'petstore.swagger.io', + "HTTP_HOST": "petstore.swagger.io", } - response = client.post('/v1/pets', **headers) + response = client.post("/v1/pets", **headers) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( - 'Server not found for ' - 'http://petstore.swagger.io/v1/pets' + "status": 400, + "title": ( + "Server not found for " + "http://petstore.swagger.io/v1/pets" ), } ] @@ -116,42 +117,43 @@ def test_post_server_invalid(self, client): assert response.json() == expected_data def test_post_required_header_param_missing(self, client): - client.cookies.load({'user': 1}) - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + client.cookies.load({"user": 1}) + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" pet_healthy = False data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "healthy": pet_healthy, + "wings": { + "healthy": pet_healthy, }, - 'healthy': pet_healthy, - 'wings': { - 'healthy': pet_healthy, - } } - content_type = 'application/json' + content_type = "application/json" headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'staging.gigantic-server.com', + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "staging.gigantic-server.com", } response = client.post( - '/v1/pets', data_json, content_type, secure=True, **headers) + "/v1/pets", data_json, content_type, secure=True, **headers + ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': 'Missing required parameter: api-key', + "status": 400, + "title": "Missing required parameter: api-key", } ] } @@ -159,26 +161,27 @@ def test_post_required_header_param_missing(self, client): assert response.json() == expected_data def test_post_media_type_invalid(self, client): - client.cookies.load({'user': 1}) - data = 'data' - content_type = 'text/html' + client.cookies.load({"user": 1}) + data = "data" + content_type = "text/html" headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'staging.gigantic-server.com', - 'HTTP_API_KEY': self.api_key_encoded, + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "staging.gigantic-server.com", + "HTTP_API_KEY": self.api_key_encoded, } response = client.post( - '/v1/pets', data, content_type, secure=True, **headers) + "/v1/pets", data, content_type, secure=True, **headers + ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 415, - 'title': ( + "status": 415, + "title": ( "Content for the following mimetype not found: " "text/html. " "Valid mimetypes: ['application/json', 'text/plain']" @@ -191,30 +194,31 @@ def test_post_media_type_invalid(self, client): def test_post_required_cookie_param_missing(self, client): data_json = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } - content_type = 'application/json' + content_type = "application/json" headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'staging.gigantic-server.com', - 'HTTP_API_KEY': self.api_key_encoded, + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "staging.gigantic-server.com", + "HTTP_API_KEY": self.api_key_encoded, } response = client.post( - '/v1/pets', data_json, content_type, secure=True, **headers) + "/v1/pets", data_json, content_type, secure=True, **headers + ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': "Missing required parameter: user", + "status": 400, + "title": "Missing required parameter: user", } ] } @@ -222,31 +226,31 @@ def test_post_required_cookie_param_missing(self, client): assert response.json() == expected_data def test_post_valid(self, client): - client.cookies.load({'user': 1}) - content_type = 'application/json' + client.cookies.load({"user": 1}) + content_type = "application/json" data_json = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'staging.gigantic-server.com', - 'HTTP_API_KEY': self.api_key_encoded, + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "staging.gigantic-server.com", + "HTTP_API_KEY": self.api_key_encoded, } response = client.post( - '/v1/pets', data_json, content_type, secure=True, **headers) + "/v1/pets", data_json, content_type, secure=True, **headers + ) assert response.status_code == 201 assert not response.content class TestPetDetailView(BaseTestDjangoProject): - def test_get_server_invalid(self, client): - response = client.get('/v1/pets/12') + response = client.get("/v1/pets/12") expected_data = ( b"You may need to add 'testserver' to ALLOWED_HOSTS." @@ -256,19 +260,19 @@ def test_get_server_invalid(self, client): def test_get_unauthorized(self, client): headers = { - 'HTTP_HOST': 'petstore.swagger.io', + "HTTP_HOST": "petstore.swagger.io", } - response = client.get('/v1/pets/12', **headers) + response = client.get("/v1/pets/12", **headers) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 403, - 'title': 'Security not valid for any requirement', + "status": 403, + "title": "Security not valid for any requirement", } ] } @@ -277,22 +281,22 @@ def test_get_unauthorized(self, client): def test_delete_method_invalid(self, client): headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'petstore.swagger.io', + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "petstore.swagger.io", } - response = client.delete('/v1/pets/12', **headers) + response = client.delete("/v1/pets/12", **headers) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 405, - 'title': ( - 'Operation delete not found for ' - 'http://petstore.swagger.io/v1/pets/12' + "status": 405, + "title": ( + "Operation delete not found for " + "http://petstore.swagger.io/v1/pets/12" ), } ] @@ -302,17 +306,17 @@ def test_delete_method_invalid(self, client): def test_get_valid(self, client): headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'petstore.swagger.io', + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "petstore.swagger.io", } - response = client.get('/v1/pets/12', **headers) + response = client.get("/v1/pets/12", **headers) expected_data = { - 'data': { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "data": { + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, }, } @@ -321,33 +325,35 @@ def test_get_valid(self, client): class BaseTestDRF(BaseTestDjangoProject): - @pytest.fixture def api_client(self): from rest_framework.test import APIClient + return APIClient() class TestDRFPetListView(BaseTestDRF): - def test_post_valid(self, api_client): - api_client.cookies.load({'user': 1}) - content_type = 'application/json' + api_client.cookies.load({"user": 1}) + content_type = "application/json" data_json = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } headers = { - 'HTTP_AUTHORIZATION': 'Basic testuser', - 'HTTP_HOST': 'staging.gigantic-server.com', - 'HTTP_API_KEY': self.api_key_encoded, + "HTTP_AUTHORIZATION": "Basic testuser", + "HTTP_HOST": "staging.gigantic-server.com", + "HTTP_API_KEY": self.api_key_encoded, } response = api_client.post( - '/v1/pets', dumps(data_json), content_type=content_type, - secure=True, **headers, + "/v1/pets", + dumps(data_json), + content_type=content_type, + secure=True, + **headers, ) assert response.status_code == 201 diff --git a/tests/integration/contrib/falcon/conftest.py b/tests/integration/contrib/falcon/conftest.py index 2d8c255c..93a0f7f2 100644 --- a/tests/integration/contrib/falcon/conftest.py +++ b/tests/integration/contrib/falcon/conftest.py @@ -1,11 +1,15 @@ import os import sys -from falcon import Request, Response, RequestOptions, ResponseOptions +import pytest +from falcon import Request +from falcon import RequestOptions +from falcon import Response +from falcon import ResponseOptions from falcon.routing import DefaultRouter from falcon.status_codes import HTTP_200 -from falcon.testing import create_environ, TestClient -import pytest +from falcon.testing import TestClient +from falcon.testing import create_environ @pytest.fixture @@ -15,6 +19,7 @@ def create_env(method, path, server_name): host=server_name, path=path, ) + return create_env @@ -27,24 +32,29 @@ def router(): @pytest.fixture def request_factory(environ_factory, router): - server_name = 'localhost' + server_name = "localhost" def create_request( - method, path, subdomain=None, query_string=None, - content_type='application/json'): + method, + path, + subdomain=None, + query_string=None, + content_type="application/json", + ): environ = environ_factory(method, path, server_name) options = RequestOptions() # return create_req(options=options, **environ) req = Request(environ, options) return req + return create_request @pytest.fixture def response_factory(environ_factory): def create_response( - data, status_code=200, headers=None, - content_type='application/json'): + data, status_code=200, headers=None, content_type="application/json" + ): options = ResponseOptions() resp = Response(options) resp.body = data @@ -52,13 +62,14 @@ def create_response( resp.status = HTTP_200 resp.set_headers(headers or {}) return resp + return create_response -@pytest.fixture(autouse=True, scope='module') +@pytest.fixture(autouse=True, scope="module") def falcon_setup(): directory = os.path.abspath(os.path.dirname(__file__)) - falcon_project_dir = os.path.join(directory, 'data/v3.0') + falcon_project_dir = os.path.join(directory, "data/v3.0") sys.path.insert(0, falcon_project_dir) yield sys.path.remove(falcon_project_dir) @@ -67,6 +78,7 @@ def falcon_setup(): @pytest.fixture def app(): from falconproject.__main__ import app + return app diff --git a/tests/integration/contrib/falcon/data/v3.0/falconproject/__main__.py b/tests/integration/contrib/falcon/data/v3.0/falconproject/__main__.py index c44eea23..6fb9d901 100644 --- a/tests/integration/contrib/falcon/data/v3.0/falconproject/__main__.py +++ b/tests/integration/contrib/falcon/data/v3.0/falconproject/__main__.py @@ -1,7 +1,7 @@ from falcon import App - from falconproject.openapi import openapi_middleware -from falconproject.pets.resources import PetListResource, PetDetailResource +from falconproject.pets.resources import PetDetailResource +from falconproject.pets.resources import PetListResource app = App(middleware=[openapi_middleware]) diff --git a/tests/integration/contrib/falcon/data/v3.0/falconproject/openapi.py b/tests/integration/contrib/falcon/data/v3.0/falconproject/openapi.py index 0a0691f3..b199ece4 100644 --- a/tests/integration/contrib/falcon/data/v3.0/falconproject/openapi.py +++ b/tests/integration/contrib/falcon/data/v3.0/falconproject/openapi.py @@ -1,8 +1,9 @@ from pathlib import Path +import yaml + from openapi_core import create_spec from openapi_core.contrib.falcon.middlewares import FalconOpenAPIMiddleware -import yaml openapi_spec_path = Path("tests/integration/data/v3.0/petstore.yaml") spec_dict = yaml.load(openapi_spec_path.read_text(), yaml.Loader) diff --git a/tests/integration/contrib/falcon/data/v3.0/falconproject/pets/resources.py b/tests/integration/contrib/falcon/data/v3.0/falconproject/pets/resources.py index c4ccc64a..154d50ff 100644 --- a/tests/integration/contrib/falcon/data/v3.0/falconproject/pets/resources.py +++ b/tests/integration/contrib/falcon/data/v3.0/falconproject/pets/resources.py @@ -1,7 +1,8 @@ from json import dumps from falcon.constants import MEDIA_JSON -from falcon.status_codes import HTTP_200, HTTP_201 +from falcon.status_codes import HTTP_200 +from falcon.status_codes import HTTP_201 class PetListResource: @@ -9,58 +10,58 @@ def on_get(self, request, response): assert request.context.openapi assert not request.context.openapi.errors assert request.context.openapi.parameters.query == { - 'page': 1, - 'limit': 12, - 'search': '', + "page": 1, + "limit": 12, + "search": "", } data = [ { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, }, ] response.status = HTTP_200 response.content_type = MEDIA_JSON response.text = dumps({"data": data}) - response.set_header('X-Rate-Limit', '12') + response.set_header("X-Rate-Limit", "12") def on_post(self, request, response): assert request.context.openapi assert not request.context.openapi.errors assert request.context.openapi.parameters.cookie == { - 'user': 1, + "user": 1, } assert request.context.openapi.parameters.header == { - 'api-key': '12345', + "api-key": "12345", } - assert request.context.openapi.body.__class__.__name__ == 'PetCreate' - assert request.context.openapi.body.name == 'Cat' - assert request.context.openapi.body.ears.__class__.__name__ == 'Ears' + assert request.context.openapi.body.__class__.__name__ == "PetCreate" + assert request.context.openapi.body.name == "Cat" + assert request.context.openapi.body.ears.__class__.__name__ == "Ears" assert request.context.openapi.body.ears.healthy is True response.status = HTTP_201 - response.set_header('X-Rate-Limit', '12') + response.set_header("X-Rate-Limit", "12") class PetDetailResource: def on_get(self, request, response, petId=None): - assert petId == '12' + assert petId == "12" assert request.context.openapi assert not request.context.openapi.errors assert request.context.openapi.parameters.path == { - 'petId': 12, + "petId": 12, } data = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } response.status = HTTP_200 response.content_type = MEDIA_JSON response.text = dumps({"data": data}) - response.set_header('X-Rate-Limit', '12') + response.set_header("X-Rate-Limit", "12") diff --git a/tests/integration/contrib/falcon/test_falcon_project.py b/tests/integration/contrib/falcon/test_falcon_project.py index 14fbc229..c67b5b7b 100644 --- a/tests/integration/contrib/falcon/test_falcon_project.py +++ b/tests/integration/contrib/falcon/test_falcon_project.py @@ -1,55 +1,56 @@ from base64 import b64encode from json import dumps -from falcon.constants import MEDIA_URLENCODED import pytest +from falcon.constants import MEDIA_URLENCODED class BaseTestFalconProject: - api_key = '12345' + api_key = "12345" @property def api_key_encoded(self): - api_key_bytes = self.api_key.encode('utf8') + api_key_bytes = self.api_key.encode("utf8") api_key_bytes_enc = b64encode(api_key_bytes) - return str(api_key_bytes_enc, 'utf8') + return str(api_key_bytes_enc, "utf8") class TestPetListResource(BaseTestFalconProject): - def test_get_no_required_param(self, client): headers = { - 'Content-Type': 'application/json', + "Content-Type": "application/json", } with pytest.warns(DeprecationWarning): response = client.simulate_get( - '/v1/pets', host='petstore.swagger.io', headers=headers) + "/v1/pets", host="petstore.swagger.io", headers=headers + ) assert response.status_code == 400 def test_get_valid(self, client): headers = { - 'Content-Type': 'application/json', + "Content-Type": "application/json", } query_string = "limit=12" with pytest.warns(DeprecationWarning): response = client.simulate_get( - '/v1/pets', - host='petstore.swagger.io', headers=headers, + "/v1/pets", + host="petstore.swagger.io", + headers=headers, query_string=query_string, ) assert response.status_code == 200 assert response.json == { - 'data': [ + "data": [ { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, }, ], @@ -57,21 +58,21 @@ def test_get_valid(self, client): def test_post_server_invalid(self, client): response = client.simulate_post( - '/v1/pets', - host='petstore.swagger.io', + "/v1/pets", + host="petstore.swagger.io", ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( - 'Server not found for ' - 'http://petstore.swagger.io/v1/pets' + "status": 400, + "title": ( + "Server not found for " + "http://petstore.swagger.io/v1/pets" ), } ] @@ -80,47 +81,50 @@ def test_post_server_invalid(self, client): assert response.json == expected_data def test_post_required_header_param_missing(self, client): - cookies = {'user': 1} - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + cookies = {"user": 1} + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" pet_healthy = False data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "healthy": pet_healthy, + "wings": { + "healthy": pet_healthy, }, - 'healthy': pet_healthy, - 'wings': { - 'healthy': pet_healthy, - } } - content_type = 'application/json' + content_type = "application/json" headers = { - 'Authorization': 'Basic testuser', - 'Content-Type': content_type, + "Authorization": "Basic testuser", + "Content-Type": content_type, } body = dumps(data_json) response = client.simulate_post( - '/v1/pets', - host='staging.gigantic-server.com', headers=headers, - body=body, cookies=cookies, protocol='https', + "/v1/pets", + host="staging.gigantic-server.com", + headers=headers, + body=body, + cookies=cookies, + protocol="https", ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': 'Missing required parameter: api-key', + "status": 400, + "title": "Missing required parameter: api-key", } ] } @@ -128,32 +132,35 @@ def test_post_required_header_param_missing(self, client): assert response.json == expected_data def test_post_media_type_invalid(self, client): - cookies = {'user': 1} - data = 'data' + cookies = {"user": 1} + data = "data" # noly 3 media types are supported by falcon by default: # json, multipart and urlencoded content_type = MEDIA_URLENCODED headers = { - 'Authorization': 'Basic testuser', - 'Api-Key': self.api_key_encoded, - 'Content-Type': content_type, + "Authorization": "Basic testuser", + "Api-Key": self.api_key_encoded, + "Content-Type": content_type, } response = client.simulate_post( - '/v1/pets', - host='staging.gigantic-server.com', headers=headers, - body=data, cookies=cookies, protocol='https', + "/v1/pets", + host="staging.gigantic-server.com", + headers=headers, + body=data, + cookies=cookies, + protocol="https", ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 415, - 'title': ( + "status": 415, + "title": ( "Content for the following mimetype not found: " f"{content_type}. " "Valid mimetypes: ['application/json', 'text/plain']" @@ -165,36 +172,38 @@ def test_post_media_type_invalid(self, client): assert response.json == expected_data def test_post_required_cookie_param_missing(self, client): - content_type = 'application/json' + content_type = "application/json" data_json = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } headers = { - 'Authorization': 'Basic testuser', - 'Api-Key': self.api_key_encoded, - 'Content-Type': content_type, + "Authorization": "Basic testuser", + "Api-Key": self.api_key_encoded, + "Content-Type": content_type, } body = dumps(data_json) response = client.simulate_post( - '/v1/pets', - host='staging.gigantic-server.com', headers=headers, - body=body, protocol='https', + "/v1/pets", + host="staging.gigantic-server.com", + headers=headers, + body=body, + protocol="https", ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': "Missing required parameter: user", + "status": 400, + "title": "Missing required parameter: user", } ] } @@ -202,26 +211,29 @@ def test_post_required_cookie_param_missing(self, client): assert response.json == expected_data def test_post_valid(self, client): - cookies = {'user': 1} - content_type = 'application/json' + cookies = {"user": 1} + content_type = "application/json" data_json = { - 'id': 12, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 12, + "name": "Cat", + "ears": { + "healthy": True, }, } headers = { - 'Authorization': 'Basic testuser', - 'Api-Key': self.api_key_encoded, - 'Content-Type': content_type, + "Authorization": "Basic testuser", + "Api-Key": self.api_key_encoded, + "Content-Type": content_type, } body = dumps(data_json) response = client.simulate_post( - '/v1/pets', - host='staging.gigantic-server.com', headers=headers, - body=body, cookies=cookies, protocol='https', + "/v1/pets", + host="staging.gigantic-server.com", + headers=headers, + body=body, + cookies=cookies, + protocol="https", ) assert response.status_code == 201 @@ -229,23 +241,22 @@ def test_post_valid(self, client): class TestPetDetailResource: - def test_get_server_invalid(self, client): - headers = {'Content-Type': 'application/json'} + headers = {"Content-Type": "application/json"} - response = client.simulate_get('/v1/pets/12', headers=headers) + response = client.simulate_get("/v1/pets/12", headers=headers) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( - 'Server not found for ' - 'http://falconframework.org/v1/pets/12' + "status": 400, + "title": ( + "Server not found for " + "http://falconframework.org/v1/pets/12" ), } ] @@ -254,28 +265,30 @@ def test_get_server_invalid(self, client): assert response.json == expected_data def test_get_path_invalid(self, client): - headers = {'Content-Type': 'application/json'} + headers = {"Content-Type": "application/json"} response = client.simulate_get( - '/v1/pet/invalid', host='petstore.swagger.io', headers=headers) + "/v1/pet/invalid", host="petstore.swagger.io", headers=headers + ) assert response.status_code == 404 def test_get_unauthorized(self, client): - headers = {'Content-Type': 'application/json'} + headers = {"Content-Type": "application/json"} response = client.simulate_get( - '/v1/pets/12', host='petstore.swagger.io', headers=headers) + "/v1/pets/12", host="petstore.swagger.io", headers=headers + ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 403, - 'title': 'Security not valid for any requirement', + "status": 403, + "title": "Security not valid for any requirement", } ] } @@ -283,40 +296,42 @@ def test_get_unauthorized(self, client): assert response.json == expected_data def test_get_valid(self, client): - auth = 'authuser' - content_type = 'application/json' + auth = "authuser" + content_type = "application/json" headers = { - 'Authorization': f'Basic {auth}', - 'Content-Type': content_type, + "Authorization": f"Basic {auth}", + "Content-Type": content_type, } response = client.simulate_get( - '/v1/pets/12', host='petstore.swagger.io', headers=headers) + "/v1/pets/12", host="petstore.swagger.io", headers=headers + ) assert response.status_code == 200 def test_delete_method_invalid(self, client): - auth = 'authuser' - content_type = 'application/json' + auth = "authuser" + content_type = "application/json" headers = { - 'Authorization': f'Basic {auth}', - 'Content-Type': content_type, + "Authorization": f"Basic {auth}", + "Content-Type": content_type, } response = client.simulate_delete( - '/v1/pets/12', host='petstore.swagger.io', headers=headers) + "/v1/pets/12", host="petstore.swagger.io", headers=headers + ) expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 405, - 'title': ( - 'Operation delete not found for ' - 'http://petstore.swagger.io/v1/pets/12' + "status": 405, + "title": ( + "Operation delete not found for " + "http://petstore.swagger.io/v1/pets/12" ), } ] diff --git a/tests/integration/contrib/flask/conftest.py b/tests/integration/contrib/flask/conftest.py index c737f009..a59e1d52 100644 --- a/tests/integration/contrib/flask/conftest.py +++ b/tests/integration/contrib/flask/conftest.py @@ -1,6 +1,9 @@ -from flask.wrappers import Request, Response import pytest -from werkzeug.routing import Map, Rule, Subdomain +from flask.wrappers import Request +from flask.wrappers import Response +from werkzeug.routing import Map +from werkzeug.routing import Rule +from werkzeug.routing import Subdomain from werkzeug.test import create_environ @@ -11,42 +14,55 @@ def environ_factory(): @pytest.fixture def map(): - return Map([ - # Static URLs - Rule('/', endpoint='static/index'), - Rule('/about', endpoint='static/about'), - Rule('/help', endpoint='static/help'), - # Knowledge Base - Subdomain('kb', [ - Rule('/', endpoint='kb/index'), - Rule('/browse/', endpoint='kb/browse'), - Rule('/browse//', endpoint='kb/browse'), - Rule('/browse//', endpoint='kb/browse') - ]) - ], default_subdomain='www') + return Map( + [ + # Static URLs + Rule("/", endpoint="static/index"), + Rule("/about", endpoint="static/about"), + Rule("/help", endpoint="static/help"), + # Knowledge Base + Subdomain( + "kb", + [ + Rule("/", endpoint="kb/index"), + Rule("/browse/", endpoint="kb/browse"), + Rule("/browse//", endpoint="kb/browse"), + Rule("/browse//", endpoint="kb/browse"), + ], + ), + ], + default_subdomain="www", + ) @pytest.fixture def request_factory(map, environ_factory): - server_name = 'localhost' + server_name = "localhost" def create_request(method, path, subdomain=None, query_string=None): environ = environ_factory(query_string=query_string) req = Request(environ) urls = map.bind_to_environ( - environ, server_name=server_name, subdomain=subdomain) + environ, server_name=server_name, subdomain=subdomain + ) req.url_rule, req.view_args = urls.match( - path, method, return_rule=True) + path, method, return_rule=True + ) return req + return create_request @pytest.fixture def response_factory(): def create_response( - data, status_code=200, headers=None, - content_type='application/json'): + data, status_code=200, headers=None, content_type="application/json" + ): return Response( - data, status=status_code, headers=headers, - content_type=content_type) + data, + status=status_code, + headers=headers, + content_type=content_type, + ) + return create_response diff --git a/tests/integration/contrib/flask/test_flask_decorator.py b/tests/integration/contrib/flask/test_flask_decorator.py index b8e037aa..518a39e5 100644 --- a/tests/integration/contrib/flask/test_flask_decorator.py +++ b/tests/integration/contrib/flask/test_flask_decorator.py @@ -1,5 +1,7 @@ -from flask import Flask, make_response, jsonify import pytest +from flask import Flask +from flask import jsonify +from flask import make_response from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator from openapi_core.shortcuts import create_spec @@ -12,7 +14,7 @@ class TestFlaskOpenAPIDecorator: @pytest.fixture def spec(self, factory): - specfile = 'contrib/flask/data/v3.0/flask_factory.yaml' + specfile = "contrib/flask/data/v3.0/flask_factory.yaml" return create_spec(factory.spec_from_file(specfile)) @pytest.fixture @@ -22,8 +24,8 @@ def decorator(self, spec): @pytest.fixture def app(self): app = Flask("__main__") - app.config['DEBUG'] = True - app.config['TESTING'] = True + app.config["DEBUG"] = True + app.config["TESTING"] = True return app @pytest.fixture @@ -36,14 +38,16 @@ def client(self, app): def view_response(self): def view_response(*args, **kwargs): return self.view_response_callable(*args, **kwargs) + return view_response @pytest.fixture(autouse=True) def details_view(self, app, decorator, view_response): - @app.route("/browse//", methods=['GET', 'POST']) + @app.route("/browse//", methods=["GET", "POST"]) @decorator def browse_details(*args, **kwargs): return view_response(*args, **kwargs) + return browse_details @pytest.fixture(autouse=True) @@ -52,52 +56,57 @@ def list_view(self, app, decorator, view_response): @decorator def browse_list(*args, **kwargs): return view_response(*args, **kwargs) + return browse_list def test_invalid_content_type(self, client): def view_response_callable(*args, **kwargs): from flask.globals import request + assert request.openapi assert not request.openapi.errors - assert request.openapi.parameters == Parameters(path={ - 'id': 12, - }) - resp = make_response('success', 200) - resp.headers['X-Rate-Limit'] = '12' + assert request.openapi.parameters == Parameters( + path={ + "id": 12, + } + ) + resp = make_response("success", 200) + resp.headers["X-Rate-Limit"] = "12" return resp + self.view_response_callable = view_response_callable - result = client.get('/browse/12/') + result = client.get("/browse/12/") assert result.json == { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 415, - 'title': ( + "status": 415, + "title": ( "Content for the following mimetype not found: " "text/html. Valid mimetypes: ['application/json']" - ) + ), } ] } def test_server_error(self, client): - result = client.get('/browse/12/', base_url='https://localhost') + result = client.get("/browse/12/", base_url="https://localhost") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( - 'Server not found for ' - 'https://localhost/browse/{id}/' + "status": 400, + "title": ( + "Server not found for " + "https://localhost/browse/{id}/" ), } ] @@ -106,19 +115,19 @@ def test_server_error(self, client): assert result.json == expected_data def test_operation_error(self, client): - result = client.post('/browse/12/') + result = client.post("/browse/12/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 405, - 'title': ( - 'Operation post not found for ' - 'http://localhost/browse/{id}/' + "status": 405, + "title": ( + "Operation post not found for " + "http://localhost/browse/{id}/" ), } ] @@ -127,19 +136,18 @@ def test_operation_error(self, client): assert result.json == expected_data def test_path_error(self, client): - result = client.get('/browse/') + result = client.get("/browse/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 404, - 'title': ( - 'Path not found for ' - 'http://localhost/browse/' + "status": 404, + "title": ( + "Path not found for " "http://localhost/browse/" ), } ] @@ -148,20 +156,20 @@ def test_path_error(self, client): assert result.json == expected_data def test_endpoint_error(self, client): - result = client.get('/browse/invalidparameter/') + result = client.get("/browse/invalidparameter/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( + "status": 400, + "title": ( "Failed to cast value to integer type: " "invalidparameter" - ) + ), } ] } @@ -170,19 +178,23 @@ def test_endpoint_error(self, client): def test_valid(self, client): def view_response_callable(*args, **kwargs): from flask.globals import request + assert request.openapi assert not request.openapi.errors - assert request.openapi.parameters == Parameters(path={ - 'id': 12, - }) - resp = jsonify(data='data') - resp.headers['X-Rate-Limit'] = '12' + assert request.openapi.parameters == Parameters( + path={ + "id": 12, + } + ) + resp = jsonify(data="data") + resp.headers["X-Rate-Limit"] = "12" return resp + self.view_response_callable = view_response_callable - result = client.get('/browse/12/') + result = client.get("/browse/12/") assert result.status_code == 200 assert result.json == { - 'data': 'data', + "data": "data", } diff --git a/tests/integration/contrib/flask/test_flask_requests.py b/tests/integration/contrib/flask/test_flask_requests.py index 64d3f8cc..00a75c6d 100644 --- a/tests/integration/contrib/flask/test_flask_requests.py +++ b/tests/integration/contrib/flask/test_flask_requests.py @@ -1,15 +1,15 @@ from urllib.parse import urljoin -from werkzeug.datastructures import Headers, ImmutableMultiDict +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableMultiDict from openapi_core.contrib.flask import FlaskOpenAPIRequest from openapi_core.validation.request.datatypes import RequestParameters class TestFlaskOpenAPIRequest: - def test_simple(self, request_factory, request): - request = request_factory('GET', '/', subdomain='www') + request = request_factory("GET", "/", subdomain="www") openapi_request = FlaskOpenAPIRequest(request) @@ -24,21 +24,26 @@ def test_simple(self, request_factory, request): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - urljoin(request.host_url, request.path) + assert openapi_request.full_url_pattern == urljoin( + request.host_url, request.path + ) assert openapi_request.body == request.data assert openapi_request.mimetype == request.mimetype def test_multiple_values(self, request_factory, request): request = request_factory( - 'GET', '/', subdomain='www', query_string='a=b&a=c') + "GET", "/", subdomain="www", query_string="a=b&a=c" + ) openapi_request = FlaskOpenAPIRequest(request) path = {} - query = ImmutableMultiDict([ - ('a', 'b'), ('a', 'c'), - ]) + query = ImmutableMultiDict( + [ + ("a", "b"), + ("a", "c"), + ] + ) headers = Headers(request.headers) cookies = {} assert openapi_request.parameters == RequestParameters( @@ -48,17 +53,18 @@ def test_multiple_values(self, request_factory, request): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - urljoin(request.host_url, request.path) + assert openapi_request.full_url_pattern == urljoin( + request.host_url, request.path + ) assert openapi_request.body == request.data assert openapi_request.mimetype == request.mimetype def test_url_rule(self, request_factory, request): - request = request_factory('GET', '/browse/12/', subdomain='kb') + request = request_factory("GET", "/browse/12/", subdomain="kb") openapi_request = FlaskOpenAPIRequest(request) - path = {'id': 12} + path = {"id": 12} query = ImmutableMultiDict([]) headers = Headers(request.headers) cookies = {} @@ -69,7 +75,8 @@ def test_url_rule(self, request_factory, request): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - urljoin(request.host_url, '/browse/{id}/') + assert openapi_request.full_url_pattern == urljoin( + request.host_url, "/browse/{id}/" + ) assert openapi_request.body == request.data assert openapi_request.mimetype == request.mimetype diff --git a/tests/integration/contrib/flask/test_flask_responses.py b/tests/integration/contrib/flask/test_flask_responses.py index f072e5aa..5b2fd1a7 100644 --- a/tests/integration/contrib/flask/test_flask_responses.py +++ b/tests/integration/contrib/flask/test_flask_responses.py @@ -2,9 +2,8 @@ class TestFlaskOpenAPIResponse: - def test_invalid_server(self, response_factory): - response = response_factory('Not Found', status_code=404) + response = response_factory("Not Found", status_code=404) openapi_response = FlaskOpenAPIResponse(response) diff --git a/tests/integration/contrib/flask/test_flask_validation.py b/tests/integration/contrib/flask/test_flask_validation.py index a3e5f6ac..e4d0ccb2 100644 --- a/tests/integration/contrib/flask/test_flask_validation.py +++ b/tests/integration/contrib/flask/test_flask_validation.py @@ -1,30 +1,28 @@ import pytest -from openapi_core.contrib.flask import ( - FlaskOpenAPIRequest, FlaskOpenAPIResponse, -) +from openapi_core.contrib.flask import FlaskOpenAPIRequest +from openapi_core.contrib.flask import FlaskOpenAPIResponse from openapi_core.shortcuts import create_spec from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.response.validators import ResponseValidator class TestFlaskOpenAPIValidation: - @pytest.fixture def flask_spec(self, factory): - specfile = 'contrib/flask/data/v3.0/flask_factory.yaml' + specfile = "contrib/flask/data/v3.0/flask_factory.yaml" return create_spec(factory.spec_from_file(specfile)) - def test_response_validator_path_pattern(self, - flask_spec, - request_factory, - response_factory): + def test_response_validator_path_pattern( + self, flask_spec, request_factory, response_factory + ): validator = ResponseValidator(flask_spec) - request = request_factory('GET', '/browse/12/', subdomain='kb') + request = request_factory("GET", "/browse/12/", subdomain="kb") openapi_request = FlaskOpenAPIRequest(request) response = response_factory( '{"data": "data"}', - status_code=200, headers={'X-Rate-Limit': '12'}, + status_code=200, + headers={"X-Rate-Limit": "12"}, ) openapi_response = FlaskOpenAPIResponse(response) result = validator.validate(openapi_request, openapi_response) @@ -32,7 +30,7 @@ def test_response_validator_path_pattern(self, def test_request_validator_path_pattern(self, flask_spec, request_factory): validator = RequestValidator(flask_spec) - request = request_factory('GET', '/browse/12/', subdomain='kb') + request = request_factory("GET", "/browse/12/", subdomain="kb") openapi_request = FlaskOpenAPIRequest(request) result = validator.validate(openapi_request) assert not result.errors diff --git a/tests/integration/contrib/flask/test_flask_views.py b/tests/integration/contrib/flask/test_flask_views.py index 6fc2ff96..d61dd7dc 100644 --- a/tests/integration/contrib/flask/test_flask_views.py +++ b/tests/integration/contrib/flask/test_flask_views.py @@ -1,5 +1,7 @@ -from flask import Flask, make_response, jsonify import pytest +from flask import Flask +from flask import jsonify +from flask import make_response from openapi_core.contrib.flask.views import FlaskOpenAPIView from openapi_core.shortcuts import create_spec @@ -11,14 +13,14 @@ class TestFlaskOpenAPIView: @pytest.fixture def spec(self, factory): - specfile = 'contrib/flask/data/v3.0/flask_factory.yaml' + specfile = "contrib/flask/data/v3.0/flask_factory.yaml" return create_spec(factory.spec_from_file(specfile)) @pytest.fixture def app(self): app = Flask("__main__") - app.config['DEBUG'] = True - app.config['TESTING'] = True + app.config["DEBUG"] = True + app.config["TESTING"] = True return app @pytest.fixture @@ -37,7 +39,8 @@ def get(self, id): def post(self, id): return outer.view_response - return MyDetailsView.as_view('browse_details', spec) + + return MyDetailsView.as_view("browse_details", spec) @pytest.fixture def list_view_func(self, spec): @@ -46,7 +49,8 @@ def list_view_func(self, spec): class MyListView(FlaskOpenAPIView): def get(self): return outer.view_response - return MyListView.as_view('browse_list', spec) + + return MyListView.as_view("browse_list", spec) @pytest.fixture(autouse=True) def view(self, app, details_view_func, list_view_func): @@ -54,42 +58,42 @@ def view(self, app, details_view_func, list_view_func): app.add_url_rule("/browse/", view_func=list_view_func) def test_invalid_content_type(self, client): - self.view_response = make_response('success', 200) - self.view_response.headers['X-Rate-Limit'] = '12' + self.view_response = make_response("success", 200) + self.view_response.headers["X-Rate-Limit"] = "12" - result = client.get('/browse/12/') + result = client.get("/browse/12/") assert result.status_code == 415 assert result.json == { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 415, - 'title': ( + "status": 415, + "title": ( "Content for the following mimetype not found: " "text/html. Valid mimetypes: ['application/json']" - ) + ), } ] } def test_server_error(self, client): - result = client.get('/browse/12/', base_url='https://localhost') + result = client.get("/browse/12/", base_url="https://localhost") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( - 'Server not found for ' - 'https://localhost/browse/{id}/' + "status": 400, + "title": ( + "Server not found for " + "https://localhost/browse/{id}/" ), } ] @@ -98,19 +102,19 @@ def test_server_error(self, client): assert result.json == expected_data def test_operation_error(self, client): - result = client.post('/browse/12/') + result = client.post("/browse/12/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 405, - 'title': ( - 'Operation post not found for ' - 'http://localhost/browse/{id}/' + "status": 405, + "title": ( + "Operation post not found for " + "http://localhost/browse/{id}/" ), } ] @@ -119,19 +123,18 @@ def test_operation_error(self, client): assert result.json == expected_data def test_path_error(self, client): - result = client.get('/browse/') + result = client.get("/browse/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 404, - 'title': ( - 'Path not found for ' - 'http://localhost/browse/' + "status": 404, + "title": ( + "Path not found for " "http://localhost/browse/" ), } ] @@ -140,20 +143,20 @@ def test_path_error(self, client): assert result.json == expected_data def test_endpoint_error(self, client): - result = client.get('/browse/invalidparameter/') + result = client.get("/browse/invalidparameter/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( + "status": 400, + "title": ( "Failed to cast value to integer type: " "invalidparameter" - ) + ), } ] } @@ -161,21 +164,19 @@ def test_endpoint_error(self, client): assert result.json == expected_data def test_missing_required_header(self, client): - self.view_response = jsonify(data='data') + self.view_response = jsonify(data="data") - result = client.get('/browse/12/') + result = client.get("/browse/12/") expected_data = { - 'errors': [ + "errors": [ { - 'class': ( + "class": ( "" ), - 'status': 400, - 'title': ( - "Missing required header: X-Rate-Limit" - ) + "status": 400, + "title": ("Missing required header: X-Rate-Limit"), } ] } @@ -183,12 +184,12 @@ def test_missing_required_header(self, client): assert result.json == expected_data def test_valid(self, client): - self.view_response = jsonify(data='data') - self.view_response.headers['X-Rate-Limit'] = '12' + self.view_response = jsonify(data="data") + self.view_response.headers["X-Rate-Limit"] = "12" - result = client.get('/browse/12/') + result = client.get("/browse/12/") assert result.status_code == 200 assert result.json == { - 'data': 'data', + "data": "data", } diff --git a/tests/integration/contrib/requests/conftest.py b/tests/integration/contrib/requests/conftest.py index c095aa59..57f032df 100644 --- a/tests/integration/contrib/requests/conftest.py +++ b/tests/integration/contrib/requests/conftest.py @@ -1,39 +1,46 @@ from io import BytesIO -from urllib.parse import urljoin, parse_qs +from urllib.parse import parse_qs +from urllib.parse import urljoin import pytest -from requests.models import Request, Response +from requests.models import Request +from requests.models import Response from requests.structures import CaseInsensitiveDict from urllib3.response import HTTPResponse @pytest.fixture def request_factory(): - schema = 'http' - server_name = 'localhost' + schema = "http" + server_name = "localhost" - def create_request(method, path, subdomain=None, query_string=''): - base_url = '://'.join([schema, server_name]) + def create_request(method, path, subdomain=None, query_string=""): + base_url = "://".join([schema, server_name]) url = urljoin(base_url, path) params = parse_qs(query_string) headers = { - 'Content-Type': 'application/json', + "Content-Type": "application/json", } return Request(method, url, params=params, headers=headers) + return create_request @pytest.fixture def response_factory(): def create_response( - data, status_code=200, content_type='application/json'): - fp = BytesIO(bytes(data, 'latin-1')) + data, status_code=200, content_type="application/json" + ): + fp = BytesIO(bytes(data, "latin-1")) raw = HTTPResponse(fp, preload_content=False) resp = Response() - resp.headers = CaseInsensitiveDict({ - 'Content-Type': content_type, - }) + resp.headers = CaseInsensitiveDict( + { + "Content-Type": content_type, + } + ) resp.status_code = status_code resp.raw = raw return resp + return create_response diff --git a/tests/integration/contrib/requests/test_requests_requests.py b/tests/integration/contrib/requests/test_requests_requests.py index d6f92d43..fca1b4a1 100644 --- a/tests/integration/contrib/requests/test_requests_requests.py +++ b/tests/integration/contrib/requests/test_requests_requests.py @@ -1,16 +1,13 @@ +from werkzeug.datastructures import Headers from werkzeug.datastructures import ImmutableMultiDict from openapi_core.contrib.requests import RequestsOpenAPIRequest from openapi_core.validation.request.datatypes import RequestParameters -from werkzeug.datastructures import Headers - - class TestRequestsOpenAPIRequest: - def test_simple(self, request_factory, request): - request = request_factory('GET', '/', subdomain='www') + request = request_factory("GET", "/", subdomain="www") openapi_request = RequestsOpenAPIRequest(request) @@ -26,20 +23,24 @@ def test_simple(self, request_factory, request): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == 'http://localhost/' + assert openapi_request.full_url_pattern == "http://localhost/" assert openapi_request.body == prepared.body - assert openapi_request.mimetype == 'application/json' + assert openapi_request.mimetype == "application/json" def test_multiple_values(self, request_factory, request): request = request_factory( - 'GET', '/', subdomain='www', query_string='a=b&a=c') + "GET", "/", subdomain="www", query_string="a=b&a=c" + ) openapi_request = RequestsOpenAPIRequest(request) path = {} - query = ImmutableMultiDict([ - ('a', 'b'), ('a', 'c'), - ]) + query = ImmutableMultiDict( + [ + ("a", "b"), + ("a", "c"), + ] + ) headers = Headers(dict(request.headers)) cookies = {} assert openapi_request.parameters == RequestParameters( @@ -50,21 +51,23 @@ def test_multiple_values(self, request_factory, request): ) prepared = request.prepare() assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == 'http://localhost/' + assert openapi_request.full_url_pattern == "http://localhost/" assert openapi_request.body == prepared.body - assert openapi_request.mimetype == 'application/json' + assert openapi_request.mimetype == "application/json" def test_url_rule(self, request_factory, request): - request = request_factory('GET', '/browse/12/', subdomain='kb') + request = request_factory("GET", "/browse/12/", subdomain="kb") openapi_request = RequestsOpenAPIRequest(request) # empty when not bound to spec path = {} query = ImmutableMultiDict([]) - headers = Headers({ - 'Content-Type': 'application/json', - }) + headers = Headers( + { + "Content-Type": "application/json", + } + ) cookies = {} assert openapi_request.parameters == RequestParameters( path=path, @@ -74,7 +77,8 @@ def test_url_rule(self, request_factory, request): ) prepared = request.prepare() assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - 'http://localhost/browse/12/' + assert ( + openapi_request.full_url_pattern == "http://localhost/browse/12/" + ) assert openapi_request.body == prepared.body - assert openapi_request.mimetype == 'application/json' + assert openapi_request.mimetype == "application/json" diff --git a/tests/integration/contrib/requests/test_requests_responses.py b/tests/integration/contrib/requests/test_requests_responses.py index c9f32204..7fa17991 100644 --- a/tests/integration/contrib/requests/test_requests_responses.py +++ b/tests/integration/contrib/requests/test_requests_responses.py @@ -2,13 +2,12 @@ class TestRequestsOpenAPIResponse: - def test_invalid_server(self, response_factory): - response = response_factory('Not Found', status_code=404) + response = response_factory("Not Found", status_code=404) openapi_response = RequestsOpenAPIResponse(response) assert openapi_response.data == response.content assert openapi_response.status_code == response.status_code - mimetype = response.headers.get('Content-Type') + mimetype = response.headers.get("Content-Type") assert openapi_response.mimetype == mimetype diff --git a/tests/integration/contrib/requests/test_requests_validation.py b/tests/integration/contrib/requests/test_requests_validation.py index 736e9fb3..42734b36 100644 --- a/tests/integration/contrib/requests/test_requests_validation.py +++ b/tests/integration/contrib/requests/test_requests_validation.py @@ -2,34 +2,36 @@ import requests import responses -from openapi_core.contrib.requests import ( - RequestsOpenAPIRequest, RequestsOpenAPIResponse, -) +from openapi_core.contrib.requests import RequestsOpenAPIRequest +from openapi_core.contrib.requests import RequestsOpenAPIResponse from openapi_core.shortcuts import create_spec from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.response.validators import ResponseValidator class TestRequestsOpenAPIValidation: - @pytest.fixture def spec(self, factory): - specfile = 'contrib/requests/data/v3.0/requests_factory.yaml' + specfile = "contrib/requests/data/v3.0/requests_factory.yaml" return create_spec(factory.spec_from_file(specfile)) @responses.activate def test_response_validator_path_pattern(self, spec): responses.add( - responses.POST, 'http://localhost/browse/12/?q=string', - json={"data": "data"}, status=200, match_querystring=True, - headers={'X-Rate-Limit': '12'}, + responses.POST, + "http://localhost/browse/12/?q=string", + json={"data": "data"}, + status=200, + match_querystring=True, + headers={"X-Rate-Limit": "12"}, ) validator = ResponseValidator(spec) request = requests.Request( - 'POST', 'http://localhost/browse/12/', - params={'q': 'string'}, - headers={'content-type': 'application/json'}, - json={'param1': 1}, + "POST", + "http://localhost/browse/12/", + params={"q": "string"}, + headers={"content-type": "application/json"}, + json={"param1": 1}, ) request_prepared = request.prepare() session = requests.Session() @@ -42,10 +44,11 @@ def test_response_validator_path_pattern(self, spec): def test_request_validator_path_pattern(self, spec): validator = RequestValidator(spec) request = requests.Request( - 'POST', 'http://localhost/browse/12/', - params={'q': 'string'}, - headers={'content-type': 'application/json'}, - json={'param1': 1}, + "POST", + "http://localhost/browse/12/", + params={"q": "string"}, + headers={"content-type": "application/json"}, + json={"param1": 1}, ) openapi_request = RequestsOpenAPIRequest(request) result = validator.validate(openapi_request) @@ -54,10 +57,11 @@ def test_request_validator_path_pattern(self, spec): def test_request_validator_prepared_request(self, spec): validator = RequestValidator(spec) request = requests.Request( - 'POST', 'http://localhost/browse/12/', - params={'q': 'string'}, - headers={'content-type': 'application/json'}, - json={'param1': 1}, + "POST", + "http://localhost/browse/12/", + params={"q": "string"}, + headers={"content-type": "application/json"}, + json={"param1": 1}, ) request_prepared = request.prepare() openapi_request = RequestsOpenAPIRequest(request_prepared) diff --git a/tests/integration/schema/test_empty.py b/tests/integration/schema/test_empty.py index 332bbd04..98b12c72 100644 --- a/tests/integration/schema/test_empty.py +++ b/tests/integration/schema/test_empty.py @@ -5,7 +5,6 @@ class TestEmpty: - @pytest.fixture def spec_dict(self, factory): return factory.spec_from_file("data/v3.0/empty.yaml") diff --git a/tests/integration/schema/test_link_spec.py b/tests/integration/schema/test_link_spec.py index a1d0b9be..2ed33fa3 100644 --- a/tests/integration/schema/test_link_spec.py +++ b/tests/integration/schema/test_link_spec.py @@ -2,36 +2,35 @@ class TestLinkSpec: - def test_no_param(self, factory): spec_dict = factory.spec_from_file("data/v3.0/links.yaml") spec = create_spec(spec_dict) - resp = spec / 'paths#/status#get#responses#default' + resp = spec / "paths#/status#get#responses#default" - links = resp / 'links' + links = resp / "links" assert len(links) == 1 - link = links / 'noParamLink' - assert link['operationId'] == 'noParOp' - assert 'server' not in link - assert 'requestBody' not in link - assert 'parameters' not in link + link = links / "noParamLink" + assert link["operationId"] == "noParOp" + assert "server" not in link + assert "requestBody" not in link + assert "parameters" not in link def test_param(self, factory): spec_dict = factory.spec_from_file("data/v3.0/links.yaml") spec = create_spec(spec_dict) - resp = spec / 'paths#/status/{resourceId}#get#responses#default' + resp = spec / "paths#/status/{resourceId}#get#responses#default" - links = resp / 'links' + links = resp / "links" assert len(links) == 1 - link = links / 'paramLink' - assert link['operationId'] == 'paramOp' - assert 'server' not in link - assert link['requestBody'] == 'test' + link = links / "paramLink" + assert link["operationId"] == "paramOp" + assert "server" not in link + assert link["requestBody"] == "test" - parameters = link['parameters'] + parameters = link["parameters"] assert len(parameters) == 1 - param = parameters['opParam'] - assert param == '$request.path.resourceId' + param = parameters["opParam"] + assert param == "$request.path.resourceId" diff --git a/tests/integration/schema/test_path_params.py b/tests/integration/schema/test_path_params.py index 93659f90..028bc674 100644 --- a/tests/integration/schema/test_path_params.py +++ b/tests/integration/schema/test_path_params.py @@ -5,21 +5,19 @@ class TestMinimal: - spec_paths = [ - "data/v3.0/path_param.yaml" - ] + spec_paths = ["data/v3.0/path_param.yaml"] @pytest.mark.parametrize("spec_path", spec_paths) def test_param_present(self, factory, spec_path): spec_dict = factory.spec_from_file(spec_path) spec = create_spec(spec_dict) - path = spec / 'paths#/resource/{resId}' + path = spec / "paths#/resource/{resId}" - parameters = path / 'parameters' + parameters = path / "parameters" assert len(parameters) == 1 param = parameters[0] - assert param['name'] == 'resId' - assert param['required'] - assert param['in'] == 'path' + assert param["name"] == "resId" + assert param["required"] + assert param["in"] == "path" diff --git a/tests/integration/schema/test_spec.py b/tests/integration/schema/test_spec.py index db7cf40e..c0b2092c 100644 --- a/tests/integration/schema/test_spec.py +++ b/tests/integration/schema/test_spec.py @@ -1,22 +1,23 @@ -import pytest from base64 import b64encode -from openapi_core.shortcuts import create_spec +import pytest + from openapi_core.schema.servers import get_server_url from openapi_core.schema.specs import get_spec_url +from openapi_core.shortcuts import create_spec from openapi_core.validation.request.validators import RequestValidator from openapi_core.validation.response.validators import ResponseValidator class TestPetstore: - api_key = '12345' + api_key = "12345" @property def api_key_encoded(self): - api_key_bytes = self.api_key.encode('utf8') + api_key_bytes = self.api_key.encode("utf8") api_key_bytes_enc = b64encode(api_key_bytes) - return str(api_key_bytes_enc, 'utf8') + return str(api_key_bytes_enc, "utf8") @pytest.fixture def spec_uri(self): @@ -39,28 +40,28 @@ def response_validator(self, spec): return ResponseValidator(spec) def test_spec(self, spec, spec_dict): - url = 'http://petstore.swagger.io/v1' - - info = spec / 'info' - info_spec = spec_dict['info'] - assert info['title'] == info_spec['title'] - assert info['description'] == info_spec['description'] - assert info['termsOfService'] == info_spec['termsOfService'] - assert info['version'] == info_spec['version'] - - contact = info / 'contact' - contact_spec = info_spec['contact'] - assert contact['name'] == contact_spec['name'] - assert contact['url'] == contact_spec['url'] - assert contact['email'] == contact_spec['email'] - - license = info / 'license' - license_spec = info_spec['license'] - assert license['name'] == license_spec['name'] - assert license['url'] == license_spec['url'] - - security = spec / 'security' - security_spec = spec_dict.get('security', []) + url = "http://petstore.swagger.io/v1" + + info = spec / "info" + info_spec = spec_dict["info"] + assert info["title"] == info_spec["title"] + assert info["description"] == info_spec["description"] + assert info["termsOfService"] == info_spec["termsOfService"] + assert info["version"] == info_spec["version"] + + contact = info / "contact" + contact_spec = info_spec["contact"] + assert contact["name"] == contact_spec["name"] + assert contact["url"] == contact_spec["url"] + assert contact["email"] == contact_spec["email"] + + license = info / "license" + license_spec = info_spec["license"] + assert license["name"] == license_spec["name"] + assert license["url"] == license_spec["url"] + + security = spec / "security" + security_spec = spec_dict.get("security", []) for idx, security_reqs in enumerate(security): security_reqs_spec = security_spec[idx] for scheme_name, security_req in security_reqs.items(): @@ -68,41 +69,47 @@ def test_spec(self, spec, spec_dict): assert get_spec_url(spec) == url - servers = spec / 'servers' + servers = spec / "servers" for idx, server in enumerate(servers): - server_spec = spec_dict['servers'][idx] - assert server['url'] == server_spec['url'] + server_spec = spec_dict["servers"][idx] + assert server["url"] == server_spec["url"] assert get_server_url(server) == url - variables = server / 'variables' + variables = server / "variables" for variable_name, variable in variables.items(): - variable_spec = server_spec['variables'][variable_name] - assert variable['default'] == variable_spec['default'] - assert variable['enum'] == variable_spec.get('enum') + variable_spec = server_spec["variables"][variable_name] + assert variable["default"] == variable_spec["default"] + assert variable["enum"] == variable_spec.get("enum") - paths = spec / 'paths' + paths = spec / "paths" for path_name, path in paths.items(): - path_spec = spec_dict['paths'][path_name] - assert path.getkey('summary') == path_spec.get('summary') - assert path.getkey('description') == path_spec.get('description') + path_spec = spec_dict["paths"][path_name] + assert path.getkey("summary") == path_spec.get("summary") + assert path.getkey("description") == path_spec.get("description") - servers = path.get('servers', []) - servers_spec = path_spec.get('servers', []) + servers = path.get("servers", []) + servers_spec = path_spec.get("servers", []) for idx, server in enumerate(servers): server_spec = servers_spec[idx] - assert server.url == server_spec['url'] - assert server.default_url == server_spec['url'] - assert server.description == server_spec.get('description') + assert server.url == server_spec["url"] + assert server.default_url == server_spec["url"] + assert server.description == server_spec.get("description") - variables = server.get('variables', {}) + variables = server.get("variables", {}) for variable_name, variable in variables.items(): - variable_spec = server_spec['variables'][variable_name] - assert variable['default'] == variable_spec['default'] - assert variable.getkey('enum') == variable_spec.get('enum') + variable_spec = server_spec["variables"][variable_name] + assert variable["default"] == variable_spec["default"] + assert variable.getkey("enum") == variable_spec.get("enum") operations = [ - 'get', 'put', 'post', 'delete', 'options', - 'head', 'patch', 'trace', + "get", + "put", + "post", + "delete", + "options", + "head", + "patch", + "trace", ] for http_method in operations: if http_method not in path: @@ -110,46 +117,50 @@ def test_spec(self, spec, spec_dict): operation = path / http_method operation_spec = path_spec[http_method] - assert operation['operationId'] is not None - assert operation['tags'] == operation_spec['tags'] - assert operation['summary'] == operation_spec.get('summary') - assert operation.getkey('description') == operation_spec.get( - 'description') + assert operation["operationId"] is not None + assert operation["tags"] == operation_spec["tags"] + assert operation["summary"] == operation_spec.get("summary") + assert operation.getkey("description") == operation_spec.get( + "description" + ) - ext_docs = operation.get('externalDocs') - ext_docs_spec = operation_spec.get('externalDocs') + ext_docs = operation.get("externalDocs") + ext_docs_spec = operation_spec.get("externalDocs") assert bool(ext_docs_spec) == bool(ext_docs) if ext_docs_spec: - assert ext_docs['url'] == ext_docs_spec['url'] - assert ext_docs.getkey('description') == ext_docs_spec.get( - 'description') + assert ext_docs["url"] == ext_docs_spec["url"] + assert ext_docs.getkey("description") == ext_docs_spec.get( + "description" + ) - servers = operation.get('servers', []) - servers_spec = operation_spec.get('servers', []) + servers = operation.get("servers", []) + servers_spec = operation_spec.get("servers", []) for idx, server in enumerate(servers): server_spec = servers_spec[idx] - assert server['url'] == server_spec['url'] - assert get_server_url(server) == server_spec['url'] - assert server['description'] == server_spec.get( - 'description') + assert server["url"] == server_spec["url"] + assert get_server_url(server) == server_spec["url"] + assert server["description"] == server_spec.get( + "description" + ) - variables = server.get('variables', {}) + variables = server.get("variables", {}) for variable_name, variable in variables.items(): - variable_spec = server_spec['variables'][variable_name] - assert variable['default'] == variable_spec['default'] - assert variable.getkey('enum') == variable_spec.get( - 'enum') - - security = operation.get('security', []) - security_spec = operation_spec.get('security') + variable_spec = server_spec["variables"][variable_name] + assert variable["default"] == variable_spec["default"] + assert variable.getkey("enum") == variable_spec.get( + "enum" + ) + + security = operation.get("security", []) + security_spec = operation_spec.get("security") if security_spec is not None: for idx, security_reqs in enumerate(security): security_reqs_spec = security_spec[idx] for scheme_name, security_req in security_reqs.items(): security_req == security_reqs_spec[scheme_name] - responses = operation / 'responses' - responses_spec = operation_spec.get('responses') + responses = operation / "responses" + responses_spec = operation_spec.get("responses") for http_status, response in responses.items(): response_spec = responses_spec[http_status] @@ -157,128 +168,131 @@ def test_spec(self, spec, spec_dict): continue # @todo: test with defererence - if '$ref' in response_spec: + if "$ref" in response_spec: continue - description_spec = response_spec['description'] + description_spec = response_spec["description"] - assert response.getkey('description') == description_spec + assert response.getkey("description") == description_spec - headers = response.get('headers', {}) + headers = response.get("headers", {}) for parameter_name, parameter in headers.items(): - headers_spec = response_spec['headers'] + headers_spec = response_spec["headers"] parameter_spec = headers_spec[parameter_name] - schema = parameter.get('schema') - schema_spec = parameter_spec.get('schema') + schema = parameter.get("schema") + schema_spec = parameter_spec.get("schema") assert bool(schema_spec) == bool(schema) if not schema_spec: continue # @todo: test with defererence - if '$ref' in schema_spec: + if "$ref" in schema_spec: continue - assert schema['type'] ==\ - schema_spec['type'] - assert schema.getkey('format') ==\ - schema_spec.get('format') - assert schema.getkey('required') == schema_spec.get( - 'required') + assert schema["type"] == schema_spec["type"] + assert schema.getkey("format") == schema_spec.get( + "format" + ) + assert schema.getkey("required") == schema_spec.get( + "required" + ) - content = parameter.get('content', {}) - content_spec = parameter_spec.get('content') + content = parameter.get("content", {}) + content_spec = parameter_spec.get("content") assert bool(content_spec) == bool(content) if not content_spec: continue for mimetype, media_type in content.items(): - media_spec = parameter_spec['content'][mimetype] - schema = media_type.get('schema') - schema_spec = media_spec.get('schema') + media_spec = parameter_spec["content"][mimetype] + schema = media_type.get("schema") + schema_spec = media_spec.get("schema") assert bool(schema_spec) == bool(schema) if not schema_spec: continue # @todo: test with defererence - if '$ref' in schema_spec: + if "$ref" in schema_spec: continue - assert schema['type'] ==\ - schema_spec['type'] - assert schema.getkey('format') ==\ - schema_spec.get('format') - assert schema.getkey('required') == \ - schema_spec.get('required') + assert schema["type"] == schema_spec["type"] + assert schema.getkey("format") == schema_spec.get( + "format" + ) + assert schema.getkey( + "required" + ) == schema_spec.get("required") - content_spec = response_spec.get('content') + content_spec = response_spec.get("content") if not content_spec: continue - content = response.get('content', {}) + content = response.get("content", {}) for mimetype, media_type in content.items(): - content_spec = response_spec['content'][mimetype] + content_spec = response_spec["content"][mimetype] - example_spec = content_spec.get('example') - assert media_type.getkey('example') == example_spec + example_spec = content_spec.get("example") + assert media_type.getkey("example") == example_spec - schema = media_type.get('schema') - schema_spec = content_spec.get('schema') + schema = media_type.get("schema") + schema_spec = content_spec.get("schema") assert bool(schema_spec) == bool(schema) if not schema_spec: continue # @todo: test with defererence - if '$ref' in schema_spec: + if "$ref" in schema_spec: continue - assert schema['type'] == schema_spec['type'] - assert schema.getkey('required') == schema_spec.get( - 'required') + assert schema["type"] == schema_spec["type"] + assert schema.getkey("required") == schema_spec.get( + "required" + ) - request_body = operation.get('requestBody') - request_body_spec = operation_spec.get('requestBody') + request_body = operation.get("requestBody") + request_body_spec = operation_spec.get("requestBody") assert bool(request_body_spec) == bool(request_body) if not request_body_spec: continue - assert bool(request_body.getkey('required')) ==\ - request_body_spec.get('required') + assert bool( + request_body.getkey("required") + ) == request_body_spec.get("required") - content = request_body / 'content' + content = request_body / "content" for mimetype, media_type in content.items(): - content_spec = request_body_spec['content'][mimetype] - schema_spec = content_spec.get('schema') + content_spec = request_body_spec["content"][mimetype] + schema_spec = content_spec.get("schema") if not schema_spec: continue # @todo: test with defererence - if '$ref' in schema_spec: + if "$ref" in schema_spec: continue - schema = content.get('schema') + schema = content.get("schema") assert bool(schema_spec) == bool(schema) - assert schema.type.value ==\ - schema_spec['type'] - assert schema.format ==\ - schema_spec.get('format') + assert schema.type.value == schema_spec["type"] + assert schema.format == schema_spec.get("format") assert schema.required == schema_spec.get( - 'required', False) + "required", False + ) - components = spec.get('components') + components = spec.get("components") if not components: return - schemas = components.get('schemas', {}) + schemas = components.get("schemas", {}) for schema_name, schema in schemas.items(): - schema_spec = spec_dict['components']['schemas'][schema_name] - assert schema.getkey('readOnly') == schema_spec.get('readOnly') - assert schema.getkey('writeOnly') == schema_spec.get('writeOnly') + schema_spec = spec_dict["components"]["schemas"][schema_name] + assert schema.getkey("readOnly") == schema_spec.get("readOnly") + assert schema.getkey("writeOnly") == schema_spec.get("writeOnly") diff --git a/tests/integration/validation/test_minimal.py b/tests/integration/validation/test_minimal.py index 97b5233f..076a7de7 100644 --- a/tests/integration/validation/test_minimal.py +++ b/tests/integration/validation/test_minimal.py @@ -1,9 +1,8 @@ import pytest from openapi_core.shortcuts import create_spec -from openapi_core.templating.paths.exceptions import ( - PathNotFound, OperationNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound from openapi_core.testing import MockRequest from openapi_core.validation.request.datatypes import Parameters from openapi_core.validation.request.validators import RequestValidator @@ -16,12 +15,12 @@ class TestMinimal: "https://bad.remote.domain.net/", "http://localhost", "http://localhost:8080", - "https://u:p@a.b:1337" + "https://u:p@a.b:1337", ] spec_paths = [ "data/v3.0/minimal_with_servers.yaml", - "data/v3.0/minimal.yaml" + "data/v3.0/minimal.yaml", ] @pytest.mark.parametrize("server", servers) diff --git a/tests/integration/validation/test_petstore.py b/tests/integration/validation/test_petstore.py index d237c8d9..8a92aa6f 100644 --- a/tests/integration/validation/test_petstore.py +++ b/tests/integration/validation/test_petstore.py @@ -1,8 +1,9 @@ import json -import pytest -from datetime import datetime from base64 import b64encode +from datetime import datetime from uuid import UUID + +import pytest from isodate.tzinfo import UTC from openapi_core.casting.schemas.exceptions import CastError @@ -10,19 +11,19 @@ from openapi_core.deserializing.parameters.exceptions import ( EmptyQueryParameterValue, ) +from openapi_core.exceptions import MissingRequiredHeader +from openapi_core.exceptions import MissingRequiredParameter from openapi_core.extensions.models.models import BaseModel -from openapi_core.exceptions import ( - MissingRequiredHeader, MissingRequiredParameter, -) -from openapi_core.shortcuts import ( - create_spec, spec_validate_parameters, spec_validate_body, - spec_validate_security, spec_validate_data, spec_validate_headers, -) +from openapi_core.shortcuts import create_spec +from openapi_core.shortcuts import spec_validate_body +from openapi_core.shortcuts import spec_validate_data +from openapi_core.shortcuts import spec_validate_headers +from openapi_core.shortcuts import spec_validate_parameters +from openapi_core.shortcuts import spec_validate_security from openapi_core.templating.media_types.exceptions import MediaTypeNotFound -from openapi_core.templating.paths.exceptions import ( - ServerNotFound, -) -from openapi_core.testing import MockRequest, MockResponse +from openapi_core.templating.paths.exceptions import ServerNotFound +from openapi_core.testing import MockRequest +from openapi_core.testing import MockResponse from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue from openapi_core.validation.request.datatypes import Parameters from openapi_core.validation.request.validators import RequestValidator @@ -31,44 +32,47 @@ class TestPetstore: - api_key = '12345' + api_key = "12345" @property def api_key_encoded(self): - api_key_bytes = self.api_key.encode('utf8') + api_key_bytes = self.api_key.encode("utf8") api_key_bytes_enc = b64encode(api_key_bytes) - return str(api_key_bytes_enc, 'utf8') + return str(api_key_bytes_enc, "utf8") - @pytest.fixture(scope='module') + @pytest.fixture(scope="module") def spec_uri(self): return "file://tests/integration/data/v3.0/petstore.yaml" - @pytest.fixture(scope='module') + @pytest.fixture(scope="module") def spec_dict(self, factory): return factory.spec_from_file("data/v3.0/petstore.yaml") - @pytest.fixture(scope='module') + @pytest.fixture(scope="module") def spec(self, spec_dict, spec_uri): return create_spec(spec_dict, spec_uri) - @pytest.fixture(scope='module') + @pytest.fixture(scope="module") def request_validator(self, spec): return RequestValidator(spec) - @pytest.fixture(scope='module') + @pytest.fixture(scope="module") def response_validator(self, spec): return ResponseValidator(spec) def test_get_pets(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': '20', + "limit": "20", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -77,20 +81,20 @@ def test_get_pets(self, spec, response_validator): assert parameters == Parameters( query={ - 'limit': 20, - 'page': 1, - 'search': '', + "limit": 20, + "page": 1, + "search": "", } ) assert body is None data_json = { - 'data': [], + "data": [], } data = json.dumps(data_json) headers = { - 'Content-Type': 'application/json', - 'x-next': 'next-url', + "Content-Type": "application/json", + "x-next": "next-url", } response = MockResponse(data, headers=headers) @@ -100,19 +104,22 @@ def test_get_pets(self, spec, response_validator): assert isinstance(response_result.data, BaseModel) assert response_result.data.data == [] assert response_result.headers == { - 'x-next': 'next-url', + "x-next": "next-url", } def test_get_pets_response(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': '20', + "limit": "20", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -121,20 +128,20 @@ def test_get_pets_response(self, spec, response_validator): assert parameters == Parameters( query={ - 'limit': 20, - 'page': 1, - 'search': '', + "limit": 20, + "page": 1, + "search": "", } ) assert body is None data_json = { - 'data': [ + "data": [ { - 'id': 1, - 'name': 'Cat', - 'ears': { - 'healthy': True, + "id": 1, + "name": "Cat", + "ears": { + "healthy": True, }, } ], @@ -148,18 +155,21 @@ def test_get_pets_response(self, spec, response_validator): 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' + assert response_result.data.data[0].name == "Cat" def test_get_pets_response_no_schema(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': '20', + "limit": "20", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -168,15 +178,15 @@ def test_get_pets_response_no_schema(self, spec, response_validator): assert parameters == Parameters( query={ - 'limit': 20, - 'page': 1, - 'search': '', + "limit": 20, + "page": 1, + "search": "", } ) assert body is None - data = '' - response = MockResponse(data, status_code=404, mimetype='text/html') + data = "" + response = MockResponse(data, status_code=404, mimetype="text/html") with pytest.warns(UserWarning): response_result = response_validator.validate(request, response) @@ -185,15 +195,18 @@ def test_get_pets_response_no_schema(self, spec, response_validator): assert response_result.data == data def test_get_pets_invalid_response(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': '20', + "limit": "20", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -202,19 +215,19 @@ def test_get_pets_invalid_response(self, spec, response_validator): assert parameters == Parameters( query={ - 'limit': 20, - 'page': 1, - 'search': '', + "limit": 20, + "page": 1, + "search": "", } ) assert body is None response_data_json = { - 'data': [ + "data": [ { - 'id': 1, - 'name': { - 'first_name': 'Cat', + "id": 1, + "name": { + "first_name": "Cat", }, } ], @@ -230,7 +243,7 @@ def test_get_pets_invalid_response(self, spec, response_validator): schema_errors = response_result.errors[0].schema_errors assert response_result.errors == [ InvalidSchemaValue( - type='object', + type="object", value=response_data_json, schema_errors=schema_errors, ), @@ -238,16 +251,19 @@ def test_get_pets_invalid_response(self, spec, response_validator): assert response_result.data is None def test_get_pets_ids_param(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': '20', - 'ids': ['12', '13'], + "limit": "20", + "ids": ["12", "13"], } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -256,16 +272,16 @@ def test_get_pets_ids_param(self, spec, response_validator): assert parameters == Parameters( query={ - 'limit': 20, - 'page': 1, - 'search': '', - 'ids': [12, 13], + "limit": 20, + "page": 1, + "search": "", + "ids": [12, 13], } ) assert body is None data_json = { - 'data': [], + "data": [], } data = json.dumps(data_json) response = MockResponse(data) @@ -277,16 +293,19 @@ def test_get_pets_ids_param(self, spec, response_validator): assert response_result.data.data == [] def test_get_pets_tags_param(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = [ - ('limit', '20'), - ('tags', 'cats,dogs'), + ("limit", "20"), + ("tags", "cats,dogs"), ] request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -295,16 +314,16 @@ def test_get_pets_tags_param(self, spec, response_validator): assert parameters == Parameters( query={ - 'limit': 20, - 'page': 1, - 'search': '', - 'tags': ['cats', 'dogs'], + "limit": 20, + "page": 1, + "search": "", + "tags": ["cats", "dogs"], } ) assert body is None data_json = { - 'data': [], + "data": [], } data = json.dumps(data_json) response = MockResponse(data) @@ -316,16 +335,19 @@ def test_get_pets_tags_param(self, spec, response_validator): assert response_result.data.data == [] def test_get_pets_parameter_deserialization_error(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': 1, - 'tags': 12, + "limit": 1, + "tags": 12, } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -337,15 +359,18 @@ def test_get_pets_parameter_deserialization_error(self, spec): assert body is None def test_get_pets_wrong_parameter_type(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': 'twenty', + "limit": "twenty", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -357,10 +382,12 @@ def test_get_pets_wrong_parameter_type(self, spec): assert body is None def test_get_pets_raises_missing_required_param(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" request = MockRequest( - host_url, 'GET', '/pets', + host_url, + "GET", + "/pets", path_pattern=path_pattern, ) @@ -373,15 +400,18 @@ def test_get_pets_raises_missing_required_param(self, spec): assert body is None def test_get_pets_empty_value(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': '', + "limit": "", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -392,16 +422,19 @@ def test_get_pets_empty_value(self, spec): assert body is None def test_get_pets_allow_empty_value(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': 20, - 'search': '', + "limit": 20, + "search": "", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -409,9 +442,9 @@ def test_get_pets_allow_empty_value(self, spec): assert parameters == Parameters( query={ - 'page': 1, - 'limit': 20, - 'search': '', + "page": 1, + "limit": 20, + "search": "", } ) @@ -420,15 +453,18 @@ def test_get_pets_allow_empty_value(self, spec): assert body is None def test_get_pets_none_value(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': None, + "limit": None, } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -436,9 +472,9 @@ def test_get_pets_none_value(self, spec): assert parameters == Parameters( query={ - 'limit': None, - 'page': 1, - 'search': '', + "limit": None, + "page": 1, + "search": "", } ) @@ -447,16 +483,19 @@ def test_get_pets_none_value(self, spec): assert body is None def test_get_pets_param_order(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" query_params = { - 'limit': None, - 'order': 'desc', + "limit": None, + "order": "desc", } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -464,10 +503,10 @@ def test_get_pets_param_order(self, spec): assert parameters == Parameters( query={ - 'limit': None, - 'order': 'desc', - 'page': 1, - 'search': '', + "limit": None, + "order": "desc", + "page": 1, + "search": "", } ) @@ -476,20 +515,23 @@ def test_get_pets_param_order(self, spec): assert body is None def test_get_pets_param_coordinates(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets" coordinates = { - 'lat': 1.12, - 'lon': 32.12, + "lat": 1.12, + "lon": 32.12, } query_params = { - 'limit': None, - 'coordinates': json.dumps(coordinates), + "limit": None, + "coordinates": json.dumps(coordinates), } request = MockRequest( - host_url, 'GET', '/pets', - path_pattern=path_pattern, args=query_params, + host_url, + "GET", + "/pets", + path_pattern=path_pattern, + args=query_params, ) with pytest.warns(DeprecationWarning): @@ -497,10 +539,10 @@ def test_get_pets_param_coordinates(self, spec): assert parameters == Parameters( query={ - 'limit': None, - 'page': 1, - 'search': '', - 'coordinates': coordinates, + "limit": None, + "page": 1, + "search": "", + "coordinates": coordinates, } ) @@ -509,64 +551,68 @@ def test_get_pets_param_coordinates(self, spec): assert body is None def test_post_birds(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" pet_healthy = False data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "healthy": pet_healthy, + "wings": { + "healthy": pet_healthy, }, - 'healthy': pet_healthy, - 'wings': { - 'healthy': pet_healthy, - } } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } userdata = { - 'name': 'user1', + "name": "user1", } userdata_json = json.dumps(userdata) cookies = { - 'user': '123', - 'userdata': userdata_json, + "user": "123", + "userdata": userdata_json, } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + headers=headers, + cookies=cookies, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, - 'userdata': { - 'name': 'user1', + "user": 123, + "userdata": { + "name": "user1", }, }, ) body = spec_validate_body(spec, request) - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] - address_model = schemas['Address']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] + address_model = schemas["Address"]["x-model"] assert body.__class__.__name__ == pet_model assert body.name == pet_name assert body.tag == pet_tag @@ -581,56 +627,60 @@ def test_post_birds(self, spec, spec_dict): assert security == {} def test_post_cats(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" pet_healthy = False data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "healthy": pet_healthy, + "ears": { + "healthy": pet_healthy, }, - 'healthy': pet_healthy, - 'ears': { - 'healthy': pet_healthy, - } } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + headers=headers, + cookies=cookies, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) body = spec_validate_body(spec, request) - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] - address_model = schemas['Address']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] + address_model = schemas["Address"]["x-model"] assert body.__class__.__name__ == pet_model assert body.name == pet_name assert body.tag == pet_tag @@ -641,56 +691,60 @@ def test_post_cats(self, spec, spec_dict): assert body.healthy == pet_healthy def test_post_cats_boolean_string(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" pet_healthy = False data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "healthy": pet_healthy, + "ears": { + "healthy": pet_healthy, }, - 'healthy': pet_healthy, - 'ears': { - 'healthy': pet_healthy, - } } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + headers=headers, + cookies=cookies, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) body = spec_validate_body(spec, request) - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] - address_model = schemas['Address']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] + address_model = schemas["Address"]["x-model"] assert body.__class__.__name__ == pet_model assert body.name == pet_name assert body.tag == pet_tag @@ -701,36 +755,40 @@ def test_post_cats_boolean_string(self, spec, spec_dict): assert body.healthy is False def test_post_no_one_of_schema(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' - alias = 'kitty' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" + alias = "kitty" data_json = { - 'name': pet_name, - 'alias': alias, + "name": pet_name, + "alias": alias, } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + headers=headers, + cookies=cookies, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) @@ -738,79 +796,88 @@ def test_post_no_one_of_schema(self, spec, spec_dict): spec_validate_body(spec, request) def test_post_cats_only_required_body(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" pet_healthy = True data_json = { - 'name': pet_name, - 'ears': { - 'healthy': pet_healthy, - } + "name": pet_name, + "ears": { + "healthy": pet_healthy, + }, } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + headers=headers, + cookies=cookies, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) body = spec_validate_body(spec, request) - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] assert body.__class__.__name__ == pet_model assert body.name == pet_name - assert not hasattr(body, 'tag') - assert not hasattr(body, 'address') + assert not hasattr(body, "tag") + assert not hasattr(body, "address") def test_post_pets_raises_invalid_mimetype(self, spec): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" data_json = { - 'name': 'Cat', - 'tag': 'cats', + "name": "Cat", + "tag": "cats", } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, mimetype='text/html', - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + mimetype="text/html", + headers=headers, + cookies=cookies, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) @@ -818,24 +885,27 @@ def test_post_pets_raises_invalid_mimetype(self, spec): spec_validate_body(spec, request) def test_post_pets_missing_cookie(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" pet_healthy = True data_json = { - 'name': pet_name, - 'ears': { - 'healthy': pet_healthy, - } + "name": pet_name, + "ears": { + "healthy": pet_healthy, + }, } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, headers=headers, ) @@ -844,32 +914,35 @@ def test_post_pets_missing_cookie(self, spec, spec_dict): body = spec_validate_body(spec, request) - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] assert body.__class__.__name__ == pet_model assert body.name == pet_name - assert not hasattr(body, 'tag') - assert not hasattr(body, 'address') + assert not hasattr(body, "tag") + assert not hasattr(body, "address") def test_post_pets_missing_header(self, spec, spec_dict): - host_url = 'https://staging.gigantic-server.com/v1' - path_pattern = '/v1/pets' - pet_name = 'Cat' + host_url = "https://staging.gigantic-server.com/v1" + path_pattern = "/v1/pets" + pet_name = "Cat" pet_healthy = True data_json = { - 'name': pet_name, - 'ears': { - 'healthy': pet_healthy, - } + "name": pet_name, + "ears": { + "healthy": pet_healthy, + }, } data = json.dumps(data_json) cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, cookies=cookies, ) @@ -878,32 +951,37 @@ def test_post_pets_missing_header(self, spec, spec_dict): body = spec_validate_body(spec, request) - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] assert body.__class__.__name__ == pet_model assert body.name == pet_name - assert not hasattr(body, 'tag') - assert not hasattr(body, 'address') + assert not hasattr(body, "tag") + assert not hasattr(body, "address") def test_post_pets_raises_invalid_server_error(self, spec): - host_url = 'http://flowerstore.swagger.io/v1' - path_pattern = '/v1/pets' + host_url = "http://flowerstore.swagger.io/v1" + path_pattern = "/v1/pets" data_json = { - 'name': 'Cat', - 'tag': 'cats', + "name": "Cat", + "tag": "cats", } data = json.dumps(data_json) headers = { - 'api-key': '12345', + "api-key": "12345", } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - host_url, 'POST', '/pets', - path_pattern=path_pattern, data=data, mimetype='text/html', - headers=headers, cookies=cookies, + host_url, + "POST", + "/pets", + path_pattern=path_pattern, + data=data, + mimetype="text/html", + headers=headers, + cookies=cookies, ) with pytest.raises(ServerNotFound): @@ -913,13 +991,13 @@ def test_post_pets_raises_invalid_server_error(self, spec): spec_validate_body(spec, request) data_id = 1 - data_name = 'test' + data_name = "test" data_json = { - 'data': { - 'id': data_id, - 'name': data_name, - 'ears': { - 'healthy': True, + "data": { + "id": data_id, + "name": data_name, + "ears": { + "healthy": True, }, }, } @@ -930,18 +1008,21 @@ def test_post_pets_raises_invalid_server_error(self, spec): spec_validate_data(spec, request, response) def test_get_pet(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets/{petId}' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets/{petId}" view_args = { - 'petId': '1', + "petId": "1", } - auth = 'authuser' + auth = "authuser" headers = { - 'Authorization': f'Basic {auth}', + "Authorization": f"Basic {auth}", } request = MockRequest( - host_url, 'GET', '/pets/1', - path_pattern=path_pattern, view_args=view_args, + host_url, + "GET", + "/pets/1", + path_pattern=path_pattern, + view_args=view_args, headers=headers, ) @@ -949,7 +1030,7 @@ def test_get_pet(self, spec, response_validator): assert parameters == Parameters( path={ - 'petId': 1, + "petId": 1, } ) @@ -960,17 +1041,17 @@ def test_get_pet(self, spec, response_validator): security = spec_validate_security(spec, request) assert security == { - 'petstore_auth': auth, + "petstore_auth": auth, } data_id = 1 - data_name = 'test' + data_name = "test" data_json = { - 'data': { - 'id': data_id, - 'name': data_name, - 'ears': { - 'healthy': True, + "data": { + "id": data_id, + "name": data_name, + "ears": { + "healthy": True, }, }, } @@ -986,21 +1067,24 @@ def test_get_pet(self, spec, response_validator): assert response_result.data.data.name == data_name def test_get_pet_not_found(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets/{petId}' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets/{petId}" view_args = { - 'petId': '1', + "petId": "1", } request = MockRequest( - host_url, 'GET', '/pets/1', - path_pattern=path_pattern, view_args=view_args, + host_url, + "GET", + "/pets/1", + path_pattern=path_pattern, + view_args=view_args, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( path={ - 'petId': 1, + "petId": 1, } ) @@ -1009,12 +1093,12 @@ def test_get_pet_not_found(self, spec, response_validator): assert body is None code = 404 - message = 'Not found' - rootCause = 'Pet not found' + message = "Not found" + rootCause = "Pet not found" data_json = { - 'code': 404, - 'message': message, - 'rootCause': rootCause, + "code": 404, + "message": message, + "rootCause": rootCause, } data = json.dumps(data_json) response = MockResponse(data, status_code=404) @@ -1028,21 +1112,24 @@ def test_get_pet_not_found(self, spec, response_validator): assert response_result.data.rootCause == rootCause def test_get_pet_wildcard(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/pets/{petId}' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/pets/{petId}" view_args = { - 'petId': '1', + "petId": "1", } request = MockRequest( - host_url, 'GET', '/pets/1', - path_pattern=path_pattern, view_args=view_args, + host_url, + "GET", + "/pets/1", + path_pattern=path_pattern, + view_args=view_args, ) parameters = spec_validate_parameters(spec, request) assert parameters == Parameters( path={ - 'petId': 1, + "petId": 1, } ) @@ -1050,8 +1137,8 @@ def test_get_pet_wildcard(self, spec, response_validator): assert body is None - data = b'imagedata' - response = MockResponse(data, mimetype='image/png') + data = b"imagedata" + response = MockResponse(data, mimetype="image/png") with pytest.warns(UserWarning): response_result = response_validator.validate(request, response) @@ -1060,11 +1147,13 @@ def test_get_pet_wildcard(self, spec, response_validator): assert response_result.data == data def test_get_tags(self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" request = MockRequest( - host_url, 'GET', '/tags', + host_url, + "GET", + "/tags", path_pattern=path_pattern, ) @@ -1074,7 +1163,7 @@ def test_get_tags(self, spec, response_validator): assert parameters == Parameters() assert body is None - data_json = ['cats', 'birds'] + data_json = ["cats", "birds"] data = json.dumps(data_json) response = MockResponse(data) @@ -1084,19 +1173,22 @@ def test_get_tags(self, spec, response_validator): assert response_result.data == data_json def test_post_tags_extra_body_properties(self, spec, spec_dict): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' - pet_name = 'Dog' - alias = 'kitty' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" + pet_name = "Dog" + alias = "kitty" data_json = { - 'name': pet_name, - 'alias': alias, + "name": pet_name, + "alias": alias, } data = json.dumps(data_json) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1107,14 +1199,17 @@ def test_post_tags_extra_body_properties(self, spec, spec_dict): spec_validate_body(spec, request) def test_post_tags_empty_body(self, spec, spec_dict): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" data_json = {} data = json.dumps(data_json) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1125,14 +1220,17 @@ def test_post_tags_empty_body(self, spec, spec_dict): spec_validate_body(spec, request) def test_post_tags_wrong_property_type(self, spec): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" tag_name = 123 data = json.dumps(tag_name) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1142,19 +1240,21 @@ def test_post_tags_wrong_property_type(self, spec): with pytest.raises(InvalidSchemaValue): spec_validate_body(spec, request) - def test_post_tags_additional_properties( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' - pet_name = 'Dog' + def test_post_tags_additional_properties(self, spec, response_validator): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" + pet_name = "Dog" data_json = { - 'name': pet_name, + "name": pet_name, } data = json.dumps(data_json) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1165,14 +1265,14 @@ def test_post_tags_additional_properties( assert body.name == pet_name code = 400 - message = 'Bad request' - rootCause = 'Tag already exist' - additionalinfo = 'Tag Dog already exist' + message = "Bad request" + rootCause = "Tag already exist" + additionalinfo = "Tag Dog already exist" data_json = { - 'code': code, - 'message': message, - 'rootCause': rootCause, - 'additionalinfo': additionalinfo, + "code": code, + "message": message, + "rootCause": rootCause, + "additionalinfo": additionalinfo, } data = json.dumps(data_json) response = MockResponse(data, status_code=404) @@ -1186,21 +1286,23 @@ def test_post_tags_additional_properties( assert response_result.data.rootCause == rootCause assert response_result.data.additionalinfo == additionalinfo - def test_post_tags_created_now( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' - created = 'now' - pet_name = 'Dog' + def test_post_tags_created_now(self, spec, response_validator): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" + created = "now" + pet_name = "Dog" data_json = { - 'created': created, - 'name': pet_name, + "created": created, + "name": pet_name, } data = json.dumps(data_json) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1212,14 +1314,14 @@ def test_post_tags_created_now( assert body.name == pet_name code = 400 - message = 'Bad request' - rootCause = 'Tag already exist' - additionalinfo = 'Tag Dog already exist' + message = "Bad request" + rootCause = "Tag already exist" + additionalinfo = "Tag Dog already exist" data_json = { - 'code': 400, - 'message': 'Bad request', - 'rootCause': 'Tag already exist', - 'additionalinfo': 'Tag Dog already exist', + "code": 400, + "message": "Bad request", + "rootCause": "Tag already exist", + "additionalinfo": "Tag Dog already exist", } data = json.dumps(data_json) response = MockResponse(data, status_code=404) @@ -1233,21 +1335,23 @@ def test_post_tags_created_now( assert response_result.data.rootCause == rootCause assert response_result.data.additionalinfo == additionalinfo - def test_post_tags_created_datetime( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' - created = '2016-04-16T16:06:05Z' - pet_name = 'Dog' + def test_post_tags_created_datetime(self, spec, response_validator): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" + created = "2016-04-16T16:06:05Z" + pet_name = "Dog" data_json = { - 'created': created, - 'name': pet_name, + "created": created, + "name": pet_name, } data = json.dumps(data_json) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1259,14 +1363,14 @@ def test_post_tags_created_datetime( assert body.name == pet_name code = 400 - message = 'Bad request' - rootCause = 'Tag already exist' - additionalinfo = 'Tag Dog already exist' + message = "Bad request" + rootCause = "Tag already exist" + additionalinfo = "Tag Dog already exist" response_data_json = { - 'code': code, - 'message': message, - 'rootCause': rootCause, - 'additionalinfo': additionalinfo, + "code": code, + "message": message, + "rootCause": rootCause, + "additionalinfo": additionalinfo, } response_data = json.dumps(response_data_json) response = MockResponse(response_data, status_code=404) @@ -1288,21 +1392,23 @@ def test_post_tags_created_datetime( assert response_result.data.rootCause == rootCause assert response_result.data.additionalinfo == additionalinfo - def test_post_tags_created_invalid_type( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' - created = 'long time ago' - pet_name = 'Dog' + def test_post_tags_created_invalid_type(self, spec, response_validator): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" + created = "long time ago" + pet_name = "Dog" data_json = { - 'created': created, - 'name': pet_name, + "created": created, + "name": pet_name, } data = json.dumps(data_json) request = MockRequest( - host_url, 'POST', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "POST", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1312,15 +1418,15 @@ def test_post_tags_created_invalid_type( assert parameters == Parameters() code = 400 - message = 'Bad request' - correlationId = UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') - rootCause = 'Tag already exist' - additionalinfo = 'Tag Dog already exist' + message = "Bad request" + correlationId = UUID("a8098c1a-f86e-11da-bd1a-00112444be1e") + rootCause = "Tag already exist" + additionalinfo = "Tag Dog already exist" data_json = { - 'message': message, - 'correlationId': str(correlationId), - 'rootCause': rootCause, - 'additionalinfo': additionalinfo, + "message": message, + "correlationId": str(correlationId), + "rootCause": rootCause, + "additionalinfo": additionalinfo, } data = json.dumps(data_json) response = MockResponse(data, status_code=404) @@ -1335,18 +1441,20 @@ def test_post_tags_created_invalid_type( assert response_result.data.rootCause == rootCause assert response_result.data.additionalinfo == additionalinfo - def test_delete_tags_with_requestbody( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' + def test_delete_tags_with_requestbody(self, spec, response_validator): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" ids = [1, 2, 3] data_json = { - 'ids': ids, + "ids": ids, } data = json.dumps(data_json) request = MockRequest( - host_url, 'DELETE', '/tags', - path_pattern=path_pattern, data=data, + host_url, + "DELETE", + "/tags", + path_pattern=path_pattern, + data=data, ) parameters = spec_validate_parameters(spec, request) @@ -1358,7 +1466,7 @@ def test_delete_tags_with_requestbody( data = None headers = { - 'x-delete-confirm': 'true', + "x-delete-confirm": "true", } response = MockResponse(data, status_code=200, headers=headers) @@ -1371,15 +1479,16 @@ def test_delete_tags_with_requestbody( response_headers = spec_validate_headers(spec, request, response) assert response_headers == { - 'x-delete-confirm': True, + "x-delete-confirm": True, } - def test_delete_tags_no_requestbody( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' + def test_delete_tags_no_requestbody(self, spec, response_validator): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" request = MockRequest( - host_url, 'DELETE', '/tags', + host_url, + "DELETE", + "/tags", path_pattern=path_pattern, ) @@ -1390,11 +1499,14 @@ def test_delete_tags_no_requestbody( assert body is None def test_delete_tags_raises_missing_required_response_header( - self, spec, response_validator): - host_url = 'http://petstore.swagger.io/v1' - path_pattern = '/v1/tags' + self, spec, response_validator + ): + host_url = "http://petstore.swagger.io/v1" + path_pattern = "/v1/tags" request = MockRequest( - host_url, 'DELETE', '/tags', + host_url, + "DELETE", + "/tags", path_pattern=path_pattern, ) @@ -1411,6 +1523,6 @@ def test_delete_tags_raises_missing_required_response_header( response_result = response_validator.validate(request, response) assert response_result.errors == [ - MissingRequiredHeader(name='x-delete-confirm'), + MissingRequiredHeader(name="x-delete-confirm"), ] assert response_result.data is None diff --git a/tests/integration/validation/test_read_only_write_only.py b/tests/integration/validation/test_read_only_write_only.py index b38ca14c..b6dca0bf 100644 --- a/tests/integration/validation/test_read_only_write_only.py +++ b/tests/integration/validation/test_read_only_write_only.py @@ -3,10 +3,11 @@ import pytest from openapi_core.shortcuts import create_spec +from openapi_core.testing import MockRequest +from openapi_core.testing import MockResponse 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 +from openapi_core.validation.response.validators import ResponseValidator @pytest.fixture @@ -19,22 +20,24 @@ def request_validator(spec): return RequestValidator(spec) -@pytest.fixture(scope='class') +@pytest.fixture(scope="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: - def test_write_a_read_only_property(self, request_validator): - data = json.dumps({ - 'id': 10, - 'name': "Pedro", - }) + data = json.dumps( + { + "id": 10, + "name": "Pedro", + } + ) - request = MockRequest(host_url='', method='POST', - path='/users', data=data) + request = MockRequest( + host_url="", method="POST", path="/users", data=data + ) result = request_validator.validate(request) @@ -42,13 +45,14 @@ def test_write_a_read_only_property(self, request_validator): assert result.body is None def test_read_only_property_response(self, response_validator): - data = json.dumps({ - 'id': 10, - 'name': "Pedro", - }) + data = json.dumps( + { + "id": 10, + "name": "Pedro", + } + ) - request = MockRequest(host_url='', method='POST', - path='/users') + request = MockRequest(host_url="", method="POST", path="/users") response = MockResponse(data) @@ -56,39 +60,42 @@ def test_read_only_property_response(self, response_validator): assert not result.errors assert result.data == { - 'id': 10, - 'name': "Pedro", + "id": 10, + "name": "Pedro", } class TestWriteOnly: - def test_write_only_property(self, request_validator): - data = json.dumps({ - 'name': "Pedro", - 'hidden': False, - }) + data = json.dumps( + { + "name": "Pedro", + "hidden": False, + } + ) - request = MockRequest(host_url='', method='POST', - path='/users', data=data) + 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, + "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') + 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) diff --git a/tests/integration/validation/test_security_override.py b/tests/integration/validation/test_security_override.py index 76903f06..d6fabee7 100644 --- a/tests/integration/validation/test_security_override.py +++ b/tests/integration/validation/test_security_override.py @@ -3,9 +3,9 @@ import pytest from openapi_core.shortcuts import create_spec +from openapi_core.testing import MockRequest from openapi_core.validation.exceptions import InvalidSecurity from openapi_core.validation.request.validators import RequestValidator -from openapi_core.testing import MockRequest @pytest.fixture @@ -13,7 +13,7 @@ def request_validator(spec): return RequestValidator(spec) -@pytest.fixture(scope='class') +@pytest.fixture(scope="class") def spec(factory): spec_dict = factory.spec_from_file("data/v3.0/security_override.yaml") return create_spec(spec_dict) @@ -21,30 +21,29 @@ def spec(factory): class TestSecurityOverride: - host_url = 'http://petstore.swagger.io' + host_url = "http://petstore.swagger.io" - api_key = '12345' + api_key = "12345" @property def api_key_encoded(self): - api_key_bytes = self.api_key.encode('utf8') + api_key_bytes = self.api_key.encode("utf8") api_key_bytes_enc = b64encode(api_key_bytes) - return str(api_key_bytes_enc, 'utf8') + return str(api_key_bytes_enc, "utf8") def test_default(self, request_validator): - args = {'api_key': self.api_key} - request = MockRequest( - self.host_url, 'get', '/resource/one', args=args) + args = {"api_key": self.api_key} + request = MockRequest(self.host_url, "get", "/resource/one", args=args) result = request_validator.validate(request) assert not result.errors assert result.security == { - 'api_key': self.api_key, + "api_key": self.api_key, } def test_default_invalid(self, request_validator): - request = MockRequest(self.host_url, 'get', '/resource/one') + request = MockRequest(self.host_url, "get", "/resource/one") result = request_validator.validate(request) @@ -52,23 +51,23 @@ def test_default_invalid(self, request_validator): assert result.security is None def test_override(self, request_validator): - authorization = 'Basic ' + self.api_key_encoded + authorization = "Basic " + self.api_key_encoded headers = { - 'Authorization': authorization, + "Authorization": authorization, } request = MockRequest( - self.host_url, 'post', '/resource/one', headers=headers) + self.host_url, "post", "/resource/one", headers=headers + ) result = request_validator.validate(request) assert not result.errors assert result.security == { - 'petstore_auth': self.api_key_encoded, + "petstore_auth": self.api_key_encoded, } def test_override_invalid(self, request_validator): - request = MockRequest( - self.host_url, 'post', '/resource/one') + request = MockRequest(self.host_url, "post", "/resource/one") result = request_validator.validate(request) @@ -76,8 +75,7 @@ def test_override_invalid(self, request_validator): assert result.security is None def test_remove(self, request_validator): - request = MockRequest( - self.host_url, 'put', '/resource/one') + request = MockRequest(self.host_url, "put", "/resource/one") result = request_validator.validate(request) diff --git a/tests/integration/validation/test_validators.py b/tests/integration/validation/test_validators.py index 65e23b11..f974b9f5 100644 --- a/tests/integration/validation/test_validators.py +++ b/tests/integration/validation/test_validators.py @@ -1,23 +1,23 @@ -from base64 import b64encode import json +from base64 import b64encode + import pytest from openapi_core.casting.schemas.exceptions import CastError from openapi_core.deserializing.media_types.exceptions import ( MediaTypeDeserializeError, ) +from openapi_core.exceptions import MissingRequiredParameter +from openapi_core.exceptions import MissingRequiredRequestBody +from openapi_core.exceptions import MissingResponseContent from openapi_core.extensions.models.models import BaseModel -from openapi_core.exceptions import ( - MissingRequiredParameter, MissingRequiredRequestBody, - MissingResponseContent, -) from openapi_core.shortcuts import create_spec from openapi_core.templating.media_types.exceptions import MediaTypeNotFound -from openapi_core.templating.paths.exceptions import ( - PathNotFound, OperationNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound from openapi_core.templating.responses.exceptions import ResponseNotFound -from openapi_core.testing import MockRequest, MockResponse +from openapi_core.testing import MockRequest +from openapi_core.testing import MockResponse from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue from openapi_core.validation.exceptions import InvalidSecurity from openapi_core.validation.request.datatypes import Parameters @@ -27,30 +27,30 @@ class TestRequestValidator: - host_url = 'http://petstore.swagger.io' + host_url = "http://petstore.swagger.io" - api_key = '12345' + api_key = "12345" @property def api_key_encoded(self): - api_key_bytes = self.api_key.encode('utf8') + api_key_bytes = self.api_key.encode("utf8") api_key_bytes_enc = b64encode(api_key_bytes) - return str(api_key_bytes_enc, 'utf8') + return str(api_key_bytes_enc, "utf8") - @pytest.fixture(scope='session') + @pytest.fixture(scope="session") def spec_dict(self, factory): return factory.spec_from_file("data/v3.0/petstore.yaml") - @pytest.fixture(scope='session') + @pytest.fixture(scope="session") def spec(self, spec_dict): return create_spec(spec_dict) - @pytest.fixture(scope='session') + @pytest.fixture(scope="session") def validator(self, spec): return RequestValidator(spec, base_url=self.host_url) def test_request_server_error(self, validator): - request = MockRequest('http://petstore.invalid.net/v1', 'get', '/') + request = MockRequest("http://petstore.invalid.net/v1", "get", "/") result = validator.validate(request) @@ -60,7 +60,7 @@ def test_request_server_error(self, validator): assert result.parameters == Parameters() def test_invalid_path(self, validator): - request = MockRequest(self.host_url, 'get', '/v1') + request = MockRequest(self.host_url, "get", "/v1") result = validator.validate(request) @@ -70,7 +70,7 @@ def test_invalid_path(self, validator): assert result.parameters == Parameters() def test_invalid_operation(self, validator): - request = MockRequest(self.host_url, 'patch', '/v1/pets') + request = MockRequest(self.host_url, "patch", "/v1/pets") result = validator.validate(request) @@ -80,7 +80,7 @@ def test_invalid_operation(self, validator): assert result.parameters == Parameters() def test_missing_parameter(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') + request = MockRequest(self.host_url, "get", "/v1/pets") with pytest.warns(DeprecationWarning): result = validator.validate(request) @@ -89,16 +89,19 @@ def test_missing_parameter(self, validator): assert result.body is None assert result.parameters == Parameters( query={ - 'page': 1, - 'search': '', + "page": 1, + "search": "", }, ) def test_get_pets(self, validator): - args = {'limit': '10', 'ids': ['1', '2'], 'api_key': self.api_key} + args = {"limit": "10", "ids": ["1", "2"], "api_key": self.api_key} request = MockRequest( - self.host_url, 'get', '/v1/pets', - path_pattern='/v1/pets', args=args, + self.host_url, + "get", + "/v1/pets", + path_pattern="/v1/pets", + args=args, ) with pytest.warns(DeprecationWarning): @@ -108,25 +111,27 @@ def test_get_pets(self, validator): assert result.body is None assert result.parameters == Parameters( query={ - 'limit': 10, - 'page': 1, - 'search': '', - 'ids': [1, 2], + "limit": 10, + "page": 1, + "search": "", + "ids": [1, 2], }, ) assert result.security == { - 'api_key': self.api_key, + "api_key": self.api_key, } def test_get_pets_webob(self, validator): from webob.multidict import GetDict + request = MockRequest( - self.host_url, 'get', '/v1/pets', - path_pattern='/v1/pets', + self.host_url, + "get", + "/v1/pets", + path_pattern="/v1/pets", ) request.parameters.query = GetDict( - [('limit', '5'), ('ids', '1'), ('ids', '2')], - {} + [("limit", "5"), ("ids", "1"), ("ids", "2")], {} ) with pytest.warns(DeprecationWarning): @@ -136,24 +141,27 @@ def test_get_pets_webob(self, validator): assert result.body is None assert result.parameters == Parameters( query={ - 'limit': 5, - 'page': 1, - 'search': '', - 'ids': [1, 2], + "limit": 5, + "page": 1, + "search": "", + "ids": [1, 2], }, ) def test_missing_body(self, validator): headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - 'https://development.gigantic-server.com', 'post', '/v1/pets', - path_pattern='/v1/pets', - headers=headers, cookies=cookies, + "https://development.gigantic-server.com", + "post", + "/v1/pets", + path_pattern="/v1/pets", + headers=headers, + cookies=cookies, ) result = validator.validate(request) @@ -163,25 +171,30 @@ def test_missing_body(self, validator): assert result.body is None assert result.parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) def test_invalid_content_type(self, validator): data = "csv,data" headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - 'https://development.gigantic-server.com', 'post', '/v1/pets', - path_pattern='/v1/pets', mimetype='text/csv', data=data, - headers=headers, cookies=cookies, + "https://development.gigantic-server.com", + "post", + "/v1/pets", + path_pattern="/v1/pets", + mimetype="text/csv", + data=data, + headers=headers, + cookies=cookies, ) result = validator.validate(request) @@ -191,46 +204,50 @@ def test_invalid_content_type(self, validator): assert result.body is None assert result.parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) def test_invalid_complex_parameter(self, validator, spec_dict): - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "ears": { + "healthy": True, }, - 'ears': { - 'healthy': True, - } } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } userdata = { - 'name': 1, + "name": 1, } userdata_json = json.dumps(userdata) cookies = { - 'user': '123', - 'userdata': userdata_json, + "user": "123", + "userdata": userdata_json, } request = MockRequest( - 'https://development.gigantic-server.com', 'post', '/v1/pets', - path_pattern='/v1/pets', data=data, - headers=headers, cookies=cookies, + "https://development.gigantic-server.com", + "post", + "/v1/pets", + path_pattern="/v1/pets", + data=data, + headers=headers, + cookies=cookies, ) result = validator.validate(request) @@ -239,17 +256,17 @@ def test_invalid_complex_parameter(self, validator, spec_dict): assert type(result.errors[0]) == InvalidSchemaValue assert result.parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) assert result.security == {} - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] - address_model = schemas['Address']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] + address_model = schemas["Address"]["x-model"] assert result.body.__class__.__name__ == pet_model assert result.body.name == pet_name assert result.body.tag == pet_tag @@ -259,33 +276,37 @@ def test_invalid_complex_parameter(self, validator, spec_dict): assert result.body.address.city == pet_city def test_post_pets(self, validator, spec_dict): - pet_name = 'Cat' - pet_tag = 'cats' - pet_street = 'Piekna' - pet_city = 'Warsaw' + pet_name = "Cat" + pet_tag = "cats" + pet_street = "Piekna" + pet_city = "Warsaw" data_json = { - 'name': pet_name, - 'tag': pet_tag, - 'position': 2, - 'address': { - 'street': pet_street, - 'city': pet_city, + "name": pet_name, + "tag": pet_tag, + "position": 2, + "address": { + "street": pet_street, + "city": pet_city, + }, + "ears": { + "healthy": True, }, - 'ears': { - 'healthy': True, - } } data = json.dumps(data_json) headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - 'https://development.gigantic-server.com', 'post', '/v1/pets', - path_pattern='/v1/pets', data=data, - headers=headers, cookies=cookies, + "https://development.gigantic-server.com", + "post", + "/v1/pets", + path_pattern="/v1/pets", + data=data, + headers=headers, + cookies=cookies, ) result = validator.validate(request) @@ -293,17 +314,17 @@ def test_post_pets(self, validator, spec_dict): assert result.errors == [] assert result.parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) assert result.security == {} - schemas = spec_dict['components']['schemas'] - pet_model = schemas['PetCreate']['x-model'] - address_model = schemas['Address']['x-model'] + schemas = spec_dict["components"]["schemas"] + pet_model = schemas["PetCreate"]["x-model"] + address_model = schemas["Address"]["x-model"] assert result.body.__class__.__name__ == pet_model assert result.body.name == pet_name assert result.body.tag == pet_tag @@ -313,18 +334,22 @@ def test_post_pets(self, validator, spec_dict): assert result.body.address.city == pet_city def test_post_pets_plain_no_schema(self, validator, spec_dict): - data = 'plain text' + data = "plain text" headers = { - 'api-key': self.api_key_encoded, + "api-key": self.api_key_encoded, } cookies = { - 'user': '123', + "user": "123", } request = MockRequest( - 'https://development.gigantic-server.com', 'post', '/v1/pets', - path_pattern='/v1/pets', data=data, - headers=headers, cookies=cookies, - mimetype='text/plain', + "https://development.gigantic-server.com", + "post", + "/v1/pets", + path_pattern="/v1/pets", + data=data, + headers=headers, + cookies=cookies, + mimetype="text/plain", ) with pytest.warns(UserWarning): @@ -333,10 +358,10 @@ def test_post_pets_plain_no_schema(self, validator, spec_dict): assert result.errors == [] assert result.parameters == Parameters( header={ - 'api-key': self.api_key, + "api-key": self.api_key, }, cookie={ - 'user': 123, + "user": 123, }, ) assert result.security == {} @@ -344,25 +369,33 @@ def test_post_pets_plain_no_schema(self, validator, spec_dict): def test_get_pet_unauthorized(self, validator): request = MockRequest( - self.host_url, 'get', '/v1/pets/1', - path_pattern='/v1/pets/{petId}', view_args={'petId': '1'}, + self.host_url, + "get", + "/v1/pets/1", + path_pattern="/v1/pets/{petId}", + view_args={"petId": "1"}, ) result = validator.validate(request) - assert result.errors == [InvalidSecurity(), ] + assert result.errors == [ + InvalidSecurity(), + ] assert result.body is None assert result.parameters == Parameters() assert result.security is None def test_get_pet(self, validator): - authorization = 'Basic ' + self.api_key_encoded + authorization = "Basic " + self.api_key_encoded headers = { - 'Authorization': authorization, + "Authorization": authorization, } request = MockRequest( - self.host_url, 'get', '/v1/pets/1', - path_pattern='/v1/pets/{petId}', view_args={'petId': '1'}, + self.host_url, + "get", + "/v1/pets/1", + path_pattern="/v1/pets/{petId}", + view_args={"petId": "1"}, headers=headers, ) @@ -372,17 +405,16 @@ def test_get_pet(self, validator): assert result.body is None assert result.parameters == Parameters( path={ - 'petId': 1, + "petId": 1, }, ) assert result.security == { - 'petstore_auth': self.api_key_encoded, + "petstore_auth": self.api_key_encoded, } class TestPathItemParamsValidator: - - @pytest.fixture(scope='session') + @pytest.fixture(scope="session") def spec_dict(self): return { "openapi": "3.0.0", @@ -404,25 +436,23 @@ def spec_dict(self): ], "get": { "responses": { - "default": { - "description": "Return the resource." - } + "default": {"description": "Return the resource."} } - } + }, } - } + }, } - @pytest.fixture(scope='session') + @pytest.fixture(scope="session") def spec(self, spec_dict): return create_spec(spec_dict) - @pytest.fixture(scope='session') + @pytest.fixture(scope="session") def validator(self, spec): - return RequestValidator(spec, base_url='http://example.com') + return RequestValidator(spec, base_url="http://example.com") def test_request_missing_param(self, validator): - request = MockRequest('http://example.com', 'get', '/resource') + request = MockRequest("http://example.com", "get", "/resource") result = validator.validate(request) assert len(result.errors) == 1 @@ -432,8 +462,10 @@ def test_request_missing_param(self, validator): def test_request_invalid_param(self, validator): request = MockRequest( - 'http://example.com', 'get', '/resource', - args={'resId': 'invalid'}, + "http://example.com", + "get", + "/resource", + args={"resId": "invalid"}, ) result = validator.validate(request) @@ -444,14 +476,16 @@ def test_request_invalid_param(self, validator): def test_request_valid_param(self, validator): request = MockRequest( - 'http://example.com', 'get', '/resource', - args={'resId': '10'}, + "http://example.com", + "get", + "/resource", + args={"resId": "10"}, ) result = validator.validate(request) assert len(result.errors) == 0 assert result.body is None - assert result.parameters == Parameters(query={'resId': 10}) + assert result.parameters == Parameters(query={"resId": 10}) def test_request_override_param(self, spec_dict): # override path parameter on operation @@ -467,8 +501,9 @@ def test_request_override_param(self, spec_dict): } ] validator = RequestValidator( - create_spec(spec_dict), base_url='http://example.com') - request = MockRequest('http://example.com', 'get', '/resource') + create_spec(spec_dict), base_url="http://example.com" + ) + request = MockRequest("http://example.com", "get", "/resource") result = validator.validate(request) assert len(result.errors) == 0 @@ -490,8 +525,9 @@ def test_request_override_param_uniqueness(self, spec_dict): } ] validator = RequestValidator( - create_spec(spec_dict), base_url='http://example.com') - request = MockRequest('http://example.com', 'get', '/resource') + create_spec(spec_dict), base_url="http://example.com" + ) + request = MockRequest("http://example.com", "get", "/resource") result = validator.validate(request) assert len(result.errors) == 1 @@ -502,7 +538,7 @@ def test_request_override_param_uniqueness(self, spec_dict): class TestResponseValidator: - host_url = 'http://petstore.swagger.io' + host_url = "http://petstore.swagger.io" @pytest.fixture def spec_dict(self, factory): @@ -517,8 +553,8 @@ def validator(self, spec): return ResponseValidator(spec, base_url=self.host_url) def test_invalid_server(self, validator): - request = MockRequest('http://petstore.invalid.net/v1', 'get', '/') - response = MockResponse('Not Found', status_code=404) + request = MockRequest("http://petstore.invalid.net/v1", "get", "/") + response = MockResponse("Not Found", status_code=404) result = validator.validate(request, response) @@ -528,8 +564,8 @@ def test_invalid_server(self, validator): assert result.headers == {} def test_invalid_operation(self, validator): - request = MockRequest(self.host_url, 'patch', '/v1/pets') - response = MockResponse('Not Found', status_code=404) + request = MockRequest(self.host_url, "patch", "/v1/pets") + response = MockResponse("Not Found", status_code=404) result = validator.validate(request, response) @@ -539,8 +575,8 @@ def test_invalid_operation(self, validator): assert result.headers == {} def test_invalid_response(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') - response = MockResponse('Not Found', status_code=409) + request = MockRequest(self.host_url, "get", "/v1/pets") + response = MockResponse("Not Found", status_code=409) result = validator.validate(request, response) @@ -550,8 +586,8 @@ def test_invalid_response(self, validator): assert result.headers == {} def test_invalid_content_type(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') - response = MockResponse('Not Found', mimetype='text/csv') + request = MockRequest(self.host_url, "get", "/v1/pets") + response = MockResponse("Not Found", mimetype="text/csv") result = validator.validate(request, response) @@ -561,7 +597,7 @@ def test_invalid_content_type(self, validator): assert result.headers == {} def test_missing_body(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') + request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse(None) result = validator.validate(request, response) @@ -572,7 +608,7 @@ def test_missing_body(self, validator): assert result.headers == {} def test_invalid_media_type(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') + request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse("abcde") result = validator.validate(request, response) @@ -583,7 +619,7 @@ def test_invalid_media_type(self, validator): assert result.headers == {} def test_invalid_media_type_value(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') + request = MockRequest(self.host_url, "get", "/v1/pets") response = MockResponse("{}") result = validator.validate(request, response) @@ -594,13 +630,10 @@ def test_invalid_media_type_value(self, validator): assert result.headers == {} def test_invalid_value(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/tags') + request = MockRequest(self.host_url, "get", "/v1/tags") response_json = { - 'data': [ - { - 'id': 1, - 'name': 'Sparky' - }, + "data": [ + {"id": 1, "name": "Sparky"}, ], } response_data = json.dumps(response_json) @@ -614,14 +647,14 @@ def test_invalid_value(self, validator): assert result.headers == {} def test_get_pets(self, validator): - request = MockRequest(self.host_url, 'get', '/v1/pets') + request = MockRequest(self.host_url, "get", "/v1/pets") response_json = { - 'data': [ + "data": [ { - 'id': 1, - 'name': 'Sparky', - 'ears': { - 'healthy': True, + "id": 1, + "name": "Sparky", + "ears": { + "healthy": True, }, }, ], @@ -635,5 +668,5 @@ def test_get_pets(self, validator): assert isinstance(result.data, BaseModel) assert len(result.data.data) == 1 assert result.data.data[0].id == 1 - assert result.data.data[0].name == 'Sparky' + assert result.data.data[0].name == "Sparky" assert result.headers == {} diff --git a/tests/unit/casting/test_schema_casters.py b/tests/unit/casting/test_schema_casters.py index a2aaa445..78ed9b9f 100644 --- a/tests/unit/casting/test_schema_casters.py +++ b/tests/unit/casting/test_schema_casters.py @@ -6,31 +6,31 @@ class TestSchemaCaster: - @pytest.fixture def caster_factory(self): def create_caster(schema): return SchemaCastersFactory().create(schema) + return create_caster def test_array_invalid_type(self, caster_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, } schema = SpecPath.from_spec(spec) - value = ['test', 'test2'] + value = ["test", "test2"] with pytest.raises(CastError): caster_factory(schema)(value) def test_array_invalid_value(self, caster_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, } schema = SpecPath.from_spec(spec) diff --git a/tests/unit/contrib/django/test_django.py b/tests/unit/contrib/django/test_django.py index bd39d277..8d5b8aa9 100644 --- a/tests/unit/contrib/django/test_django.py +++ b/tests/unit/contrib/django/test_django.py @@ -1,76 +1,78 @@ import pytest from werkzeug.datastructures import Headers -from openapi_core.contrib.django import ( - DjangoOpenAPIRequest, DjangoOpenAPIResponse, -) +from openapi_core.contrib.django import DjangoOpenAPIRequest +from openapi_core.contrib.django import DjangoOpenAPIResponse from openapi_core.validation.request.datatypes import RequestParameters class BaseTestDjango: - - @pytest.fixture(autouse=True, scope='module') + @pytest.fixture(autouse=True, scope="module") def django_settings(self): import django from django.conf import settings from django.contrib import admin - from django.urls import path, re_path + from django.urls import path + from django.urls import re_path if settings.configured: from django.utils.functional import empty + settings._wrapped = empty settings.configure( - SECRET_KEY='secretkey', + SECRET_KEY="secretkey", ALLOWED_HOSTS=[ - 'testserver', + "testserver", ], INSTALLED_APPS=[ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.messages', - 'django.contrib.sessions', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.messages", + "django.contrib.sessions", ], MIDDLEWARE=[ - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - ] + "django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + ], ) django.setup() settings.ROOT_URLCONF = ( - path('admin/', admin.site.urls), - re_path('^test/test-regexp/$', lambda d: None) + path("admin/", admin.site.urls), + re_path("^test/test-regexp/$", lambda d: None), ) @pytest.fixture def request_factory(self): from django.test.client import RequestFactory + return RequestFactory() @pytest.fixture def response_factory(self): from django.http import HttpResponse - def create(content=b'', status_code=None): + def create(content=b"", status_code=None): return HttpResponse(content, status=status_code) return create class TestDjangoOpenAPIRequest(BaseTestDjango): - def test_no_resolver(self, request_factory): - request = request_factory.get('/admin/') + request = request_factory.get("/admin/") openapi_request = DjangoOpenAPIRequest(request) path = {} query = {} - headers = Headers({ - 'Cookie': '', - }) + headers = Headers( + { + "Cookie": "", + } + ) cookies = {} assert openapi_request.parameters == RequestParameters( path=path, @@ -79,23 +81,28 @@ def test_no_resolver(self, request_factory): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - request._current_scheme_host + request.path + assert ( + openapi_request.full_url_pattern + == request._current_scheme_host + request.path + ) assert openapi_request.body == request.body assert openapi_request.mimetype == request.content_type def test_simple(self, request_factory): from django.urls import resolve - request = request_factory.get('/admin/') - request.resolver_match = resolve('/admin/') + + request = request_factory.get("/admin/") + request.resolver_match = resolve("/admin/") openapi_request = DjangoOpenAPIRequest(request) path = {} query = {} - headers = Headers({ - 'Cookie': '', - }) + headers = Headers( + { + "Cookie": "", + } + ) cookies = {} assert openapi_request.parameters == RequestParameters( path=path, @@ -104,25 +111,30 @@ def test_simple(self, request_factory): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - request._current_scheme_host + request.path + assert ( + openapi_request.full_url_pattern + == request._current_scheme_host + request.path + ) assert openapi_request.body == request.body assert openapi_request.mimetype == request.content_type def test_url_rule(self, request_factory): from django.urls import resolve - request = request_factory.get('/admin/auth/group/1/') - request.resolver_match = resolve('/admin/auth/group/1/') + + request = request_factory.get("/admin/auth/group/1/") + request.resolver_match = resolve("/admin/auth/group/1/") openapi_request = DjangoOpenAPIRequest(request) path = { - 'object_id': '1', + "object_id": "1", } query = {} - headers = Headers({ - 'Cookie': '', - }) + headers = Headers( + { + "Cookie": "", + } + ) cookies = {} assert openapi_request.parameters == RequestParameters( path=path, @@ -131,23 +143,28 @@ def test_url_rule(self, request_factory): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - request._current_scheme_host + "/admin/auth/group/{object_id}/" + assert ( + openapi_request.full_url_pattern + == request._current_scheme_host + "/admin/auth/group/{object_id}/" + ) assert openapi_request.body == request.body assert openapi_request.mimetype == request.content_type def test_url_regexp_pattern(self, request_factory): from django.urls import resolve - request = request_factory.get('/test/test-regexp/') - request.resolver_match = resolve('/test/test-regexp/') + + request = request_factory.get("/test/test-regexp/") + request.resolver_match = resolve("/test/test-regexp/") openapi_request = DjangoOpenAPIRequest(request) path = {} query = {} - headers = Headers({ - 'Cookie': '', - }) + headers = Headers( + { + "Cookie": "", + } + ) cookies = {} assert openapi_request.parameters == RequestParameters( path=path, @@ -156,26 +173,27 @@ def test_url_regexp_pattern(self, request_factory): cookie=cookies, ) assert openapi_request.method == request.method.lower() - assert openapi_request.full_url_pattern == \ - request._current_scheme_host + "/test/test-regexp/" + assert ( + openapi_request.full_url_pattern + == request._current_scheme_host + "/test/test-regexp/" + ) assert openapi_request.body == request.body assert openapi_request.mimetype == request.content_type class TestDjangoOpenAPIResponse(BaseTestDjango): - def test_stream_response(self, response_factory): response = response_factory() - response.writelines(['foo\n', 'bar\n', 'baz\n']) + response.writelines(["foo\n", "bar\n", "baz\n"]) openapi_response = DjangoOpenAPIResponse(response) - assert openapi_response.data == b'foo\nbar\nbaz\n' + assert openapi_response.data == b"foo\nbar\nbaz\n" assert openapi_response.status_code == response.status_code assert openapi_response.mimetype == response["Content-Type"] def test_redirect_response(self, response_factory): - response = response_factory('/redirected/', status_code=302) + response = response_factory("/redirected/", status_code=302) openapi_response = DjangoOpenAPIResponse(response) diff --git a/tests/unit/deserializing/test_media_types_deserializers.py b/tests/unit/deserializing/test_media_types_deserializers.py index 52f7e5a4..246f656d 100644 --- a/tests/unit/deserializing/test_media_types_deserializers.py +++ b/tests/unit/deserializing/test_media_types_deserializers.py @@ -7,17 +7,18 @@ class TestMediaTypeDeserializer: - @pytest.fixture def deserializer_factory(self): def create_deserializer(media_type, custom_deserializers=None): return MediaTypeDeserializersFactory( - custom_deserializers=custom_deserializers).create(media_type) + custom_deserializers=custom_deserializers + ).create(media_type) + return create_deserializer def test_unsupported(self, deserializer_factory): - mimetype = 'application/unsupported' - value = '' + mimetype = "application/unsupported" + value = "" with pytest.warns(UserWarning): result = deserializer_factory(mimetype)(value) @@ -25,14 +26,14 @@ def test_unsupported(self, deserializer_factory): assert result == value def test_json_empty(self, deserializer_factory): - mimetype = 'application/json' - value = '' + mimetype = "application/json" + value = "" with pytest.raises(DeserializeError): deserializer_factory(mimetype)(value) def test_json_empty_object(self, deserializer_factory): - mimetype = 'application/json' + mimetype = "application/json" value = "{}" result = deserializer_factory(mimetype)(value) @@ -40,56 +41,58 @@ def test_json_empty_object(self, deserializer_factory): assert result == {} def test_urlencoded_form_empty(self, deserializer_factory): - mimetype = 'application/x-www-form-urlencoded' - value = '' + mimetype = "application/x-www-form-urlencoded" + value = "" result = deserializer_factory(mimetype)(value) assert result == {} def test_urlencoded_form_simple(self, deserializer_factory): - mimetype = 'application/x-www-form-urlencoded' - value = 'param1=test' + mimetype = "application/x-www-form-urlencoded" + value = "param1=test" result = deserializer_factory(mimetype)(value) - assert result == {'param1': 'test'} + assert result == {"param1": "test"} - @pytest.mark.parametrize('value', [b'', '']) + @pytest.mark.parametrize("value", [b"", ""]) def test_data_form_empty(self, deserializer_factory, value): - mimetype = 'multipart/form-data' + mimetype = "multipart/form-data" result = deserializer_factory(mimetype)(value) assert result == {} def test_data_form_simple(self, deserializer_factory): - mimetype = 'multipart/form-data' + mimetype = "multipart/form-data" value = ( b'Content-Type: multipart/form-data; boundary="' b'===============2872712225071193122=="\n' - b'MIME-Version: 1.0\n\n' - b'--===============2872712225071193122==\n' - b'Content-Type: text/plain\nMIME-Version: 1.0\n' + b"MIME-Version: 1.0\n\n" + b"--===============2872712225071193122==\n" + b"Content-Type: text/plain\nMIME-Version: 1.0\n" b'Content-Disposition: form-data; name="param1"\n\ntest\n' - b'--===============2872712225071193122==--\n' + b"--===============2872712225071193122==--\n" ) result = deserializer_factory(mimetype)(value) - assert result == {'param1': b'test'} + assert result == {"param1": b"test"} def test_custom_simple(self, deserializer_factory): - custom_mimetype = 'application/custom' + custom_mimetype = "application/custom" value = "{}" def custom_deserializer(value): - return 'custom' + return "custom" + custom_deserializers = { custom_mimetype: custom_deserializer, } result = deserializer_factory( - custom_mimetype, custom_deserializers=custom_deserializers)(value) + custom_mimetype, custom_deserializers=custom_deserializers + )(value) - assert result == 'custom' + assert result == "custom" diff --git a/tests/unit/deserializing/test_parameters_deserializers.py b/tests/unit/deserializing/test_parameters_deserializers.py index 9bb80f90..b51444c6 100644 --- a/tests/unit/deserializing/test_parameters_deserializers.py +++ b/tests/unit/deserializing/test_parameters_deserializers.py @@ -1,30 +1,26 @@ import pytest -from openapi_core.deserializing.parameters.factories import ( - ParameterDeserializersFactory, -) from openapi_core.deserializing.parameters.exceptions import ( EmptyQueryParameterValue, ) +from openapi_core.deserializing.parameters.factories import ( + ParameterDeserializersFactory, +) from openapi_core.spec.paths import SpecPath class TestParameterDeserializer: - @pytest.fixture def deserializer_factory(self): def create_deserializer(param): return ParameterDeserializersFactory().create(param) + return create_deserializer def test_unsupported(self, deserializer_factory): - spec = { - 'name': 'param', - 'in': 'header', - 'style': 'unsupported' - } + spec = {"name": "param", "in": "header", "style": "unsupported"} param = SpecPath.from_spec(spec) - value = '' + value = "" with pytest.warns(UserWarning): result = deserializer_factory(param)(value) @@ -33,22 +29,22 @@ def test_unsupported(self, deserializer_factory): def test_query_empty(self, deserializer_factory): spec = { - 'name': 'param', - 'in': 'query', + "name": "param", + "in": "query", } param = SpecPath.from_spec(spec) - value = '' + value = "" with pytest.raises(EmptyQueryParameterValue): deserializer_factory(param)(value) def test_query_valid(self, deserializer_factory): spec = { - 'name': 'param', - 'in': 'query', + "name": "param", + "in": "query", } param = SpecPath.from_spec(spec) - value = 'test' + value = "test" result = deserializer_factory(param)(value) diff --git a/tests/unit/extensions/test_models.py b/tests/unit/extensions/test_models.py index d5f6681e..5878b62d 100644 --- a/tests/unit/extensions/test_models.py +++ b/tests/unit/extensions/test_models.py @@ -1,10 +1,10 @@ import pytest -from openapi_core.extensions.models.models import BaseModel, Model +from openapi_core.extensions.models.models import BaseModel +from openapi_core.extensions.models.models import Model class TestBaseModelDict: - def test_not_implemented(self): model = BaseModel() @@ -13,7 +13,6 @@ def test_not_implemented(self): class TestModelDict: - def test_dict_empty(self): model = Model() @@ -23,8 +22,8 @@ def test_dict_empty(self): def test_dict(self): properties = { - 'prop1': 'value1', - 'prop2': 'value2', + "prop1": "value1", + "prop2": "value2", } model = Model(properties) @@ -33,9 +32,9 @@ def test_dict(self): assert result == properties def test_attribute(self): - prop_value = 'value1' + prop_value = "value1" properties = { - 'prop1': prop_value, + "prop1": prop_value, } model = Model(properties) diff --git a/tests/unit/schema/test_schema_parameters.py b/tests/unit/schema/test_schema_parameters.py index 4728ebd7..f8638490 100644 --- a/tests/unit/schema/test_schema_parameters.py +++ b/tests/unit/schema/test_schema_parameters.py @@ -1,43 +1,49 @@ import pytest -from openapi_core.schema.parameters import get_style, get_explode +from openapi_core.schema.parameters import get_explode +from openapi_core.schema.parameters import get_style from openapi_core.spec.paths import SpecPath class TestGetStyle: - - @pytest.mark.parametrize('location,expected', [ - ('query', 'form'), - ('path', 'simple'), - ('header', 'simple'), - ('cookie', 'form'), - ]) + @pytest.mark.parametrize( + "location,expected", + [ + ("query", "form"), + ("path", "simple"), + ("header", "simple"), + ("cookie", "form"), + ], + ) def test_defaults(self, location, expected): spec = { - 'name': 'default', - 'in': location, + "name": "default", + "in": location, } param = SpecPath.from_spec(spec) result = get_style(param) assert result == expected - @pytest.mark.parametrize('style,location', [ - ('matrix', 'path'), - ('label', 'apth'), - ('form', 'query'), - ('form', 'cookie'), - ('simple', 'path'), - ('simple', 'header'), - ('spaceDelimited', 'query'), - ('pipeDelimited', 'query'), - ('deepObject', 'query'), - ]) + @pytest.mark.parametrize( + "style,location", + [ + ("matrix", "path"), + ("label", "apth"), + ("form", "query"), + ("form", "cookie"), + ("simple", "path"), + ("simple", "header"), + ("spaceDelimited", "query"), + ("pipeDelimited", "query"), + ("deepObject", "query"), + ], + ) def test_defined(self, style, location): spec = { - 'name': 'default', - 'in': location, - 'style': style, + "name": "default", + "in": location, + "style": style, } param = SpecPath.from_spec(spec) result = get_style(param) @@ -46,55 +52,70 @@ def test_defined(self, style, location): class TestGetExplode: - - @pytest.mark.parametrize('style,location', [ - ('matrix', 'path'), - ('label', 'path'), - ('simple', 'path'), - ('spaceDelimited', 'query'), - ('pipeDelimited', 'query'), - ('deepObject', 'query'), - ]) + @pytest.mark.parametrize( + "style,location", + [ + ("matrix", "path"), + ("label", "path"), + ("simple", "path"), + ("spaceDelimited", "query"), + ("pipeDelimited", "query"), + ("deepObject", "query"), + ], + ) def test_defaults_false(self, style, location): spec = { - 'name': 'default', - 'in': location, - 'style': style, + "name": "default", + "in": location, + "style": style, } param = SpecPath.from_spec(spec) result = get_explode(param) assert result is False - @pytest.mark.parametrize('location', ['query', 'cookie']) + @pytest.mark.parametrize("location", ["query", "cookie"]) def test_defaults_true(self, location): spec = { - 'name': 'default', - 'in': location, - 'style': 'form', + "name": "default", + "in": location, + "style": "form", } param = SpecPath.from_spec(spec) result = get_explode(param) assert result is True - @pytest.mark.parametrize('location', ['path', 'query', 'cookie', 'header']) - @pytest.mark.parametrize('style', [ - 'matrix', 'label', 'form', 'form', 'simple', 'spaceDelimited', - 'pipeDelimited', 'deepObject', - ]) - @pytest.mark.parametrize('schema_type', [ - 'string', 'array' 'object', - ]) - @pytest.mark.parametrize('explode', [False, True]) + @pytest.mark.parametrize("location", ["path", "query", "cookie", "header"]) + @pytest.mark.parametrize( + "style", + [ + "matrix", + "label", + "form", + "form", + "simple", + "spaceDelimited", + "pipeDelimited", + "deepObject", + ], + ) + @pytest.mark.parametrize( + "schema_type", + [ + "string", + "array" "object", + ], + ) + @pytest.mark.parametrize("explode", [False, True]) def test_defined(self, location, style, schema_type, explode): spec = { - 'name': 'default', - 'in': location, - 'explode': explode, - 'schema': { - 'type': schema_type, - } + "name": "default", + "in": location, + "explode": explode, + "schema": { + "type": schema_type, + }, } param = SpecPath.from_spec(spec) result = get_explode(param) diff --git a/tests/unit/security/test_providers.py b/tests/unit/security/test_providers.py index 755ab94f..560357f4 100644 --- a/tests/unit/security/test_providers.py +++ b/tests/unit/security/test_providers.py @@ -6,29 +6,30 @@ class TestHttpProvider: - @pytest.mark.parametrize( - 'header', - ['authorization', 'Authorization', 'AUTHORIZATION'], + "header", + ["authorization", "Authorization", "AUTHORIZATION"], ) @pytest.mark.parametrize( - 'scheme', - ['basic', 'bearer', 'digest'], + "scheme", + ["basic", "bearer", "digest"], ) def test_header(self, header, scheme): """Tests HttpProvider against Issue29427 https://bugs.python.org/issue29427 """ spec = { - 'type': 'http', - 'scheme': scheme, + "type": "http", + "scheme": scheme, } - value = 'MQ' + value = "MQ" headers = { - header: ' '.join([scheme.title(), value]), + header: " ".join([scheme.title(), value]), } request = MockRequest( - 'http://localhost', 'GET', '/pets', + "http://localhost", + "GET", + "/pets", headers=headers, ) scheme = SpecPath.from_spec(spec) diff --git a/tests/unit/templating/test_paths_finders.py b/tests/unit/templating/test_paths_finders.py index a30109d8..cfbc68d0 100644 --- a/tests/unit/templating/test_paths_finders.py +++ b/tests/unit/templating/test_paths_finders.py @@ -2,16 +2,16 @@ from openapi_core.spec.paths import SpecPath from openapi_core.templating.datatypes import TemplateResult -from openapi_core.templating.paths.exceptions import ( - PathNotFound, OperationNotFound, ServerNotFound, -) +from openapi_core.templating.paths.exceptions import OperationNotFound +from openapi_core.templating.paths.exceptions import PathNotFound +from openapi_core.templating.paths.exceptions import ServerNotFound from openapi_core.templating.paths.finders import PathFinder from openapi_core.testing import MockRequest class BaseTestSimpleServer: - server_url = 'http://petstore.swagger.io' + server_url = "http://petstore.swagger.io" @pytest.fixture def server_variable(self): @@ -28,37 +28,39 @@ def server_variables(self, server_variable): @pytest.fixture def server(self, server_variables): server = { - 'url': self.server_url, + "url": self.server_url, } if server_variables: - server['variables'] = server_variables + server["variables"] = server_variables return server @pytest.fixture def servers(self, server): - return [server, ] + return [ + server, + ] class BaseTestVariableServer(BaseTestSimpleServer): - server_url = 'http://petstore.swagger.io/{version}' - server_variable_name = 'version' - server_variable_default = 'v1' - server_variable_enum = ['v1', 'v2'] + server_url = "http://petstore.swagger.io/{version}" + server_variable_name = "version" + server_variable_default = "v1" + server_variable_enum = ["v1", "v2"] @pytest.fixture def server_variable(self): return { self.server_variable_name: { - 'default': self.server_variable_default, - 'enum': self.server_variable_enum, + "default": self.server_variable_default, + "enum": self.server_variable_enum, } } class BaseTestSimplePath: - path_name = '/resource' + path_name = "/resource" @pytest.fixture def path(self, operations): @@ -73,56 +75,58 @@ def paths(self, path): class BaseTestVariablePath(BaseTestSimplePath): - path_name = '/resource/{resource_id}' - path_parameter_name = 'resource_id' + path_name = "/resource/{resource_id}" + path_parameter_name = "resource_id" @pytest.fixture def parameter(self): return { - 'name': self.path_parameter_name, - 'in': 'path', + "name": self.path_parameter_name, + "in": "path", } @pytest.fixture def parameters(self, parameter): - return [parameter, ] + return [ + parameter, + ] @pytest.fixture def path(self, operations, parameters): path = operations.copy() - path['parameters'] = parameters + path["parameters"] = parameters return path class BaseTestSpecServer: - location = 'spec' + location = "spec" @pytest.fixture def info(self): return { - 'title': 'Test schema', - 'version': '1.0', + "title": "Test schema", + "version": "1.0", } @pytest.fixture def operation(self): return { - 'responses': [], + "responses": [], } @pytest.fixture def operations(self, operation): return { - 'get': operation, + "get": operation, } @pytest.fixture def spec(self, info, paths, servers): spec = { - 'info': info, - 'servers': servers, - 'paths': paths, + "info": info, + "servers": servers, + "paths": paths, } return SpecPath.from_spec(spec) @@ -133,329 +137,409 @@ def finder(self, spec): class BaseTestPathServer(BaseTestSpecServer): - location = 'path' + location = "path" @pytest.fixture def path(self, operations, servers): path = operations.copy() - path['servers'] = servers + path["servers"] = servers return path @pytest.fixture def spec(self, info, paths): spec = { - 'info': info, - 'paths': paths, + "info": info, + "paths": paths, } return SpecPath.from_spec(spec) class BaseTestOperationServer(BaseTestSpecServer): - location = 'operation' + location = "operation" @pytest.fixture def operation(self, servers): return { - 'responses': [], - 'servers': servers, + "responses": [], + "servers": servers, } @pytest.fixture def spec(self, info, paths): spec = { - 'info': info, - 'paths': paths, + "info": info, + "paths": paths, } return SpecPath.from_spec(spec) class BaseTestServerNotFound: - @pytest.fixture def servers(self): return [] @pytest.mark.xfail(reason="returns default server") def test_raises(self, finder): - request_uri = '/resource' - request = MockRequest( - 'http://petstore.swagger.io', 'get', request_uri) + request_uri = "/resource" + request = MockRequest("http://petstore.swagger.io", "get", request_uri) with pytest.raises(ServerNotFound): finder.find(request) class BaseTestOperationNotFound: - @pytest.fixture def operations(self): return {} def test_raises(self, finder): - request_uri = '/resource' - request = MockRequest( - 'http://petstore.swagger.io', 'get', request_uri) + request_uri = "/resource" + request = MockRequest("http://petstore.swagger.io", "get", request_uri) with pytest.raises(OperationNotFound): finder.find(request) class BaseTestValid: - def test_simple(self, finder, spec): - request_uri = '/resource' - method = 'get' + request_uri = "/resource" + method = "get" request = MockRequest( - 'http://petstore.swagger.io', method, request_uri) + "http://petstore.swagger.io", method, request_uri + ) result = finder.find(request) - path = spec / 'paths' / self.path_name - operation = spec / 'paths' / self.path_name / method - server = eval(self.location) / 'servers' / 0 + path = spec / "paths" / self.path_name + operation = spec / "paths" / self.path_name / method + server = eval(self.location) / "servers" / 0 path_result = TemplateResult(self.path_name, {}) server_result = TemplateResult(self.server_url, {}) assert result == ( - path, operation, server, path_result, server_result, + path, + operation, + server, + path_result, + server_result, ) class BaseTestVariableValid: - - @pytest.mark.parametrize('version', ['v1', 'v2']) + @pytest.mark.parametrize("version", ["v1", "v2"]) def test_variable(self, finder, spec, version): - request_uri = f'/{version}/resource' - method = 'get' + request_uri = f"/{version}/resource" + method = "get" request = MockRequest( - 'http://petstore.swagger.io', method, request_uri) + "http://petstore.swagger.io", method, request_uri + ) result = finder.find(request) - path = spec / 'paths' / self.path_name - operation = spec / 'paths' / self.path_name / method - server = eval(self.location) / 'servers' / 0 + path = spec / "paths" / self.path_name + operation = spec / "paths" / self.path_name / method + server = eval(self.location) / "servers" / 0 path_result = TemplateResult(self.path_name, {}) - server_result = TemplateResult(self.server_url, {'version': version}) + server_result = TemplateResult(self.server_url, {"version": version}) assert result == ( - path, operation, server, path_result, server_result, + path, + operation, + server, + path_result, + server_result, ) class BaseTestPathVariableValid: - - @pytest.mark.parametrize('res_id', ['111', '222']) + @pytest.mark.parametrize("res_id", ["111", "222"]) def test_path_variable(self, finder, spec, res_id): - request_uri = f'/resource/{res_id}' - method = 'get' + request_uri = f"/resource/{res_id}" + method = "get" request = MockRequest( - 'http://petstore.swagger.io', method, request_uri) + "http://petstore.swagger.io", method, request_uri + ) result = finder.find(request) - path = spec / 'paths' / self.path_name - operation = spec / 'paths' / self.path_name / method - server = eval(self.location) / 'servers' / 0 - path_result = TemplateResult(self.path_name, {'resource_id': res_id}) + path = spec / "paths" / self.path_name + operation = spec / "paths" / self.path_name / method + server = eval(self.location) / "servers" / 0 + path_result = TemplateResult(self.path_name, {"resource_id": res_id}) server_result = TemplateResult(self.server_url, {}) assert result == ( - path, operation, server, path_result, server_result, + path, + operation, + server, + path_result, + server_result, ) class BaseTestPathNotFound: - @pytest.fixture def paths(self): return {} def test_raises(self, finder): - request_uri = '/resource' - request = MockRequest( - 'http://petstore.swagger.io', 'get', request_uri) + request_uri = "/resource" + request = MockRequest("http://petstore.swagger.io", "get", request_uri) with pytest.raises(PathNotFound): finder.find(request) class TestSpecSimpleServerServerNotFound( - BaseTestServerNotFound, BaseTestSpecServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestServerNotFound, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestSpecSimpleServerOperationNotFound( - BaseTestOperationNotFound, BaseTestSpecServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestOperationNotFound, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestSpecSimpleServerPathNotFound( - BaseTestPathNotFound, BaseTestSpecServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestPathNotFound, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestOperationSimpleServerServerNotFound( - BaseTestServerNotFound, BaseTestOperationServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestServerNotFound, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestOperationSimpleServerOperationNotFound( - BaseTestOperationNotFound, BaseTestOperationServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestOperationNotFound, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestOperationSimpleServerPathNotFound( - BaseTestPathNotFound, BaseTestOperationServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestPathNotFound, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestPathSimpleServerServerNotFound( - BaseTestServerNotFound, BaseTestPathServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestServerNotFound, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestPathSimpleServerOperationNotFound( - BaseTestOperationNotFound, BaseTestPathServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestOperationNotFound, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestPathSimpleServerPathNotFound( - BaseTestPathNotFound, BaseTestPathServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestPathNotFound, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestSpecSimpleServerValid( - BaseTestValid, BaseTestSpecServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestValid, BaseTestSpecServer, BaseTestSimplePath, BaseTestSimpleServer +): pass class TestOperationSimpleServerValid( - BaseTestValid, BaseTestOperationServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestValid, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestSimpleServer, +): pass class TestPathSimpleServerValid( - BaseTestValid, BaseTestPathServer, - BaseTestSimplePath, BaseTestSimpleServer): + BaseTestValid, BaseTestPathServer, BaseTestSimplePath, BaseTestSimpleServer +): pass class TestSpecSimpleServerVariablePathValid( - BaseTestPathVariableValid, BaseTestSpecServer, - BaseTestVariablePath, BaseTestSimpleServer): + BaseTestPathVariableValid, + BaseTestSpecServer, + BaseTestVariablePath, + BaseTestSimpleServer, +): pass class TestOperationSimpleServerVariablePathValid( - BaseTestPathVariableValid, BaseTestOperationServer, - BaseTestVariablePath, BaseTestSimpleServer): + BaseTestPathVariableValid, + BaseTestOperationServer, + BaseTestVariablePath, + BaseTestSimpleServer, +): pass class TestPathSimpleServerVariablePathValid( - BaseTestPathVariableValid, BaseTestPathServer, - BaseTestVariablePath, BaseTestSimpleServer): + BaseTestPathVariableValid, + BaseTestPathServer, + BaseTestVariablePath, + BaseTestSimpleServer, +): pass class TestSpecVariableServerServerNotFound( - BaseTestServerNotFound, BaseTestSpecServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestServerNotFound, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestSpecVariableServerOperationNotFound( - BaseTestOperationNotFound, BaseTestSpecServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestOperationNotFound, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestSpecVariableServerPathNotFound( - BaseTestPathNotFound, BaseTestSpecServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestPathNotFound, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestOperationVariableServerServerNotFound( - BaseTestServerNotFound, BaseTestOperationServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestServerNotFound, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestOperationVariableServerOperationNotFound( - BaseTestOperationNotFound, BaseTestOperationServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestOperationNotFound, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestOperationVariableServerPathNotFound( - BaseTestPathNotFound, BaseTestOperationServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestPathNotFound, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestPathVariableServerServerNotFound( - BaseTestServerNotFound, BaseTestPathServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestServerNotFound, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestPathVariableServerOperationNotFound( - BaseTestOperationNotFound, BaseTestPathServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestOperationNotFound, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestPathVariableServerPathNotFound( - BaseTestPathNotFound, BaseTestPathServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestPathNotFound, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestSpecVariableServerValid( - BaseTestVariableValid, BaseTestSpecServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestVariableValid, + BaseTestSpecServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestOperationVariableServerValid( - BaseTestVariableValid, BaseTestOperationServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestVariableValid, + BaseTestOperationServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass class TestPathVariableServerValid( - BaseTestVariableValid, BaseTestPathServer, - BaseTestSimplePath, BaseTestVariableServer): + BaseTestVariableValid, + BaseTestPathServer, + BaseTestSimplePath, + BaseTestVariableServer, +): pass -class TestSimilarPaths( - BaseTestSpecServer, BaseTestSimpleServer): +class TestSimilarPaths(BaseTestSpecServer, BaseTestSimpleServer): - path_name = '/tokens' - path_2_name = '/keys/{id}/tokens' + path_name = "/tokens" + path_2_name = "/keys/{id}/tokens" @pytest.fixture def operation_2(self): return { - 'responses': [], + "responses": [], } @pytest.fixture def operations_2(self, operation_2): return { - 'get': operation_2, + "get": operation_2, } @pytest.fixture @@ -474,40 +558,44 @@ def paths(self, path, path_2): } def test_valid(self, finder, spec): - token_id = '123' - request_uri = f'/keys/{token_id}/tokens' - method = 'get' + token_id = "123" + request_uri = f"/keys/{token_id}/tokens" + method = "get" request = MockRequest( - 'http://petstore.swagger.io', method, request_uri) + "http://petstore.swagger.io", method, request_uri + ) result = finder.find(request) - path_2 = spec / 'paths' / self.path_2_name - operation_2 = spec / 'paths' / self.path_2_name / method - server = eval(self.location) / 'servers' / 0 - path_result = TemplateResult(self.path_2_name, {'id': token_id}) + path_2 = spec / "paths" / self.path_2_name + operation_2 = spec / "paths" / self.path_2_name / method + server = eval(self.location) / "servers" / 0 + path_result = TemplateResult(self.path_2_name, {"id": token_id}) server_result = TemplateResult(self.server_url, {}) assert result == ( - path_2, operation_2, server, path_result, server_result, + path_2, + operation_2, + server, + path_result, + server_result, ) -class TestConcretePaths( - BaseTestSpecServer, BaseTestSimpleServer): +class TestConcretePaths(BaseTestSpecServer, BaseTestSimpleServer): - path_name = '/keys/{id}/tokens' - path_2_name = '/keys/master/tokens' + path_name = "/keys/{id}/tokens" + path_2_name = "/keys/master/tokens" @pytest.fixture def operation_2(self): return { - 'responses': [], + "responses": [], } @pytest.fixture def operations_2(self, operation_2): return { - 'get': operation_2, + "get": operation_2, } @pytest.fixture @@ -526,38 +614,42 @@ def paths(self, path, path_2): } def test_valid(self, finder, spec): - request_uri = '/keys/master/tokens' - method = 'get' + request_uri = "/keys/master/tokens" + method = "get" request = MockRequest( - 'http://petstore.swagger.io', method, request_uri) + "http://petstore.swagger.io", method, request_uri + ) result = finder.find(request) - path_2 = spec / 'paths' / self.path_2_name - operation_2 = spec / 'paths' / self.path_2_name / method - server = eval(self.location) / 'servers' / 0 + path_2 = spec / "paths" / self.path_2_name + operation_2 = spec / "paths" / self.path_2_name / method + server = eval(self.location) / "servers" / 0 path_result = TemplateResult(self.path_2_name, {}) server_result = TemplateResult(self.server_url, {}) assert result == ( - path_2, operation_2, server, path_result, server_result, + path_2, + operation_2, + server, + path_result, + server_result, ) -class TestTemplateConcretePaths( - BaseTestSpecServer, BaseTestSimpleServer): +class TestTemplateConcretePaths(BaseTestSpecServer, BaseTestSimpleServer): - path_name = '/keys/{id}/tokens/{id2}' - path_2_name = '/keys/{id}/tokens/master' + path_name = "/keys/{id}/tokens/{id2}" + path_2_name = "/keys/{id}/tokens/master" @pytest.fixture def operation_2(self): return { - 'responses': [], + "responses": [], } @pytest.fixture def operations_2(self, operation_2): return { - 'get': operation_2, + "get": operation_2, } @pytest.fixture @@ -576,18 +668,23 @@ def paths(self, path, path_2): } def test_valid(self, finder, spec): - token_id = '123' - request_uri = f'/keys/{token_id}/tokens/master' - method = 'get' + token_id = "123" + request_uri = f"/keys/{token_id}/tokens/master" + method = "get" request = MockRequest( - 'http://petstore.swagger.io', method, request_uri) + "http://petstore.swagger.io", method, request_uri + ) result = finder.find(request) - path_2 = spec / 'paths' / self.path_2_name - operation_2 = spec / 'paths' / self.path_2_name / method - server = eval(self.location) / 'servers' / 0 - path_result = TemplateResult(self.path_2_name, {'id': '123'}) + path_2 = spec / "paths" / self.path_2_name + operation_2 = spec / "paths" / self.path_2_name / method + server = eval(self.location) / "servers" / 0 + path_result = TemplateResult(self.path_2_name, {"id": "123"}) server_result = TemplateResult(self.server_url, {}) assert result == ( - path_2, operation_2, server, path_result, server_result, + path_2, + operation_2, + server, + path_result, + server_result, ) diff --git a/tests/unit/templating/test_responses_finders.py b/tests/unit/templating/test_responses_finders.py index 0bf8b648..8b3500fb 100644 --- a/tests/unit/templating/test_responses_finders.py +++ b/tests/unit/templating/test_responses_finders.py @@ -7,35 +7,34 @@ class TestResponses: - - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def spec(self): return { - '200': mock.sentinel.response_200, - '299': mock.sentinel.response_299, - '2XX': mock.sentinel.response_2XX, - 'default': mock.sentinel.response_default, + "200": mock.sentinel.response_200, + "299": mock.sentinel.response_299, + "2XX": mock.sentinel.response_2XX, + "default": mock.sentinel.response_default, } - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def responses(self, spec): return SpecPath.from_spec(spec) - @pytest.fixture(scope='class') + @pytest.fixture(scope="class") def finder(self, responses): return ResponseFinder(responses) def test_default(self, finder, responses): response = finder.find() - assert response == responses / 'default' + assert response == responses / "default" def test_range(self, finder, responses): - response = finder.find('201') + response = finder.find("201") - assert response == responses / '2XX' + assert response == responses / "2XX" def test_exact(self, finder, responses): - response = finder.find('200') + response = finder.find("200") - assert response == responses / '200' + assert response == responses / "200" diff --git a/tests/unit/templating/test_util.py b/tests/unit/templating/test_util.py index bd695409..b6a5eb9b 100644 --- a/tests/unit/templating/test_util.py +++ b/tests/unit/templating/test_util.py @@ -2,23 +2,22 @@ class TestSearch: - def test_endswith(self): - path_patter = '/{test}/test' - full_url_pattern = '/test1/test/test2/test' + path_patter = "/{test}/test" + full_url_pattern = "/test1/test/test2/test" result = search(path_patter, full_url_pattern) assert result.named == { - 'test': 'test2', + "test": "test2", } def test_exact(self): - path_patter = '/{test}/test' - full_url_pattern = '/test/test' + path_patter = "/{test}/test" + full_url_pattern = "/test/test" result = search(path_patter, full_url_pattern) assert result.named == { - 'test': 'test', + "test": "test", } diff --git a/tests/unit/unmarshalling/test_unmarshal.py b/tests/unit/unmarshalling/test_unmarshal.py index 8d88b1f0..bb484986 100644 --- a/tests/unit/unmarshalling/test_unmarshal.py +++ b/tests/unit/unmarshalling/test_unmarshal.py @@ -1,15 +1,20 @@ import datetime import uuid -from isodate.tzinfo import UTC, FixedOffset import pytest +from isodate.tzinfo import UTC +from isodate.tzinfo import FixedOffset from openapi_core.spec.paths import SpecPath from openapi_core.unmarshalling.schemas.enums import UnmarshalContext from openapi_core.unmarshalling.schemas.exceptions import ( - InvalidSchemaFormatValue, InvalidSchemaValue, UnmarshalError, FormatterNotFoundError, ) +from openapi_core.unmarshalling.schemas.exceptions import ( + InvalidSchemaFormatValue, +) +from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue +from openapi_core.unmarshalling.schemas.exceptions import UnmarshalError from openapi_core.unmarshalling.schemas.factories import ( SchemaUnmarshallersFactory, ) @@ -24,46 +29,47 @@ def create_unmarshaller(schema, custom_formatters=None, context=None): format_checker = build_format_checker(**custom_formatters) return SchemaUnmarshallersFactory( format_checker=format_checker, - custom_formatters=custom_formatters, context=context).create( - schema) + custom_formatters=custom_formatters, + context=context, + ).create(schema) + return create_unmarshaller class TestUnmarshal: - def test_no_schema(self, unmarshaller_factory): schema = None - value = 'test' + value = "test" with pytest.raises(TypeError): unmarshaller_factory(schema).unmarshal(value) def test_schema_type_invalid(self, unmarshaller_factory): spec = { - 'type': 'integer', + "type": "integer", } schema = SpecPath.from_spec(spec) - value = 'test' + value = "test" with pytest.raises(InvalidSchemaFormatValue): unmarshaller_factory(schema).unmarshal(value) def test_schema_custom_format_invalid(self, unmarshaller_factory): - class CustomFormatter(Formatter): def unmarshal(self, value): raise ValueError + formatter = CustomFormatter() - custom_format = 'custom' + custom_format = "custom" custom_formatters = { custom_format: formatter, } spec = { - 'type': 'string', - 'format': 'custom', + "type": "string", + "format": "custom", } schema = SpecPath.from_spec(spec) - value = 'test' + value = "test" with pytest.raises(InvalidSchemaFormatValue): unmarshaller_factory( @@ -73,39 +79,44 @@ def unmarshal(self, value): class TestSchemaUnmarshallerCall: - def test_deprecated(self, unmarshaller_factory): spec = { - 'type': 'string', - 'deprecated': True, + "type": "string", + "deprecated": True, } schema = SpecPath.from_spec(spec) - value = 'test' + value = "test" with pytest.warns(DeprecationWarning): result = unmarshaller_factory(schema)(value) assert result == value - @pytest.mark.parametrize('schema_type', [ - 'boolean', 'array', 'integer', 'number', - ]) + @pytest.mark.parametrize( + "schema_type", + [ + "boolean", + "array", + "integer", + "number", + ], + ) def test_non_string_empty_value(self, schema_type, unmarshaller_factory): spec = { - 'type': schema_type, + "type": schema_type, } schema = SpecPath.from_spec(spec) - value = '' + value = "" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_string_valid(self, unmarshaller_factory): spec = { - 'type': 'string', + "type": "string", } schema = SpecPath.from_spec(spec) - value = 'test' + value = "test" result = unmarshaller_factory(schema)(value) @@ -113,8 +124,8 @@ def test_string_valid(self, unmarshaller_factory): def test_string_format_uuid_valid(self, unmarshaller_factory): spec = { - 'type': 'string', - 'format': 'uuid', + "type": "string", + "format": "uuid", } schema = SpecPath.from_spec(spec) value = str(uuid.uuid4()) @@ -124,10 +135,11 @@ def test_string_format_uuid_valid(self, unmarshaller_factory): assert result == uuid.UUID(value) def test_string_format_uuid_uuid_quirks_invalid( - self, unmarshaller_factory): + self, unmarshaller_factory + ): spec = { - 'type': 'string', - 'format': 'uuid', + "type": "string", + "format": "uuid", } schema = SpecPath.from_spec(spec) value = uuid.uuid4() @@ -137,19 +149,19 @@ def test_string_format_uuid_uuid_quirks_invalid( def test_string_format_password(self, unmarshaller_factory): spec = { - 'type': 'string', - 'format': 'password', + "type": "string", + "format": "password", } schema = SpecPath.from_spec(spec) - value = 'password' + value = "password" result = unmarshaller_factory(schema)(value) - assert result == 'password' + assert result == "password" def test_string_float_invalid(self, unmarshaller_factory): spec = { - 'type': 'string', + "type": "string", } schema = SpecPath.from_spec(spec) value = 1.23 @@ -159,11 +171,11 @@ def test_string_float_invalid(self, unmarshaller_factory): def test_string_format_date(self, unmarshaller_factory): spec = { - 'type': 'string', - 'format': 'date', + "type": "string", + "format": "date", } schema = SpecPath.from_spec(spec) - value = '2018-01-02' + value = "2018-01-02" result = unmarshaller_factory(schema)(value) @@ -171,22 +183,22 @@ def test_string_format_date(self, unmarshaller_factory): def test_string_format_datetime_invalid(self, unmarshaller_factory): spec = { - 'type': 'string', - 'format': 'date-time', + "type": "string", + "format": "date-time", } schema = SpecPath.from_spec(spec) - value = '2018-01-02T00:00:00' + value = "2018-01-02T00:00:00" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_string_format_datetime_utc(self, unmarshaller_factory): spec = { - 'type': 'string', - 'format': 'date-time', + "type": "string", + "format": "date-time", } schema = SpecPath.from_spec(spec) - value = '2018-01-02T00:00:00Z' + value = "2018-01-02T00:00:00Z" result = unmarshaller_factory(schema)(value) @@ -195,11 +207,11 @@ def test_string_format_datetime_utc(self, unmarshaller_factory): def test_string_format_datetime_tz(self, unmarshaller_factory): spec = { - 'type': 'string', - 'format': 'date-time', + "type": "string", + "format": "date-time", } schema = SpecPath.from_spec(spec) - value = '2020-04-01T12:00:00+02:00' + value = "2020-04-01T12:00:00+02:00" result = unmarshaller_factory(schema)(value) @@ -207,40 +219,42 @@ def test_string_format_datetime_tz(self, unmarshaller_factory): assert result == datetime.datetime(2020, 4, 1, 12, 0, 0, tzinfo=tzinfo) def test_string_format_custom(self, unmarshaller_factory): - formatted = 'x-custom' + formatted = "x-custom" class CustomFormatter(Formatter): def unmarshal(self, value): return formatted - custom_format = 'custom' + + custom_format = "custom" spec = { - 'type': 'string', - 'format': custom_format, + "type": "string", + "format": custom_format, } schema = SpecPath.from_spec(spec) - value = 'x' + value = "x" formatter = CustomFormatter() custom_formatters = { custom_format: formatter, } result = unmarshaller_factory( - schema, custom_formatters=custom_formatters)(value) + schema, custom_formatters=custom_formatters + )(value) assert result == formatted def test_string_format_custom_value_error(self, unmarshaller_factory): - class CustomFormatter(Formatter): def unmarshal(self, value): raise ValueError - custom_format = 'custom' + + custom_format = "custom" spec = { - 'type': 'string', - 'format': custom_format, + "type": "string", + "format": custom_format, } schema = SpecPath.from_spec(spec) - value = 'x' + value = "x" formatter = CustomFormatter() custom_formatters = { custom_format: formatter, @@ -248,38 +262,39 @@ def unmarshal(self, value): with pytest.raises(InvalidSchemaFormatValue): unmarshaller_factory(schema, custom_formatters=custom_formatters)( - value) + value + ) def test_string_format_unknown(self, unmarshaller_factory): - unknown_format = 'unknown' + unknown_format = "unknown" spec = { - 'type': 'string', - 'format': unknown_format, + "type": "string", + "format": unknown_format, } schema = SpecPath.from_spec(spec) - value = 'x' + value = "x" with pytest.raises(FormatterNotFoundError): unmarshaller_factory(schema)(value) def test_string_format_invalid_value(self, unmarshaller_factory): - custom_format = 'custom' + custom_format = "custom" spec = { - 'type': 'string', - 'format': custom_format, + "type": "string", + "format": custom_format, } schema = SpecPath.from_spec(spec) - value = 'x' + value = "x" with pytest.raises( FormatterNotFoundError, - match='Formatter not found for custom format', + match="Formatter not found for custom format", ): unmarshaller_factory(schema)(value) def test_integer_valid(self, unmarshaller_factory): spec = { - 'type': 'integer', + "type": "integer", } schema = SpecPath.from_spec(spec) value = 123 @@ -290,29 +305,29 @@ def test_integer_valid(self, unmarshaller_factory): def test_integer_string_invalid(self, unmarshaller_factory): spec = { - 'type': 'integer', + "type": "integer", } schema = SpecPath.from_spec(spec) - value = '123' + value = "123" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_integer_enum_invalid(self, unmarshaller_factory): spec = { - 'type': 'integer', - 'enum': [1, 2, 3], + "type": "integer", + "enum": [1, 2, 3], } schema = SpecPath.from_spec(spec) - value = '123' + value = "123" with pytest.raises(UnmarshalError): unmarshaller_factory(schema)(value) def test_integer_enum(self, unmarshaller_factory): spec = { - 'type': 'integer', - 'enum': [1, 2, 3], + "type": "integer", + "enum": [1, 2, 3], } schema = SpecPath.from_spec(spec) value = 2 @@ -323,11 +338,11 @@ def test_integer_enum(self, unmarshaller_factory): def test_integer_enum_string_invalid(self, unmarshaller_factory): spec = { - 'type': 'integer', - 'enum': [1, 2, 3], + "type": "integer", + "enum": [1, 2, 3], } schema = SpecPath.from_spec(spec) - value = '2' + value = "2" with pytest.raises(UnmarshalError): unmarshaller_factory(schema)(value) @@ -335,9 +350,9 @@ def test_integer_enum_string_invalid(self, unmarshaller_factory): def test_integer_default_nullable(self, unmarshaller_factory): default_value = 123 spec = { - 'type': 'integer', - 'default': default_value, - 'nullable': True, + "type": "integer", + "default": default_value, + "nullable": True, } schema = SpecPath.from_spec(spec) value = None @@ -348,20 +363,20 @@ def test_integer_default_nullable(self, unmarshaller_factory): def test_integer_invalid(self, unmarshaller_factory): spec = { - 'type': 'integer', + "type": "integer", } schema = SpecPath.from_spec(spec) - value = 'abc' + value = "abc" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_array_valid(self, unmarshaller_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'integer', - } + "type": "array", + "items": { + "type": "integer", + }, } schema = SpecPath.from_spec(spec) value = [1, 2, 3] @@ -372,10 +387,10 @@ def test_array_valid(self, unmarshaller_factory): def test_array_null(self, unmarshaller_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'integer', - } + "type": "array", + "items": { + "type": "integer", + }, } schema = SpecPath.from_spec(spec) value = None @@ -385,11 +400,11 @@ def test_array_null(self, unmarshaller_factory): def test_array_nullable(self, unmarshaller_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'integer', + "type": "array", + "items": { + "type": "integer", }, - 'nullable': True, + "nullable": True, } schema = SpecPath.from_spec(spec) value = None @@ -399,33 +414,33 @@ def test_array_nullable(self, unmarshaller_factory): def test_array_of_string_string_invalid(self, unmarshaller_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'string', - } + "type": "array", + "items": { + "type": "string", + }, } schema = SpecPath.from_spec(spec) - value = '123' + value = "123" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_array_of_integer_string_invalid(self, unmarshaller_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'integer', - } + "type": "array", + "items": { + "type": "integer", + }, } schema = SpecPath.from_spec(spec) - value = '123' + value = "123" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_boolean_valid(self, unmarshaller_factory): spec = { - 'type': 'boolean', + "type": "boolean", } schema = SpecPath.from_spec(spec) value = True @@ -436,17 +451,17 @@ def test_boolean_valid(self, unmarshaller_factory): def test_boolean_string_invalid(self, unmarshaller_factory): spec = { - 'type': 'boolean', + "type": "boolean", } schema = SpecPath.from_spec(spec) - value = 'True' + value = "True" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_number_valid(self, unmarshaller_factory): spec = { - 'type': 'number', + "type": "number", } schema = SpecPath.from_spec(spec) value = 1.23 @@ -457,17 +472,17 @@ def test_number_valid(self, unmarshaller_factory): def test_number_string_invalid(self, unmarshaller_factory): spec = { - 'type': 'number', + "type": "number", } schema = SpecPath.from_spec(spec) - value = '1.23' + value = "1.23" with pytest.raises(InvalidSchemaValue): unmarshaller_factory(schema)(value) def test_number_int(self, unmarshaller_factory): spec = { - 'type': 'number', + "type": "number", } schema = SpecPath.from_spec(spec) value = 1 @@ -478,7 +493,7 @@ def test_number_int(self, unmarshaller_factory): def test_number_float(self, unmarshaller_factory): spec = { - 'type': 'number', + "type": "number", } schema = SpecPath.from_spec(spec) value = 1.2 @@ -489,8 +504,8 @@ def test_number_float(self, unmarshaller_factory): def test_number_format_float(self, unmarshaller_factory): spec = { - 'type': 'number', - 'format': 'float', + "type": "number", + "format": "float", } schema = SpecPath.from_spec(spec) value = 1.2 @@ -500,8 +515,8 @@ def test_number_format_float(self, unmarshaller_factory): def test_number_format_double(self, unmarshaller_factory): spec = { - 'type': 'number', - 'format': 'double', + "type": "number", + "format": "double", } schema = SpecPath.from_spec(spec) value = 1.2 @@ -511,96 +526,98 @@ def test_number_format_double(self, unmarshaller_factory): def test_object_nullable(self, unmarshaller_factory): spec = { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'object', - 'nullable': True, + "type": "object", + "properties": { + "foo": { + "type": "object", + "nullable": True, } }, } schema = SpecPath.from_spec(spec) - value = {'foo': None} + value = {"foo": None} result = unmarshaller_factory(schema)(value) - assert result == {'foo': None} + assert result == {"foo": None} def test_schema_any_one_of(self, unmarshaller_factory): spec = { - 'oneOf': [ + "oneOf": [ { - 'type': 'string', + "type": "string", }, { - 'type': 'array', - 'items': { - 'type': 'string', - } - } + "type": "array", + "items": { + "type": "string", + }, + }, ], } schema = SpecPath.from_spec(spec) - assert unmarshaller_factory(schema)(['hello']) == ['hello'] + assert unmarshaller_factory(schema)(["hello"]) == ["hello"] def test_schema_any_all_of(self, unmarshaller_factory): spec = { - 'allOf': [ + "allOf": [ { - 'type': 'array', - 'items': { - 'type': 'string', - } + "type": "array", + "items": { + "type": "string", + }, } ], } schema = SpecPath.from_spec(spec) - assert unmarshaller_factory(schema)(['hello']) == ['hello'] + assert unmarshaller_factory(schema)(["hello"]) == ["hello"] - @pytest.mark.parametrize('value', [ - { - 'somestr': {}, - 'someint': 123, - }, - { - 'somestr': [ - 'content1', 'content2' - ], - 'someint': 123, - }, - { - 'somestr': 123, - 'someint': 123, - }, - { - 'somestr': 'content', - 'someint': 123, - 'not_in_scheme_prop': 123, - }, - ]) + @pytest.mark.parametrize( + "value", + [ + { + "somestr": {}, + "someint": 123, + }, + { + "somestr": ["content1", "content2"], + "someint": 123, + }, + { + "somestr": 123, + "someint": 123, + }, + { + "somestr": "content", + "someint": 123, + "not_in_scheme_prop": 123, + }, + ], + ) def test_schema_any_all_of_invalid_properties( - self, value, unmarshaller_factory): + self, value, unmarshaller_factory + ): spec = { - 'allOf': [ + "allOf": [ { - 'type': 'object', - 'required': ['somestr'], - 'properties': { - 'somestr': { - 'type': 'string', + "type": "object", + "required": ["somestr"], + "properties": { + "somestr": { + "type": "string", }, }, }, { - 'type': 'object', - 'required': ['someint'], - 'properties': { - 'someint': { - 'type': 'integer', + "type": "object", + "required": ["someint"], + "properties": { + "someint": { + "type": "integer", }, }, - } + }, ], - 'additionalProperties': False, + "additionalProperties": False, } schema = SpecPath.from_spec(spec) @@ -609,16 +626,16 @@ def test_schema_any_all_of_invalid_properties( def test_schema_any_all_of_any(self, unmarshaller_factory): spec = { - 'allOf': [ + "allOf": [ {}, { - 'type': 'string', - 'format': 'date', + "type": "string", + "format": "date", }, ], } schema = SpecPath.from_spec(spec) - value = '2018-01-02' + value = "2018-01-02" result = unmarshaller_factory(schema)(value) @@ -627,19 +644,23 @@ def test_schema_any_all_of_any(self, unmarshaller_factory): def test_schema_any(self, unmarshaller_factory): spec = {} schema = SpecPath.from_spec(spec) - assert unmarshaller_factory(schema)('string') == 'string' - - @pytest.mark.parametrize('value', [ - {'additional': 1}, - {'foo': 'bar', 'bar': 'foo'}, - {'additional': {'bar': 1}}, - ]) - @pytest.mark.parametrize('additional_properties', [True, {}]) + assert unmarshaller_factory(schema)("string") == "string" + + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + {"foo": "bar", "bar": "foo"}, + {"additional": {"bar": 1}}, + ], + ) + @pytest.mark.parametrize("additional_properties", [True, {}]) def test_schema_free_form_object( - self, value, additional_properties, unmarshaller_factory): + self, value, additional_properties, unmarshaller_factory + ): spec = { - 'type': 'object', - 'additionalProperties': additional_properties, + "type": "object", + "additionalProperties": additional_properties, } schema = SpecPath.from_spec(spec) @@ -648,12 +669,12 @@ def test_schema_free_form_object( def test_read_only_properties(self, unmarshaller_factory): spec = { - 'type': 'object', - 'required': ['id'], - 'properties': { - 'id': { - 'type': 'integer', - 'readOnly': True, + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "readOnly": True, } }, } @@ -661,19 +682,20 @@ def test_read_only_properties(self, unmarshaller_factory): # readOnly properties may be admitted in a Response context result = unmarshaller_factory( - obj_schema, context=UnmarshalContext.RESPONSE)({"id": 10}) + obj_schema, context=UnmarshalContext.RESPONSE + )({"id": 10}) assert result == { - 'id': 10, + "id": 10, } def test_read_only_properties_invalid(self, unmarshaller_factory): spec = { - 'type': 'object', - 'required': ['id'], - 'properties': { - 'id': { - 'type': 'integer', - 'readOnly': True, + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "readOnly": True, } }, } @@ -681,17 +703,18 @@ def test_read_only_properties_invalid(self, unmarshaller_factory): # readOnly properties are not admitted on a Request context with pytest.raises(InvalidSchemaValue): - unmarshaller_factory( - obj_schema, context=UnmarshalContext.REQUEST)({"id": 10}) + unmarshaller_factory(obj_schema, context=UnmarshalContext.REQUEST)( + {"id": 10} + ) def test_write_only_properties(self, unmarshaller_factory): spec = { - 'type': 'object', - 'required': ['id'], - 'properties': { - 'id': { - 'type': 'integer', - 'writeOnly': True, + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "writeOnly": True, } }, } @@ -699,19 +722,20 @@ def test_write_only_properties(self, unmarshaller_factory): # readOnly properties may be admitted in a Response context result = unmarshaller_factory( - obj_schema, context=UnmarshalContext.REQUEST)({"id": 10}) + obj_schema, context=UnmarshalContext.REQUEST + )({"id": 10}) assert result == { - 'id': 10, + "id": 10, } def test_write_only_properties_invalid(self, unmarshaller_factory): spec = { - 'type': 'object', - 'required': ['id'], - 'properties': { - 'id': { - 'type': 'integer', - 'writeOnly': True, + "type": "object", + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "writeOnly": True, } }, } @@ -720,4 +744,5 @@ def test_write_only_properties_invalid(self, unmarshaller_factory): # readOnly properties are not admitted on a Request context with pytest.raises(InvalidSchemaValue): unmarshaller_factory( - obj_schema, context=UnmarshalContext.RESPONSE)({"id": 10}) + obj_schema, context=UnmarshalContext.RESPONSE + )({"id": 10}) diff --git a/tests/unit/unmarshalling/test_validate.py b/tests/unit/unmarshalling/test_validate.py index c867b851..5a409dd7 100644 --- a/tests/unit/unmarshalling/test_validate.py +++ b/tests/unit/unmarshalling/test_validate.py @@ -5,31 +5,40 @@ from openapi_core.extensions.models.models import Model from openapi_core.spec.paths import SpecPath +from openapi_core.unmarshalling.schemas.exceptions import ( + FormatterNotFoundError, +) +from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue from openapi_core.unmarshalling.schemas.factories import ( SchemaUnmarshallersFactory, ) -from openapi_core.unmarshalling.schemas.exceptions import ( - FormatterNotFoundError, InvalidSchemaValue, -) from openapi_core.unmarshalling.schemas.util import build_format_checker class TestSchemaValidate: - @pytest.fixture def validator_factory(self): def create_validator(schema): format_checker = build_format_checker() return SchemaUnmarshallersFactory( - format_checker=format_checker).create(schema) + format_checker=format_checker + ).create(schema) + return create_validator - @pytest.mark.parametrize('schema_type', [ - 'boolean', 'array', 'integer', 'number', 'string', - ]) + @pytest.mark.parametrize( + "schema_type", + [ + "boolean", + "array", + "integer", + "number", + "string", + ], + ) def test_null(self, schema_type, validator_factory): spec = { - 'type': schema_type, + "type": schema_type, } schema = SpecPath.from_spec(spec) value = None @@ -37,13 +46,20 @@ def test_null(self, schema_type, validator_factory): with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('schema_type', [ - 'boolean', 'array', 'integer', 'number', 'string', - ]) + @pytest.mark.parametrize( + "schema_type", + [ + "boolean", + "array", + "integer", + "number", + "string", + ], + ) def test_nullable(self, schema_type, validator_factory): spec = { - 'type': schema_type, - 'nullable': True, + "type": schema_type, + "nullable": True, } schema = SpecPath.from_spec(spec) value = None @@ -53,21 +69,21 @@ def test_nullable(self, schema_type, validator_factory): assert result is None def test_string_format_custom_missing(self, validator_factory): - custom_format = 'custom' + custom_format = "custom" spec = { - 'type': 'string', - 'format': custom_format, + "type": "string", + "format": custom_format, } schema = SpecPath.from_spec(spec) - value = 'x' + value = "x" with pytest.raises(FormatterNotFoundError): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [False, True]) + @pytest.mark.parametrize("value", [False, True]) def test_boolean(self, value, validator_factory): spec = { - 'type': 'boolean', + "type": "boolean", } schema = SpecPath.from_spec(spec) @@ -75,32 +91,32 @@ def test_boolean(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [1, 3.14, 'true', [True, False]]) + @pytest.mark.parametrize("value", [1, 3.14, "true", [True, False]]) def test_boolean_invalid(self, value, validator_factory): spec = { - 'type': 'boolean', + "type": "boolean", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [(1, 2)]) + @pytest.mark.parametrize("value", [(1, 2)]) def test_array_no_schema(self, value, validator_factory): spec = { - 'type': 'array', + "type": "array", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [[1, 2]]) + @pytest.mark.parametrize("value", [[1, 2]]) def test_array(self, value, validator_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'integer', + "type": "array", + "items": { + "type": "integer", }, } schema = SpecPath.from_spec(spec) @@ -109,20 +125,20 @@ def test_array(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [False, 1, 3.14, 'true', (3, 4)]) + @pytest.mark.parametrize("value", [False, 1, 3.14, "true", (3, 4)]) def test_array_invalid(self, value, validator_factory): spec = { - 'type': 'array', + "type": "array", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [1, 3]) + @pytest.mark.parametrize("value", [1, 3]) def test_integer(self, value, validator_factory): spec = { - 'type': 'integer', + "type": "integer", } schema = SpecPath.from_spec(spec) @@ -130,32 +146,32 @@ def test_integer(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [False, 3.14, 'true', [1, 2]]) + @pytest.mark.parametrize("value", [False, 3.14, "true", [1, 2]]) def test_integer_invalid(self, value, validator_factory): spec = { - 'type': 'integer', + "type": "integer", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [0, 1, 2]) + @pytest.mark.parametrize("value", [0, 1, 2]) def test_integer_minimum_invalid(self, value, validator_factory): spec = { - 'type': 'integer', - 'minimum': 3, + "type": "integer", + "minimum": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [4, 5, 6]) + @pytest.mark.parametrize("value", [4, 5, 6]) def test_integer_minimum(self, value, validator_factory): spec = { - 'type': 'integer', - 'minimum': 3, + "type": "integer", + "minimum": 3, } schema = SpecPath.from_spec(spec) @@ -163,22 +179,22 @@ def test_integer_minimum(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [4, 5, 6]) + @pytest.mark.parametrize("value", [4, 5, 6]) def test_integer_maximum_invalid(self, value, validator_factory): spec = { - 'type': 'integer', - 'maximum': 3, + "type": "integer", + "maximum": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [0, 1, 2]) + @pytest.mark.parametrize("value", [0, 1, 2]) def test_integer_maximum(self, value, validator_factory): spec = { - 'type': 'integer', - 'maximum': 3, + "type": "integer", + "maximum": 3, } schema = SpecPath.from_spec(spec) @@ -186,22 +202,22 @@ def test_integer_maximum(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [1, 2, 4]) + @pytest.mark.parametrize("value", [1, 2, 4]) def test_integer_multiple_of_invalid(self, value, validator_factory): spec = { - 'type': 'integer', - 'multipleOf': 3, + "type": "integer", + "multipleOf": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [3, 6, 18]) + @pytest.mark.parametrize("value", [3, 6, 18]) def test_integer_multiple_of(self, value, validator_factory): spec = { - 'type': 'integer', - 'multipleOf': 3, + "type": "integer", + "multipleOf": 3, } schema = SpecPath.from_spec(spec) @@ -209,10 +225,10 @@ def test_integer_multiple_of(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [1, 3.14]) + @pytest.mark.parametrize("value", [1, 3.14]) def test_number(self, value, validator_factory): spec = { - 'type': 'number', + "type": "number", } schema = SpecPath.from_spec(spec) @@ -220,32 +236,32 @@ def test_number(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [False, 'true', [1, 3]]) + @pytest.mark.parametrize("value", [False, "true", [1, 3]]) def test_number_invalid(self, value, validator_factory): spec = { - 'type': 'number', + "type": "number", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [0, 1, 2]) + @pytest.mark.parametrize("value", [0, 1, 2]) def test_number_minimum_invalid(self, value, validator_factory): spec = { - 'type': 'number', - 'minimum': 3, + "type": "number", + "minimum": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [3, 4, 5]) + @pytest.mark.parametrize("value", [3, 4, 5]) def test_number_minimum(self, value, validator_factory): spec = { - 'type': 'number', - 'minimum': 3, + "type": "number", + "minimum": 3, } schema = SpecPath.from_spec(spec) @@ -253,24 +269,24 @@ def test_number_minimum(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [1, 2, 3]) + @pytest.mark.parametrize("value", [1, 2, 3]) def test_number_exclusive_minimum_invalid(self, value, validator_factory): spec = { - 'type': 'number', - 'minimum': 3, - 'exclusiveMinimum': True, + "type": "number", + "minimum": 3, + "exclusiveMinimum": True, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [4, 5, 6]) + @pytest.mark.parametrize("value", [4, 5, 6]) def test_number_exclusive_minimum(self, value, validator_factory): spec = { - 'type': 'number', - 'minimum': 3, - 'exclusiveMinimum': True, + "type": "number", + "minimum": 3, + "exclusiveMinimum": True, } schema = SpecPath.from_spec(spec) @@ -278,22 +294,22 @@ def test_number_exclusive_minimum(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [4, 5, 6]) + @pytest.mark.parametrize("value", [4, 5, 6]) def test_number_maximum_invalid(self, value, validator_factory): spec = { - 'type': 'number', - 'maximum': 3, + "type": "number", + "maximum": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [1, 2, 3]) + @pytest.mark.parametrize("value", [1, 2, 3]) def test_number_maximum(self, value, validator_factory): spec = { - 'type': 'number', - 'maximum': 3, + "type": "number", + "maximum": 3, } schema = SpecPath.from_spec(spec) @@ -301,24 +317,24 @@ def test_number_maximum(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [3, 4, 5]) + @pytest.mark.parametrize("value", [3, 4, 5]) def test_number_exclusive_maximum_invalid(self, value, validator_factory): spec = { - 'type': 'number', - 'maximum': 3, - 'exclusiveMaximum': True, + "type": "number", + "maximum": 3, + "exclusiveMaximum": True, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [0, 1, 2]) + @pytest.mark.parametrize("value", [0, 1, 2]) def test_number_exclusive_maximum(self, value, validator_factory): spec = { - 'type': 'number', - 'maximum': 3, - 'exclusiveMaximum': True, + "type": "number", + "maximum": 3, + "exclusiveMaximum": True, } schema = SpecPath.from_spec(spec) @@ -326,22 +342,22 @@ def test_number_exclusive_maximum(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [1, 2, 4]) + @pytest.mark.parametrize("value", [1, 2, 4]) def test_number_multiple_of_invalid(self, value, validator_factory): spec = { - 'type': 'number', - 'multipleOf': 3, + "type": "number", + "multipleOf": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [3, 6, 18]) + @pytest.mark.parametrize("value", [3, 6, 18]) def test_number_multiple_of(self, value, validator_factory): spec = { - 'type': 'number', - 'multipleOf': 3, + "type": "number", + "multipleOf": 3, } schema = SpecPath.from_spec(spec) @@ -349,10 +365,10 @@ def test_number_multiple_of(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', ['true', b'test']) + @pytest.mark.parametrize("value", ["true", b"test"]) def test_string(self, value, validator_factory): spec = { - 'type': 'string', + "type": "string", } schema = SpecPath.from_spec(spec) @@ -360,37 +376,49 @@ def test_string(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [False, 1, 3.14, [1, 3]]) + @pytest.mark.parametrize("value", [False, 1, 3.14, [1, 3]]) def test_string_invalid(self, value, validator_factory): spec = { - 'type': 'string', + "type": "string", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - b'true', 'test', False, 1, 3.14, [1, 3], - datetime.datetime(1989, 1, 2), - ]) + @pytest.mark.parametrize( + "value", + [ + b"true", + "test", + False, + 1, + 3.14, + [1, 3], + datetime.datetime(1989, 1, 2), + ], + ) def test_string_format_date_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'date', + "type": "string", + "format": "date", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - '1989-01-02', '2018-01-02', - ]) + @pytest.mark.parametrize( + "value", + [ + "1989-01-02", + "2018-01-02", + ], + ) def test_string_format_date(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'date', + "type": "string", + "format": "date", } schema = SpecPath.from_spec(spec) @@ -398,13 +426,16 @@ def test_string_format_date(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [ - '12345678-1234-5678-1234-567812345678', - ]) + @pytest.mark.parametrize( + "value", + [ + "12345678-1234-5678-1234-567812345678", + ], + ) def test_string_format_uuid(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'uuid', + "type": "string", + "format": "uuid", } schema = SpecPath.from_spec(spec) @@ -412,51 +443,70 @@ def test_string_format_uuid(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [ - b'true', 'true', False, 1, 3.14, [1, 3], - datetime.date(2018, 1, 2), datetime.datetime(2018, 1, 2, 23, 59, 59), - ]) + @pytest.mark.parametrize( + "value", + [ + b"true", + "true", + False, + 1, + 3.14, + [1, 3], + datetime.date(2018, 1, 2), + datetime.datetime(2018, 1, 2, 23, 59, 59), + ], + ) def test_string_format_uuid_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'uuid', + "type": "string", + "format": "uuid", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - b'true', 'true', False, 1, 3.14, [1, 3], - '1989-01-02', - ]) + @pytest.mark.parametrize( + "value", + [ + b"true", + "true", + False, + 1, + 3.14, + [1, 3], + "1989-01-02", + ], + ) def test_string_format_datetime_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'date-time', + "type": "string", + "format": "date-time", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - '1989-01-02T00:00:00Z', - '2018-01-02T23:59:59Z', - ]) + @pytest.mark.parametrize( + "value", + [ + "1989-01-02T00:00:00Z", + "2018-01-02T23:59:59Z", + ], + ) @mock.patch( - 'openapi_schema_validator._format.' - 'DATETIME_HAS_STRICT_RFC3339', True + "openapi_schema_validator._format." "DATETIME_HAS_STRICT_RFC3339", True ) @mock.patch( - 'openapi_schema_validator._format.' - 'DATETIME_HAS_ISODATE', False + "openapi_schema_validator._format." "DATETIME_HAS_ISODATE", False ) def test_string_format_datetime_strict_rfc3339( - self, value, validator_factory): + self, value, validator_factory + ): spec = { - 'type': 'string', - 'format': 'date-time', + "type": "string", + "format": "date-time", } schema = SpecPath.from_spec(spec) @@ -464,22 +514,24 @@ def test_string_format_datetime_strict_rfc3339( assert result is None - @pytest.mark.parametrize('value', [ - '1989-01-02T00:00:00Z', - '2018-01-02T23:59:59Z', - ]) + @pytest.mark.parametrize( + "value", + [ + "1989-01-02T00:00:00Z", + "2018-01-02T23:59:59Z", + ], + ) @mock.patch( - 'openapi_schema_validator._format.' - 'DATETIME_HAS_STRICT_RFC3339', False + "openapi_schema_validator._format." "DATETIME_HAS_STRICT_RFC3339", + False, ) @mock.patch( - 'openapi_schema_validator._format.' - 'DATETIME_HAS_ISODATE', True + "openapi_schema_validator._format." "DATETIME_HAS_ISODATE", True ) def test_string_format_datetime_isodate(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'date-time', + "type": "string", + "format": "date-time", } schema = SpecPath.from_spec(spec) @@ -487,27 +539,39 @@ def test_string_format_datetime_isodate(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [ - 'true', False, 1, 3.14, [1, 3], '1989-01-02', - '1989-01-02T00:00:00Z', - ]) + @pytest.mark.parametrize( + "value", + [ + "true", + False, + 1, + 3.14, + [1, 3], + "1989-01-02", + "1989-01-02T00:00:00Z", + ], + ) def test_string_format_binary_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'binary', + "type": "string", + "format": "binary", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - b'stream', b'text', - ]) + @pytest.mark.parametrize( + "value", + [ + b"stream", + b"text", + ], + ) def test_string_format_binary(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'binary', + "type": "string", + "format": "binary", } schema = SpecPath.from_spec(spec) @@ -515,13 +579,17 @@ def test_string_format_binary(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [ - b'dGVzdA==', 'dGVzdA==', - ]) + @pytest.mark.parametrize( + "value", + [ + b"dGVzdA==", + "dGVzdA==", + ], + ) def test_string_format_byte(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'byte', + "type": "string", + "format": "byte", } schema = SpecPath.from_spec(spec) @@ -529,50 +597,60 @@ def test_string_format_byte(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [ - 'tsssst', b'tsssst', b'tesddddsdsdst', - ]) + @pytest.mark.parametrize( + "value", + [ + "tsssst", + b"tsssst", + b"tesddddsdsdst", + ], + ) def test_string_format_byte_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'format': 'byte', + "type": "string", + "format": "byte", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - 'test', b'stream', datetime.date(1989, 1, 2), - datetime.datetime(1989, 1, 2, 0, 0, 0), - ]) + @pytest.mark.parametrize( + "value", + [ + "test", + b"stream", + datetime.date(1989, 1, 2), + datetime.datetime(1989, 1, 2, 0, 0, 0), + ], + ) def test_string_format_unknown(self, value, validator_factory): - unknown_format = 'unknown' + unknown_format = "unknown" spec = { - 'type': 'string', - 'format': unknown_format, + "type": "string", + "format": unknown_format, } schema = SpecPath.from_spec(spec) with pytest.raises(FormatterNotFoundError): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', ["", "a", "ab"]) + @pytest.mark.parametrize("value", ["", "a", "ab"]) def test_string_min_length_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'minLength': 3, + "type": "string", + "minLength": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', ["abc", "abcd"]) + @pytest.mark.parametrize("value", ["abc", "abcd"]) def test_string_min_length(self, value, validator_factory): spec = { - 'type': 'string', - 'minLength': 3, + "type": "string", + "minLength": 3, } schema = SpecPath.from_spec(spec) @@ -580,33 +658,38 @@ def test_string_min_length(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', ["", ]) + @pytest.mark.parametrize( + "value", + [ + "", + ], + ) def test_string_max_length_invalid_schema(self, value, validator_factory): spec = { - 'type': 'string', - 'maxLength': -1, + "type": "string", + "maxLength": -1, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', ["ab", "abc"]) + @pytest.mark.parametrize("value", ["ab", "abc"]) def test_string_max_length_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'maxLength': 1, + "type": "string", + "maxLength": 1, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', ['', 'a']) + @pytest.mark.parametrize("value", ["", "a"]) def test_string_max_length(self, value, validator_factory): spec = { - 'type': 'string', - 'maxLength': 1, + "type": "string", + "maxLength": 1, } schema = SpecPath.from_spec(spec) @@ -614,22 +697,22 @@ def test_string_max_length(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', ['foo', 'bar']) + @pytest.mark.parametrize("value", ["foo", "bar"]) def test_string_pattern_invalid(self, value, validator_factory): spec = { - 'type': 'string', - 'pattern': 'baz', + "type": "string", + "pattern": "baz", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', ['bar', 'foobar']) + @pytest.mark.parametrize("value", ["bar", "foobar"]) def test_string_pattern(self, value, validator_factory): spec = { - 'type': 'string', - 'pattern': 'bar', + "type": "string", + "pattern": "bar", } schema = SpecPath.from_spec(spec) @@ -637,123 +720,147 @@ def test_string_pattern(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', ['true', False, 1, 3.14, [1, 3]]) + @pytest.mark.parametrize("value", ["true", False, 1, 3.14, [1, 3]]) def test_object_not_an_object(self, value, validator_factory): spec = { - 'type': 'object', + "type": "object", } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [Model(), ]) + @pytest.mark.parametrize( + "value", + [ + Model(), + ], + ) def test_object_multiple_one_of(self, value, validator_factory): one_of = [ { - 'type': 'object', + "type": "object", }, { - 'type': 'object', + "type": "object", }, ] spec = { - 'type': 'object', - 'oneOf': one_of, + "type": "object", + "oneOf": one_of, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [{}, ]) + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) def test_object_different_type_one_of(self, value, validator_factory): one_of = [ { - 'type': 'integer', + "type": "integer", }, { - 'type': 'string', + "type": "string", }, ] spec = { - 'type': 'object', - 'oneOf': one_of, + "type": "object", + "oneOf": one_of, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [{}, ]) + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) def test_object_no_one_of(self, value, validator_factory): one_of = [ { - 'type': 'object', - 'required': ['test1', ], - 'properties': { - 'test1': { - 'type': 'string', + "type": "object", + "required": [ + "test1", + ], + "properties": { + "test1": { + "type": "string", }, }, }, { - 'type': 'object', - 'required': ['test2', ], - 'properties': { - 'test2': { - 'type': 'string', + "type": "object", + "required": [ + "test2", + ], + "properties": { + "test2": { + "type": "string", }, }, }, ] spec = { - 'type': 'object', - 'oneOf': one_of, + "type": "object", + "oneOf": one_of, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - { - 'foo': 'FOO', - }, - { - 'foo': 'FOO', - 'bar': 'BAR', - }, - ]) + @pytest.mark.parametrize( + "value", + [ + { + "foo": "FOO", + }, + { + "foo": "FOO", + "bar": "BAR", + }, + ], + ) def test_unambiguous_one_of(self, value, validator_factory): one_of = [ { - 'type': 'object', - 'required': ['foo', ], - 'properties': { - 'foo': { - 'type': 'string', + "type": "object", + "required": [ + "foo", + ], + "properties": { + "foo": { + "type": "string", }, }, - 'additionalProperties': False, + "additionalProperties": False, }, { - 'type': 'object', - 'required': ['foo', 'bar'], - 'properties': { - 'foo': { - 'type': 'string', + "type": "object", + "required": ["foo", "bar"], + "properties": { + "foo": { + "type": "string", }, - 'bar': { - 'type': 'string', + "bar": { + "type": "string", }, }, - 'additionalProperties': False, + "additionalProperties": False, }, ] spec = { - 'type': 'object', - 'oneOf': one_of, + "type": "object", + "oneOf": one_of, } schema = SpecPath.from_spec(spec) @@ -761,11 +868,16 @@ def test_unambiguous_one_of(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [{}, ]) + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) def test_object_default_property(self, value, validator_factory): spec = { - 'type': 'object', - 'default': 'value1', + "type": "object", + "default": "value1", } schema = SpecPath.from_spec(spec) @@ -773,100 +885,112 @@ def test_object_default_property(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [{}, ]) + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) def test_object_min_properties_invalid_schema( - self, value, validator_factory): + self, value, validator_factory + ): spec = { - 'type': 'object', - 'minProperties': 2, + "type": "object", + "minProperties": 2, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - {'a': 1}, - {'a': 1, 'b': 2}, - {'a': 1, 'b': 2, 'c': 3}, - ]) + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) def test_object_min_properties_invalid(self, value, validator_factory): spec = { - 'type': 'object', - 'properties': { - k: {'type': 'number'} - for k in ['a', 'b', 'c'] - }, - 'minProperties': 4, + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "minProperties": 4, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - {'a': 1}, - {'a': 1, 'b': 2}, - {'a': 1, 'b': 2, 'c': 3}, - ]) + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) def test_object_min_properties(self, value, validator_factory): spec = { - 'type': 'object', - 'properties': { - k: {'type': 'number'} - for k in ['a', 'b', 'c'] - }, - 'minProperties': 1, + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "minProperties": 1, } schema = SpecPath.from_spec(spec) result = validator_factory(schema).validate(value) assert result is None - @pytest.mark.parametrize('value', [{}, ]) + @pytest.mark.parametrize( + "value", + [ + {}, + ], + ) def test_object_max_properties_invalid_schema( - self, value, validator_factory): + self, value, validator_factory + ): spec = { - 'type': 'object', - 'maxProperties': -1, + "type": "object", + "maxProperties": -1, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - {'a': 1}, - {'a': 1, 'b': 2}, - {'a': 1, 'b': 2, 'c': 3}, - ]) + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) def test_object_max_properties_invalid(self, value, validator_factory): spec = { - 'type': 'object', - 'properties': { - k: {'type': 'number'} - for k in ['a', 'b', 'c'] - }, - 'maxProperties': 0, + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "maxProperties": 0, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - {'a': 1}, - {'a': 1, 'b': 2}, - {'a': 1, 'b': 2, 'c': 3}, - ]) + @pytest.mark.parametrize( + "value", + [ + {"a": 1}, + {"a": 1, "b": 2}, + {"a": 1, "b": 2, "c": 3}, + ], + ) def test_object_max_properties(self, value, validator_factory): spec = { - 'type': 'object', - 'properties': { - k: {'type': 'number'} - for k in ['a', 'b', 'c'] - }, - 'maxProperties': 3, + "type": "object", + "properties": {k: {"type": "number"} for k in ["a", "b", "c"]}, + "maxProperties": 3, } schema = SpecPath.from_spec(spec) @@ -874,10 +998,15 @@ def test_object_max_properties(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [{'additional': 1}, ]) + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + ], + ) def test_object_additional_properties(self, value, validator_factory): spec = { - 'type': 'object', + "type": "object", } schema = SpecPath.from_spec(spec) @@ -885,27 +1014,39 @@ def test_object_additional_properties(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [{'additional': 1}, ]) + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + ], + ) def test_object_additional_properties_false( - self, value, validator_factory): + self, value, validator_factory + ): spec = { - 'type': 'object', - 'additionalProperties': False, + "type": "object", + "additionalProperties": False, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [{'additional': 1}, ]) + @pytest.mark.parametrize( + "value", + [ + {"additional": 1}, + ], + ) def test_object_additional_properties_object( - self, value, validator_factory): + self, value, validator_factory + ): additional_properties = { - 'type': 'integer', + "type": "integer", } spec = { - 'type': 'object', - 'additionalProperties': additional_properties, + "type": "object", + "additionalProperties": additional_properties, } schema = SpecPath.from_spec(spec) @@ -913,28 +1054,28 @@ def test_object_additional_properties_object( assert result is None - @pytest.mark.parametrize('value', [[], [1], [1, 2]]) + @pytest.mark.parametrize("value", [[], [1], [1, 2]]) def test_list_min_items_invalid(self, value, validator_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, - 'minItems': 3, + "minItems": 3, } schema = SpecPath.from_spec(spec) with pytest.raises(Exception): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [[], [1], [1, 2]]) + @pytest.mark.parametrize("value", [[], [1], [1, 2]]) def test_list_min_items(self, value, validator_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, - 'minItems': 0, + "minItems": 0, } schema = SpecPath.from_spec(spec) @@ -942,71 +1083,79 @@ def test_list_min_items(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [[], ]) + @pytest.mark.parametrize( + "value", + [ + [], + ], + ) def test_list_max_items_invalid_schema(self, value, validator_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, - 'maxItems': -1, + "maxItems": -1, } schema = SpecPath.from_spec(spec) with pytest.raises(InvalidSchemaValue): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [[1, 2], [2, 3, 4]]) + @pytest.mark.parametrize("value", [[1, 2], [2, 3, 4]]) def test_list_max_items_invalid(self, value, validator_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, - 'maxItems': 1, + "maxItems": 1, } schema = SpecPath.from_spec(spec) with pytest.raises(Exception): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [[1, 2, 1], [2, 2]]) + @pytest.mark.parametrize("value", [[1, 2, 1], [2, 2]]) def test_list_unique_items_invalid(self, value, validator_factory): spec = { - 'type': 'array', - 'items': { - 'type': 'number', + "type": "array", + "items": { + "type": "number", }, - 'uniqueItems': True, + "uniqueItems": True, } schema = SpecPath.from_spec(spec) with pytest.raises(Exception): validator_factory(schema).validate(value) - @pytest.mark.parametrize('value', [ - { - 'someint': 123, - }, - { - 'somestr': 'content', - }, - { - 'somestr': 'content', - 'someint': 123, - }, - ]) + @pytest.mark.parametrize( + "value", + [ + { + "someint": 123, + }, + { + "somestr": "content", + }, + { + "somestr": "content", + "someint": 123, + }, + ], + ) def test_object_with_properties(self, value, validator_factory): spec = { - 'type': 'object', - 'properties': { - 'somestr': { - 'type': 'string', + "type": "object", + "properties": { + "somestr": { + "type": "string", + }, + "someint": { + "type": "integer", }, - 'someint': { - 'type': 'integer', - } - } + }, } schema = SpecPath.from_spec(spec) @@ -1014,39 +1163,40 @@ def test_object_with_properties(self, value, validator_factory): assert result is None - @pytest.mark.parametrize('value', [ - { - 'somestr': {}, - 'someint': 123, - }, - { - 'somestr': [ - 'content1', 'content2' - ], - 'someint': 123, - }, - { - 'somestr': 123, - 'someint': 123, - }, - { - 'somestr': 'content', - 'someint': 123, - 'not_in_scheme_prop': 123, - }, - ]) + @pytest.mark.parametrize( + "value", + [ + { + "somestr": {}, + "someint": 123, + }, + { + "somestr": ["content1", "content2"], + "someint": 123, + }, + { + "somestr": 123, + "someint": 123, + }, + { + "somestr": "content", + "someint": 123, + "not_in_scheme_prop": 123, + }, + ], + ) def test_object_with_invalid_properties(self, value, validator_factory): spec = { - 'type': 'object', - 'properties': { - 'somestr': { - 'type': 'string', + "type": "object", + "properties": { + "somestr": { + "type": "string", + }, + "someint": { + "type": "integer", }, - 'someint': { - 'type': 'integer', - } }, - 'additionalProperties': False, + "additionalProperties": False, } schema = SpecPath.from_spec(spec) diff --git a/tests/unit/validation/test_request_shortcuts.py b/tests/unit/validation/test_request_shortcuts.py index 3881a73c..78536f25 100644 --- a/tests/unit/validation/test_request_shortcuts.py +++ b/tests/unit/validation/test_request_shortcuts.py @@ -4,16 +4,14 @@ from openapi_core.testing.datatypes import ResultMock from openapi_core.testing.factories import FactoryClassMock -from openapi_core.validation.request.shortcuts import ( - spec_validate_parameters, spec_validate_body, -) +from openapi_core.validation.request.shortcuts import spec_validate_body +from openapi_core.validation.request.shortcuts import spec_validate_parameters class TestSpecValidateParameters: - @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestParametersValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestParametersValidator." + "validate" ) def test_no_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -27,8 +25,8 @@ def test_no_request_factory(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestParametersValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestParametersValidator." + "validate" ) def test_no_request_factory_error(self, mock_validate): spec = mock.sentinel.spec @@ -41,8 +39,8 @@ def test_no_request_factory_error(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestParametersValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestParametersValidator." + "validate" ) def test_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -59,8 +57,8 @@ def test_request_factory(self, mock_validate): ) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestParametersValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestParametersValidator." + "validate" ) def test_request_factory_error(self, mock_validate): spec = mock.sentinel.spec @@ -77,10 +75,9 @@ def test_request_factory_error(self, mock_validate): class TestSpecValidateBody: - @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestBodyValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestBodyValidator." + "validate" ) def test_no_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -94,8 +91,8 @@ def test_no_request_factory(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestBodyValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestBodyValidator." + "validate" ) def test_no_request_factory_error(self, mock_validate): spec = mock.sentinel.spec @@ -108,8 +105,8 @@ def test_no_request_factory_error(self, mock_validate): mock_validate.aasert_called_once_with(request) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestBodyValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestBodyValidator." + "validate" ) def test_request_factory(self, mock_validate): spec = mock.sentinel.spec @@ -126,8 +123,8 @@ def test_request_factory(self, mock_validate): ) @mock.patch( - 'openapi_core.validation.request.shortcuts.RequestBodyValidator.' - 'validate' + "openapi_core.validation.request.shortcuts.RequestBodyValidator." + "validate" ) def test_request_factory_error(self, mock_validate): spec = mock.sentinel.spec diff --git a/tests/unit/validation/test_response_shortcuts.py b/tests/unit/validation/test_response_shortcuts.py index dd8855df..ef38899f 100644 --- a/tests/unit/validation/test_response_shortcuts.py +++ b/tests/unit/validation/test_response_shortcuts.py @@ -8,10 +8,9 @@ class TestSpecValidateData: - @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseDataValidator.' - 'validate' + "openapi_core.validation.response.shortcuts.ResponseDataValidator." + "validate" ) def test_no_factories(self, mock_validate): spec = mock.sentinel.spec @@ -26,8 +25,8 @@ def test_no_factories(self, mock_validate): mock_validate.aasert_called_once_with(request, response) @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseDataValidator.' - 'validate' + "openapi_core.validation.response.shortcuts.ResponseDataValidator." + "validate" ) def test_no_factories_error(self, mock_validate): spec = mock.sentinel.spec @@ -41,8 +40,8 @@ def test_no_factories_error(self, mock_validate): mock_validate.aasert_called_once_with(request, response) @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseDataValidator.' - 'validate' + "openapi_core.validation.response.shortcuts.ResponseDataValidator." + "validate" ) def test_factories(self, mock_validate): spec = mock.sentinel.spec @@ -54,8 +53,11 @@ def test_factories(self, mock_validate): response_factory = FactoryClassMock result = spec_validate_data( - spec, request, response, - request_factory, response_factory, + spec, + request, + response, + request_factory, + response_factory, ) assert result == data @@ -65,8 +67,8 @@ def test_factories(self, mock_validate): ) @mock.patch( - 'openapi_core.validation.response.shortcuts.ResponseDataValidator.' - 'validate' + "openapi_core.validation.response.shortcuts.ResponseDataValidator." + "validate" ) def test_factories_error(self, mock_validate): spec = mock.sentinel.spec @@ -78,8 +80,11 @@ def test_factories_error(self, mock_validate): with pytest.raises(ValueError): spec_validate_data( - spec, request, response, - request_factory, response_factory, + spec, + request, + response, + request_factory, + response_factory, ) mock_validate.assert_called_once_with(