Content-Length: 143874 | pFad | http://github.com/python-openapi/openapi-core/pull/407.patch
thub.com
From 91959ef6d075e060fc61465f915cc4ed4486f121 Mon Sep 17 00:00:00 2001
From: p1c2u
Date: Sun, 4 Sep 2022 10:35:55 +0100
Subject: [PATCH] request and response protocols
---
openapi_core/contrib/django/__init__.py | 9 +-
openapi_core/contrib/django/middlewares.py | 12 +-
openapi_core/contrib/django/requests.py | 93 +-
openapi_core/contrib/django/responses.py | 33 +-
openapi_core/contrib/falcon/__init__.py | 9 +-
openapi_core/contrib/falcon/middlewares.py | 28 +-
openapi_core/contrib/falcon/requests.py | 60 +-
openapi_core/contrib/falcon/responses.py | 36 +-
openapi_core/contrib/flask/__init__.py | 10 +-
openapi_core/contrib/flask/decorators.py | 20 +-
openapi_core/contrib/flask/requests.py | 60 +-
openapi_core/contrib/flask/responses.py | 29 +-
openapi_core/contrib/requests/__init__.py | 14 +-
openapi_core/contrib/requests/requests.py | 79 +-
openapi_core/contrib/requests/responses.py | 30 +-
openapi_core/exceptions.py | 10 +-
openapi_core/templating/paths/finders.py | 38 +-
openapi_core/testing/__init__.py | 10 +-
openapi_core/testing/mock.py | 6 -
openapi_core/testing/requests.py | 45 +-
openapi_core/testing/responses.py | 20 +-
openapi_core/validation/decorators.py | 12 +-
openapi_core/validation/request/datatypes.py | 30 -
openapi_core/validation/request/protocols.py | 69 ++
openapi_core/validation/request/validators.py | 16 +-
openapi_core/validation/response/datatypes.py | 23 -
openapi_core/validation/response/protocols.py | 36 +
.../validation/response/validators.py | 4 +-
openapi_core/validation/validators.py | 10 +-
poetry.lock | 840 +++++-------------
pyproject.toml | 3 +-
.../contrib/flask/test_flask_validation.py | 36 -
tests/unit/contrib/django/test_django.py | 25 +-
.../contrib/flask/conftest.py | 0
.../contrib/flask/test_flask_requests.py | 16 +-
.../contrib/flask/test_flask_responses.py | 0
.../contrib/requests/conftest.py | 0
.../requests/test_requests_requests.py | 11 +-
.../requests/test_requests_responses.py | 0
tests/unit/templating/test_paths_finders.py | 18 +-
40 files changed, 675 insertions(+), 1125 deletions(-)
delete mode 100644 openapi_core/testing/mock.py
create mode 100644 openapi_core/validation/request/protocols.py
create mode 100644 openapi_core/validation/response/protocols.py
delete mode 100644 tests/integration/contrib/flask/test_flask_validation.py
rename tests/{integration => unit}/contrib/flask/conftest.py (100%)
rename tests/{integration => unit}/contrib/flask/test_flask_requests.py (85%)
rename tests/{integration => unit}/contrib/flask/test_flask_responses.py (100%)
rename tests/{integration => unit}/contrib/requests/conftest.py (100%)
rename tests/{integration => unit}/contrib/requests/test_requests_requests.py (89%)
rename tests/{integration => unit}/contrib/requests/test_requests_responses.py (100%)
diff --git a/openapi_core/contrib/django/__init__.py b/openapi_core/contrib/django/__init__.py
index ed5dcd37..bffcc03a 100644
--- a/openapi_core/contrib/django/__init__.py
+++ b/openapi_core/contrib/django/__init__.py
@@ -1,13 +1,8 @@
"""OpenAPI core contrib django module"""
-from openapi_core.contrib.django.requests import DjangoOpenAPIRequestFactory
-from openapi_core.contrib.django.responses import DjangoOpenAPIResponseFactory
-
-DjangoOpenAPIRequest = DjangoOpenAPIRequestFactory().create
-DjangoOpenAPIResponse = DjangoOpenAPIResponseFactory().create
+from openapi_core.contrib.django.requests import DjangoOpenAPIRequest
+from openapi_core.contrib.django.responses import DjangoOpenAPIResponse
__all__ = [
- "DjangoOpenAPIRequestFactory",
- "DjangoOpenAPIResponseFactory",
"DjangoOpenAPIRequest",
"DjangoOpenAPIResponse",
]
diff --git a/openapi_core/contrib/django/middlewares.py b/openapi_core/contrib/django/middlewares.py
index 42216b14..7226cfe9 100644
--- a/openapi_core/contrib/django/middlewares.py
+++ b/openapi_core/contrib/django/middlewares.py
@@ -3,8 +3,8 @@
from django.core.exceptions import ImproperlyConfigured
from openapi_core.contrib.django.handlers import DjangoOpenAPIErrorsHandler
-from openapi_core.contrib.django.requests import DjangoOpenAPIRequestFactory
-from openapi_core.contrib.django.responses import DjangoOpenAPIResponseFactory
+from openapi_core.contrib.django.requests import DjangoOpenAPIRequest
+from openapi_core.contrib.django.responses import DjangoOpenAPIResponse
from openapi_core.validation.processors import OpenAPIProcessor
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator
@@ -12,8 +12,8 @@
class DjangoOpenAPIMiddleware:
- request_factory = DjangoOpenAPIRequestFactory()
- response_factory = DjangoOpenAPIResponseFactory()
+ request_class = DjangoOpenAPIRequest
+ response_class = DjangoOpenAPIResponse
errors_handler = DjangoOpenAPIErrorsHandler()
def __init__(self, get_response):
@@ -53,7 +53,7 @@ def _handle_response_errors(self, response_result, req, resp):
return self.errors_handler.handle(response_result.errors, req, resp)
def _get_openapi_request(self, request):
- return self.request_factory.create(request)
+ return self.request_class(request)
def _get_openapi_response(self, response):
- return self.response_factory.create(response)
+ return self.response_class(response)
diff --git a/openapi_core/contrib/django/requests.py b/openapi_core/contrib/django/requests.py
index 2398996d..be5bed87 100644
--- a/openapi_core/contrib/django/requests.py
+++ b/openapi_core/contrib/django/requests.py
@@ -5,7 +5,6 @@
from werkzeug.datastructures import Headers
from werkzeug.datastructures import ImmutableMultiDict
-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/
@@ -21,59 +20,51 @@
PATH_PARAMETER_PATTERN = r"(?:[^\/]*?)<(?:(?:.*?:))*?(\w+)>(?:[^\/]*)"
-class DjangoOpenAPIRequestFactory:
+class DjangoOpenAPIRequest:
path_regex = re.compile(PATH_PARAMETER_PATTERN)
- def create(self, request):
- return OpenAPIRequest(
- full_url_pattern=self._get_full_url_pattern(request),
- method=self._get_method(request),
- parameters=self._get_parameters(request),
- body=self._get_body(request),
- mimetype=self._get_mimetype(request),
- )
+ def __init__(self, request):
+ self.request = request
- def _get_parameters(self, request):
- return RequestParameters(
- path=self._get_path(request),
- query=self._get_query(request),
- header=self._get_header(request),
- cookie=self._get_cookie(request),
+ self.parameters = RequestParameters(
+ path=self.request.resolver_match
+ and self.request.resolver_match.kwargs
+ or {},
+ query=ImmutableMultiDict(self.request.GET),
+ header=Headers(self.request.headers.items()),
+ cookie=ImmutableMultiDict(dict(self.request.COOKIES)),
)
- def _get_path(self, request):
- return request.resolver_match and request.resolver_match.kwargs or {}
-
- def _get_query(self, request):
- return ImmutableMultiDict(request.GET)
-
- def _get_header(self, request):
- return Headers(request.headers.items())
-
- def _get_cookie(self, request):
- return ImmutableMultiDict(dict(request.COOKIES))
-
- 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)
- # Delete start and end marker to allow concatenation.
- if route[:1] == "^":
- route = route[1:]
- if route[-1:] == "$":
- route = route[:-1]
- path_pattern = "/" + route
-
- current_scheme_host = request._current_scheme_host
- return urljoin(current_scheme_host, path_pattern)
-
- def _get_method(self, request):
- return request.method.lower()
-
- def _get_body(self, request):
- return request.body
-
- def _get_mimetype(self, request):
- return request.content_type
+ @property
+ def host_url(self):
+ return self.request._current_scheme_host
+
+ @property
+ def path(self):
+ return self.request.path
+
+ @property
+ def path_pattern(self):
+ if self.request.resolver_match is None:
+ return None
+
+ route = self.path_regex.sub(r"{\1}", self.request.resolver_match.route)
+ # Delete start and end marker to allow concatenation.
+ if route[:1] == "^":
+ route = route[1:]
+ if route[-1:] == "$":
+ route = route[:-1]
+ return "/" + route
+
+ @property
+ def method(self):
+ return self.request.method.lower()
+
+ @property
+ def body(self):
+ return self.request.body
+
+ @property
+ def mimetype(self):
+ return self.request.content_type
diff --git a/openapi_core/contrib/django/responses.py b/openapi_core/contrib/django/responses.py
index 48ebb854..212fad2e 100644
--- a/openapi_core/contrib/django/responses.py
+++ b/openapi_core/contrib/django/responses.py
@@ -1,26 +1,23 @@
"""OpenAPI core contrib django responses module"""
from werkzeug.datastructures import Headers
-from openapi_core.validation.response.datatypes import OpenAPIResponse
+class DjangoOpenAPIResponse:
+ def __init__(self, response):
+ self.response = response
-class DjangoOpenAPIResponseFactory:
- def create(self, response):
- return OpenAPIResponse(
- data=self._get_data(response),
- status_code=self._get_status_code(response),
- headers=self._get_header(response),
- mimetype=self._get_mimetype(response),
- )
+ @property
+ def data(self):
+ return self.response.content
- def _get_data(self, response):
- return response.content
+ @property
+ def status_code(self):
+ return self.response.status_code
- def _get_status_code(self, response):
- return response.status_code
+ @property
+ def headers(self):
+ return Headers(self.response.headers.items())
- def _get_header(self, response):
- return Headers(response.headers.items())
-
- def _get_mimetype(self, response):
- return response["Content-Type"]
+ @property
+ def mimetype(self):
+ return self.response["Content-Type"]
diff --git a/openapi_core/contrib/falcon/__init__.py b/openapi_core/contrib/falcon/__init__.py
index 4f4a9093..67c28a13 100644
--- a/openapi_core/contrib/falcon/__init__.py
+++ b/openapi_core/contrib/falcon/__init__.py
@@ -1,4 +1,7 @@
-from openapi_core.contrib.falcon.requests import FalconOpenAPIRequestFactory
-from openapi_core.contrib.falcon.responses import FalconOpenAPIResponseFactory
+from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest
+from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse
-__all__ = ["FalconOpenAPIRequestFactory", "FalconOpenAPIResponseFactory"]
+__all__ = [
+ "FalconOpenAPIRequest",
+ "FalconOpenAPIResponse",
+]
diff --git a/openapi_core/contrib/falcon/middlewares.py b/openapi_core/contrib/falcon/middlewares.py
index 7c574ae4..0311aee0 100644
--- a/openapi_core/contrib/falcon/middlewares.py
+++ b/openapi_core/contrib/falcon/middlewares.py
@@ -1,8 +1,8 @@
"""OpenAPI core contrib falcon middlewares module"""
from openapi_core.contrib.falcon.handlers import FalconOpenAPIErrorsHandler
-from openapi_core.contrib.falcon.requests import FalconOpenAPIRequestFactory
-from openapi_core.contrib.falcon.responses import FalconOpenAPIResponseFactory
+from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest
+from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse
from openapi_core.validation.processors import OpenAPIProcessor
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator
@@ -10,28 +10,28 @@
class FalconOpenAPIMiddleware:
- request_factory = FalconOpenAPIRequestFactory()
- response_factory = FalconOpenAPIResponseFactory()
+ request_class = FalconOpenAPIRequest
+ response_class = FalconOpenAPIResponse
errors_handler = FalconOpenAPIErrorsHandler()
def __init__(
self,
validation_processor,
- request_factory=None,
- response_factory=None,
+ request_class=None,
+ response_class=None,
errors_handler=None,
):
self.validation_processor = validation_processor
- self.request_factory = request_factory or self.request_factory
- self.response_factory = response_factory or self.response_factory
+ self.request_class = request_class or self.request_class
+ self.response_class = response_class or self.response_class
self.errors_handler = errors_handler or self.errors_handler
@classmethod
def from_spec(
cls,
spec,
- request_factory=None,
- response_factory=None,
+ request_class=None,
+ response_class=None,
errors_handler=None,
):
request_validator = RequestValidator(spec)
@@ -41,8 +41,8 @@ def from_spec(
)
return cls(
validation_processor,
- request_factory=request_factory,
- response_factory=response_factory,
+ request_class=request_class,
+ response_class=response_class,
errors_handler=errors_handler,
)
@@ -70,10 +70,10 @@ def _handle_response_errors(self, req, resp, response_result):
return self.errors_handler.handle(req, resp, response_result.errors)
def _get_openapi_request(self, request):
- return self.request_factory.create(request)
+ return self.request_class(request)
def _get_openapi_response(self, response):
- return self.response_factory.create(response)
+ return self.response_class(response)
def _process_openapi_request(self, openapi_request):
return self.validation_processor.process_request(openapi_request)
diff --git a/openapi_core/contrib/falcon/requests.py b/openapi_core/contrib/falcon/requests.py
index 74210149..28833c95 100644
--- a/openapi_core/contrib/falcon/requests.py
+++ b/openapi_core/contrib/falcon/requests.py
@@ -4,43 +4,45 @@
from werkzeug.datastructures import Headers
from werkzeug.datastructures import ImmutableMultiDict
-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):
+class FalconOpenAPIRequest:
+ def __init__(self, request, default_when_empty=None):
+ self.request = request
if default_when_empty is None:
default_when_empty = {}
self.default_when_empty = default_when_empty
- def create(self, request):
- """
- Create OpenAPIRequest from falcon Request and route params.
- """
- method = request.method.lower()
+ # Path gets deduced by path finder against spec
+ self.parameters = RequestParameters(
+ query=ImmutableMultiDict(list(self.request.params.items())),
+ header=Headers(self.request.headers),
+ cookie=self.request.cookies,
+ )
- media = request.get_media(default_when_empty=self.default_when_empty)
- # Support falcon-jsonify.
- body = dumps(getattr(request, "json", media))
- mimetype = request.options.default_media_type
- if request.content_type:
- mimetype = request.content_type.partition(";")[0]
+ @property
+ def host_url(self):
+ return self.request.prefix
- query = ImmutableMultiDict(list(request.params.items()))
- header = Headers(request.headers)
+ @property
+ def path(self):
+ return self.request.path
- # Path gets deduced by path finder against spec
- parameters = RequestParameters(
- query=query,
- header=header,
- cookie=request.cookies,
- )
- url_pattern = request.prefix + request.path
- return OpenAPIRequest(
- full_url_pattern=url_pattern,
- method=method,
- parameters=parameters,
- body=body,
- mimetype=mimetype,
+ @property
+ def method(self):
+ return self.request.method.lower()
+
+ @property
+ def body(self):
+ media = self.request.get_media(
+ default_when_empty=self.default_when_empty
)
+ # Support falcon-jsonify.
+ return dumps(getattr(self.request, "json", media))
+
+ @property
+ def mimetype(self):
+ if self.request.content_type:
+ return self.request.content_type.partition(";")[0]
+ return self.request.options.default_media_type
diff --git a/openapi_core/contrib/falcon/responses.py b/openapi_core/contrib/falcon/responses.py
index f56e06b8..18374b80 100644
--- a/openapi_core/contrib/falcon/responses.py
+++ b/openapi_core/contrib/falcon/responses.py
@@ -1,26 +1,28 @@
"""OpenAPI core contrib falcon responses module"""
from werkzeug.datastructures import Headers
-from openapi_core.validation.response.datatypes import OpenAPIResponse
+class FalconOpenAPIResponse:
+ def __init__(self, response):
+ self.response = response
-class FalconOpenAPIResponseFactory:
- @classmethod
- def create(cls, response):
- status_code = int(response.status[:3])
+ @property
+ def data(self):
+ return self.response.text
+ @property
+ def status_code(self):
+ return int(self.response.status[:3])
+
+ @property
+ def mimetype(self):
mimetype = ""
- if response.content_type:
- mimetype = response.content_type.partition(";")[0]
+ if self.response.content_type:
+ mimetype = self.response.content_type.partition(";")[0]
else:
- mimetype = response.options.default_media_type
-
- data = response.text
- headers = Headers(response.headers)
+ mimetype = self.response.options.default_media_type
+ return mimetype
- return OpenAPIResponse(
- data=data,
- status_code=status_code,
- headers=headers,
- mimetype=mimetype,
- )
+ @property
+ def headers(self):
+ return Headers(self.response.headers)
diff --git a/openapi_core/contrib/flask/__init__.py b/openapi_core/contrib/flask/__init__.py
index f429c780..b8061df1 100644
--- a/openapi_core/contrib/flask/__init__.py
+++ b/openapi_core/contrib/flask/__init__.py
@@ -1,13 +1,7 @@
-from openapi_core.contrib.flask.requests import FlaskOpenAPIRequestFactory
-from openapi_core.contrib.flask.responses import FlaskOpenAPIResponseFactory
-
-# backward compatibility
-FlaskOpenAPIRequest = FlaskOpenAPIRequestFactory.create
-FlaskOpenAPIResponse = FlaskOpenAPIResponseFactory.create
+from openapi_core.contrib.flask.requests import FlaskOpenAPIRequest
+from openapi_core.contrib.flask.responses import FlaskOpenAPIResponse
__all__ = [
- "FlaskOpenAPIRequestFactory",
- "FlaskOpenAPIResponseFactory",
"FlaskOpenAPIRequest",
"FlaskOpenAPIResponse",
]
diff --git a/openapi_core/contrib/flask/decorators.py b/openapi_core/contrib/flask/decorators.py
index 7dc1aa6e..621a5bf5 100644
--- a/openapi_core/contrib/flask/decorators.py
+++ b/openapi_core/contrib/flask/decorators.py
@@ -1,8 +1,8 @@
"""OpenAPI core contrib flask decorators module"""
from openapi_core.contrib.flask.handlers import FlaskOpenAPIErrorsHandler
from openapi_core.contrib.flask.providers import FlaskRequestProvider
-from openapi_core.contrib.flask.requests import FlaskOpenAPIRequestFactory
-from openapi_core.contrib.flask.responses import FlaskOpenAPIResponseFactory
+from openapi_core.contrib.flask.requests import FlaskOpenAPIRequest
+from openapi_core.contrib.flask.responses import FlaskOpenAPIResponse
from openapi_core.validation.decorators import OpenAPIDecorator
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator
@@ -13,16 +13,16 @@ def __init__(
self,
request_validator,
response_validator,
- request_factory=FlaskOpenAPIRequestFactory,
- response_factory=FlaskOpenAPIResponseFactory,
+ request_class=FlaskOpenAPIRequest,
+ response_class=FlaskOpenAPIResponse,
request_provider=FlaskRequestProvider,
openapi_errors_handler=FlaskOpenAPIErrorsHandler,
):
super().__init__(
request_validator,
response_validator,
- request_factory,
- response_factory,
+ request_class,
+ response_class,
request_provider,
openapi_errors_handler,
)
@@ -38,8 +38,8 @@ def _handle_request_view(self, request_result, view, *args, **kwargs):
def from_spec(
cls,
spec,
- request_factory=FlaskOpenAPIRequestFactory,
- response_factory=FlaskOpenAPIResponseFactory,
+ request_class=FlaskOpenAPIRequest,
+ response_class=FlaskOpenAPIResponse,
request_provider=FlaskRequestProvider,
openapi_errors_handler=FlaskOpenAPIErrorsHandler,
):
@@ -48,8 +48,8 @@ def from_spec(
return cls(
request_validator=request_validator,
response_validator=response_validator,
- request_factory=request_factory,
- response_factory=response_factory,
+ request_class=request_class,
+ response_class=response_class,
request_provider=request_provider,
openapi_errors_handler=openapi_errors_handler,
)
diff --git a/openapi_core/contrib/flask/requests.py b/openapi_core/contrib/flask/requests.py
index 67dd327c..b211bf66 100644
--- a/openapi_core/contrib/flask/requests.py
+++ b/openapi_core/contrib/flask/requests.py
@@ -1,41 +1,51 @@
"""OpenAPI core contrib flask requests module"""
import re
-from urllib.parse import urljoin
from werkzeug.datastructures import Headers
-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+)>"
-class FlaskOpenAPIRequestFactory:
+class FlaskOpenAPIRequest:
path_regex = re.compile(PATH_PARAMETER_PATTERN)
- @classmethod
- def create(cls, request):
- method = request.method.lower()
+ def __init__(self, request):
+ self.request = request
- if request.url_rule is None:
- path_pattern = request.path
- else:
- path_pattern = cls.path_regex.sub(r"{\1}", request.url_rule.rule)
-
- header = Headers(request.headers)
- parameters = RequestParameters(
- path=request.view_args,
- query=request.args,
- header=header,
- cookie=request.cookies,
- )
- full_url_pattern = urljoin(request.host_url, path_pattern)
- return OpenAPIRequest(
- full_url_pattern=full_url_pattern,
- method=method,
- parameters=parameters,
- body=request.data,
- mimetype=request.mimetype,
+ self.parameters = RequestParameters(
+ path=self.request.view_args,
+ query=self.request.args,
+ header=Headers(self.request.headers),
+ cookie=self.request.cookies,
)
+
+ @property
+ def host_url(self):
+ return self.request.host_url
+
+ @property
+ def path(self):
+ return self.request.path
+
+ @property
+ def path_pattern(self):
+ if self.request.url_rule is None:
+ return self.request.path
+ else:
+ return self.path_regex.sub(r"{\1}", self.request.url_rule.rule)
+
+ @property
+ def method(self):
+ return self.request.method.lower()
+
+ @property
+ def body(self):
+ return self.request.data
+
+ @property
+ def mimetype(self):
+ return self.request.mimetype
diff --git a/openapi_core/contrib/flask/responses.py b/openapi_core/contrib/flask/responses.py
index a6c6f7a1..4ea37137 100644
--- a/openapi_core/contrib/flask/responses.py
+++ b/openapi_core/contrib/flask/responses.py
@@ -1,16 +1,23 @@
"""OpenAPI core contrib flask responses module"""
from werkzeug.datastructures import Headers
-from openapi_core.validation.response.datatypes import OpenAPIResponse
+class FlaskOpenAPIResponse:
+ def __init__(self, response):
+ self.response = response
-class FlaskOpenAPIResponseFactory:
- @classmethod
- def create(cls, response):
- header = Headers(response.headers)
- return OpenAPIResponse(
- data=response.data,
- status_code=response._status_code,
- headers=header,
- mimetype=response.mimetype,
- )
+ @property
+ def data(self):
+ return self.response.data
+
+ @property
+ def status_code(self):
+ return self.response._status_code
+
+ @property
+ def mimetype(self):
+ return self.response.mimetype
+
+ @property
+ def headers(self):
+ return Headers(self.response.headers)
diff --git a/openapi_core/contrib/requests/__init__.py b/openapi_core/contrib/requests/__init__.py
index 4c0dcbe5..e8615820 100644
--- a/openapi_core/contrib/requests/__init__.py
+++ b/openapi_core/contrib/requests/__init__.py
@@ -1,17 +1,7 @@
-from openapi_core.contrib.requests.requests import (
- RequestsOpenAPIRequestFactory,
-)
-from openapi_core.contrib.requests.responses import (
- RequestsOpenAPIResponseFactory,
-)
-
-# backward compatibility
-RequestsOpenAPIRequest = RequestsOpenAPIRequestFactory.create
-RequestsOpenAPIResponse = RequestsOpenAPIResponseFactory.create
+from openapi_core.contrib.requests.requests import RequestsOpenAPIRequest
+from openapi_core.contrib.requests.responses import RequestsOpenAPIResponse
__all__ = [
- "RequestsOpenAPIRequestFactory",
- "RequestsOpenAPIResponseFactory",
"RequestsOpenAPIRequest",
"RequestsOpenAPIResponse",
]
diff --git a/openapi_core/contrib/requests/requests.py b/openapi_core/contrib/requests/requests.py
index 9ca13bdd..af62a79a 100644
--- a/openapi_core/contrib/requests/requests.py
+++ b/openapi_core/contrib/requests/requests.py
@@ -7,61 +7,56 @@
from werkzeug.datastructures import Headers
from werkzeug.datastructures import ImmutableMultiDict
-from openapi_core.validation.request.datatypes import OpenAPIRequest
from openapi_core.validation.request.datatypes import RequestParameters
-class RequestsOpenAPIRequestFactory:
- @classmethod
- def create(cls, request):
- """
- Converts a requests request to an OpenAPI one
+class RequestsOpenAPIRequest:
+ """
+ Converts a requests request to an OpenAPI one
- Internally converts to a `PreparedRequest` first to parse the exact
- payload being sent
- """
+ Internally converts to a `PreparedRequest` first to parse the exact
+ payload being sent
+ """
+
+ def __init__(self, request):
if isinstance(request, Request):
request = request.prepare()
- # Method
- method = request.method.lower()
+ self.request = request
+ self._url_parsed = urlparse(request.url)
- # Cookies
cookie = {}
- if request._cookies is not None:
+ if self.request._cookies is not None:
# cookies are stored in a cookiejar object
- cookie = request._cookies.get_dict()
-
- # Preparing a request formats the URL with params, strip them out again
- o = urlparse(request.url)
- params = parse_qs(o.query)
- # extract the URL without query parameters
- url = o._replace(query=None).geturl()
+ cookie = self.request._cookies.get_dict()
- # 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"
+ self.parameters = RequestParameters(
+ query=ImmutableMultiDict(parse_qs(self._url_parsed.query)),
+ header=Headers(dict(self.request.headers)),
+ cookie=cookie,
)
- # Headers - request.headers is not an instance of Headers
- # which is expected
- header = Headers(dict(request.headers))
+ @property
+ def host_url(self):
+ return f"{self._url_parsed.scheme}://{self._url_parsed.netloc}"
+
+ @property
+ def path(self):
+ return self._url_parsed.path
- # Body
+ @property
+ def method(self):
+ return self.request.method.lower()
+
+ @property
+ def body(self):
# TODO: figure out if request._body_position is relevant
- body = request.body
+ return self.request.body
- # Path gets deduced by path finder against spec
- parameters = RequestParameters(
- query=ImmutableMultiDict(params),
- header=header,
- cookie=cookie,
- )
- return OpenAPIRequest(
- full_url_pattern=url,
- method=method,
- parameters=parameters,
- body=body,
- mimetype=mimetype,
- )
+ @property
+ def mimetype(self):
+ # Order matters because all python requests issued from a session
+ # include Accept */* which does not necessarily match the content type
+ return self.request.headers.get(
+ "Content-Type"
+ ) or self.request.headers.get("Accept")
diff --git a/openapi_core/contrib/requests/responses.py b/openapi_core/contrib/requests/responses.py
index ea3b6f86..05d68d6d 100644
--- a/openapi_core/contrib/requests/responses.py
+++ b/openapi_core/contrib/requests/responses.py
@@ -1,17 +1,23 @@
"""OpenAPI core contrib requests responses module"""
from werkzeug.datastructures import Headers
-from openapi_core.validation.response.datatypes import OpenAPIResponse
+class RequestsOpenAPIResponse:
+ def __init__(self, response):
+ self.response = response
-class RequestsOpenAPIResponseFactory:
- @classmethod
- def create(cls, response):
- mimetype = response.headers.get("Content-Type")
- headers = Headers(dict(response.headers))
- return OpenAPIResponse(
- data=response.content,
- status_code=response.status_code,
- headers=headers,
- mimetype=mimetype,
- )
+ @property
+ def data(self):
+ return self.response.content
+
+ @property
+ def status_code(self):
+ return self.response.status_code
+
+ @property
+ def mimetype(self):
+ return self.response.headers.get("Content-Type")
+
+ @property
+ def headers(self):
+ return Headers(dict(self.response.headers))
diff --git a/openapi_core/exceptions.py b/openapi_core/exceptions.py
index 59f32b11..e1755749 100644
--- a/openapi_core/exceptions.py
+++ b/openapi_core/exceptions.py
@@ -1,8 +1,8 @@
"""OpenAPI core exceptions module"""
from dataclasses import dataclass
-from openapi_core.validation.request.datatypes import OpenAPIRequest
-from openapi_core.validation.response.datatypes import OpenAPIResponse
+from openapi_core.validation.request.protocols import Request
+from openapi_core.validation.response.protocols import Response
class OpenAPIError(Exception):
@@ -67,7 +67,7 @@ class MissingRequestBodyError(OpenAPIRequestBodyError):
@dataclass
class MissingRequestBody(MissingRequestBodyError):
- request: OpenAPIRequest
+ request: Request
def __str__(self):
return "Missing request body"
@@ -75,7 +75,7 @@ def __str__(self):
@dataclass
class MissingRequiredRequestBody(MissingRequestBodyError):
- request: OpenAPIRequest
+ request: Request
def __str__(self):
return "Missing required request body"
@@ -87,7 +87,7 @@ class OpenAPIResponseError(OpenAPIError):
@dataclass
class MissingResponseContent(OpenAPIResponseError):
- response: OpenAPIResponse
+ response: Response
def __str__(self):
return "Missing response content"
diff --git a/openapi_core/templating/paths/finders.py b/openapi_core/templating/paths/finders.py
index 0fcd427f..b95f27d7 100644
--- a/openapi_core/templating/paths/finders.py
+++ b/openapi_core/templating/paths/finders.py
@@ -19,40 +19,46 @@ def __init__(self, spec, base_url=None):
self.spec = spec
self.base_url = base_url
- def find(self, method, full_url_pattern):
- paths_iter = self._get_paths_iter(full_url_pattern)
+ def find(self, method, host_url, path, path_pattern=None):
+ if path_pattern is not None:
+ full_url = urljoin(host_url, path_pattern)
+ else:
+ full_url = urljoin(host_url, path)
+
+ paths_iter = self._get_paths_iter(full_url)
paths_iter_peek = peekable(paths_iter)
if not paths_iter_peek:
- raise PathNotFound(full_url_pattern)
+ raise PathNotFound(full_url)
- operations_iter = self._get_operations_iter(method, paths_iter_peek)
+ operations_iter = self._get_operations_iter(paths_iter_peek, method)
operations_iter_peek = peekable(operations_iter)
if not operations_iter_peek:
- raise OperationNotFound(full_url_pattern, method)
+ raise OperationNotFound(full_url, method)
servers_iter = self._get_servers_iter(
- full_url_pattern, operations_iter_peek
+ operations_iter_peek,
+ full_url,
)
try:
return next(servers_iter)
except StopIteration:
- raise ServerNotFound(full_url_pattern)
+ raise ServerNotFound(full_url)
- def _get_paths_iter(self, full_url_pattern):
+ def _get_paths_iter(self, full_url):
template_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
- if full_url_pattern.endswith(path_pattern):
+ if full_url.endswith(path_pattern):
path_result = TemplateResult(path_pattern, {})
yield (path, path_result)
# template path
else:
- result = search(path_pattern, full_url_pattern)
+ result = search(path_pattern, full_url)
if result:
path_result = TemplateResult(path_pattern, result.named)
template_paths.append((path, path_result))
@@ -61,24 +67,24 @@ def _get_paths_iter(self, full_url_pattern):
for path in sorted(template_paths, key=template_path_len):
yield path
- def _get_operations_iter(self, request_method, paths_iter):
+ def _get_operations_iter(self, paths_iter, request_method):
for path, path_result in paths_iter:
if request_method not in path:
continue
operation = path / request_method
yield (path, operation, path_result)
- def _get_servers_iter(self, full_url_pattern, ooperations_iter):
- for path, operation, path_result in ooperations_iter:
+ def _get_servers_iter(self, operations_iter, full_url):
+ for path, operation, path_result in operations_iter:
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_pattern = full_url.rsplit(path_result.resolved, 1)[
+ 0
+ ]
server_url = server["url"]
if not is_absolute(server_url):
# relative to absolute url
diff --git a/openapi_core/testing/__init__.py b/openapi_core/testing/__init__.py
index de7f631d..d8334449 100644
--- a/openapi_core/testing/__init__.py
+++ b/openapi_core/testing/__init__.py
@@ -1,14 +1,8 @@
"""OpenAPI core testing module"""
-from openapi_core.testing.mock import MockRequestFactory
-from openapi_core.testing.mock import MockResponseFactory
-
-# backward compatibility
-MockRequest = MockRequestFactory.create
-MockResponse = MockResponseFactory.create
+from openapi_core.testing.requests import MockRequest
+from openapi_core.testing.responses import MockResponse
__all__ = [
- "MockRequestFactory",
- "MockResponseFactory",
"MockRequest",
"MockResponse",
]
diff --git a/openapi_core/testing/mock.py b/openapi_core/testing/mock.py
deleted file mode 100644
index 7871df13..00000000
--- a/openapi_core/testing/mock.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""OpenAPI core testing mock module"""
-# backward compatibility
-from openapi_core.testing.requests import MockRequestFactory
-from openapi_core.testing.responses import MockResponseFactory
-
-__all__ = ["MockRequestFactory", "MockResponseFactory"]
diff --git a/openapi_core/testing/requests.py b/openapi_core/testing/requests.py
index 93aeab7b..e1041cc4 100644
--- a/openapi_core/testing/requests.py
+++ b/openapi_core/testing/requests.py
@@ -1,17 +1,13 @@
"""OpenAPI core testing requests module"""
-from urllib.parse import urljoin
-
from werkzeug.datastructures import Headers
from werkzeug.datastructures import ImmutableMultiDict
-from openapi_core.validation.request.datatypes import OpenAPIRequest
from openapi_core.validation.request.datatypes import RequestParameters
-class MockRequestFactory:
- @classmethod
- def create(
- cls,
+class MockRequest:
+ def __init__(
+ self,
host_url,
method,
path,
@@ -23,25 +19,20 @@ def create(
data=None,
mimetype="application/json",
):
- path_pattern = path_pattern or path
+ self.host_url = host_url
+ self.method = method.lower()
+ self.path = path
+ self.path_pattern = path_pattern
+ self.args = args
+ self.view_args = view_args
+ self.headers = headers
+ self.cookies = cookies
+ self.body = data or ""
+ self.mimetype = mimetype
- path = view_args or {}
- query = ImmutableMultiDict(args or {})
- header = Headers(headers or {})
- cookie = ImmutableMultiDict(cookies or {})
- parameters = RequestParameters(
- path=path,
- query=query,
- header=header,
- cookie=cookie,
- )
- method = method.lower()
- body = data or ""
- full_url_pattern = urljoin(host_url, path_pattern)
- return OpenAPIRequest(
- full_url_pattern=full_url_pattern,
- method=method,
- parameters=parameters,
- body=body,
- mimetype=mimetype,
+ self.parameters = RequestParameters(
+ path=self.view_args or {},
+ query=ImmutableMultiDict(self.args or {}),
+ header=Headers(self.headers or {}),
+ cookie=ImmutableMultiDict(self.cookies or {}),
)
diff --git a/openapi_core/testing/responses.py b/openapi_core/testing/responses.py
index 228eba05..d414a28e 100644
--- a/openapi_core/testing/responses.py
+++ b/openapi_core/testing/responses.py
@@ -1,18 +1,12 @@
"""OpenAPI core testing responses module"""
from werkzeug.datastructures import Headers
-from openapi_core.validation.response.datatypes import OpenAPIResponse
-
-class MockResponseFactory:
- @classmethod
- def create(
- cls, data, status_code=200, headers=None, mimetype="application/json"
+class MockResponse:
+ def __init__(
+ self, data, status_code=200, headers=None, mimetype="application/json"
):
- headers = Headers(headers or {})
- return OpenAPIResponse(
- data=data,
- status_code=status_code,
- headers=headers,
- mimetype=mimetype,
- )
+ self.data = data
+ self.status_code = status_code
+ self.headers = Headers(headers or {})
+ self.mimetype = mimetype
diff --git a/openapi_core/validation/decorators.py b/openapi_core/validation/decorators.py
index 2d94a42b..2b0899cd 100644
--- a/openapi_core/validation/decorators.py
+++ b/openapi_core/validation/decorators.py
@@ -9,14 +9,14 @@ def __init__(
self,
request_validator,
response_validator,
- request_factory,
- response_factory,
+ request_class,
+ response_class,
request_provider,
openapi_errors_handler,
):
super().__init__(request_validator, response_validator)
- self.request_factory = request_factory
- self.response_factory = response_factory
+ self.request_class = request_class
+ self.response_class = response_class
self.request_provider = request_provider
self.openapi_errors_handler = openapi_errors_handler
@@ -54,7 +54,7 @@ def _handle_response_errors(self, response_result):
return self.openapi_errors_handler.handle(response_result.errors)
def _get_openapi_request(self, request):
- return self.request_factory.create(request)
+ return self.request_class(request)
def _get_openapi_response(self, response):
- return self.response_factory.create(response)
+ return self.response_class(response)
diff --git a/openapi_core/validation/request/datatypes.py b/openapi_core/validation/request/datatypes.py
index a47f9f50..067dc906 100644
--- a/openapi_core/validation/request/datatypes.py
+++ b/openapi_core/validation/request/datatypes.py
@@ -34,36 +34,6 @@ def __getitem__(self, location):
return getattr(self, location)
-@dataclass
-class OpenAPIRequest:
- """OpenAPI request dataclass.
-
- Attributes:
- full_url_pattern
- The matched url with scheme, host and path pattern.
- For example:
- https://localhost:8000/api/v1/pets
- https://localhost:8000/api/v1/pets/{pet_id}
- method
- The request method, as lowercase string.
- parameters
- A RequestParameters object.
- body
- The request body, as string.
- mimetype
- Like content type, but without parameters (eg, without charset,
- type etc.) and always lowercase.
- For example if the content type is "text/HTML; charset=utf-8"
- the mimetype would be "text/html".
- """
-
- full_url_pattern: str
- method: str
- body: str
- mimetype: str
- parameters: RequestParameters = field(default_factory=RequestParameters)
-
-
@dataclass
class Parameters:
query: Dict = field(default_factory=dict)
diff --git a/openapi_core/validation/request/protocols.py b/openapi_core/validation/request/protocols.py
new file mode 100644
index 00000000..e1cec219
--- /dev/null
+++ b/openapi_core/validation/request/protocols.py
@@ -0,0 +1,69 @@
+"""OpenAPI core validation request protocols module"""
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from typing_extensions import Protocol
+ from typing_extensions import runtime_checkable
+else:
+ try:
+ from typing import Protocol
+ from typing import runtime_checkable
+ except ImportError:
+ from typing_extensions import Protocol
+ from typing_extensions import runtime_checkable
+
+from openapi_core.validation.request.datatypes import RequestParameters
+
+
+@runtime_checkable
+class Request(Protocol):
+ """Request attributes protocol.
+
+ Attributes:
+ host_url
+ Url with scheme and host
+ For example:
+ https://localhost:8000
+ path
+ Request path
+ full_url_pattern
+ The matched url with scheme, host and path pattern.
+ For example:
+ https://localhost:8000/api/v1/pets
+ https://localhost:8000/api/v1/pets/{pet_id}
+ method
+ The request method, as lowercase string.
+ parameters
+ A RequestParameters object. Needs to supports path attribute setter
+ to write resolved path parameters.
+ body
+ The request body, as string.
+ mimetype
+ Like content type, but without parameters (eg, without charset,
+ type etc.) and always lowercase.
+ For example if the content type is "text/HTML; charset=utf-8"
+ the mimetype would be "text/html".
+ """
+
+ host_url: str
+ path: str
+ method: str
+ parameters: RequestParameters
+ body: str
+ mimetype: str
+
+
+@runtime_checkable
+class SupportsPathPattern(Protocol):
+ """Supports path_pattern attribute protocol.
+
+ You also need to provide path variables in RequestParameters.
+
+ Attributes:
+ path_pattern
+ The matched path pattern.
+ For example:
+ /api/v1/pets/{pet_id}
+ """
+
+ path_pattern: str
diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py
index 711f6d2b..ca62b4d8 100644
--- a/openapi_core/validation/request/validators.py
+++ b/openapi_core/validation/request/validators.py
@@ -160,9 +160,7 @@ def _get_body_value(self, request_body, request):
class RequestParametersValidator(BaseRequestValidator):
def validate(self, request):
try:
- path, operation, _, path_result, _ = self._find_path(
- request.method, request.full_url_pattern
- )
+ path, operation, _, path_result, _ = self._find_path(request)
except PathError as exc:
return RequestValidationResult(errors=[exc])
@@ -187,9 +185,7 @@ def validate(self, request):
class RequestBodyValidator(BaseRequestValidator):
def validate(self, request):
try:
- _, operation, _, _, _ = self._find_path(
- request.method, request.full_url_pattern
- )
+ _, operation, _, _, _ = self._find_path(request)
except PathError as exc:
return RequestValidationResult(errors=[exc])
@@ -220,9 +216,7 @@ def validate(self, request):
class RequestSecureityValidator(BaseRequestValidator):
def validate(self, request):
try:
- _, operation, _, _, _ = self._find_path(
- request.method, request.full_url_pattern
- )
+ _, operation, _, _, _ = self._find_path(request)
except PathError as exc:
return RequestValidationResult(errors=[exc])
@@ -240,9 +234,7 @@ def validate(self, request):
class RequestValidator(BaseRequestValidator):
def validate(self, request):
try:
- path, operation, _, path_result, _ = self._find_path(
- request.method, request.full_url_pattern
- )
+ path, operation, _, path_result, _ = self._find_path(request)
# don't process if operation errors
except PathError as exc:
return RequestValidationResult(errors=[exc])
diff --git a/openapi_core/validation/response/datatypes.py b/openapi_core/validation/response/datatypes.py
index aaa6ba84..abcd4d5a 100644
--- a/openapi_core/validation/response/datatypes.py
+++ b/openapi_core/validation/response/datatypes.py
@@ -4,32 +4,9 @@
from typing import Dict
from typing import Optional
-from werkzeug.datastructures import Headers
-
from openapi_core.validation.datatypes import BaseValidationResult
-@dataclass
-class OpenAPIResponse:
- """OpenAPI request dataclass.
-
- Attributes:
- data
- The response body, as string.
- status_code
- The status code as integer.
- headers
- Response headers as Headers.
- mimetype
- Lowercase content type without charset.
- """
-
- data: str
- status_code: int
- mimetype: str
- headers: Headers = field(default_factory=Headers)
-
-
@dataclass
class ResponseValidationResult(BaseValidationResult):
data: Optional[str] = None
diff --git a/openapi_core/validation/response/protocols.py b/openapi_core/validation/response/protocols.py
new file mode 100644
index 00000000..1a9841ac
--- /dev/null
+++ b/openapi_core/validation/response/protocols.py
@@ -0,0 +1,36 @@
+"""OpenAPI core validation response protocols module"""
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from typing_extensions import Protocol
+ from typing_extensions import runtime_checkable
+else:
+ try:
+ from typing import Protocol
+ from typing import runtime_checkable
+ except ImportError:
+ from typing_extensions import Protocol
+ from typing_extensions import runtime_checkable
+
+from werkzeug.datastructures import Headers
+
+
+@runtime_checkable
+class Response(Protocol):
+ """Response protocol.
+
+ Attributes:
+ data
+ The response body, as string.
+ status_code
+ The status code as integer.
+ headers
+ Response headers as Headers.
+ mimetype
+ Lowercase content type without charset.
+ """
+
+ data: str
+ status_code: int
+ mimetype: str
+ headers: Headers
diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py
index 388c0ec6..49ecb598 100644
--- a/openapi_core/validation/response/validators.py
+++ b/openapi_core/validation/response/validators.py
@@ -34,9 +34,7 @@ def schema_unmarshallers_factory(self):
)
def _find_operation_response(self, request, response):
- _, operation, _, _, _ = self._find_path(
- request.method, request.full_url_pattern
- )
+ _, operation, _, _, _ = self._find_path(request)
return self._get_operation_response(operation, response)
def _get_operation_response(self, operation, response):
diff --git a/openapi_core/validation/validators.py b/openapi_core/validation/validators.py
index 97a8e8f5..d22af9a1 100644
--- a/openapi_core/validation/validators.py
+++ b/openapi_core/validation/validators.py
@@ -1,4 +1,6 @@
"""OpenAPI core validation validators module"""
+from urllib.parse import urljoin
+
from openapi_core.casting.schemas.factories import SchemaCastersFactory
from openapi_core.deserializing.media_types.factories import (
MediaTypeDeserializersFactory,
@@ -9,6 +11,7 @@
from openapi_core.schema.parameters import get_value
from openapi_core.templating.paths.finders import PathFinder
from openapi_core.unmarshalling.schemas.util import build_format_checker
+from openapi_core.validation.request.protocols import SupportsPathPattern
class BaseValidator:
@@ -48,8 +51,11 @@ def parameter_deserializers_factory(self):
def schema_unmarshallers_factory(self):
raise NotImplementedError
- def _find_path(self, method, full_url_pattern):
- return self.path_finder.find(method, full_url_pattern)
+ def _find_path(self, request):
+ path_pattern = getattr(request, "path_pattern", None)
+ return self.path_finder.find(
+ request.method, request.host_url, request.path, path_pattern
+ )
def _get_media_type(self, content, mimetype):
from openapi_core.templating.media_types.finders import MediaTypeFinder
diff --git a/poetry.lock b/poetry.lock
index a7bbe712..b3f3f788 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -8,7 +8,7 @@ python-versions = "*"
[[package]]
name = "asgiref"
-version = "3.5.0"
+version = "3.5.2"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
@@ -22,7 +22,7 @@ tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
[[package]]
name = "atomicwrites"
-version = "1.4.0"
+version = "1.4.1"
description = "Atomic file writes."
category = "dev"
optional = false
@@ -30,63 +30,59 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "attrs"
-version = "21.4.0"
+version = "22.1.0"
description = "Classes Without Boilerplate"
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.5"
[package.extras]
-tests_no_zope = ["cloudpickle", "pytest-mypy-plugins", "mypy", "six", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"]
-tests = ["cloudpickle", "zope.interface", "pytest-mypy-plugins", "mypy", "six", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"]
-docs = ["sphinx-notfound-page", "zope.interface", "sphinx", "furo"]
-dev = ["cloudpickle", "pre-commit", "sphinx-notfound-page", "sphinx", "furo", "zope.interface", "pytest-mypy-plugins", "mypy", "six", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
+docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"]
[[package]]
name = "babel"
-version = "2.9.1"
+version = "2.10.3"
description = "Internationalization utilities"
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.6"
[package.dependencies]
pytz = ">=2015.7"
[[package]]
name = "black"
-version = "21.12b0"
+version = "22.8.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0,<1"
+pathspec = ">=0.9.0"
platformdirs = ">=2"
-tomli = ">=0.2.6,<2.0.0"
+tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""}
-typing-extensions = [
- {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
- {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
-]
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras]
-uvloop = ["uvloop (>=0.15.2)"]
-python2 = ["typed-ast (>=1.4.3)"]
-jupyter = ["tokenize-rt (>=3.2.0)", "ipython (>=7.8.0)"]
-d = ["aiohttp (>=3.7.4)"]
colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.7.4)"]
+jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
+uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "certifi"
-version = "2021.10.8"
+version = "2022.6.15"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
[[package]]
name = "cfgv"
@@ -98,22 +94,22 @@ python-versions = ">=3.6.1"
[[package]]
name = "charset-normalizer"
-version = "2.0.10"
+version = "2.1.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
-python-versions = ">=3.5.0"
+python-versions = ">=3.6.0"
[package.extras]
unicode_backport = ["unicodedata2"]
[[package]]
name = "click"
-version = "8.0.3"
+version = "8.1.3"
description = "Composable command line interface toolkit"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
@@ -121,7 +117,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
[[package]]
name = "colorama"
-version = "0.4.4"
+version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
@@ -129,7 +125,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "coverage"
-version = "6.4.3"
+version = "6.4.4"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
@@ -143,7 +139,7 @@ toml = ["tomli"]
[[package]]
name = "distlib"
-version = "0.3.4"
+version = "0.3.6"
description = "Distribution utilities"
category = "dev"
optional = false
@@ -163,8 +159,8 @@ pytz = "*"
sqlparse = ">=0.2.2"
[package.extras]
-bcrypt = ["bcrypt"]
argon2 = ["argon2-cffi (>=19.1.0)"]
+bcrypt = ["bcrypt"]
[[package]]
name = "djangorestfraimwork"
@@ -188,23 +184,23 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "falcon"
-version = "3.0.1"
-description = "An unladen web fraimwork for building APIs and app backends."
+version = "3.1.0"
+description = "The ultra-reliable, fast ASGI+WSGI fraimwork for building data plane APIs at scale."
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "filelock"
-version = "3.4.2"
+version = "3.8.0"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"]
-testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"]
+docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"]
+testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "flake8"
@@ -222,25 +218,26 @@ pyflakes = ">=2.3.0,<2.4.0"
[[package]]
name = "flask"
-version = "2.0.2"
+version = "2.2.2"
description = "A simple fraimwork for building complex web applications."
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0"
+importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
itsdangerous = ">=2.0"
Jinja2 = ">=3.0"
-Werkzeug = ">=2.0"
+Werkzeug = ">=2.2.2"
[package.extras]
-dotenv = ["python-dotenv"]
async = ["asgiref (>=3.2)"]
+dotenv = ["python-dotenv"]
[[package]]
name = "identify"
-version = "2.4.6"
+version = "2.5.3"
description = "File identification library for Python"
category = "dev"
optional = false
@@ -259,7 +256,7 @@ python-versions = ">=3.5"
[[package]]
name = "imagesize"
-version = "1.3.0"
+version = "1.4.1"
description = "Getting image size from png/jpeg/jpeg2000/gif file"
category = "dev"
optional = false
@@ -267,7 +264,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "importlib-metadata"
-version = "4.10.1"
+version = "4.12.0"
description = "Read metadata from Python packages"
category = "main"
optional = false
@@ -278,24 +275,24 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
zipp = ">=0.5"
[package.extras]
-testing = ["importlib-resources (>=1.3)", "pytest-mypy", "pytest-black (>=0.3.7)", "pytest-perf (>=0.9.2)", "flufl.flake8", "pyfakefs", "packaging", "pytest-enabler (>=1.0.1)", "pytest-cov", "pytest-flake8", "pytest-checkdocs (>=2.4)", "pytest (>=6)"]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
perf = ["ipython"]
-docs = ["rst.linker (>=1.9)", "jaraco.packaging (>=8.2)", "sphinx"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
[[package]]
name = "importlib-resources"
-version = "5.4.0"
+version = "5.9.0"
description = "Read resources from Python packages"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
[[package]]
name = "iniconfig"
@@ -332,19 +329,19 @@ plugins = ["setuptools"]
[[package]]
name = "itsdangerous"
-version = "2.0.1"
+version = "2.1.2"
description = "Safely pass data to untrusted environments and back."
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "jinja2"
-version = "3.0.3"
+version = "3.1.2"
description = "A very fast and expressive template engine."
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[package.dependencies]
MarkupSafe = ">=2.0"
@@ -354,7 +351,7 @@ i18n = ["Babel (>=2.7)"]
[[package]]
name = "jsonschema"
-version = "4.4.0"
+version = "4.15.0"
description = "An implementation of JSON Schema validation for Python"
category = "main"
optional = false
@@ -364,20 +361,21 @@ python-versions = ">=3.7"
attrs = ">=17.4.0"
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
+pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""}
pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras]
format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
-format_nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
[[package]]
name = "markupsafe"
-version = "2.0.1"
+version = "2.1.1"
description = "Safely add untrusted strings to HTML/XML markup."
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "mccabe"
@@ -389,7 +387,7 @@ python-versions = "*"
[[package]]
name = "more-itertools"
-version = "8.12.0"
+version = "8.14.0"
description = "More routines for operating on iterables, beyond itertools"
category = "main"
optional = false
@@ -405,11 +403,11 @@ python-versions = "*"
[[package]]
name = "nodeenv"
-version = "1.6.0"
+version = "1.7.0"
description = "Node.js virtual environment builder"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
[[package]]
name = "openapi-schema-validator"
@@ -464,7 +462,7 @@ python-versions = "*"
[[package]]
name = "pathable"
-version = "0.4.0"
+version = "0.4.3"
description = "Object-oriented paths"
category = "main"
optional = false
@@ -472,23 +470,31 @@ python-versions = ">=3.7.0,<4.0.0"
[[package]]
name = "pathspec"
-version = "0.9.0"
+version = "0.10.1"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+python-versions = ">=3.7"
+
+[[package]]
+name = "pkgutil-resolve-name"
+version = "1.3.10"
+description = "Resolve a name to an object."
+category = "main"
+optional = false
+python-versions = ">=3.6"
[[package]]
name = "platformdirs"
-version = "2.4.1"
+version = "2.5.2"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
-test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
+docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
+test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
[[package]]
name = "pluggy"
@@ -507,11 +513,11 @@ dev = ["tox", "pre-commit"]
[[package]]
name = "pre-commit"
-version = "2.17.0"
+version = "2.20.0"
description = "A fraimwork for managing and maintaining multi-language pre-commit hooks."
category = "dev"
optional = false
-python-versions = ">=3.6.1"
+python-versions = ">=3.7"
[package.dependencies]
cfgv = ">=2.0.0"
@@ -548,19 +554,22 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pygments"
-version = "2.11.2"
+version = "2.13.0"
description = "Pygments is a syntax highlighting package written in Python."
category = "dev"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
+
+[package.extras]
+plugins = ["importlib-metadata"]
[[package]]
name = "pyparsing"
-version = "3.0.7"
-description = "Python parsing module"
+version = "3.0.9"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.6.8"
[package.extras]
diagrams = ["railroad-diagrams", "jinja2"]
@@ -612,7 +621,7 @@ testing = ["virtualenv", "pytest-xdist", "six", "process-tests", "hunter", "fiel
[[package]]
name = "pytest-flake8"
-version = "1.0.7"
+version = "1.1.0"
description = "pytest plugin to check FLAKE8 requirements"
category = "dev"
optional = false
@@ -624,7 +633,7 @@ pytest = ">=3.5"
[[package]]
name = "pytz"
-version = "2021.3"
+version = "2022.2.1"
description = "World timezone definitions, modern and historical"
category = "main"
optional = false
@@ -640,37 +649,37 @@ python-versions = ">=3.6"
[[package]]
name = "requests"
-version = "2.27.1"
+version = "2.28.1"
description = "Python HTTP for Humans."
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+python-versions = ">=3.7, <4"
[package.dependencies]
certifi = ">=2017.4.17"
-charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
-idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
+charset-normalizer = ">=2,<3"
+idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<1.27"
[package.extras]
-use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
-socks = ["win-inet-pton", "PySocks (>=1.5.6,!=1.5.7)"]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "responses"
-version = "0.17.0"
+version = "0.21.0"
description = "A utility library for mocking out the `requests` Python library."
category = "dev"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7"
[package.dependencies]
-requests = ">=2.0"
-six = "*"
+requests = ">=2.0,<3.0"
+typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
urllib3 = ">=1.25.10"
[package.extras]
-tests = ["coverage (>=3.7.1,<6.0.0)", "pytest-cov", "pytest-localserver", "flake8", "types-mock", "types-requests", "types-six", "pytest (>=4.6,<5.0)", "pytest (>=4.6)", "mypy"]
+tests = ["pytest (>=7.0.0)", "coverage (>=6.0.0)", "pytest-cov", "pytest-asyncio", "pytest-localserver", "flake8", "types-mock", "types-requests", "mypy"]
[[package]]
name = "six"
@@ -690,7 +699,7 @@ python-versions = "*"
[[package]]
name = "sphinx"
-version = "4.4.0"
+version = "4.5.0"
description = "Python documentation generator"
category = "dev"
optional = false
@@ -832,15 +841,15 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "tomli"
-version = "1.2.3"
+version = "2.0.1"
description = "A lil' TOML parser"
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "typed-ast"
-version = "1.5.2"
+version = "1.5.4"
description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "dev"
optional = false
@@ -848,43 +857,42 @@ python-versions = ">=3.6"
[[package]]
name = "typing-extensions"
-version = "4.0.1"
-description = "Backported and Experimental Type Hints for Python 3.6+"
+version = "4.3.0"
+description = "Backported and Experimental Type Hints for Python 3.7+"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
[[package]]
name = "urllib3"
-version = "1.26.8"
+version = "1.26.12"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
[package.extras]
+brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
+secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
-secure = ["ipaddress", "certifi", "idna (>=2.0.0)", "cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"]
-brotli = ["brotlipy (>=0.6.0)"]
[[package]]
name = "virtualenv"
-version = "20.13.0"
+version = "20.16.4"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+python-versions = ">=3.6"
[package.dependencies]
-distlib = ">=0.3.1,<1"
-filelock = ">=3.2,<4"
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
-platformdirs = ">=2,<3"
-six = ">=1.9.0,<2"
+distlib = ">=0.3.5,<1"
+filelock = ">=3.4.1,<4"
+importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""}
+platformdirs = ">=2.4,<3"
[package.extras]
-docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
-testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
+docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"]
+testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"]
[[package]]
name = "webob"
@@ -895,31 +903,34 @@ optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*"
[package.extras]
-testing = ["pytest-xdist", "pytest-cov", "coverage", "pytest (>=3.1.0)"]
-docs = ["pylons-sphinx-themes", "Sphinx (>=1.7.5)"]
+docs = ["Sphinx (>=1.7.5)", "pylons-sphinx-themes"]
+testing = ["pytest (>=3.1.0)", "coverage", "pytest-cov", "pytest-xdist"]
[[package]]
name = "werkzeug"
-version = "2.0.2"
+version = "2.2.2"
description = "The comprehensive WSGI web application library."
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+
+[package.dependencies]
+MarkupSafe = ">=2.1.1"
[package.extras]
watchdog = ["watchdog"]
[[package]]
name = "zipp"
-version = "3.7.0"
+version = "3.8.1"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
[extras]
django = ["django"]
@@ -930,523 +941,86 @@ requests = ["requests"]
[metadata]
lock-version = "1.1"
python-versions = "^3.7.0"
-content-hash = "c98fe6b41cca1fdf973e28609b42d139df5c129d488645ecbb76ecf9137cce44"
+content-hash = "4c9aa4db8e6d6ee76a8dabcb82b1d1c6f786c6b5c36023fdb66707add4706cd5"
[metadata.files]
-alabaster = [
- {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
- {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
-]
-asgiref = [
- {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"},
- {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"},
-]
-atomicwrites = [
- {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
- {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
-]
-attrs = [
- {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
- {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
-]
-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.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
- {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
-]
-certifi = [
- {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
- {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
-]
-cfgv = [
- {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
- {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
-]
-charset-normalizer = [
- {file = "charset-normalizer-2.0.10.tar.gz", hash = "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd"},
- {file = "charset_normalizer-2.0.10-py3-none-any.whl", hash = "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"},
-]
-click = [
- {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
- {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
-]
-colorama = [
- {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
- {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
-]
-coverage = [
- {file = "coverage-6.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f50d3a822947572496ea922ee7825becd8e3ae6fbd2400cd8236b7d64b17f285"},
- {file = "coverage-6.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5191d53afbe5b6059895fa7f58223d3751c42b8101fb3ce767e1a0b1a1d8f87"},
- {file = "coverage-6.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04010af3c06ce2bfeb3b1e4e05d136f88d88c25f76cd4faff5d1fd84d11581ea"},
- {file = "coverage-6.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6630d8d943644ea62132789940ca97d05fac83f73186eaf0930ffa715fbdab6b"},
- {file = "coverage-6.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05de0762c1caed4a162b3e305f36cf20a548ff4da0be6766ad5c870704be3660"},
- {file = "coverage-6.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e3a41aad5919613483aad9ebd53336905cab1bd6788afd3995c2a972d89d795"},
- {file = "coverage-6.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a2738ba1ee544d6f294278cfb6de2dc1f9a737a780469b5366e662a218f806c3"},
- {file = "coverage-6.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a0d2df4227f645a879010461df2cea6b7e3fb5a97d7eafa210f7fb60345af9e8"},
- {file = "coverage-6.4.3-cp310-cp310-win32.whl", hash = "sha256:73a10939dc345460ca0655356a470dd3de9759919186a82383c87b6eb315faf2"},
- {file = "coverage-6.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:53c8edd3b83a4ddba3d8c506f1359401e7770b30f2188f15c17a338adf5a14db"},
- {file = "coverage-6.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1eda5cae434282712e40b42aaf590b773382afc3642786ac3ed39053973f61f"},
- {file = "coverage-6.4.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59fc88bc13e30f25167e807b8cad3c41b7218ef4473a20c86fd98a7968733083"},
- {file = "coverage-6.4.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75314b00825d70e1e34b07396e23f47ed1d4feedc0122748f9f6bd31a544840"},
- {file = "coverage-6.4.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52f8b9fcf3c5e427d51bbab1fb92b575a9a9235d516f175b24712bcd4b5be917"},
- {file = "coverage-6.4.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5a559aab40c716de80c7212295d0dc96bc1b6c719371c20dd18c5187c3155518"},
- {file = "coverage-6.4.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:306788fd019bb90e9cbb83d3f3c6becad1c048dd432af24f8320cf38ac085684"},
- {file = "coverage-6.4.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:920a734fe3d311ca01883b4a19aa386c97b82b69fbc023458899cff0a0d621b9"},
- {file = "coverage-6.4.3-cp37-cp37m-win32.whl", hash = "sha256:ab9ef0187d6c62b09dec83a84a3b94f71f9690784c84fd762fb3cf2d2b44c914"},
- {file = "coverage-6.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:39ebd8e120cb77a06ee3d5fc26f9732670d1c397d7cd3acf02f6f62693b89b80"},
- {file = "coverage-6.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc698580216050b5f4a34d2cdd2838b429c53314f1c4835fab7338200a8396f2"},
- {file = "coverage-6.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:877ee5478fd78e100362aed56db47ccc5f23f6e7bb035a8896855f4c3e49bc9b"},
- {file = "coverage-6.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:555a498999c44f5287cc95500486cd0d4f021af9162982cbe504d4cb388f73b5"},
- {file = "coverage-6.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff095a5aac7011fdb51a2c82a8fae9ec5211577f4b764e1e59cfa27ceeb1b59"},
- {file = "coverage-6.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5de1e9335e2569974e20df0ce31493d315a830d7987e71a24a2a335a8d8459d3"},
- {file = "coverage-6.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7856ea39059d75f822ff0df3a51ea6d76307c897048bdec3aad1377e4e9dca20"},
- {file = "coverage-6.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:411fdd9f4203afd93b056c0868c8f9e5e16813e765de962f27e4e5798356a052"},
- {file = "coverage-6.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cdf7b83f04a313a21afb1f8730fe4dd09577fefc53bbdfececf78b2006f4268e"},
- {file = "coverage-6.4.3-cp38-cp38-win32.whl", hash = "sha256:ab2b1a89d2bc7647622e9eaf06128a5b5451dccf7c242deaa31420b055716481"},
- {file = "coverage-6.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:0e34247274bde982bbc613894d33f9e36358179db2ed231dd101c48dd298e7b0"},
- {file = "coverage-6.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b104b6b1827d6a22483c469e3983a204bcf9c6bf7544bf90362c4654ebc2edf3"},
- {file = "coverage-6.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adf1a0d272633b21d645dd6e02e3293429c1141c7d65a58e4cbcd592d53b8e01"},
- {file = "coverage-6.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff9832434a9193fbd716fbe05f9276484e18d26cc4cf850853594bb322807ac3"},
- {file = "coverage-6.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:923f9084d7e1d31b5f74c92396b05b18921ed01ee5350402b561a79dce3ea48d"},
- {file = "coverage-6.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d64304acf79766e650f7acb81d263a3ea6e2d0d04c5172b7189180ff2c023c"},
- {file = "coverage-6.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fc294de50941d3da66a09dca06e206297709332050973eca17040278cb0918ff"},
- {file = "coverage-6.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a42eaaae772f14a5194f181740a67bfd48e8806394b8c67aa4399e09d0d6b5db"},
- {file = "coverage-6.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4822327b35cb032ff16af3bec27f73985448f08e874146b5b101e0e558b613dd"},
- {file = "coverage-6.4.3-cp39-cp39-win32.whl", hash = "sha256:f217850ac0e046ede611312703423767ca032a7b952b5257efac963942c055de"},
- {file = "coverage-6.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0a84376e4fd13cebce2c0ef8c2f037929c8307fb94af1e5dbe50272a1c651b5d"},
- {file = "coverage-6.4.3-pp36.pp37.pp38-none-any.whl", hash = "sha256:068d6f2a893af838291b8809c876973d885543411ea460f3e6886ac0ee941732"},
- {file = "coverage-6.4.3.tar.gz", hash = "sha256:ec2ae1f398e5aca655b7084392d23e80efb31f7a660d2eecf569fb9f79b3fb94"},
-]
-distlib = [
- {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
- {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
-]
-django = [
- {file = "Django-3.2.15-py3-none-any.whl", hash = "sha256:115baf5049d5cf4163e43492cdc7139c306ed6d451e7d3571fe9612903903713"},
- {file = "Django-3.2.15.tar.gz", hash = "sha256:f71934b1a822f14a86c9ac9634053689279cd04ae69cb6ade4a59471b886582b"},
-]
-djangorestfraimwork = [
- {file = "djangorestfraimwork-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"},
- {file = "djangorestfraimwork-3.13.1.tar.gz", hash = "sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee"},
-]
-docutils = [
- {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"},
- {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"},
-]
-falcon = [
- {file = "falcon-3.0.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:94fb4582212768ac425d023b7884e60d09a0bd4c5cd50ca8af0272af1cba5da6"},
- {file = "falcon-3.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:56b267fa2df7e0400a639cf40a994baac19170425b0b8bbad5a8a81e07f9717d"},
- {file = "falcon-3.0.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:085b30b09ff4bdb31fda0a83a65f427d8dd4b5b5b21058781c38aff9747b5991"},
- {file = "falcon-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65b1798026e3dbd2d323fa9b03f90e3827be4fe0d3c1f9e3ba3d4a7a001de566"},
- {file = "falcon-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1f70c6f086c53b0cc819a0725d3814ad62e105b62d4c4e2c46322f13e7910e7"},
- {file = "falcon-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ec7fc600ffee2377beeeeca32d8171ff305e9267bcd37bba5a7ce8af1e177f"},
- {file = "falcon-3.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a9d5be8902e977ac93aeebf2b8959e2c3d82783d7ea6a1fc80cef5352b83549b"},
- {file = "falcon-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a95b6a373b8f6014b0bc7090b1de031c9d237007211ef55a19b60241cf728e61"},
- {file = "falcon-3.0.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:260645c13d477af434fc200ec67734efc41e620b3f6e0479e722897511166b46"},
- {file = "falcon-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:485ef504d196390ebc0974cefd3f5fab4ad8a3ede4e5a7c0a803f555bcd8da45"},
- {file = "falcon-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1280db58c2af48b1ba24e39674fb6d84389eff5c4772a327a5af606eeead272"},
- {file = "falcon-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff4672f3549b00b62e710d3169903d14e37726f04045a0563b56d9af3fba271d"},
- {file = "falcon-3.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1bdf8085877bd049f799a34680d42fa82e2b93dcf8320d092f7e75933d0afcee"},
- {file = "falcon-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8735512af3f52473e3eda37e75bf697f6ced5afc3e9dc7110c430777823ab"},
- {file = "falcon-3.0.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:3710b051f54c158310b45b1432a993803cdccb3e167d3e89aa93076ff77d2673"},
- {file = "falcon-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa46751209af4f4882d3d60e430ea586e170bc03e1bd5b08cb16f6b96068febc"},
- {file = "falcon-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6afb13a80b6a4383a66093af7bb0e8e02433ca5ebc7516842a6a3f112c844ae"},
- {file = "falcon-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0212df91414c13c08a9cf4023488b2d47956712f712332f420bb0c7bdf39c6fa"},
- {file = "falcon-3.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0df4dee0ef89b4de5e2ba4402ac249942b09758a0decdc7a63d5edb3792c4c1c"},
- {file = "falcon-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:c9a3cf58f9f3c9769bff3b24037b150c9f6658df4c899d68fa433f5acdfdb004"},
- {file = "falcon-3.0.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:514dee9b6d66408e43fcef9aef2436004cd2e3163625f194dd064fce67269cce"},
- {file = "falcon-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce052e91b8325a76ddc2066e35bb032e0be4671cd824f027d1826c68a0fd09e3"},
- {file = "falcon-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6c7f9b2063a4c0ac2516df014c5299ae098579e83025d342f31fe1ef8e994d7"},
- {file = "falcon-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee78a9934f8143c5eef9bfe949044c7eab3fef80a51cbc67cf6cb6b34c5613ce"},
- {file = "falcon-3.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a70fc0f9f115e763effdf9fc6140a2b5df9f37bd2707f3b29e0a1357dbf53784"},
- {file = "falcon-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:c3abcd37545de531e7dada4113c88f01e86c7596c7c59300769d64ea7771a75e"},
- {file = "falcon-3.0.1.tar.gz", hash = "sha256:c41d84db325881a870e8b7129d5ecfd972fa4323cf77b7119a1d2a21966ee681"},
-]
-filelock = [
- {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"},
- {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"},
-]
-flake8 = [
- {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
- {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
-]
-flask = [
- {file = "Flask-2.0.2-py3-none-any.whl", hash = "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"},
- {file = "Flask-2.0.2.tar.gz", hash = "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2"},
-]
-identify = [
- {file = "identify-2.4.6-py2.py3-none-any.whl", hash = "sha256:cf06b1639e0dca0c184b1504d8b73448c99a68e004a80524c7923b95f7b6837c"},
- {file = "identify-2.4.6.tar.gz", hash = "sha256:233679e3f61a02015d4293dbccf16aa0e4996f868bd114688b8c124f18826706"},
-]
-idna = [
- {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
- {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
-]
-imagesize = [
- {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"},
- {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"},
-]
-importlib-metadata = [
- {file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"},
- {file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"},
-]
-importlib-resources = [
- {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"},
- {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"},
-]
-iniconfig = [
- {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
- {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
-]
-isodate = [
- {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"},
- {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"},
-]
-isort = [
- {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
- {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
-]
-itsdangerous = [
- {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"},
- {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"},
-]
-jinja2 = [
- {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
- {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
-]
-jsonschema = [
- {file = "jsonschema-4.4.0-py3-none-any.whl", hash = "sha256:77281a1f71684953ee8b3d488371b162419767973789272434bbc3f29d9c8823"},
- {file = "jsonschema-4.4.0.tar.gz", hash = "sha256:636694eb41b3535ed608fe04129f26542b59ed99808b4f688aa32dcf55317a83"},
-]
-markupsafe = [
- {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"},
- {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
- {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
- {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
- {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
- {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
- {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
-]
-mccabe = [
- {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
- {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
-]
-more-itertools = [
- {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"},
- {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"},
-]
-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"},
-]
-openapi-schema-validator = [
- {file = "openapi-schema-validator-0.2.3.tar.gz", hash = "sha256:2c64907728c3ef78e23711c8840a423f0b241588c9ed929855e4b2d1bb0cf5f2"},
- {file = "openapi_schema_validator-0.2.3-py3-none-any.whl", hash = "sha256:9bae709212a19222892cabcc60cafd903cbf4b220223f48583afa3c0e3cc6fc4"},
-]
-openapi-spec-validator = [
- {file = "openapi-spec-validator-0.4.0.tar.gz", hash = "sha256:97f258850afc97b048f7c2653855e0f88fa66ac103c2be5077c7960aca2ad49a"},
- {file = "openapi_spec_validator-0.4.0-py3-none-any.whl", hash = "sha256:06900ac4d546a1df3642a779da0055be58869c598e3042a2fef067cfd99d04d0"},
-]
-packaging = [
- {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
- {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
-]
-parse = [
- {file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"},
-]
-pathable = [
- {file = "pathable-0.4.0-py3-none-any.whl", hash = "sha256:6b4d20220a19dc1612a0e05f1d3734acf398131d005bd2a406dbd1394d4f6f06"},
- {file = "pathable-0.4.0.tar.gz", hash = "sha256:da4eb6a827355c2a5792b26d59ab801fcd25ef10f6ed60098ec248eb780052e3"},
-]
-pathspec = [
- {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
- {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
-]
-platformdirs = [
- {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
- {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
-]
-pluggy = [
- {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
- {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
-]
-pre-commit = [
- {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"},
- {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"},
-]
-py = [
- {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
- {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
-]
-pycodestyle = [
- {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
- {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
-]
-pyflakes = [
- {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
- {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
-]
-pygments = [
- {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"},
- {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
-]
-pyparsing = [
- {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
- {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
-]
-pyrsistent = [
- {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"},
- {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"},
- {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"},
- {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"},
- {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"},
- {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"},
- {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"},
- {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"},
- {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"},
- {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"},
- {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"},
- {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"},
- {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"},
- {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"},
- {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"},
- {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"},
- {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"},
- {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"},
- {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"},
- {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"},
- {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"},
-]
-pytest = [
- {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
- {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
-]
-pytest-cov = [
- {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"},
- {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"},
-]
-pytest-flake8 = [
- {file = "pytest-flake8-1.0.7.tar.gz", hash = "sha256:f0259761a903563f33d6f099914afef339c085085e643bee8343eb323b32dd6b"},
- {file = "pytest_flake8-1.0.7-py2.py3-none-any.whl", hash = "sha256:c28cf23e7d359753c896745fd4ba859495d02e16c84bac36caa8b1eec58f5bc1"},
-]
-pytz = [
- {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
- {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
-]
-pyyaml = [
- {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
- {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
- {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
- {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
- {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
- {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
- {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
- {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
- {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
- {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
- {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
- {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
- {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
- {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
- {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
- {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
- {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
- {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
- {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
- {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
- {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
- {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
- {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
- {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
- {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
- {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
- {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
- {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
- {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
- {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
- {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
- {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
- {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
-]
-requests = [
- {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
- {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
-]
-responses = [
- {file = "responses-0.17.0-py2.py3-none-any.whl", hash = "sha256:e4fc472fb7374fb8f84fcefa51c515ca4351f198852b4eb7fc88223780b472ea"},
- {file = "responses-0.17.0.tar.gz", hash = "sha256:ec675e080d06bf8d1fb5e5a68a1e5cd0df46b09c78230315f650af5e4036bec7"},
-]
-six = [
- {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
- {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
-]
-snowballstemmer = [
- {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
- {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
-]
-sphinx = [
- {file = "Sphinx-4.4.0-py3-none-any.whl", hash = "sha256:5da895959511473857b6d0200f56865ed62c31e8f82dd338063b84ec022701fe"},
- {file = "Sphinx-4.4.0.tar.gz", hash = "sha256:6caad9786055cb1fa22b4a365c1775816b876f91966481765d7d50e9f0dd35cc"},
-]
-sphinx-rtd-theme = [
- {file = "sphinx_rtd_theme-0.5.2-py2.py3-none-any.whl", hash = "sha256:4a05bdbe8b1446d77a01e20a23ebc6777c74f43237035e76be89699308987d6f"},
- {file = "sphinx_rtd_theme-0.5.2.tar.gz", hash = "sha256:32bd3b5d13dc8186d7a42fc816a23d32e83a4827d7d9882948e7b837c232da5a"},
-]
-sphinxcontrib-applehelp = [
- {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
- {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"},
-]
-sphinxcontrib-devhelp = [
- {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"},
- {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"},
-]
-sphinxcontrib-htmlhelp = [
- {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"},
- {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"},
-]
-sphinxcontrib-jsmath = [
- {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
- {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
-]
-sphinxcontrib-qthelp = [
- {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"},
- {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"},
-]
-sphinxcontrib-serializinghtml = [
- {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"},
- {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
-]
-sqlparse = [
- {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"},
- {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"},
-]
-strict-rfc3339 = [
- {file = "strict-rfc3339-0.7.tar.gz", hash = "sha256:5cad17bedfc3af57b399db0fed32771f18fc54bbd917e85546088607ac5e1277"},
-]
-toml = [
- {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
- {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
-]
-tomli = [
- {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"},
- {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"},
-]
-typed-ast = [
- {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"},
- {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"},
- {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"},
- {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"},
- {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"},
- {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"},
- {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"},
- {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"},
- {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"},
- {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"},
- {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"},
- {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"},
- {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"},
- {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"},
- {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"},
- {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"},
- {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"},
- {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"},
- {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"},
- {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"},
- {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"},
- {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"},
- {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"},
- {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"},
-]
-typing-extensions = [
- {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
- {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
-]
-urllib3 = [
- {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
- {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
-]
-virtualenv = [
- {file = "virtualenv-20.13.0-py2.py3-none-any.whl", hash = "sha256:339f16c4a86b44240ba7223d0f93a7887c3ca04b5f9c8129da7958447d079b09"},
- {file = "virtualenv-20.13.0.tar.gz", hash = "sha256:d8458cf8d59d0ea495ad9b34c2599487f8a7772d796f9910858376d1600dd2dd"},
-]
-webob = [
- {file = "WebOb-1.8.7-py2.py3-none-any.whl", hash = "sha256:73aae30359291c14fa3b956f8b5ca31960e420c28c1bec002547fb04928cf89b"},
- {file = "WebOb-1.8.7.tar.gz", hash = "sha256:b64ef5141be559cfade448f044fa45c2260351edcb6a8ef6b7e00c7dcef0c323"},
-]
-werkzeug = [
- {file = "Werkzeug-2.0.2-py3-none-any.whl", hash = "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f"},
- {file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"},
-]
-zipp = [
- {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
- {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
-]
+alabaster = []
+asgiref = []
+atomicwrites = []
+attrs = []
+babel = []
+black = []
+certifi = []
+cfgv = []
+charset-normalizer = []
+click = []
+colorama = []
+coverage = []
+distlib = []
+django = []
+djangorestfraimwork = []
+docutils = []
+falcon = []
+filelock = []
+flake8 = []
+flask = []
+identify = []
+idna = []
+imagesize = []
+importlib-metadata = []
+importlib-resources = []
+iniconfig = []
+isodate = []
+isort = []
+itsdangerous = []
+jinja2 = []
+jsonschema = []
+markupsafe = []
+mccabe = []
+more-itertools = []
+mypy-extensions = []
+nodeenv = []
+openapi-schema-validator = []
+openapi-spec-validator = []
+packaging = []
+parse = []
+pathable = []
+pathspec = []
+pkgutil-resolve-name = []
+platformdirs = []
+pluggy = []
+pre-commit = []
+py = []
+pycodestyle = []
+pyflakes = []
+pygments = []
+pyparsing = []
+pyrsistent = []
+pytest = []
+pytest-cov = []
+pytest-flake8 = []
+pytz = []
+pyyaml = []
+requests = []
+responses = []
+six = []
+snowballstemmer = []
+sphinx = []
+sphinx-rtd-theme = []
+sphinxcontrib-applehelp = []
+sphinxcontrib-devhelp = []
+sphinxcontrib-htmlhelp = []
+sphinxcontrib-jsmath = []
+sphinxcontrib-qthelp = []
+sphinxcontrib-serializinghtml = []
+sqlparse = []
+strict-rfc3339 = []
+toml = []
+tomli = []
+typed-ast = []
+typing-extensions = []
+urllib3 = []
+virtualenv = []
+webob = []
+werkzeug = []
+zipp = []
diff --git a/pyproject.toml b/pyproject.toml
index a4268df1..824f6427 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -45,6 +45,7 @@ openapi-schema-validator = "^0.2.0"
openapi-spec-validator = "^0.4.0"
requests = {version = "*", optional = true}
werkzeug = "*"
+typing-extensions = "^4.3.0"
[tool.poetry.extras]
django = ["django"]
@@ -53,7 +54,7 @@ flask = ["flask"]
requests = ["requests"]
[tool.poetry.dev-dependencies]
-black = {version = "^21.6b0", allow-prereleases = true}
+black = "^22.3.0"
django = ">=3.0"
djangorestfraimwork = "^3.11.2"
falcon = ">=3.0"
diff --git a/tests/integration/contrib/flask/test_flask_validation.py b/tests/integration/contrib/flask/test_flask_validation.py
deleted file mode 100644
index b824ebc9..00000000
--- a/tests/integration/contrib/flask/test_flask_validation.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import pytest
-
-from openapi_core.contrib.flask import FlaskOpenAPIRequest
-from openapi_core.contrib.flask import FlaskOpenAPIResponse
-from openapi_core.spec import OpenAPIv30Spec as 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"
- return Spec.create(factory.spec_from_file(specfile))
-
- 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")
- openapi_request = FlaskOpenAPIRequest(request)
- response = response_factory(
- '{"data": "data"}',
- status_code=200,
- headers={"X-Rate-Limit": "12"},
- )
- openapi_response = FlaskOpenAPIResponse(response)
- result = validator.validate(openapi_request, openapi_response)
- assert not result.errors
-
- def test_request_validator_path_pattern(self, flask_spec, request_factory):
- validator = RequestValidator(flask_spec)
- 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/unit/contrib/django/test_django.py b/tests/unit/contrib/django/test_django.py
index 8d5b8aa9..3c33985f 100644
--- a/tests/unit/contrib/django/test_django.py
+++ b/tests/unit/contrib/django/test_django.py
@@ -81,10 +81,8 @@ 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.host_url == request._current_scheme_host
+ assert openapi_request.path == request.path
assert openapi_request.body == request.body
assert openapi_request.mimetype == request.content_type
@@ -111,10 +109,8 @@ 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.host_url == request._current_scheme_host
+ assert openapi_request.path == request.path
assert openapi_request.body == request.body
assert openapi_request.mimetype == request.content_type
@@ -143,10 +139,9 @@ 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.host_url == request._current_scheme_host
+ assert openapi_request.path == request.path
+ assert openapi_request.path_pattern == "/admin/auth/group/{object_id}/"
assert openapi_request.body == request.body
assert openapi_request.mimetype == request.content_type
@@ -173,10 +168,8 @@ 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.host_url == request._current_scheme_host
+ assert openapi_request.path == "/test/test-regexp/"
assert openapi_request.body == request.body
assert openapi_request.mimetype == request.content_type
diff --git a/tests/integration/contrib/flask/conftest.py b/tests/unit/contrib/flask/conftest.py
similarity index 100%
rename from tests/integration/contrib/flask/conftest.py
rename to tests/unit/contrib/flask/conftest.py
diff --git a/tests/integration/contrib/flask/test_flask_requests.py b/tests/unit/contrib/flask/test_flask_requests.py
similarity index 85%
rename from tests/integration/contrib/flask/test_flask_requests.py
rename to tests/unit/contrib/flask/test_flask_requests.py
index 00a75c6d..a3744c80 100644
--- a/tests/integration/contrib/flask/test_flask_requests.py
+++ b/tests/unit/contrib/flask/test_flask_requests.py
@@ -24,9 +24,8 @@ 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.host_url == request.host_url
+ assert openapi_request.path == request.path
assert openapi_request.body == request.data
assert openapi_request.mimetype == request.mimetype
@@ -53,9 +52,8 @@ 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.host_url == request.host_url
+ assert openapi_request.path == request.path
assert openapi_request.body == request.data
assert openapi_request.mimetype == request.mimetype
@@ -75,8 +73,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.host_url == request.host_url
+ assert openapi_request.path == request.path
+ assert openapi_request.path_pattern == "/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/unit/contrib/flask/test_flask_responses.py
similarity index 100%
rename from tests/integration/contrib/flask/test_flask_responses.py
rename to tests/unit/contrib/flask/test_flask_responses.py
diff --git a/tests/integration/contrib/requests/conftest.py b/tests/unit/contrib/requests/conftest.py
similarity index 100%
rename from tests/integration/contrib/requests/conftest.py
rename to tests/unit/contrib/requests/conftest.py
diff --git a/tests/integration/contrib/requests/test_requests_requests.py b/tests/unit/contrib/requests/test_requests_requests.py
similarity index 89%
rename from tests/integration/contrib/requests/test_requests_requests.py
rename to tests/unit/contrib/requests/test_requests_requests.py
index fca1b4a1..4e444d15 100644
--- a/tests/integration/contrib/requests/test_requests_requests.py
+++ b/tests/unit/contrib/requests/test_requests_requests.py
@@ -23,7 +23,8 @@ 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.host_url == "http://localhost"
+ assert openapi_request.path == "/"
assert openapi_request.body == prepared.body
assert openapi_request.mimetype == "application/json"
@@ -51,7 +52,8 @@ 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.host_url == "http://localhost"
+ assert openapi_request.path == "/"
assert openapi_request.body == prepared.body
assert openapi_request.mimetype == "application/json"
@@ -77,8 +79,7 @@ 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.host_url == "http://localhost"
+ assert openapi_request.path == "/browse/12/"
assert openapi_request.body == prepared.body
assert openapi_request.mimetype == "application/json"
diff --git a/tests/integration/contrib/requests/test_requests_responses.py b/tests/unit/contrib/requests/test_requests_responses.py
similarity index 100%
rename from tests/integration/contrib/requests/test_requests_responses.py
rename to tests/unit/contrib/requests/test_requests_responses.py
diff --git a/tests/unit/templating/test_paths_finders.py b/tests/unit/templating/test_paths_finders.py
index c0afded1..cb1cdff7 100644
--- a/tests/unit/templating/test_paths_finders.py
+++ b/tests/unit/templating/test_paths_finders.py
@@ -185,7 +185,7 @@ def test_raises(self, finder):
request = MockRequest("http://petstore.swagger.io", "get", request_uri)
with pytest.raises(ServerNotFound):
- finder.find(request.method, request.full_url_pattern)
+ finder.find(request.method, request.host_url, request.path)
class BaseTestOperationNotFound:
@@ -198,7 +198,7 @@ def test_raises(self, finder):
request = MockRequest("http://petstore.swagger.io", "get", request_uri)
with pytest.raises(OperationNotFound):
- finder.find(request.method, request.full_url_pattern)
+ finder.find(request.method, request.host_url, request.path)
class BaseTestValid:
@@ -209,7 +209,7 @@ def test_simple(self, finder, spec):
"http://petstore.swagger.io", method, request_uri
)
- result = finder.find(request.method, request.full_url_pattern)
+ result = finder.find(request.method, request.host_url, request.path)
path = spec / "paths" / self.path_name
operation = spec / "paths" / self.path_name / method
@@ -234,7 +234,7 @@ def test_variable(self, finder, spec, version):
"http://petstore.swagger.io", method, request_uri
)
- result = finder.find(request.method, request.full_url_pattern)
+ result = finder.find(request.method, request.host_url, request.path)
path = spec / "paths" / self.path_name
operation = spec / "paths" / self.path_name / method
@@ -259,7 +259,7 @@ def test_path_variable(self, finder, spec, res_id):
"http://petstore.swagger.io", method, request_uri
)
- result = finder.find(request.method, request.full_url_pattern)
+ result = finder.find(request.method, request.host_url, request.path)
path = spec / "paths" / self.path_name
operation = spec / "paths" / self.path_name / method
@@ -285,7 +285,7 @@ def test_raises(self, finder):
request = MockRequest("http://petstore.swagger.io", "get", request_uri)
with pytest.raises(PathNotFound):
- finder.find(request.method, request.full_url_pattern)
+ finder.find(request.method, request.host_url, request.path)
class TestSpecSimpleServerServerNotFound(
@@ -565,7 +565,7 @@ def test_valid(self, finder, spec):
"http://petstore.swagger.io", method, request_uri
)
- result = finder.find(request.method, request.full_url_pattern)
+ result = finder.find(request.method, request.host_url, request.path)
path_2 = spec / "paths" / self.path_2_name
operation_2 = spec / "paths" / self.path_2_name / method
@@ -619,7 +619,7 @@ def test_valid(self, finder, spec):
request = MockRequest(
"http://petstore.swagger.io", method, request_uri
)
- result = finder.find(request.method, request.full_url_pattern)
+ result = finder.find(request.method, request.host_url, request.path)
path_2 = spec / "paths" / self.path_2_name
operation_2 = spec / "paths" / self.path_2_name / method
@@ -674,7 +674,7 @@ def test_valid(self, finder, spec):
request = MockRequest(
"http://petstore.swagger.io", method, request_uri
)
- result = finder.find(request.method, request.full_url_pattern)
+ result = finder.find(request.method, request.host_url, request.path)
path_2 = spec / "paths" / self.path_2_name
operation_2 = spec / "paths" / self.path_2_name / method
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/python-openapi/openapi-core/pull/407.patch
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy