Added support for AWS Sigv4 for UrlLib3. (#547)
* WIP: Added support for AWS Sigv4 for UrlLib3. Signed-off-by: dblock <dblock@amazon.com> * Refactored common implementation. Signed-off-by: dblock <dblock@amazon.com> * Added sigv4 samples. Signed-off-by: dblock <dblock@amazon.com> * Updated CHANGELOG. Signed-off-by: dblock <dblock@amazon.com> * Add documentation. Signed-off-by: dblock <dblock@amazon.com> * Use the correct class in tests. Signed-off-by: dblock <dblock@amazon.com> * Renamed samples. Signed-off-by: dblock <dblock@amazon.com> * Split up requests and urllib3 unit tests. Signed-off-by: dblock <dblock@amazon.com> * Rename AWSV4Signer. Signed-off-by: dblock <dblock@amazon.com> * Clarified documentation of when to use Urllib3AWSV4SignerAuth vs. RequestHttpConnection. Signed-off-by: dblock <dblock@amazon.com> * Move fetch_url inside the signer class. Signed-off-by: dblock <dblock@amazon.com> * Added unit test for Urllib3AWSV4SignerAuth adding headers. Signed-off-by: dblock <dblock@amazon.com> * Added unit test for signing to include query string. Signed-off-by: dblock <dblock@amazon.com> --------- Signed-off-by: dblock <dblock@amazon.com>
This commit is contained in:
committed by
GitHub
parent
fa8f3a7ae0
commit
a1f942b6f9
@@ -9,6 +9,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
- Added `pool_maxsize` for `Urllib3HttpConnection` ([#535](https://github.com/opensearch-project/opensearch-py/pull/535))
|
||||
- Added benchmarks ([#537](https://github.com/opensearch-project/opensearch-py/pull/537))
|
||||
- Added guide on making raw JSON REST requests ([#542](https://github.com/opensearch-project/opensearch-py/pull/542))
|
||||
- Added support for AWS SigV4 for urllib3 ([#547](https://github.com/opensearch-project/opensearch-py/pull/547))
|
||||
### Changed
|
||||
- Generate `tasks` client from API specs ([#508](https://github.com/opensearch-project/opensearch-py/pull/508))
|
||||
- Generate `ingest` client from API specs ([#513](https://github.com/opensearch-project/opensearch-py/pull/513))
|
||||
|
||||
+14
-2
@@ -45,7 +45,19 @@ docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" opensear
|
||||
|
||||
Tests require a live instance of OpenSearch running in docker.
|
||||
|
||||
This will start a new instance and run tests against the latest version of OpenSearch.
|
||||
If you have one running.
|
||||
|
||||
```
|
||||
python setup.py test
|
||||
```
|
||||
|
||||
To run tests in a specific test file.
|
||||
|
||||
```
|
||||
python setup.py test -s test_opensearchpy/test_connection.py
|
||||
```
|
||||
|
||||
If you want to auto-start one, the following will start a new instance and run tests against the latest version of OpenSearch.
|
||||
|
||||
```
|
||||
./.ci/run-tests
|
||||
@@ -76,7 +88,7 @@ You can also run individual tests matching a pattern (`pytest -k [pattern]`).
|
||||
```
|
||||
./.ci/run-tests true 1.3.0 test_no_http_compression
|
||||
|
||||
test_opensearchpy/test_connection.py::TestUrllib3Connection::test_no_http_compression PASSED [ 33%]
|
||||
test_opensearchpy/test_connection.py::TestUrllib3HttpConnection::test_no_http_compression PASSED [ 33%]
|
||||
test_opensearchpy/test_connection.py::TestRequestsConnection::test_no_http_compression PASSED [ 66%]
|
||||
test_opensearchpy/test_async/test_connection.py::TestAIOHttpConnection::test_no_http_compression PASSED [100%]
|
||||
```
|
||||
|
||||
+9
-4
@@ -1,5 +1,6 @@
|
||||
- [Authentication](#authentication)
|
||||
- [IAM Authentication](#iam-authentication)
|
||||
- [IAM Authentication with a Synchronous Client](#iam-authentication-with-a-synchronous-client)
|
||||
- [IAM Authentication with an Async Client](#iam-authentication-with-an-async-client)
|
||||
- [Kerberos](#kerberos)
|
||||
|
||||
@@ -9,24 +10,28 @@ OpenSearch allows you to use different methods for the authentication via `conne
|
||||
|
||||
## IAM Authentication
|
||||
|
||||
Opensearch-py supports IAM-based authentication via `AWSV4SignerAuth`, which uses `RequestHttpConnection` as the transport class for communicating with OpenSearch clusters running in Amazon Managed OpenSearch and OpenSearch Serverless, and works in conjunction with [botocore](https://pypi.org/project/botocore/).
|
||||
This library supports IAM-based authentication when communicating with OpenSearch clusters running in Amazon Managed OpenSearch and OpenSearch Serverless.
|
||||
|
||||
## IAM Authentication with a Synchronous Client
|
||||
|
||||
For `Urllib3HttpConnection` use `Urllib3AWSV4SignerAuth`, and for `RequestHttpConnection` use `RequestsAWSV4SignerAuth`.
|
||||
|
||||
```python
|
||||
from opensearchpy import OpenSearch, RequestsHttpConnection, AWSV4SignerAuth
|
||||
from opensearchpy import OpenSearch, Urllib3HttpConnection, Urllib3AWSV4SignerAuth
|
||||
import boto3
|
||||
|
||||
host = '' # cluster endpoint, for example: my-test-domain.us-east-1.es.amazonaws.com
|
||||
region = 'us-west-2'
|
||||
service = 'es' # 'aoss' for OpenSearch Serverless
|
||||
credentials = boto3.Session().get_credentials()
|
||||
auth = AWSV4SignerAuth(credentials, region, service)
|
||||
auth = Urllib3AWSV4SignerAuth(credentials, region, service)
|
||||
|
||||
client = OpenSearch(
|
||||
hosts = [{'host': host, 'port': 443}],
|
||||
http_auth = auth,
|
||||
use_ssl = True,
|
||||
verify_certs = True,
|
||||
connection_class = RequestsHttpConnection,
|
||||
connection_class = Urllib3HttpConnection,
|
||||
pool_maxsize = 20
|
||||
)
|
||||
|
||||
|
||||
@@ -71,7 +71,12 @@ from .exceptions import (
|
||||
UnknownDslObject,
|
||||
ValidationException,
|
||||
)
|
||||
from .helpers import AWSV4SignerAsyncAuth, AWSV4SignerAuth
|
||||
from .helpers import (
|
||||
AWSV4SignerAsyncAuth,
|
||||
AWSV4SignerAuth,
|
||||
RequestsAWSV4SignerAuth,
|
||||
Urllib3AWSV4SignerAuth,
|
||||
)
|
||||
from .helpers.aggs import A
|
||||
from .helpers.analysis import analyzer, char_filter, normalizer, token_filter, tokenizer
|
||||
from .helpers.document import Document, InnerDoc, MetaField
|
||||
@@ -166,6 +171,8 @@ __all__ = [
|
||||
"OpenSearchWarning",
|
||||
"OpenSearchDeprecationWarning",
|
||||
"AWSV4SignerAuth",
|
||||
"Urllib3AWSV4SignerAuth",
|
||||
"RequestsAWSV4SignerAuth",
|
||||
"AWSV4SignerAsyncAuth",
|
||||
"A",
|
||||
"AttrDict",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
import ssl
|
||||
import time
|
||||
import warnings
|
||||
from typing import Callable
|
||||
|
||||
import urllib3 # type: ignore
|
||||
from urllib3.exceptions import ReadTimeoutError
|
||||
@@ -128,10 +129,17 @@ class Urllib3HttpConnection(Connection):
|
||||
opaque_id=opaque_id,
|
||||
**kwargs
|
||||
)
|
||||
if http_auth is not None:
|
||||
if isinstance(http_auth, (tuple, list)):
|
||||
http_auth = ":".join(http_auth)
|
||||
self.headers.update(urllib3.make_headers(basic_auth=http_auth))
|
||||
|
||||
self.http_auth = http_auth
|
||||
if self.http_auth is not None:
|
||||
if isinstance(self.http_auth, Callable):
|
||||
pass
|
||||
elif isinstance(self.http_auth, (tuple, list)):
|
||||
self.headers.update(
|
||||
urllib3.make_headers(basic_auth=":".join(http_auth))
|
||||
)
|
||||
else:
|
||||
self.headers.update(urllib3.make_headers(basic_auth=http_auth))
|
||||
|
||||
pool_class = urllib3.HTTPConnectionPool
|
||||
kw = {}
|
||||
@@ -218,6 +226,7 @@ class Urllib3HttpConnection(Connection):
|
||||
url = "%s?%s" % (url, urlencode(params))
|
||||
|
||||
full_url = self.host + url
|
||||
|
||||
start = time.time()
|
||||
orig_body = body
|
||||
try:
|
||||
@@ -240,6 +249,10 @@ class Urllib3HttpConnection(Connection):
|
||||
body = self._gzip_compress(body)
|
||||
request_headers["content-encoding"] = "gzip"
|
||||
|
||||
if self.http_auth is not None:
|
||||
if isinstance(self.http_auth, Callable):
|
||||
request_headers.update(self.http_auth(method, full_url, body))
|
||||
|
||||
response = self.pool.urlopen(
|
||||
method, url, body, retries=Retry(False), headers=request_headers, **kw
|
||||
)
|
||||
|
||||
@@ -39,7 +39,7 @@ from .actions import (
|
||||
)
|
||||
from .asyncsigner import AWSV4SignerAsyncAuth
|
||||
from .errors import BulkIndexError, ScanError
|
||||
from .signer import AWSV4SignerAuth
|
||||
from .signer import AWSV4SignerAuth, RequestsAWSV4SignerAuth, Urllib3AWSV4SignerAuth
|
||||
|
||||
__all__ = [
|
||||
"BulkIndexError",
|
||||
@@ -54,6 +54,8 @@ __all__ = [
|
||||
"_process_bulk_chunk",
|
||||
"AWSV4SignerAuth",
|
||||
"AWSV4SignerAsyncAuth",
|
||||
"RequestsAWSV4SignerAuth",
|
||||
"Urllib3AWSV4SignerAuth",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -48,5 +48,6 @@ try:
|
||||
from .._async.helpers.actions import async_streaming_bulk as async_streaming_bulk
|
||||
from .asyncsigner import AWSV4SignerAsyncAuth as AWSV4SignerAsyncAuth
|
||||
from .signer import AWSV4SignerAuth as AWSV4SignerAuth
|
||||
from .signer import RequestsAWSV4SignerAuth, Urllib3AWSV4SignerAuth
|
||||
except (ImportError, SyntaxError):
|
||||
pass
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
# GitHub history for details.
|
||||
|
||||
import sys
|
||||
from typing import Any, Callable, Dict
|
||||
|
||||
import requests
|
||||
|
||||
@@ -17,38 +18,12 @@ if PY3:
|
||||
from urllib.parse import parse_qs, urlencode, urlparse
|
||||
|
||||
|
||||
def fetch_url(prepared_request): # type: ignore
|
||||
class AWSV4Signer:
|
||||
"""
|
||||
This is a util method that helps in reconstructing the request url.
|
||||
:param prepared_request: unsigned request
|
||||
:return: reconstructed url
|
||||
"""
|
||||
url = urlparse(prepared_request.url)
|
||||
path = url.path or "/"
|
||||
|
||||
# fetch the query string if present in the request
|
||||
querystring = ""
|
||||
if url.query:
|
||||
querystring = "?" + urlencode(
|
||||
parse_qs(url.query, keep_blank_values=True), doseq=True
|
||||
)
|
||||
|
||||
# fetch the host information from headers
|
||||
headers = dict(
|
||||
(key.lower(), value) for key, value in prepared_request.headers.items()
|
||||
)
|
||||
location = headers.get("host") or url.netloc
|
||||
|
||||
# construct the url and return
|
||||
return url.scheme + "://" + location + path + querystring
|
||||
|
||||
|
||||
class AWSV4SignerAuth(requests.auth.AuthBase):
|
||||
"""
|
||||
AWS V4 Request Signer for Requests.
|
||||
Generic AWS V4 Request Signer.
|
||||
"""
|
||||
|
||||
def __init__(self, credentials, region, service="es"): # type: ignore
|
||||
def __init__(self, credentials, region: str, service: str = "es") -> Any: # type: ignore
|
||||
if not credentials:
|
||||
raise ValueError("Credentials cannot be empty")
|
||||
self.credentials = credentials
|
||||
@@ -61,27 +36,20 @@ class AWSV4SignerAuth(requests.auth.AuthBase):
|
||||
raise ValueError("Service name cannot be empty")
|
||||
self.service = service
|
||||
|
||||
def __call__(self, request): # type: ignore
|
||||
return self._sign_request(request) # type: ignore
|
||||
|
||||
def _sign_request(self, prepared_request): # type: ignore
|
||||
def sign(self, method: str, url: str, body: Any) -> Dict[str, str]:
|
||||
"""
|
||||
This method helps in signing the request by injecting the required headers.
|
||||
:param prepared_request: unsigned request
|
||||
:return: signed request
|
||||
This method signs the request and returns headers.
|
||||
:param method: HTTP method
|
||||
:param url: url
|
||||
:param body: body
|
||||
:return: headers
|
||||
"""
|
||||
|
||||
from botocore.auth import SigV4Auth
|
||||
from botocore.awsrequest import AWSRequest
|
||||
|
||||
url = fetch_url(prepared_request) # type: ignore
|
||||
|
||||
# create an AWS request object and sign it using SigV4Auth
|
||||
aws_request = AWSRequest(
|
||||
method=prepared_request.method.upper(),
|
||||
url=url,
|
||||
data=prepared_request.body,
|
||||
)
|
||||
aws_request = AWSRequest(method=method.upper(), url=url, data=body)
|
||||
|
||||
# credentials objects expose access_key, secret_key and token attributes
|
||||
# via @property annotations that call _refresh() on every access,
|
||||
@@ -101,9 +69,74 @@ class AWSV4SignerAuth(requests.auth.AuthBase):
|
||||
sig_v4_auth.add_auth(aws_request)
|
||||
|
||||
# copy the headers from AWS request object into the prepared_request
|
||||
prepared_request.headers.update(dict(aws_request.headers.items()))
|
||||
prepared_request.headers["X-Amz-Content-SHA256"] = sig_v4_auth.payload(
|
||||
aws_request
|
||||
headers = dict(aws_request.headers.items())
|
||||
headers["X-Amz-Content-SHA256"] = sig_v4_auth.payload(aws_request)
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
class RequestsAWSV4SignerAuth(requests.auth.AuthBase):
|
||||
"""
|
||||
AWS V4 Request Signer for Requests.
|
||||
"""
|
||||
|
||||
def __init__(self, credentials, region, service="es"): # type: ignore
|
||||
self.signer = AWSV4Signer(credentials, region, service)
|
||||
|
||||
def __call__(self, request): # type: ignore
|
||||
return self._sign_request(request) # type: ignore
|
||||
|
||||
def _sign_request(self, prepared_request): # type: ignore
|
||||
"""
|
||||
This method helps in signing the request by injecting the required headers.
|
||||
:param prepared_request: unsigned request
|
||||
:return: signed request
|
||||
"""
|
||||
|
||||
prepared_request.headers.update(
|
||||
self.signer.sign(
|
||||
prepared_request.method,
|
||||
self._fetch_url(prepared_request), # type: ignore
|
||||
prepared_request.body,
|
||||
)
|
||||
)
|
||||
|
||||
return prepared_request
|
||||
|
||||
def _fetch_url(self, prepared_request): # type: ignore
|
||||
"""
|
||||
This is a util method that helps in reconstructing the request url.
|
||||
:param prepared_request: unsigned request
|
||||
:return: reconstructed url
|
||||
"""
|
||||
url = urlparse(prepared_request.url)
|
||||
path = url.path or "/"
|
||||
|
||||
# fetch the query string if present in the request
|
||||
querystring = ""
|
||||
if url.query:
|
||||
querystring = "?" + urlencode(
|
||||
parse_qs(url.query, keep_blank_values=True), doseq=True
|
||||
)
|
||||
|
||||
# fetch the host information from headers
|
||||
headers = dict(
|
||||
(key.lower(), value) for key, value in prepared_request.headers.items()
|
||||
)
|
||||
location = headers.get("host") or url.netloc
|
||||
|
||||
# construct the url and return
|
||||
return url.scheme + "://" + location + path + querystring
|
||||
|
||||
|
||||
# Deprecated: use RequestsAWSV4SignerAuth
|
||||
class AWSV4SignerAuth(RequestsAWSV4SignerAuth):
|
||||
pass
|
||||
|
||||
|
||||
class Urllib3AWSV4SignerAuth(Callable): # type: ignore
|
||||
def __init__(self, credentials, region, service="es"): # type: ignore
|
||||
self.signer = AWSV4Signer(credentials, region, service)
|
||||
|
||||
def __call__(self, method: str, url: str, body: Any) -> Dict[str, str]:
|
||||
return self.signer.sign(method, url, body)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
## AWS SigV4 Samples
|
||||
|
||||
Create an OpenSearch domain in (AWS) which support IAM based AuthN/AuthZ.
|
||||
|
||||
```
|
||||
export AWS_ACCESS_KEY_ID=
|
||||
export AWS_SECRET_ACCESS_KEY=
|
||||
export AWS_SESSION_TOKEN=
|
||||
export AWS_REGION=us-west-2
|
||||
|
||||
export SERVICE=es # use "aoss" for OpenSearch Serverless.
|
||||
export ENDPOINT=https://....us-west-2.es.amazonaws.com
|
||||
|
||||
poetry run aws/search-urllib.py
|
||||
```
|
||||
|
||||
This will output the version of OpenSearch and a search result.
|
||||
|
||||
```
|
||||
opensearch: 2.3.0
|
||||
{'director': 'Bennett Miller', 'title': 'Moneyball', 'year': 2011}
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# The OpenSearch Contributors require contributions made to
|
||||
# this file be licensed under the Apache-2.0 license or a
|
||||
# compatible open source license.
|
||||
#
|
||||
# Modifications Copyright OpenSearch Contributors. See
|
||||
# GitHub history for details.
|
||||
|
||||
import logging
|
||||
|
||||
from os import environ
|
||||
from time import sleep
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from boto3 import Session
|
||||
from opensearchpy import RequestsAWSV4SignerAuth, OpenSearch, RequestsHttpConnection
|
||||
|
||||
# verbose logging
|
||||
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
||||
|
||||
# cluster endpoint, for example: my-test-domain.us-east-1.es.amazonaws.com
|
||||
url = urlparse(environ['ENDPOINT'])
|
||||
region = environ.get('AWS_REGION', 'us-east-1')
|
||||
service = environ.get('SERVICE', 'es')
|
||||
|
||||
credentials = Session().get_credentials()
|
||||
|
||||
auth = RequestsAWSV4SignerAuth(credentials, region, service)
|
||||
|
||||
client = OpenSearch(
|
||||
hosts=[{
|
||||
'host': url.netloc,
|
||||
'port': url.port or 443
|
||||
}],
|
||||
http_auth=auth,
|
||||
use_ssl=True,
|
||||
verify_certs=True,
|
||||
connection_class=RequestsHttpConnection,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
# TODO: remove when OpenSearch Serverless adds support for /
|
||||
if service == 'es':
|
||||
info = client.info()
|
||||
print(f"{info['version']['distribution']}: {info['version']['number']}")
|
||||
|
||||
# create an index
|
||||
index = 'movies'
|
||||
client.indices.create(index=index)
|
||||
|
||||
try:
|
||||
# index data
|
||||
document = {'director': 'Bennett Miller', 'title': 'Moneyball', 'year': 2011}
|
||||
client.index(index=index, body=document, id='1')
|
||||
|
||||
# wait for the document to index
|
||||
sleep(1)
|
||||
|
||||
# search for the document
|
||||
results = client.search(body={'query': {'match': {'director': 'miller'}}})
|
||||
for hit in results['hits']['hits']:
|
||||
print(hit['_source'])
|
||||
|
||||
# delete the document
|
||||
client.delete(index=index, id='1')
|
||||
finally:
|
||||
# delete the index
|
||||
client.indices.delete(index=index)
|
||||
@@ -0,0 +1,69 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# The OpenSearch Contributors require contributions made to
|
||||
# this file be licensed under the Apache-2.0 license or a
|
||||
# compatible open source license.
|
||||
#
|
||||
# Modifications Copyright OpenSearch Contributors. See
|
||||
# GitHub history for details.
|
||||
|
||||
import logging
|
||||
|
||||
from os import environ
|
||||
from time import sleep
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from boto3 import Session
|
||||
from opensearchpy import Urllib3AWSV4SignerAuth, OpenSearch, Urllib3HttpConnection
|
||||
|
||||
# verbose logging
|
||||
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
|
||||
|
||||
# cluster endpoint, for example: my-test-domain.us-east-1.es.amazonaws.com
|
||||
url = urlparse(environ['ENDPOINT'])
|
||||
region = environ.get('AWS_REGION', 'us-east-1')
|
||||
service = environ.get('SERVICE', 'es')
|
||||
|
||||
credentials = Session().get_credentials()
|
||||
|
||||
auth = Urllib3AWSV4SignerAuth(credentials, region, service)
|
||||
|
||||
client = OpenSearch(
|
||||
hosts=[{
|
||||
'host': url.netloc,
|
||||
'port': url.port or 443
|
||||
}],
|
||||
http_auth=auth,
|
||||
use_ssl=True,
|
||||
verify_certs=True,
|
||||
connection_class=Urllib3HttpConnection,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
# TODO: remove when OpenSearch Serverless adds support for /
|
||||
if service == 'es':
|
||||
info = client.info()
|
||||
print(f"{info['version']['distribution']}: {info['version']['number']}")
|
||||
|
||||
# create an index
|
||||
index = 'movies'
|
||||
client.indices.create(index=index)
|
||||
|
||||
try:
|
||||
# index data
|
||||
document = {'director': 'Bennett Miller', 'title': 'Moneyball', 'year': 2011}
|
||||
client.index(index=index, body=document, id='1')
|
||||
|
||||
# wait for the document to index
|
||||
sleep(1)
|
||||
|
||||
# search for the document
|
||||
results = client.search(body={'query': {'match': {'director': 'miller'}}})
|
||||
for hit in results['hits']['hits']:
|
||||
print(hit['_source'])
|
||||
|
||||
# delete the document
|
||||
client.delete(index=index, id='1')
|
||||
finally:
|
||||
# delete the index
|
||||
client.indices.delete(index=index)
|
||||
Generated
+158
-530
@@ -1,174 +1,45 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.8.5"
|
||||
description = "Async http client/server framework (asyncio)"
|
||||
name = "boto3"
|
||||
version = "1.28.67"
|
||||
description = "The AWS SDK for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">= 3.7"
|
||||
files = [
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a94159871304770da4dd371f4291b20cac04e8c94f11bdea1c3478e557fbe0d8"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:13bf85afc99ce6f9ee3567b04501f18f9f8dbbb2ea11ed1a2e079670403a7c84"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ce2ac5708501afc4847221a521f7e4b245abf5178cf5ddae9d5b3856ddb2f3a"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96943e5dcc37a6529d18766597c491798b7eb7a61d48878611298afc1fca946c"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ad5c3c4590bb3cc28b4382f031f3783f25ec223557124c68754a2231d989e2b"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c413c633d0512df4dc7fd2373ec06cc6a815b7b6d6c2f208ada7e9e93a5061d"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df72ac063b97837a80d80dec8d54c241af059cc9bb42c4de68bd5b61ceb37caa"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c48c5c0271149cfe467c0ff8eb941279fd6e3f65c9a388c984e0e6cf57538e14"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:368a42363c4d70ab52c2c6420a57f190ed3dfaca6a1b19afda8165ee16416a82"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7607ec3ce4993464368505888af5beb446845a014bc676d349efec0e05085905"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0d21c684808288a98914e5aaf2a7c6a3179d4df11d249799c32d1808e79503b5"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:312fcfbacc7880a8da0ae8b6abc6cc7d752e9caa0051a53d217a650b25e9a691"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad093e823df03bb3fd37e7dec9d4670c34f9e24aeace76808fc20a507cace825"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-win32.whl", hash = "sha256:33279701c04351a2914e1100b62b2a7fdb9a25995c4a104259f9a5ead7ed4802"},
|
||||
{file = "aiohttp-3.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:6e4a280e4b975a2e7745573e3fc9c9ba0d1194a3738ce1cbaa80626cc9b4f4df"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae871a964e1987a943d83d6709d20ec6103ca1eaf52f7e0d36ee1b5bebb8b9b9"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:461908b2578955045efde733719d62f2b649c404189a09a632d245b445c9c975"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72a860c215e26192379f57cae5ab12b168b75db8271f111019509a1196dfc780"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14be025665dba6202b6a71cfcdb53210cc498e50068bc088076624471f8bb9"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8af740fc2711ad85f1a5c034a435782fbd5b5f8314c9a3ef071424a8158d7f6b"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:841cd8233cbd2111a0ef0a522ce016357c5e3aff8a8ce92bcfa14cef890d698f"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed1c46fb119f1b59304b5ec89f834f07124cd23ae5b74288e364477641060ff"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84f8ae3e09a34f35c18fa57f015cc394bd1389bce02503fb30c394d04ee6b938"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62360cb771707cb70a6fd114b9871d20d7dd2163a0feafe43fd115cfe4fe845e"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23fb25a9f0a1ca1f24c0a371523546366bb642397c94ab45ad3aedf2941cec6a"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0ba0d15164eae3d878260d4c4df859bbdc6466e9e6689c344a13334f988bb53"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5d20003b635fc6ae3f96d7260281dfaf1894fc3aa24d1888a9b2628e97c241e5"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0175d745d9e85c40dcc51c8f88c74bfbaef9e7afeeeb9d03c37977270303064c"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-win32.whl", hash = "sha256:2e1b1e51b0774408f091d268648e3d57f7260c1682e7d3a63cb00d22d71bb945"},
|
||||
{file = "aiohttp-3.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:043d2299f6dfdc92f0ac5e995dfc56668e1587cea7f9aa9d8a78a1b6554e5755"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cae533195e8122584ec87531d6df000ad07737eaa3c81209e85c928854d2195c"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f21e83f355643c345177a5d1d8079f9f28b5133bcd154193b799d380331d5d3"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a75ef35f2df54ad55dbf4b73fe1da96f370e51b10c91f08b19603c64004acc"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e2e9839e14dd5308ee773c97115f1e0a1cb1d75cbeeee9f33824fa5144c7634"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44e65da1de4403d0576473e2344828ef9c4c6244d65cf4b75549bb46d40b8dd"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d847e4cde6ecc19125ccbc9bfac4a7ab37c234dd88fbb3c5c524e8e14da543"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:c7a815258e5895d8900aec4454f38dca9aed71085f227537208057853f9d13f2"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:8b929b9bd7cd7c3939f8bcfffa92fae7480bd1aa425279d51a89327d600c704d"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5db3a5b833764280ed7618393832e0853e40f3d3e9aa128ac0ba0f8278d08649"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:a0215ce6041d501f3155dc219712bc41252d0ab76474615b9700d63d4d9292af"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fd1ed388ea7fbed22c4968dd64bab0198de60750a25fe8c0c9d4bef5abe13824"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-win32.whl", hash = "sha256:6e6783bcc45f397fdebc118d772103d751b54cddf5b60fbcc958382d7dd64f3e"},
|
||||
{file = "aiohttp-3.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:b5411d82cddd212644cf9360879eb5080f0d5f7d809d03262c50dad02f01421a"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:01d4c0c874aa4ddfb8098e85d10b5e875a70adc63db91f1ae65a4b04d3344cda"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5980a746d547a6ba173fd5ee85ce9077e72d118758db05d229044b469d9029a"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a482e6da906d5e6e653be079b29bc173a48e381600161c9932d89dfae5942ef"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80bd372b8d0715c66c974cf57fe363621a02f359f1ec81cba97366948c7fc873"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1161b345c0a444ebcf46bf0a740ba5dcf50612fd3d0528883fdc0eff578006a"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd56db019015b6acfaaf92e1ac40eb8434847d9bf88b4be4efe5bfd260aee692"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:153c2549f6c004d2754cc60603d4668899c9895b8a89397444a9c4efa282aaf4"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4a01951fabc4ce26ab791da5f3f24dca6d9a6f24121746eb19756416ff2d881b"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bfb9162dcf01f615462b995a516ba03e769de0789de1cadc0f916265c257e5d8"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7dde0009408969a43b04c16cbbe252c4f5ef4574ac226bc8815cd7342d2028b6"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4149d34c32f9638f38f544b3977a4c24052042affa895352d3636fa8bffd030a"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-win32.whl", hash = "sha256:68c5a82c8779bdfc6367c967a4a1b2aa52cd3595388bf5961a62158ee8a59e22"},
|
||||
{file = "aiohttp-3.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2cf57fb50be5f52bda004b8893e63b48530ed9f0d6c96c84620dc92fe3cd9b9d"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eca4bf3734c541dc4f374ad6010a68ff6c6748f00451707f39857f429ca36ced"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1274477e4c71ce8cfe6c1ec2f806d57c015ebf84d83373676036e256bc55d690"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28c543e54710d6158fc6f439296c7865b29e0b616629767e685a7185fab4a6b9"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:910bec0c49637d213f5d9877105d26e0c4a4de2f8b1b29405ff37e9fc0ad52b8"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5443910d662db951b2e58eb70b0fbe6b6e2ae613477129a5805d0b66c54b6cb7"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e460be6978fc24e3df83193dc0cc4de46c9909ed92dd47d349a452ef49325b7"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb1558def481d84f03b45888473fc5a1f35747b5f334ef4e7a571bc0dfcb11f8"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34dd0c107799dcbbf7d48b53be761a013c0adf5571bf50c4ecad5643fe9cfcd0"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aa1990247f02a54185dc0dff92a6904521172a22664c863a03ff64c42f9b5410"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0e584a10f204a617d71d359fe383406305a4b595b333721fa50b867b4a0a1548"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a3cf433f127efa43fee6b90ea4c6edf6c4a17109d1d037d1a52abec84d8f2e42"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c11f5b099adafb18e65c2c997d57108b5bbeaa9eeee64a84302c0978b1ec948b"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:84de26ddf621d7ac4c975dbea4c945860e08cccde492269db4e1538a6a6f3c35"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-win32.whl", hash = "sha256:ab88bafedc57dd0aab55fa728ea10c1911f7e4d8b43e1d838a1739f33712921c"},
|
||||
{file = "aiohttp-3.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:5798a9aad1879f626589f3df0f8b79b3608a92e9beab10e5fda02c8a2c60db2e"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a6ce61195c6a19c785df04e71a4537e29eaa2c50fe745b732aa937c0c77169f3"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:773dd01706d4db536335fcfae6ea2440a70ceb03dd3e7378f3e815b03c97ab51"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f83a552443a526ea38d064588613aca983d0ee0038801bc93c0c916428310c28"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f7372f7341fcc16f57b2caded43e81ddd18df53320b6f9f042acad41f8e049a"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea353162f249c8097ea63c2169dd1aa55de1e8fecbe63412a9bc50816e87b761"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d47ae48db0b2dcf70bc8a3bc72b3de86e2a590fc299fdbbb15af320d2659de"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d827176898a2b0b09694fbd1088c7a31836d1a505c243811c87ae53a3f6273c1"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3562b06567c06439d8b447037bb655ef69786c590b1de86c7ab81efe1c9c15d8"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e874cbf8caf8959d2adf572a78bba17cb0e9d7e51bb83d86a3697b686a0ab4d"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6809a00deaf3810e38c628e9a33271892f815b853605a936e2e9e5129762356c"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:33776e945d89b29251b33a7e7d006ce86447b2cfd66db5e5ded4e5cd0340585c"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eaeed7abfb5d64c539e2db173f63631455f1196c37d9d8d873fc316470dfbacd"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e91d635961bec2d8f19dfeb41a539eb94bd073f075ca6dae6c8dc0ee89ad6f91"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-win32.whl", hash = "sha256:00ad4b6f185ec67f3e6562e8a1d2b69660be43070bd0ef6fcec5211154c7df67"},
|
||||
{file = "aiohttp-3.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:c0a9034379a37ae42dea7ac1e048352d96286626251862e448933c0f59cbd79c"},
|
||||
{file = "aiohttp-3.8.5.tar.gz", hash = "sha256:b9552ec52cc147dbf1944ac7ac98af7602e51ea2dcd076ed194ca3c0d1c7d0bc"},
|
||||
{file = "boto3-1.28.67-py3-none-any.whl", hash = "sha256:7d17f987a8b4f804e5ae509a30589736a72c6db7b0e2fb1338997128fdc9a3ec"},
|
||||
{file = "boto3-1.28.67.tar.gz", hash = "sha256:8db91c0648c9dcde1cf7fb4c15cd50da1fdef573595a9b9c769a303c7531b9a6"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiosignal = ">=1.1.2"
|
||||
async-timeout = ">=4.0.0a3,<5.0"
|
||||
asynctest = {version = "0.13.0", markers = "python_version < \"3.8\""}
|
||||
attrs = ">=17.3.0"
|
||||
charset-normalizer = ">=2.0,<4.0"
|
||||
frozenlist = ">=1.1.1"
|
||||
multidict = ">=4.5,<7.0"
|
||||
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
|
||||
yarl = ">=1.0,<2.0"
|
||||
botocore = ">=1.31.67,<1.32.0"
|
||||
jmespath = ">=0.7.1,<2.0.0"
|
||||
s3transfer = ">=0.7.0,<0.8.0"
|
||||
|
||||
[package.extras]
|
||||
speedups = ["Brotli", "aiodns", "cchardet"]
|
||||
crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
|
||||
|
||||
[[package]]
|
||||
name = "aiosignal"
|
||||
version = "1.3.1"
|
||||
description = "aiosignal: a list of registered asynchronous callbacks"
|
||||
name = "botocore"
|
||||
version = "1.31.67"
|
||||
description = "Low-level, data-driven core of boto 3."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">= 3.7"
|
||||
files = [
|
||||
{file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
|
||||
{file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
|
||||
{file = "botocore-1.31.67-py3-none-any.whl", hash = "sha256:487fb6ee4a6612613da370599b1a1aca0e159dd9e94b2e8aaa8e6ad9cc546ded"},
|
||||
{file = "botocore-1.31.67.tar.gz", hash = "sha256:ab3b73a2e03efa1c534a94f8db4a5cf45629a53e5478d2d154b0a3e2ffb05249"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
frozenlist = ">=1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "4.0.2"
|
||||
description = "Timeout context manager for asyncio programs"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
|
||||
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
|
||||
jmespath = ">=0.7.1,<2.0.0"
|
||||
python-dateutil = ">=2.1,<3.0.0"
|
||||
urllib3 = [
|
||||
{version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""},
|
||||
{version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "asynctest"
|
||||
version = "0.13.0"
|
||||
description = "Enhance the standard unittest package with features for testing asyncio libraries"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
{file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"},
|
||||
{file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "23.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
|
||||
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
|
||||
dev = ["attrs[docs,tests]", "pre-commit"]
|
||||
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
|
||||
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
||||
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||
crt = ["awscrt (==0.16.26)"]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
@@ -183,169 +54,101 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "3.2.0"
|
||||
version = "3.3.0"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
|
||||
{file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
|
||||
{file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
|
||||
{file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
|
||||
{file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
|
||||
{file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
|
||||
{file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frozenlist"
|
||||
version = "1.3.3"
|
||||
description = "A list-like structure which implements collections.abc.MutableSequence"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-win32.whl", hash = "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642"},
|
||||
{file = "frozenlist-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-win32.whl", hash = "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8"},
|
||||
{file = "frozenlist-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a"},
|
||||
{file = "frozenlist-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-win32.whl", hash = "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b"},
|
||||
{file = "frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-win32.whl", hash = "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38"},
|
||||
{file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"},
|
||||
{file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"},
|
||||
{file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"},
|
||||
{file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"},
|
||||
{file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"},
|
||||
{file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"},
|
||||
{file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"},
|
||||
{file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"},
|
||||
{file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"},
|
||||
{file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -360,134 +163,39 @@ files = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "6.7.0"
|
||||
description = "Read metadata from Python packages"
|
||||
name = "jmespath"
|
||||
version = "1.0.1"
|
||||
description = "JSON Matching Expressions"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"},
|
||||
{file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
perf = ["ipython"]
|
||||
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
|
||||
|
||||
[[package]]
|
||||
name = "multidict"
|
||||
version = "6.0.4"
|
||||
description = "multidict implementation"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"},
|
||||
{file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"},
|
||||
{file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"},
|
||||
{file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"},
|
||||
{file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"},
|
||||
{file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"},
|
||||
{file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"},
|
||||
{file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"},
|
||||
{file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opensearch-py"
|
||||
version = "2.2.0"
|
||||
version = "2.3.2"
|
||||
description = "Python client for OpenSearch"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4"
|
||||
files = []
|
||||
develop = false
|
||||
files = [
|
||||
{file = "opensearch-py-2.3.2.tar.gz", hash = "sha256:96e470b55107fd5bfd873722dc9808c333360eacfa174341f5cc2d021aa30448"},
|
||||
{file = "opensearch_py-2.3.2-py2.py3-none-any.whl", hash = "sha256:b1d6607380c8f19d90c142470939d051f0bac96069ce0ac25970b3c39c431f8b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = {version = ">=3,<4", optional = true, markers = "extra == \"async\""}
|
||||
certifi = ">=2022.12.07"
|
||||
python-dateutil = "*"
|
||||
requests = ">=2.4.0,<3.0.0"
|
||||
six = "*"
|
||||
urllib3 = ">=1.21.1,<2"
|
||||
urllib3 = ">=1.26.9"
|
||||
|
||||
[package.extras]
|
||||
async = ["aiohttp (>=3,<4)"]
|
||||
develop = ["black", "botocore", "coverage (<7.0.0)", "jinja2", "mock", "myst_parser", "pytest (>=3.0.0)", "pytest-cov", "pytest-mock (<4.0.0)", "pytz", "pyyaml", "requests (>=2.0.0,<3.0.0)", "sphinx", "sphinx_copybutton", "sphinx_rtd_theme"]
|
||||
docs = ["myst_parser", "sphinx", "sphinx_copybutton", "sphinx_rtd_theme"]
|
||||
kerberos = ["requests_kerberos"]
|
||||
|
||||
[package.source]
|
||||
type = "directory"
|
||||
url = ".."
|
||||
develop = ["black", "botocore", "coverage (<7.0.0)", "jinja2", "mock", "myst-parser", "pytest (>=3.0.0)", "pytest-cov", "pytest-mock (<4.0.0)", "pytz", "pyyaml", "requests (>=2.0.0,<3.0.0)", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"]
|
||||
docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"]
|
||||
kerberos = ["requests-kerberos"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
@@ -524,6 +232,23 @@ urllib3 = ">=1.21.1,<3"
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "s3transfer"
|
||||
version = "0.7.0"
|
||||
description = "An Amazon S3 Transfer Manager"
|
||||
optional = false
|
||||
python-versions = ">= 3.7"
|
||||
files = [
|
||||
{file = "s3transfer-0.7.0-py3-none-any.whl", hash = "sha256:10d6923c6359175f264811ef4bf6161a3156ce8e350e705396a7557d6293c33a"},
|
||||
{file = "s3transfer-0.7.0.tar.gz", hash = "sha256:fd3889a66f5fe17299fe75b82eae6cf722554edca744ca5d5fe308b104883d2e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
botocore = ">=1.12.36,<2.0a.0"
|
||||
|
||||
[package.extras]
|
||||
crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
@@ -535,137 +260,40 @@ files = [
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.7.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
|
||||
{file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.16"
|
||||
version = "1.26.18"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
{file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"},
|
||||
{file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"},
|
||||
{file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"},
|
||||
{file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "yarl"
|
||||
version = "1.9.2"
|
||||
description = "Yet another URL library"
|
||||
name = "urllib3"
|
||||
version = "2.0.7"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"},
|
||||
{file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"},
|
||||
{file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"},
|
||||
{file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"},
|
||||
{file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"},
|
||||
{file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"},
|
||||
{file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
idna = ">=2.0"
|
||||
multidict = ">=4.0"
|
||||
typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.15.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"},
|
||||
{file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"},
|
||||
{file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"},
|
||||
{file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "daae1667da61b85f9bbc2e5c484721c424594da7cb08fe9cf85c08d6731bcc52"
|
||||
content-hash = "1309989011bed3cb46e36fc451b65f040ef9fe9cecbe3f3706be240d4ea6d52e"
|
||||
|
||||
@@ -8,7 +8,8 @@ readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
opensearch-py = { path = "../", extras=["async"] }
|
||||
opensearch-py = { path = "../", extras=["async"], develop = true }
|
||||
boto3 = "^1.28"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
|
||||
@@ -48,11 +48,6 @@ from test_opensearchpy.TestHttpServer import TestHTTPServer
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
def gzip_decompress(data):
|
||||
buf = gzip.GzipFile(fileobj=io.BytesIO(data), mode="rb")
|
||||
return buf.read()
|
||||
|
||||
|
||||
class TestAIOHttpConnection:
|
||||
async def _get_mock_connection(
|
||||
self,
|
||||
@@ -130,7 +125,8 @@ class TestAIOHttpConnection:
|
||||
|
||||
_, kwargs = con.session.request.call_args
|
||||
|
||||
assert gzip_decompress(kwargs["data"]) == b"{}"
|
||||
buf = gzip.GzipFile(fileobj=io.BytesIO(kwargs["data"]), mode="rb")
|
||||
assert buf.read() == b"{}"
|
||||
assert kwargs["headers"]["accept-encoding"] == "gzip,deflate"
|
||||
assert kwargs["headers"]["content-encoding"] == "gzip"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# The OpenSearch Contributors require contributions made to
|
||||
# this file be licensed under the Apache-2.0 license or a
|
||||
# compatible open source license.
|
||||
#
|
||||
# Modifications Copyright OpenSearch Contributors. See
|
||||
# GitHub history for details.
|
||||
#
|
||||
# Licensed to Elasticsearch B.V. under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright
|
||||
# ownership. Elasticsearch B.V. licenses this file to you under
|
||||
# the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
@@ -0,0 +1,231 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# The OpenSearch Contributors require contributions made to
|
||||
# this file be licensed under the Apache-2.0 license or a
|
||||
# compatible open source license.
|
||||
#
|
||||
# Modifications Copyright OpenSearch Contributors. See
|
||||
# GitHub history for details.
|
||||
#
|
||||
# Licensed to Elasticsearch B.V. under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright
|
||||
# ownership. Elasticsearch B.V. licenses this file to you under
|
||||
# the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
import six
|
||||
|
||||
from opensearchpy.connection import Connection
|
||||
from opensearchpy.exceptions import NotFoundError
|
||||
|
||||
from ..test_cases import TestCase
|
||||
|
||||
try:
|
||||
from pytest import MonkeyPatch
|
||||
except ImportError: # Old version of pytest for 2.7 and 3.5
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
|
||||
from pytest import raises
|
||||
|
||||
from opensearchpy import OpenSearch, serializer
|
||||
from opensearchpy.connection import connections
|
||||
|
||||
|
||||
class TestBaseConnection(TestCase):
|
||||
def test_empty_warnings(self):
|
||||
con = Connection()
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
con._raise_warnings(())
|
||||
con._raise_warnings([])
|
||||
|
||||
self.assertEqual(w, [])
|
||||
|
||||
def test_raises_warnings(self):
|
||||
con = Connection()
|
||||
|
||||
with warnings.catch_warnings(record=True) as warn:
|
||||
con._raise_warnings(['299 OpenSearch-7.6.1-aa751 "this is deprecated"'])
|
||||
|
||||
self.assertEqual([str(w.message) for w in warn], ["this is deprecated"])
|
||||
|
||||
with warnings.catch_warnings(record=True) as warn:
|
||||
con._raise_warnings(
|
||||
[
|
||||
'299 OpenSearch-7.6.1-aa751 "this is also deprecated"',
|
||||
'299 OpenSearch-7.6.1-aa751 "this is also deprecated"',
|
||||
'299 OpenSearch-7.6.1-aa751 "guess what? deprecated"',
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
[str(w.message) for w in warn],
|
||||
["this is also deprecated", "guess what? deprecated"],
|
||||
)
|
||||
|
||||
def test_raises_warnings_when_folded(self):
|
||||
con = Connection()
|
||||
with warnings.catch_warnings(record=True) as warn:
|
||||
con._raise_warnings(
|
||||
[
|
||||
'299 OpenSearch-7.6.1-aa751 "warning",'
|
||||
'299 OpenSearch-7.6.1-aa751 "folded"',
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual([str(w.message) for w in warn], ["warning", "folded"])
|
||||
|
||||
@unittest.skipIf(six.PY2, "not compatible with python2")
|
||||
def test_raises_errors(self):
|
||||
con = Connection()
|
||||
with self.assertLogs("opensearch") as captured, self.assertRaises(
|
||||
NotFoundError
|
||||
):
|
||||
con._raise_error(404, "Not found", "application/json")
|
||||
self.assertEqual(len(captured.output), 1)
|
||||
|
||||
# NB: this should assertNoLogs() but that method is not available until python3.10
|
||||
with self.assertRaises(NotFoundError):
|
||||
con._raise_error(404, "Not found", "text/plain; charset=UTF-8")
|
||||
|
||||
def test_ipv6_host_and_port(self):
|
||||
for kwargs, expected_host in [
|
||||
({"host": "::1"}, "http://[::1]:9200"),
|
||||
({"host": "::1", "port": 443}, "http://[::1]:443"),
|
||||
({"host": "::1", "use_ssl": True}, "https://[::1]:9200"),
|
||||
({"host": "127.0.0.1", "port": 1234}, "http://127.0.0.1:1234"),
|
||||
({"host": "localhost", "use_ssl": True}, "https://localhost:9200"),
|
||||
]:
|
||||
conn = Connection(**kwargs)
|
||||
assert conn.host == expected_host
|
||||
|
||||
def test_compatibility_accept_header(self):
|
||||
try:
|
||||
conn = Connection()
|
||||
assert "accept" not in conn.headers
|
||||
|
||||
os.environ["ELASTIC_CLIENT_APIVERSIONING"] = "0"
|
||||
|
||||
conn = Connection()
|
||||
assert "accept" not in conn.headers
|
||||
|
||||
os.environ["ELASTIC_CLIENT_APIVERSIONING"] = "1"
|
||||
|
||||
conn = Connection()
|
||||
assert (
|
||||
conn.headers["accept"]
|
||||
== "application/vnd.elasticsearch+json;compatible-with=7"
|
||||
)
|
||||
finally:
|
||||
os.environ.pop("ELASTIC_CLIENT_APIVERSIONING")
|
||||
|
||||
def test_ca_certs_ssl_cert_file(self):
|
||||
cert = "/path/to/clientcert.pem"
|
||||
with MonkeyPatch().context() as monkeypatch:
|
||||
monkeypatch.setenv("SSL_CERT_FILE", cert)
|
||||
assert Connection.default_ca_certs() == cert
|
||||
|
||||
def test_ca_certs_ssl_cert_dir(self):
|
||||
cert = "/path/to/clientcert/dir"
|
||||
with MonkeyPatch().context() as monkeypatch:
|
||||
monkeypatch.setenv("SSL_CERT_DIR", cert)
|
||||
assert Connection.default_ca_certs() == cert
|
||||
|
||||
def test_ca_certs_certifi(self):
|
||||
import certifi
|
||||
|
||||
assert Connection.default_ca_certs() == certifi.where()
|
||||
|
||||
def test_no_ca_certs(self):
|
||||
with MonkeyPatch().context() as monkeypatch:
|
||||
monkeypatch.setitem(sys.modules, "certifi", None)
|
||||
assert Connection.default_ca_certs() is None
|
||||
|
||||
def test_default_connection_is_returned_by_default(self):
|
||||
c = connections.Connections()
|
||||
|
||||
con, con2 = object(), object()
|
||||
c.add_connection("default", con)
|
||||
|
||||
c.add_connection("not-default", con2)
|
||||
|
||||
assert c.get_connection() is con
|
||||
|
||||
def test_get_connection_created_connection_if_needed(self):
|
||||
c = connections.Connections()
|
||||
c.configure(
|
||||
default={"hosts": ["opensearch.com"]}, local={"hosts": ["localhost"]}
|
||||
)
|
||||
|
||||
default = c.get_connection()
|
||||
local = c.get_connection("local")
|
||||
|
||||
assert isinstance(default, OpenSearch)
|
||||
assert isinstance(local, OpenSearch)
|
||||
|
||||
assert [{"host": "opensearch.com"}] == default.transport.hosts
|
||||
assert [{"host": "localhost"}] == local.transport.hosts
|
||||
|
||||
def test_configure_preserves_unchanged_connections(self):
|
||||
c = connections.Connections()
|
||||
|
||||
c.configure(
|
||||
default={"hosts": ["opensearch.com"]}, local={"hosts": ["localhost"]}
|
||||
)
|
||||
default = c.get_connection()
|
||||
local = c.get_connection("local")
|
||||
|
||||
c.configure(
|
||||
default={"hosts": ["not-opensearch.com"]}, local={"hosts": ["localhost"]}
|
||||
)
|
||||
new_default = c.get_connection()
|
||||
new_local = c.get_connection("local")
|
||||
|
||||
assert new_local is local
|
||||
assert new_default is not default
|
||||
|
||||
def test_remove_connection_removes_both_conn_and_conf(self):
|
||||
c = connections.Connections()
|
||||
|
||||
c.configure(
|
||||
default={"hosts": ["opensearch.com"]}, local={"hosts": ["localhost"]}
|
||||
)
|
||||
c.add_connection("local2", object())
|
||||
|
||||
c.remove_connection("default")
|
||||
c.get_connection("local2")
|
||||
c.remove_connection("local2")
|
||||
|
||||
with raises(Exception):
|
||||
c.get_connection("local2")
|
||||
c.get_connection("default")
|
||||
|
||||
def test_create_connection_constructs_client(self):
|
||||
c = connections.Connections()
|
||||
c.create_connection("testing", hosts=["opensearch.com"])
|
||||
|
||||
con = c.get_connection("testing")
|
||||
assert [{"host": "opensearch.com"}] == con.transport.hosts
|
||||
|
||||
def test_create_connection_adds_our_serializer(self):
|
||||
c = connections.Connections()
|
||||
c.create_connection("testing", hosts=["opensearch.com"])
|
||||
|
||||
assert c.get_connection("testing").transport.serializer is serializer.serializer
|
||||
@@ -0,0 +1,561 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# The OpenSearch Contributors require contributions made to
|
||||
# this file be licensed under the Apache-2.0 license or a
|
||||
# compatible open source license.
|
||||
#
|
||||
# Modifications Copyright OpenSearch Contributors. See
|
||||
# GitHub history for details.
|
||||
#
|
||||
# Licensed to Elasticsearch B.V. under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright
|
||||
# ownership. Elasticsearch B.V. licenses this file to you under
|
||||
# the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import uuid
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
from mock import Mock, patch
|
||||
from requests.auth import AuthBase
|
||||
|
||||
from opensearchpy.compat import reraise_exceptions
|
||||
from opensearchpy.connection import Connection, RequestsHttpConnection
|
||||
from opensearchpy.exceptions import (
|
||||
ConflictError,
|
||||
NotFoundError,
|
||||
RequestError,
|
||||
TransportError,
|
||||
)
|
||||
|
||||
from ..test_cases import TestCase
|
||||
|
||||
if sys.version_info > (3, 0):
|
||||
from test_opensearchpy.TestHttpServer import TestHTTPServer
|
||||
|
||||
|
||||
class TestRequestsHttpConnection(TestCase):
|
||||
def _get_mock_connection(
|
||||
self, connection_params={}, status_code=200, response_body=b"{}"
|
||||
):
|
||||
con = RequestsHttpConnection(**connection_params)
|
||||
|
||||
def _dummy_send(*args, **kwargs):
|
||||
dummy_response = Mock()
|
||||
dummy_response.headers = {}
|
||||
dummy_response.status_code = status_code
|
||||
dummy_response.content = response_body
|
||||
dummy_response.request = args[0]
|
||||
dummy_response.cookies = {}
|
||||
_dummy_send.call_args = (args, kwargs)
|
||||
return dummy_response
|
||||
|
||||
con.session.send = _dummy_send
|
||||
return con
|
||||
|
||||
def _get_request(self, connection, *args, **kwargs):
|
||||
if "body" in kwargs:
|
||||
kwargs["body"] = kwargs["body"].encode("utf-8")
|
||||
|
||||
status, headers, data = connection.perform_request(*args, **kwargs)
|
||||
self.assertEqual(200, status)
|
||||
self.assertEqual("{}", data)
|
||||
|
||||
timeout = kwargs.pop("timeout", connection.timeout)
|
||||
args, kwargs = connection.session.send.call_args
|
||||
self.assertEqual(timeout, kwargs["timeout"])
|
||||
self.assertEqual(1, len(args))
|
||||
return args[0]
|
||||
|
||||
def test_custom_http_auth_is_allowed(self):
|
||||
auth = AuthBase()
|
||||
c = RequestsHttpConnection(http_auth=auth)
|
||||
|
||||
self.assertEqual(auth, c.session.auth)
|
||||
|
||||
def test_timeout_set(self):
|
||||
con = RequestsHttpConnection(timeout=42)
|
||||
self.assertEqual(42, con.timeout)
|
||||
|
||||
def test_opaque_id(self):
|
||||
con = RequestsHttpConnection(opaque_id="app-1")
|
||||
self.assertEqual(con.headers["x-opaque-id"], "app-1")
|
||||
|
||||
def test_no_http_compression(self):
|
||||
con = self._get_mock_connection()
|
||||
|
||||
self.assertFalse(con.http_compress)
|
||||
self.assertNotIn("content-encoding", con.session.headers)
|
||||
|
||||
con.perform_request("GET", "/")
|
||||
|
||||
req = con.session.send.call_args[0][0]
|
||||
self.assertNotIn("content-encoding", req.headers)
|
||||
self.assertNotIn("accept-encoding", req.headers)
|
||||
|
||||
def test_http_compression(self):
|
||||
con = self._get_mock_connection(
|
||||
{"http_compress": True},
|
||||
)
|
||||
|
||||
self.assertTrue(con.http_compress)
|
||||
|
||||
# 'content-encoding' shouldn't be set at a session level.
|
||||
# Should be applied only if the request is sent with a body.
|
||||
self.assertNotIn("content-encoding", con.session.headers)
|
||||
|
||||
con.perform_request("GET", "/", body=b"{}")
|
||||
|
||||
req = con.session.send.call_args[0][0]
|
||||
self.assertEqual(req.headers["content-encoding"], "gzip")
|
||||
self.assertEqual(req.headers["accept-encoding"], "gzip,deflate")
|
||||
|
||||
con.perform_request("GET", "/")
|
||||
|
||||
req = con.session.send.call_args[0][0]
|
||||
self.assertNotIn("content-encoding", req.headers)
|
||||
self.assertEqual(req.headers["accept-encoding"], "gzip,deflate")
|
||||
|
||||
def test_uses_https_if_verify_certs_is_off(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
con = self._get_mock_connection(
|
||||
{"use_ssl": True, "url_prefix": "url", "verify_certs": False}
|
||||
)
|
||||
self.assertEqual(1, len(w))
|
||||
self.assertEqual(
|
||||
"Connecting to https://localhost:9200 using SSL with verify_certs=False is insecure.",
|
||||
str(w[0].message),
|
||||
)
|
||||
|
||||
request = self._get_request(con, "GET", "/")
|
||||
|
||||
self.assertEqual("https://localhost:9200/url/", request.url)
|
||||
self.assertEqual("GET", request.method)
|
||||
self.assertEqual(None, request.body)
|
||||
|
||||
def test_uses_given_ca_certs(self):
|
||||
path = "/path/to/my/ca_certs.pem"
|
||||
c = RequestsHttpConnection(ca_certs=path)
|
||||
self.assertEqual(path, c.session.verify)
|
||||
|
||||
def test_uses_default_ca_certs(self):
|
||||
c = RequestsHttpConnection()
|
||||
self.assertEqual(Connection.default_ca_certs(), c.session.verify)
|
||||
|
||||
def test_uses_no_ca_certs(self):
|
||||
c = RequestsHttpConnection(verify_certs=False)
|
||||
self.assertFalse(c.session.verify)
|
||||
|
||||
def test_nowarn_when_uses_https_if_verify_certs_is_off(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
con = self._get_mock_connection(
|
||||
{
|
||||
"use_ssl": True,
|
||||
"url_prefix": "url",
|
||||
"verify_certs": False,
|
||||
"ssl_show_warn": False,
|
||||
}
|
||||
)
|
||||
self.assertEqual(0, len(w))
|
||||
|
||||
request = self._get_request(con, "GET", "/")
|
||||
|
||||
self.assertEqual("https://localhost:9200/url/", request.url)
|
||||
self.assertEqual("GET", request.method)
|
||||
self.assertEqual(None, request.body)
|
||||
|
||||
def test_merge_headers(self):
|
||||
con = self._get_mock_connection(
|
||||
connection_params={"headers": {"h1": "v1", "h2": "v2"}}
|
||||
)
|
||||
req = self._get_request(con, "GET", "/", headers={"h2": "v2p", "h3": "v3"})
|
||||
self.assertEqual(req.headers["h1"], "v1")
|
||||
self.assertEqual(req.headers["h2"], "v2p")
|
||||
self.assertEqual(req.headers["h3"], "v3")
|
||||
|
||||
def test_default_headers(self):
|
||||
con = self._get_mock_connection()
|
||||
req = self._get_request(con, "GET", "/")
|
||||
self.assertEqual(req.headers["content-type"], "application/json")
|
||||
self.assertEqual(req.headers["user-agent"], con._get_default_user_agent())
|
||||
|
||||
def test_custom_headers(self):
|
||||
con = self._get_mock_connection()
|
||||
req = self._get_request(
|
||||
con,
|
||||
"GET",
|
||||
"/",
|
||||
headers={
|
||||
"content-type": "application/x-ndjson",
|
||||
"user-agent": "custom-agent/1.2.3",
|
||||
},
|
||||
)
|
||||
self.assertEqual(req.headers["content-type"], "application/x-ndjson")
|
||||
self.assertEqual(req.headers["user-agent"], "custom-agent/1.2.3")
|
||||
|
||||
def test_http_auth(self):
|
||||
con = RequestsHttpConnection(http_auth="username:secret")
|
||||
self.assertEqual(("username", "secret"), con.session.auth)
|
||||
|
||||
def test_http_auth_tuple(self):
|
||||
con = RequestsHttpConnection(http_auth=("username", "secret"))
|
||||
self.assertEqual(("username", "secret"), con.session.auth)
|
||||
|
||||
def test_http_auth_list(self):
|
||||
con = RequestsHttpConnection(http_auth=["username", "secret"])
|
||||
self.assertEqual(("username", "secret"), con.session.auth)
|
||||
|
||||
def test_repr(self):
|
||||
con = self._get_mock_connection({"host": "opensearchpy.com", "port": 443})
|
||||
self.assertEqual(
|
||||
"<RequestsHttpConnection: http://opensearchpy.com:443>", repr(con)
|
||||
)
|
||||
|
||||
def test_conflict_error_is_returned_on_409(self):
|
||||
con = self._get_mock_connection(status_code=409)
|
||||
self.assertRaises(ConflictError, con.perform_request, "GET", "/", {}, "")
|
||||
|
||||
def test_not_found_error_is_returned_on_404(self):
|
||||
con = self._get_mock_connection(status_code=404)
|
||||
self.assertRaises(NotFoundError, con.perform_request, "GET", "/", {}, "")
|
||||
|
||||
def test_request_error_is_returned_on_400(self):
|
||||
con = self._get_mock_connection(status_code=400)
|
||||
self.assertRaises(RequestError, con.perform_request, "GET", "/", {}, "")
|
||||
|
||||
@patch("opensearchpy.connection.base.logger")
|
||||
def test_head_with_404_doesnt_get_logged(self, logger):
|
||||
con = self._get_mock_connection(status_code=404)
|
||||
self.assertRaises(NotFoundError, con.perform_request, "HEAD", "/", {}, "")
|
||||
self.assertEqual(0, logger.warning.call_count)
|
||||
|
||||
@patch("opensearchpy.connection.base.tracer")
|
||||
@patch("opensearchpy.connection.base.logger")
|
||||
def test_failed_request_logs_and_traces(self, logger, tracer):
|
||||
con = self._get_mock_connection(
|
||||
response_body=b'{"answer": 42}', status_code=500
|
||||
)
|
||||
self.assertRaises(
|
||||
TransportError,
|
||||
con.perform_request,
|
||||
"GET",
|
||||
"/",
|
||||
{"param": 42},
|
||||
"{}".encode("utf-8"),
|
||||
)
|
||||
|
||||
# trace request
|
||||
self.assertEqual(1, tracer.info.call_count)
|
||||
# trace response
|
||||
self.assertEqual(1, tracer.debug.call_count)
|
||||
# log url and duration
|
||||
self.assertEqual(1, logger.warning.call_count)
|
||||
self.assertTrue(
|
||||
re.match(
|
||||
r"^GET http://localhost:9200/\?param=42 \[status:500 request:0.[0-9]{3}s\]",
|
||||
logger.warning.call_args[0][0] % logger.warning.call_args[0][1:],
|
||||
)
|
||||
)
|
||||
|
||||
@patch("opensearchpy.connection.base.tracer")
|
||||
@patch("opensearchpy.connection.base.logger")
|
||||
def test_success_logs_and_traces(self, logger, tracer):
|
||||
con = self._get_mock_connection(response_body=b"""{"answer": "that's it!"}""")
|
||||
status, headers, data = con.perform_request(
|
||||
"GET",
|
||||
"/",
|
||||
{"param": 42},
|
||||
"""{"question": "what's that?"}""".encode("utf-8"),
|
||||
)
|
||||
|
||||
# trace request
|
||||
self.assertEqual(1, tracer.info.call_count)
|
||||
self.assertEqual(
|
||||
"""curl -H 'Content-Type: application/json' -XGET 'http://localhost:9200/?pretty¶m=42' -d '{\n "question": "what\\u0027s that?"\n}'""",
|
||||
tracer.info.call_args[0][0] % tracer.info.call_args[0][1:],
|
||||
)
|
||||
# trace response
|
||||
self.assertEqual(1, tracer.debug.call_count)
|
||||
self.assertTrue(
|
||||
re.match(
|
||||
r'#\[200\] \(0.[0-9]{3}s\)\n#{\n# "answer": "that\\u0027s it!"\n#}',
|
||||
tracer.debug.call_args[0][0] % tracer.debug.call_args[0][1:],
|
||||
)
|
||||
)
|
||||
|
||||
# log url and duration
|
||||
self.assertEqual(1, logger.info.call_count)
|
||||
self.assertTrue(
|
||||
re.match(
|
||||
r"GET http://localhost:9200/\?param=42 \[status:200 request:0.[0-9]{3}s\]",
|
||||
logger.info.call_args[0][0] % logger.info.call_args[0][1:],
|
||||
)
|
||||
)
|
||||
# log request body and response
|
||||
self.assertEqual(2, logger.debug.call_count)
|
||||
req, resp = logger.debug.call_args_list
|
||||
self.assertEqual('> {"question": "what\'s that?"}', req[0][0] % req[0][1:])
|
||||
self.assertEqual('< {"answer": "that\'s it!"}', resp[0][0] % resp[0][1:])
|
||||
|
||||
@patch("opensearchpy.connection.base.logger")
|
||||
def test_uncompressed_body_logged(self, logger):
|
||||
con = self._get_mock_connection(connection_params={"http_compress": True})
|
||||
con.perform_request("GET", "/", body=b'{"example": "body"}')
|
||||
|
||||
self.assertEqual(2, logger.debug.call_count)
|
||||
req, resp = logger.debug.call_args_list
|
||||
self.assertEqual('> {"example": "body"}', req[0][0] % req[0][1:])
|
||||
self.assertEqual("< {}", resp[0][0] % resp[0][1:])
|
||||
|
||||
con = self._get_mock_connection(
|
||||
connection_params={"http_compress": True},
|
||||
status_code=500,
|
||||
response_body=b'{"hello":"world"}',
|
||||
)
|
||||
with pytest.raises(TransportError):
|
||||
con.perform_request("GET", "/", body=b'{"example": "body2"}')
|
||||
|
||||
self.assertEqual(4, logger.debug.call_count)
|
||||
_, _, req, resp = logger.debug.call_args_list
|
||||
self.assertEqual('> {"example": "body2"}', req[0][0] % req[0][1:])
|
||||
self.assertEqual('< {"hello":"world"}', resp[0][0] % resp[0][1:])
|
||||
|
||||
def test_defaults(self):
|
||||
con = self._get_mock_connection()
|
||||
request = self._get_request(con, "GET", "/")
|
||||
|
||||
self.assertEqual("http://localhost:9200/", request.url)
|
||||
self.assertEqual("GET", request.method)
|
||||
self.assertEqual(None, request.body)
|
||||
|
||||
def test_params_properly_encoded(self):
|
||||
con = self._get_mock_connection()
|
||||
request = self._get_request(
|
||||
con, "GET", "/", params={"param": "value with spaces"}
|
||||
)
|
||||
|
||||
self.assertEqual("http://localhost:9200/?param=value+with+spaces", request.url)
|
||||
self.assertEqual("GET", request.method)
|
||||
self.assertEqual(None, request.body)
|
||||
|
||||
def test_body_attached(self):
|
||||
con = self._get_mock_connection()
|
||||
request = self._get_request(con, "GET", "/", body='{"answer": 42}')
|
||||
|
||||
self.assertEqual("http://localhost:9200/", request.url)
|
||||
self.assertEqual("GET", request.method)
|
||||
self.assertEqual('{"answer": 42}'.encode("utf-8"), request.body)
|
||||
|
||||
def test_http_auth_attached(self):
|
||||
con = self._get_mock_connection({"http_auth": "username:secret"})
|
||||
request = self._get_request(con, "GET", "/")
|
||||
|
||||
self.assertEqual(request.headers["authorization"], "Basic dXNlcm5hbWU6c2VjcmV0")
|
||||
|
||||
@patch("opensearchpy.connection.base.tracer")
|
||||
def test_url_prefix(self, tracer):
|
||||
con = self._get_mock_connection({"url_prefix": "/some-prefix/"})
|
||||
request = self._get_request(
|
||||
con, "GET", "/_search", body='{"answer": 42}', timeout=0.1
|
||||
)
|
||||
|
||||
self.assertEqual("http://localhost:9200/some-prefix/_search", request.url)
|
||||
self.assertEqual("GET", request.method)
|
||||
self.assertEqual('{"answer": 42}'.encode("utf-8"), request.body)
|
||||
|
||||
# trace request
|
||||
self.assertEqual(1, tracer.info.call_count)
|
||||
self.assertEqual(
|
||||
"curl -H 'Content-Type: application/json' -XGET 'http://localhost:9200/_search?pretty' -d '{\n \"answer\": 42\n}'",
|
||||
tracer.info.call_args[0][0] % tracer.info.call_args[0][1:],
|
||||
)
|
||||
|
||||
def test_surrogatepass_into_bytes(self):
|
||||
buf = b"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"
|
||||
con = self._get_mock_connection(response_body=buf)
|
||||
status, headers, data = con.perform_request("GET", "/")
|
||||
self.assertEqual(u"你好\uda6a", data) # fmt: skip
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not reraise_exceptions, reason="RecursionError isn't defined in Python <3.5"
|
||||
)
|
||||
def test_recursion_error_reraised(self):
|
||||
conn = RequestsHttpConnection()
|
||||
|
||||
def send_raise(*_, **__):
|
||||
raise RecursionError("Wasn't modified!")
|
||||
|
||||
conn.session.send = send_raise
|
||||
|
||||
with pytest.raises(RecursionError) as e:
|
||||
conn.perform_request("GET", "/")
|
||||
assert str(e.value) == "Wasn't modified!"
|
||||
|
||||
def mock_session(self):
|
||||
access_key = uuid.uuid4().hex
|
||||
secret_key = uuid.uuid4().hex
|
||||
token = uuid.uuid4().hex
|
||||
dummy_session = Mock()
|
||||
dummy_session.access_key = access_key
|
||||
dummy_session.secret_key = secret_key
|
||||
dummy_session.token = token
|
||||
del dummy_session.get_frozen_credentials
|
||||
|
||||
return dummy_session
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="RequestsAWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_aws_signer_as_http_auth(self):
|
||||
region = "us-west-2"
|
||||
|
||||
import requests
|
||||
|
||||
from opensearchpy.helpers.signer import RequestsAWSV4SignerAuth
|
||||
|
||||
auth = RequestsAWSV4SignerAuth(self.mock_session(), region)
|
||||
con = RequestsHttpConnection(http_auth=auth)
|
||||
prepared_request = requests.Request("GET", "http://localhost").prepare()
|
||||
auth(prepared_request)
|
||||
self.assertEqual(auth, con.session.auth)
|
||||
self.assertIn("Authorization", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Date", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Security-Token", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Content-SHA256", prepared_request.headers)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="RequestsAWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_aws_signer_when_service_is_specified(self):
|
||||
region = "us-west-1"
|
||||
service = "aoss"
|
||||
|
||||
import requests
|
||||
|
||||
from opensearchpy.helpers.signer import RequestsAWSV4SignerAuth
|
||||
|
||||
auth = RequestsAWSV4SignerAuth(self.mock_session(), region, service)
|
||||
con = RequestsHttpConnection(http_auth=auth)
|
||||
prepared_request = requests.Request("GET", "http://localhost").prepare()
|
||||
auth(prepared_request)
|
||||
self.assertEqual(auth, con.session.auth)
|
||||
self.assertIn("Authorization", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Date", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Security-Token", prepared_request.headers)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="RequestsAWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
@patch("opensearchpy.helpers.signer.AWSV4Signer.sign")
|
||||
def test_aws_signer_signs_with_query_string(self, mock_sign):
|
||||
region = "us-west-1"
|
||||
service = "aoss"
|
||||
|
||||
import requests
|
||||
|
||||
from opensearchpy.helpers.signer import RequestsAWSV4SignerAuth
|
||||
|
||||
auth = RequestsAWSV4SignerAuth(self.mock_session(), region, service)
|
||||
prepared_request = requests.Request(
|
||||
"GET", "http://localhost", params={"key1": "value1", "key2": "value2"}
|
||||
).prepare()
|
||||
auth(prepared_request)
|
||||
self.assertEqual(mock_sign.call_count, 1)
|
||||
self.assertEqual(
|
||||
mock_sign.call_args[0],
|
||||
("GET", "http://localhost/?key1=value1&key2=value2", None),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 0),
|
||||
reason="http_server is only available from python 3.x",
|
||||
)
|
||||
class TestRequestsConnectionRedirect:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
# Start servers
|
||||
cls.server1 = TestHTTPServer(port=8080)
|
||||
cls.server1.start()
|
||||
cls.server2 = TestHTTPServer(port=8090)
|
||||
cls.server2.start()
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
# Stop servers
|
||||
cls.server2.stop()
|
||||
cls.server1.stop()
|
||||
|
||||
# allow_redirects = False
|
||||
def test_redirect_failure_when_allow_redirect_false(self):
|
||||
conn = RequestsHttpConnection("localhost", port=8080, use_ssl=False, timeout=60)
|
||||
with pytest.raises(TransportError) as e:
|
||||
conn.perform_request("GET", "/redirect", allow_redirects=False)
|
||||
assert e.value.status_code == 302
|
||||
|
||||
# allow_redirects = True (Default)
|
||||
def test_redirect_success_when_allow_redirect_true(self):
|
||||
conn = RequestsHttpConnection("localhost", port=8080, use_ssl=False, timeout=60)
|
||||
user_agent = conn._get_default_user_agent()
|
||||
status, headers, data = conn.perform_request("GET", "/redirect")
|
||||
assert status == 200
|
||||
data = json.loads(data)
|
||||
assert data["headers"] == {
|
||||
"Host": "localhost:8090",
|
||||
"Accept-Encoding": "identity",
|
||||
"User-Agent": user_agent,
|
||||
}
|
||||
|
||||
|
||||
class TestSignerWithFrozenCredentials(TestRequestsHttpConnection):
|
||||
def mock_session(self):
|
||||
access_key = uuid.uuid4().hex
|
||||
secret_key = uuid.uuid4().hex
|
||||
token = uuid.uuid4().hex
|
||||
dummy_session = Mock()
|
||||
dummy_session.access_key = access_key
|
||||
dummy_session.secret_key = secret_key
|
||||
dummy_session.token = token
|
||||
dummy_session.get_frozen_credentials = Mock(return_value=dummy_session)
|
||||
|
||||
return dummy_session
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="RequestsAWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_requests_http_connection_aws_signer_frozen_credentials_as_http_auth(self):
|
||||
region = "us-west-2"
|
||||
|
||||
import requests
|
||||
|
||||
from opensearchpy.helpers.signer import RequestsAWSV4SignerAuth
|
||||
|
||||
mock_session = self.mock_session()
|
||||
|
||||
auth = RequestsAWSV4SignerAuth(mock_session, region)
|
||||
con = RequestsHttpConnection(http_auth=auth)
|
||||
prepared_request = requests.Request("GET", "http://localhost").prepare()
|
||||
auth(prepared_request)
|
||||
self.assertEqual(auth, con.session.auth)
|
||||
self.assertIn("Authorization", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Date", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Security-Token", prepared_request.headers)
|
||||
self.assertIn("X-Amz-Content-SHA256", prepared_request.headers)
|
||||
mock_session.get_frozen_credentials.assert_called_once()
|
||||
@@ -0,0 +1,406 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# The OpenSearch Contributors require contributions made to
|
||||
# this file be licensed under the Apache-2.0 license or a
|
||||
# compatible open source license.
|
||||
#
|
||||
# Modifications Copyright OpenSearch Contributors. See
|
||||
# GitHub history for details.
|
||||
#
|
||||
# Licensed to Elasticsearch B.V. under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright
|
||||
# ownership. Elasticsearch B.V. licenses this file to you under
|
||||
# the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import ssl
|
||||
import sys
|
||||
import uuid
|
||||
import warnings
|
||||
from gzip import GzipFile
|
||||
from io import BytesIO
|
||||
from platform import python_version
|
||||
|
||||
import pytest
|
||||
import urllib3
|
||||
from mock import Mock, patch
|
||||
from urllib3._collections import HTTPHeaderDict
|
||||
|
||||
from opensearchpy import __versionstr__
|
||||
from opensearchpy.compat import reraise_exceptions
|
||||
from opensearchpy.connection import Connection, Urllib3HttpConnection
|
||||
|
||||
from ..test_cases import SkipTest, TestCase
|
||||
|
||||
|
||||
class TestUrllib3HttpConnection(TestCase):
|
||||
def _get_mock_connection(self, connection_params={}, response_body=b"{}"):
|
||||
con = Urllib3HttpConnection(**connection_params)
|
||||
|
||||
def _dummy_urlopen(*args, **kwargs):
|
||||
dummy_response = Mock()
|
||||
dummy_response.headers = HTTPHeaderDict({})
|
||||
dummy_response.status = 200
|
||||
dummy_response.data = response_body
|
||||
_dummy_urlopen.call_args = (args, kwargs)
|
||||
return dummy_response
|
||||
|
||||
con.pool.urlopen = _dummy_urlopen
|
||||
return con
|
||||
|
||||
def test_ssl_context(self):
|
||||
try:
|
||||
context = ssl.create_default_context()
|
||||
except AttributeError:
|
||||
# if create_default_context raises an AttributeError Exception
|
||||
# it means SSLContext is not available for that version of python
|
||||
# and we should skip this test.
|
||||
raise SkipTest(
|
||||
"Test test_ssl_context is skipped cause SSLContext is not available for this version of python"
|
||||
)
|
||||
|
||||
con = Urllib3HttpConnection(use_ssl=True, ssl_context=context)
|
||||
self.assertEqual(len(con.pool.conn_kw.keys()), 1)
|
||||
self.assertIsInstance(con.pool.conn_kw["ssl_context"], ssl.SSLContext)
|
||||
self.assertTrue(con.use_ssl)
|
||||
|
||||
def test_opaque_id(self):
|
||||
con = Urllib3HttpConnection(opaque_id="app-1")
|
||||
self.assertEqual(con.headers["x-opaque-id"], "app-1")
|
||||
|
||||
def test_no_http_compression(self):
|
||||
con = self._get_mock_connection()
|
||||
self.assertFalse(con.http_compress)
|
||||
self.assertNotIn("accept-encoding", con.headers)
|
||||
|
||||
con.perform_request("GET", "/")
|
||||
|
||||
(_, _, req_body), kwargs = con.pool.urlopen.call_args
|
||||
|
||||
self.assertFalse(req_body)
|
||||
self.assertNotIn("accept-encoding", kwargs["headers"])
|
||||
self.assertNotIn("content-encoding", kwargs["headers"])
|
||||
|
||||
def test_http_compression(self):
|
||||
con = self._get_mock_connection({"http_compress": True})
|
||||
self.assertTrue(con.http_compress)
|
||||
self.assertEqual(con.headers["accept-encoding"], "gzip,deflate")
|
||||
|
||||
# 'content-encoding' shouldn't be set at a connection level.
|
||||
# Should be applied only if the request is sent with a body.
|
||||
self.assertNotIn("content-encoding", con.headers)
|
||||
|
||||
con.perform_request("GET", "/", body=b"{}")
|
||||
|
||||
(_, _, req_body), kwargs = con.pool.urlopen.call_args
|
||||
|
||||
buf = GzipFile(fileobj=BytesIO(req_body), mode="rb")
|
||||
|
||||
self.assertEqual(buf.read(), b"{}")
|
||||
self.assertEqual(kwargs["headers"]["accept-encoding"], "gzip,deflate")
|
||||
self.assertEqual(kwargs["headers"]["content-encoding"], "gzip")
|
||||
|
||||
con.perform_request("GET", "/")
|
||||
|
||||
(_, _, req_body), kwargs = con.pool.urlopen.call_args
|
||||
|
||||
self.assertFalse(req_body)
|
||||
self.assertEqual(kwargs["headers"]["accept-encoding"], "gzip,deflate")
|
||||
self.assertNotIn("content-encoding", kwargs["headers"])
|
||||
|
||||
def test_default_user_agent(self):
|
||||
con = Urllib3HttpConnection()
|
||||
self.assertEqual(
|
||||
con._get_default_user_agent(),
|
||||
"opensearch-py/%s (Python %s)" % (__versionstr__, python_version()),
|
||||
)
|
||||
|
||||
def test_timeout_set(self):
|
||||
con = Urllib3HttpConnection(timeout=42)
|
||||
self.assertEqual(42, con.timeout)
|
||||
|
||||
def test_keep_alive_is_on_by_default(self):
|
||||
con = Urllib3HttpConnection()
|
||||
self.assertEqual(
|
||||
{
|
||||
"connection": "keep-alive",
|
||||
"content-type": "application/json",
|
||||
"user-agent": con._get_default_user_agent(),
|
||||
},
|
||||
con.headers,
|
||||
)
|
||||
|
||||
def test_http_auth(self):
|
||||
con = Urllib3HttpConnection(http_auth="username:secret")
|
||||
self.assertEqual(
|
||||
{
|
||||
"authorization": "Basic dXNlcm5hbWU6c2VjcmV0",
|
||||
"connection": "keep-alive",
|
||||
"content-type": "application/json",
|
||||
"user-agent": con._get_default_user_agent(),
|
||||
},
|
||||
con.headers,
|
||||
)
|
||||
|
||||
def test_http_auth_tuple(self):
|
||||
con = Urllib3HttpConnection(http_auth=("username", "secret"))
|
||||
self.assertEqual(
|
||||
{
|
||||
"authorization": "Basic dXNlcm5hbWU6c2VjcmV0",
|
||||
"content-type": "application/json",
|
||||
"connection": "keep-alive",
|
||||
"user-agent": con._get_default_user_agent(),
|
||||
},
|
||||
con.headers,
|
||||
)
|
||||
|
||||
def test_http_auth_list(self):
|
||||
con = Urllib3HttpConnection(http_auth=["username", "secret"])
|
||||
self.assertEqual(
|
||||
{
|
||||
"authorization": "Basic dXNlcm5hbWU6c2VjcmV0",
|
||||
"content-type": "application/json",
|
||||
"connection": "keep-alive",
|
||||
"user-agent": con._get_default_user_agent(),
|
||||
},
|
||||
con.headers,
|
||||
)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="Urllib3AWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
@patch(
|
||||
"urllib3.HTTPConnectionPool.urlopen",
|
||||
return_value=Mock(status=200, headers=HTTPHeaderDict({}), data=b"{}"),
|
||||
)
|
||||
def test_aws_signer_as_http_auth_adds_headers(self, mock_open):
|
||||
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
|
||||
|
||||
auth = Urllib3AWSV4SignerAuth(self.mock_session(), "us-west-2")
|
||||
con = Urllib3HttpConnection(http_auth=auth, headers={"x": "y"})
|
||||
con.perform_request("GET", "/")
|
||||
self.assertEqual(mock_open.call_count, 1)
|
||||
headers = mock_open.call_args[1]["headers"]
|
||||
self.assertEqual(headers["x"], "y")
|
||||
self.assertTrue(
|
||||
headers["Authorization"].startswith("AWS4-HMAC-SHA256 Credential=")
|
||||
)
|
||||
self.assertIn("X-Amz-Date", headers)
|
||||
self.assertIn("X-Amz-Security-Token", headers)
|
||||
self.assertIn("X-Amz-Content-SHA256", headers)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="Urllib3AWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_aws_signer_as_http_auth(self):
|
||||
region = "us-west-2"
|
||||
|
||||
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
|
||||
|
||||
auth = Urllib3AWSV4SignerAuth(self.mock_session(), region)
|
||||
headers = auth("GET", "http://localhost", None)
|
||||
self.assertIn("Authorization", headers)
|
||||
self.assertIn("X-Amz-Date", headers)
|
||||
self.assertIn("X-Amz-Security-Token", headers)
|
||||
self.assertIn("X-Amz-Content-SHA256", headers)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="Urllib3AWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_aws_signer_when_region_is_null(self):
|
||||
session = self.mock_session()
|
||||
|
||||
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
|
||||
|
||||
with pytest.raises(ValueError) as e:
|
||||
Urllib3AWSV4SignerAuth(session, None)
|
||||
assert str(e.value) == "Region cannot be empty"
|
||||
|
||||
with pytest.raises(ValueError) as e:
|
||||
Urllib3AWSV4SignerAuth(session, "")
|
||||
assert str(e.value) == "Region cannot be empty"
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="Urllib3AWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_aws_signer_when_credentials_is_null(self):
|
||||
region = "us-west-1"
|
||||
|
||||
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
|
||||
|
||||
with pytest.raises(ValueError) as e:
|
||||
Urllib3AWSV4SignerAuth(None, region)
|
||||
assert str(e.value) == "Credentials cannot be empty"
|
||||
|
||||
with pytest.raises(ValueError) as e:
|
||||
Urllib3AWSV4SignerAuth("", region)
|
||||
assert str(e.value) == "Credentials cannot be empty"
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="Urllib3AWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_aws_signer_when_service_is_specified(self):
|
||||
region = "us-west-1"
|
||||
service = "aoss"
|
||||
|
||||
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
|
||||
|
||||
auth = Urllib3AWSV4SignerAuth(self.mock_session(), region, service)
|
||||
headers = auth("GET", "http://localhost", None)
|
||||
self.assertIn("Authorization", headers)
|
||||
self.assertIn("X-Amz-Date", headers)
|
||||
self.assertIn("X-Amz-Security-Token", headers)
|
||||
|
||||
def mock_session(self):
|
||||
access_key = uuid.uuid4().hex
|
||||
secret_key = uuid.uuid4().hex
|
||||
token = uuid.uuid4().hex
|
||||
dummy_session = Mock()
|
||||
dummy_session.access_key = access_key
|
||||
dummy_session.secret_key = secret_key
|
||||
dummy_session.token = token
|
||||
del dummy_session.get_frozen_credentials
|
||||
|
||||
return dummy_session
|
||||
|
||||
def test_uses_https_if_verify_certs_is_off(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
con = Urllib3HttpConnection(use_ssl=True, verify_certs=False)
|
||||
self.assertEqual(1, len(w))
|
||||
self.assertEqual(
|
||||
"Connecting to https://localhost:9200 using SSL with verify_certs=False is insecure.",
|
||||
str(w[0].message),
|
||||
)
|
||||
|
||||
self.assertIsInstance(con.pool, urllib3.HTTPSConnectionPool)
|
||||
|
||||
def test_nowarn_when_uses_https_if_verify_certs_is_off(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
con = Urllib3HttpConnection(
|
||||
use_ssl=True, verify_certs=False, ssl_show_warn=False
|
||||
)
|
||||
self.assertEqual(0, len(w))
|
||||
|
||||
self.assertIsInstance(con.pool, urllib3.HTTPSConnectionPool)
|
||||
|
||||
def test_doesnt_use_https_if_not_specified(self):
|
||||
con = Urllib3HttpConnection()
|
||||
self.assertIsInstance(con.pool, urllib3.HTTPConnectionPool)
|
||||
|
||||
def test_no_warning_when_using_ssl_context(self):
|
||||
ctx = ssl.create_default_context()
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
Urllib3HttpConnection(ssl_context=ctx)
|
||||
self.assertEqual(0, len(w))
|
||||
|
||||
def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self):
|
||||
for kwargs in (
|
||||
{"ssl_show_warn": False},
|
||||
{"ssl_show_warn": True},
|
||||
{"verify_certs": True},
|
||||
{"verify_certs": False},
|
||||
{"ca_certs": "/path/to/certs"},
|
||||
{"ssl_show_warn": True, "ca_certs": "/path/to/certs"},
|
||||
):
|
||||
kwargs["ssl_context"] = ssl.create_default_context()
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
Urllib3HttpConnection(**kwargs)
|
||||
|
||||
self.assertEqual(1, len(w))
|
||||
self.assertEqual(
|
||||
"When using `ssl_context`, all other SSL related kwargs are ignored",
|
||||
str(w[0].message),
|
||||
)
|
||||
|
||||
def test_uses_given_ca_certs(self):
|
||||
path = "/path/to/my/ca_certs.pem"
|
||||
c = Urllib3HttpConnection(use_ssl=True, ca_certs=path)
|
||||
self.assertEqual(path, c.pool.ca_certs)
|
||||
|
||||
def test_uses_default_ca_certs(self):
|
||||
c = Urllib3HttpConnection(use_ssl=True)
|
||||
self.assertEqual(Connection.default_ca_certs(), c.pool.ca_certs)
|
||||
|
||||
def test_uses_no_ca_certs(self):
|
||||
c = Urllib3HttpConnection(use_ssl=True, verify_certs=False)
|
||||
self.assertIsNone(c.pool.ca_certs)
|
||||
|
||||
@patch("opensearchpy.connection.base.logger")
|
||||
def test_uncompressed_body_logged(self, logger):
|
||||
con = self._get_mock_connection(connection_params={"http_compress": True})
|
||||
con.perform_request("GET", "/", body=b'{"example": "body"}')
|
||||
|
||||
self.assertEqual(2, logger.debug.call_count)
|
||||
req, resp = logger.debug.call_args_list
|
||||
|
||||
self.assertEqual('> {"example": "body"}', req[0][0] % req[0][1:])
|
||||
self.assertEqual("< {}", resp[0][0] % resp[0][1:])
|
||||
|
||||
def test_surrogatepass_into_bytes(self):
|
||||
buf = b"\xe4\xbd\xa0\xe5\xa5\xbd\xed\xa9\xaa"
|
||||
con = self._get_mock_connection(response_body=buf)
|
||||
status, headers, data = con.perform_request("GET", "/")
|
||||
self.assertEqual(u"你好\uda6a", data) # fmt: skip
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not reraise_exceptions, reason="RecursionError isn't defined in Python <3.5"
|
||||
)
|
||||
def test_recursion_error_reraised(self):
|
||||
conn = Urllib3HttpConnection()
|
||||
|
||||
def urlopen_raise(*_, **__):
|
||||
raise RecursionError("Wasn't modified!")
|
||||
|
||||
conn.pool.urlopen = urlopen_raise
|
||||
|
||||
with pytest.raises(RecursionError) as e:
|
||||
conn.perform_request("GET", "/")
|
||||
assert str(e.value) == "Wasn't modified!"
|
||||
|
||||
|
||||
class TestSignerWithFrozenCredentials(TestUrllib3HttpConnection):
|
||||
def mock_session(self):
|
||||
access_key = uuid.uuid4().hex
|
||||
secret_key = uuid.uuid4().hex
|
||||
token = uuid.uuid4().hex
|
||||
dummy_session = Mock()
|
||||
dummy_session.access_key = access_key
|
||||
dummy_session.secret_key = secret_key
|
||||
dummy_session.token = token
|
||||
dummy_session.get_frozen_credentials = Mock(return_value=dummy_session)
|
||||
|
||||
return dummy_session
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 6), reason="Urllib3AWSV4SignerAuth requires python3.6+"
|
||||
)
|
||||
def test_urllib3_http_connection_aws_signer_frozen_credentials_as_http_auth(self):
|
||||
region = "us-west-2"
|
||||
|
||||
from opensearchpy.helpers.signer import Urllib3AWSV4SignerAuth
|
||||
|
||||
mock_session = self.mock_session()
|
||||
|
||||
auth = Urllib3AWSV4SignerAuth(mock_session, region)
|
||||
headers = auth("GET", "http://localhost", None)
|
||||
self.assertIn("Authorization", headers)
|
||||
self.assertIn("X-Amz-Date", headers)
|
||||
self.assertIn("X-Amz-Security-Token", headers)
|
||||
self.assertIn("X-Amz-Content-SHA256", headers)
|
||||
mock_session.get_frozen_credentials.assert_called_once()
|
||||
Reference in New Issue
Block a user