Allows using different ways to retrieve hosts IP address
This commit is contained in:
parent
97cf1a8f5c
commit
84558826fb
15 changed files with 861 additions and 710 deletions
|
|
@ -3,14 +3,14 @@ when:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: python tests
|
- name: python tests
|
||||||
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
image: ghcr.io/astral-sh/uv:python3.11-alpine
|
||||||
commands:
|
commands:
|
||||||
- uv sync --group ci
|
- uv sync --group ci
|
||||||
- uv run -- coverage run --module unittest
|
- uv run -- coverage run --module unittest
|
||||||
- uv run -- coverage report
|
- uv run -- coverage report
|
||||||
|
|
||||||
- name: code formatting & linting
|
- name: code formatting & linting
|
||||||
image: ghcr.io/astral-sh/uv:python3.11-bookworm
|
image: ghcr.io/astral-sh/uv:python3.11-alpine
|
||||||
commands:
|
commands:
|
||||||
- uv sync
|
- uv sync
|
||||||
- uv run -- ruff format --diff
|
- uv run -- ruff format --diff
|
||||||
|
|
|
||||||
16
Dockerfile
16
Dockerfile
|
|
@ -1,15 +1,24 @@
|
||||||
FROM python:3.11-alpine
|
FROM python:3.11-alpine
|
||||||
|
|
||||||
|
ARG LOGGING_CONFIG_SRC="./transip_client/logging/default.yml"
|
||||||
|
ARG LOGGING_CONFIG_DST="./transip_client/logging/config.yml"
|
||||||
ARG UV_ARGS=""
|
ARG UV_ARGS=""
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:python3.11-alpine /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:python3.11-alpine \
|
||||||
|
/usr/local/bin/uv \
|
||||||
|
/usr/local/bin/uvx \
|
||||||
|
/bin/
|
||||||
|
|
||||||
|
# provides the dig package for the DNSAdapter
|
||||||
|
RUN apk add --no-cache bind-tools
|
||||||
|
|
||||||
# copy from the cache instead of linking since mounted volumes are used
|
# copy from the cache instead of linking since mounted volumes are used
|
||||||
ENV UV_LINK_MODE=copy
|
ENV UV_LINK_MODE=copy
|
||||||
ENV UV_CACHE_DIR=/app/.cache/uv
|
ENV UV_CACHE_DIR=/app/.cache/uv
|
||||||
ENV PATH="/app/.venv/bin:$PATH"
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
|
ENV LOGGING_CONFIG=$LOGGING_CONFIG_DST
|
||||||
|
|
||||||
RUN useradd --uid 1000 transip_client
|
RUN adduser -DHu 1000 transip_client
|
||||||
|
|
||||||
USER transip_client
|
USER transip_client
|
||||||
|
|
||||||
|
|
@ -25,9 +34,10 @@ RUN --mount=type=cache,uid=1000,target=/app/.cache/uv \
|
||||||
|
|
||||||
COPY pyproject.toml uv.lock /app
|
COPY pyproject.toml uv.lock /app
|
||||||
COPY transip_client /app/transip_client
|
COPY transip_client /app/transip_client
|
||||||
|
COPY $LOGGING_CONFIG_SRC $LOGGING_CONFIG_DST
|
||||||
|
|
||||||
# install dependencies + project
|
# install dependencies + project
|
||||||
RUN --mount=type=cache,uid=1000,target=/app/.cache/uv \
|
RUN --mount=type=cache,uid=1000,target=/app/.cache/uv \
|
||||||
uv sync --frozen --no-dev $UV_ARGS
|
uv sync --frozen --no-dev $UV_ARGS
|
||||||
|
|
||||||
ENTRYPOINT ["transip-listen"]
|
ENTRYPOINT ["/bin/uv", "run", "--no-sync", "--", "transip-listen"]
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ dependencies = [
|
||||||
'python-dotenv>=0.15.0',
|
'python-dotenv>=0.15.0',
|
||||||
'requests>=2.25.1',
|
'requests>=2.25.1',
|
||||||
'cryptography>=3.4.7',
|
'cryptography>=3.4.7',
|
||||||
|
"ruamel-yaml>=0.18.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,32 @@
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
from logging.config import dictConfig
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
|
|
||||||
|
yml = YAML(typ="safe", pure=True)
|
||||||
env_path = Path("..") / ".env"
|
env_path = Path("..") / ".env"
|
||||||
|
|
||||||
load_dotenv(dotenv_path=env_path)
|
load_dotenv(dotenv_path=env_path)
|
||||||
|
|
||||||
|
default_config_path = Path(__file__).resolve().parent / "logging" / "default.yml"
|
||||||
|
logging_config_path = os.environ.get("LOGGING_CONFIG", default_config_path)
|
||||||
|
|
||||||
|
with open(logging_config_path, "r") as f:
|
||||||
|
logging_config = yml.load(f.read())
|
||||||
|
dictConfig(logging_config)
|
||||||
|
|
||||||
|
|
||||||
def get_current_version():
|
def get_current_version():
|
||||||
if "VERSION" in os.environ:
|
if "VERSION" in os.environ:
|
||||||
return os.environ["VERSION"]
|
return os.environ["VERSION"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output(["git", "describe", "--tags"], text=True)
|
||||||
["git", "describe", "--tags"], universal_newlines=True
|
|
||||||
)
|
|
||||||
return output.strip()
|
return output.strip()
|
||||||
except (subprocess.CalledProcessError, OSError):
|
except (subprocess.CalledProcessError, OSError):
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -32,6 +40,7 @@ try:
|
||||||
|
|
||||||
sentry_init(
|
sentry_init(
|
||||||
dsn=os.environ.get("SENTRY_DSN"),
|
dsn=os.environ.get("SENTRY_DSN"),
|
||||||
|
environment=os.environ.get("ENVIRONMENT", "production"),
|
||||||
send_default_pii=False,
|
send_default_pii=False,
|
||||||
release=VERSION,
|
release=VERSION,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
86
transip_client/adapters.py
Normal file
86
transip_client/adapters.py
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Adapter:
|
||||||
|
def get_ip(self) -> str:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPAdapter(Adapter):
|
||||||
|
service: str
|
||||||
|
|
||||||
|
def handle_response(self, response: requests.Response) -> str:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_params(self) -> dict:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_ip(self) -> str:
|
||||||
|
try:
|
||||||
|
response = requests.get(self.service, params=self.get_params(), timeout=5)
|
||||||
|
response.raise_for_status()
|
||||||
|
except requests.RequestException as e:
|
||||||
|
raise OSError(f"Unable to retrieve current IP from {self.service}") from e
|
||||||
|
|
||||||
|
ip = self.handle_response(response)
|
||||||
|
|
||||||
|
if not ip:
|
||||||
|
raise OSError(f"Unable to determine IP from response from {self.service}")
|
||||||
|
|
||||||
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
class IpifyAdapter(HTTPAdapter):
|
||||||
|
service: str = "https://api.ipify.org"
|
||||||
|
|
||||||
|
def get_params(self) -> dict:
|
||||||
|
return {"format": "text"}
|
||||||
|
|
||||||
|
def handle_response(self, response: requests.Response) -> str:
|
||||||
|
return response.text
|
||||||
|
|
||||||
|
|
||||||
|
class DNSAdapter(Adapter):
|
||||||
|
resolvers: list[str]
|
||||||
|
dns: str
|
||||||
|
|
||||||
|
def try_resolver(self, resolver: str) -> str:
|
||||||
|
output = subprocess.check_output(
|
||||||
|
["dig", "+short", self.dns, resolver], stderr=subprocess.STDOUT, text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return output.strip()
|
||||||
|
|
||||||
|
def get_ip(self) -> str:
|
||||||
|
for resolver in self.resolvers:
|
||||||
|
try:
|
||||||
|
ip = self.try_resolver(resolver)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
if e.returncode == 9:
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise OSError("Unable to retrieve current IP") from e
|
||||||
|
|
||||||
|
if not ip:
|
||||||
|
logger.warning(f"No IP returned from {resolver}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
return ip
|
||||||
|
|
||||||
|
raise OSError("Exhausted all known IP resolvers, unable to retrieve IP")
|
||||||
|
|
||||||
|
|
||||||
|
class OpenDNSAdapter(DNSAdapter):
|
||||||
|
dns = "myip.opendns.com"
|
||||||
|
resolvers = [
|
||||||
|
"@resolver1.opendns.com",
|
||||||
|
"@resolver2.opendns.com",
|
||||||
|
"@resolver3.opendns.com",
|
||||||
|
"@resolver4.opendns.com",
|
||||||
|
]
|
||||||
|
|
@ -1,54 +1,40 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from transip_client.main import detect
|
from transip_client.main import detect
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_SERVICE = "https://api.ipify.org"
|
|
||||||
DEFAULT_API_URL = "https://api.transip.nl/v6"
|
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.argument("domains", envvar="DOMAINS", nargs=-1)
|
@click.argument("login")
|
||||||
@click.option("--token", envvar="TOKEN")
|
@click.argument("private-key-path")
|
||||||
@click.option("--login", envvar="LOGIN")
|
@click.argument("domains", nargs=-1)
|
||||||
@click.option("--private-key-path", envvar="PRIVATE_KEY_PATH")
|
@click.option(
|
||||||
@click.option("--service", envvar="SERVICE", default=DEFAULT_SERVICE)
|
"--adapter-class",
|
||||||
@click.option("--api-url", envvar="API_URL", default=DEFAULT_API_URL)
|
default="transip_client.adapters.OpenDNSAdapter",
|
||||||
@click.option("--read-only/--write", envvar="READ_ONLY", default=False)
|
)
|
||||||
|
@click.option("--read-only/--write", default=False)
|
||||||
def run(
|
def run(
|
||||||
domains: list[str],
|
domains: list[str],
|
||||||
token: str,
|
|
||||||
login: str,
|
login: str,
|
||||||
private_key_path: str,
|
private_key_path: str,
|
||||||
service: str,
|
adapter_class: str,
|
||||||
api_url: str,
|
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
if not domains:
|
if not domains:
|
||||||
raise ValueError("No domain(s) specified")
|
raise ValueError("No domain(s) specified")
|
||||||
|
|
||||||
token_retrieval = any(
|
if not Path(private_key_path).exists():
|
||||||
(
|
raise ValueError(f"Unknown private key path: {private_key_path}")
|
||||||
login,
|
|
||||||
private_key_path,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if token_retrieval and not all((login, private_key_path)):
|
if not all((login, private_key_path)):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Both a login name and the path to a private key need to be specified"
|
"Both a login name and the path to a private key need to be specified"
|
||||||
)
|
)
|
||||||
elif not token_retrieval and not token:
|
|
||||||
raise ValueError(
|
|
||||||
"Either a token or a login name with a path to a private key need"
|
|
||||||
" to be specified"
|
|
||||||
)
|
|
||||||
|
|
||||||
detect(
|
detect(
|
||||||
domains,
|
domains,
|
||||||
service,
|
|
||||||
(private_key_path, login),
|
(private_key_path, login),
|
||||||
token,
|
adapter_class,
|
||||||
api_url,
|
|
||||||
read_only,
|
read_only,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
14
transip_client/logging/default.yml
Normal file
14
transip_client/logging/default.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
version: 1
|
||||||
|
formatters:
|
||||||
|
simple:
|
||||||
|
format: '%(asctime)s %(levelname)s %(name)s %(message)s'
|
||||||
|
datefmt: '%Y-%m-%d %H:%M:%S'
|
||||||
|
handlers:
|
||||||
|
console:
|
||||||
|
level: DEBUG
|
||||||
|
formatter: simple
|
||||||
|
class: logging.StreamHandler
|
||||||
|
loggers:
|
||||||
|
transip_client:
|
||||||
|
handlers: [console]
|
||||||
|
level: INFO
|
||||||
14
transip_client/logging/development.yml
Normal file
14
transip_client/logging/development.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
version: 1
|
||||||
|
formatters:
|
||||||
|
simple:
|
||||||
|
format: '%(asctime)s %(levelname)s %(name)s %(message)s'
|
||||||
|
datefmt: '%Y-%m-%d %H:%M:%S'
|
||||||
|
handlers:
|
||||||
|
console:
|
||||||
|
level: DEBUG
|
||||||
|
formatter: simple
|
||||||
|
class: logging.StreamHandler
|
||||||
|
loggers:
|
||||||
|
transip_client:
|
||||||
|
handlers: [console]
|
||||||
|
level: DEBUG
|
||||||
21
transip_client/logging/file.yml
Normal file
21
transip_client/logging/file.yml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
version: 1
|
||||||
|
formatters:
|
||||||
|
simple:
|
||||||
|
format: '%(asctime)s %(levelname)s %(name)s %(message)s'
|
||||||
|
datefmt: '%Y-%m-%d %H:%M:%S'
|
||||||
|
handlers:
|
||||||
|
console:
|
||||||
|
level: DEBUG
|
||||||
|
formatter: simple
|
||||||
|
class: logging.StreamHandler
|
||||||
|
file:
|
||||||
|
level: INFO
|
||||||
|
formatter: simple
|
||||||
|
class: logging.handlers.RotatingFileHandler
|
||||||
|
filename: /app/transip_client/logging/logs/app.log
|
||||||
|
backupCount: 5
|
||||||
|
maxBytes: 50000000 # 50 mB
|
||||||
|
loggers:
|
||||||
|
transip_client:
|
||||||
|
handlers: [console, file]
|
||||||
|
level: INFO
|
||||||
|
|
@ -13,20 +13,15 @@ from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
||||||
from cryptography.hazmat.primitives.hashes import SHA512
|
from cryptography.hazmat.primitives.hashes import SHA512
|
||||||
|
|
||||||
|
from transip_client.utils import import_string
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
API_URL = "https://api.transip.nl/v6"
|
||||||
def _get_ip(service: str) -> str:
|
|
||||||
try:
|
|
||||||
response = requests.get(service, timeout=10)
|
|
||||||
response.raise_for_status()
|
|
||||||
except requests.RequestException as e:
|
|
||||||
raise OSError(f"Unable to retrieve current IP from {service}") from e
|
|
||||||
|
|
||||||
return response.text
|
|
||||||
|
|
||||||
|
|
||||||
|
# Note that tokens cannot be recreated when an existing token is present
|
||||||
def _get_token(private_key_path: str, login: str, api_url: str) -> str:
|
def _get_token(private_key_path: str, login: str, api_url: str) -> str:
|
||||||
request = requests.Request(
|
request = requests.Request(
|
||||||
"POST",
|
"POST",
|
||||||
|
|
@ -36,7 +31,7 @@ def _get_token(private_key_path: str, login: str, api_url: str) -> str:
|
||||||
"nonce": str(int(time.time() * 1000)),
|
"nonce": str(int(time.time() * 1000)),
|
||||||
"read_only": False,
|
"read_only": False,
|
||||||
"expiration_time": "30 minutes",
|
"expiration_time": "30 minutes",
|
||||||
"label": "Custom token",
|
"label": "Trans IP client",
|
||||||
"global_key": True,
|
"global_key": True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -53,6 +48,8 @@ def _get_token(private_key_path: str, login: str, api_url: str) -> str:
|
||||||
|
|
||||||
prepped_request.headers["Signature"] = signature.decode("ascii")
|
prepped_request.headers["Signature"] = signature.decode("ascii")
|
||||||
|
|
||||||
|
logger.info(f"Retrieving token from {api_url} for {login}")
|
||||||
|
|
||||||
with requests.Session() as session:
|
with requests.Session() as session:
|
||||||
response = session.send(prepped_request)
|
response = session.send(prepped_request)
|
||||||
|
|
||||||
|
|
@ -65,6 +62,8 @@ def _get_token(private_key_path: str, login: str, api_url: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def _get_domain(domain: str, token: str, api_url: str) -> requests.Response:
|
def _get_domain(domain: str, token: str, api_url: str) -> requests.Response:
|
||||||
|
logger.info(f"Retrieving domain information for {domain} from {api_url}")
|
||||||
|
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
return requests.get(f"{api_url}/domains/{domain}/dns", headers=headers)
|
return requests.get(f"{api_url}/domains/{domain}/dns", headers=headers)
|
||||||
|
|
||||||
|
|
@ -94,8 +93,9 @@ def _get_domain_data(
|
||||||
def _update_domain(
|
def _update_domain(
|
||||||
domain: str, payload: dict, api_url: str, token: str
|
domain: str, payload: dict, api_url: str, token: str
|
||||||
) -> requests.Response:
|
) -> requests.Response:
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
logger.info(f"Updating domain {domain} at {api_url}")
|
||||||
|
|
||||||
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
return requests.put(
|
return requests.put(
|
||||||
f"{api_url}/domains/{domain}/dns", data=json.dumps(payload), headers=headers
|
f"{api_url}/domains/{domain}/dns", data=json.dumps(payload), headers=headers
|
||||||
)
|
)
|
||||||
|
|
@ -123,23 +123,22 @@ def _update_domains(
|
||||||
logger.exception(f"Unable to update domain {domain}")
|
logger.exception(f"Unable to update domain {domain}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info(f"Updated domain {domain}")
|
logger.info(f"Updated domain {domain} at {api_url}")
|
||||||
|
|
||||||
|
|
||||||
def detect(
|
def detect(
|
||||||
domains: list[str],
|
domains: list[str],
|
||||||
service: str,
|
|
||||||
credentials: tuple[str, str],
|
credentials: tuple[str, str],
|
||||||
token: str,
|
adapter_class: str,
|
||||||
api_url: str,
|
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
ip = _get_ip(service)
|
_adapter_class = import_string(adapter_class)
|
||||||
|
adapter = _adapter_class()
|
||||||
|
ip = adapter.get_ip()
|
||||||
|
|
||||||
if all(credentials):
|
token = _get_token(*credentials, API_URL)
|
||||||
token = _get_token(*credentials, api_url)
|
|
||||||
|
|
||||||
domain_data = _get_domain_data(domains, token, api_url)
|
domain_data = _get_domain_data(domains, token, API_URL)
|
||||||
updated_domains = {}
|
updated_domains = {}
|
||||||
|
|
||||||
for data in domain_data:
|
for data in domain_data:
|
||||||
|
|
@ -156,8 +155,9 @@ def detect(
|
||||||
)
|
)
|
||||||
|
|
||||||
if dns_entries == updated_entries:
|
if dns_entries == updated_entries:
|
||||||
|
logger.info(f"No changes detected for {domain}, skipping...")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
updated_domains[domain] = {"dnsEntries": updated_entries}
|
updated_domains[domain] = {"dnsEntries": updated_entries}
|
||||||
|
|
||||||
_update_domains(updated_domains, api_url, token, read_only)
|
_update_domains(updated_domains, API_URL, token, read_only)
|
||||||
|
|
|
||||||
129
transip_client/tests/test_adapters.py
Normal file
129
transip_client/tests/test_adapters.py
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
from unittest import TestCase
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from requests.exceptions import Timeout
|
||||||
|
from requests.models import HTTPError
|
||||||
|
|
||||||
|
from transip_client.adapters import IpifyAdapter, OpenDNSAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class IpifyAdapterTestCase(TestCase):
|
||||||
|
adapter_class = IpifyAdapter
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
patcher = patch("transip_client.adapters.requests.get")
|
||||||
|
|
||||||
|
self.mocked_requests_get = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
self.mocked_requests_get.return_value = MagicMock(text="8.8.8.8")
|
||||||
|
|
||||||
|
adapter = self.adapter_class()
|
||||||
|
|
||||||
|
self.assertEqual(adapter.get_ip(), "8.8.8.8")
|
||||||
|
|
||||||
|
def test_service_unavailable(self):
|
||||||
|
self.mocked_requests_get.side_effect = Timeout
|
||||||
|
|
||||||
|
adapter = self.adapter_class()
|
||||||
|
|
||||||
|
with self.assertRaises(OSError) as exception_manager:
|
||||||
|
adapter.get_ip()
|
||||||
|
|
||||||
|
exception = exception_manager.exception
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(exception), f"Unable to retrieve current IP from {adapter.service}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_error_response(self):
|
||||||
|
request_mock = MagicMock()
|
||||||
|
request_mock.raise_for_status.side_effect = HTTPError
|
||||||
|
self.mocked_requests_get.return_value = request_mock
|
||||||
|
|
||||||
|
adapter = self.adapter_class()
|
||||||
|
|
||||||
|
with self.assertRaises(OSError) as exception_manager:
|
||||||
|
adapter.get_ip()
|
||||||
|
|
||||||
|
exception = exception_manager.exception
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(exception), f"Unable to retrieve current IP from {adapter.service}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_no_text_content(self):
|
||||||
|
self.mocked_requests_get.return_value = MagicMock(text="")
|
||||||
|
|
||||||
|
adapter = self.adapter_class()
|
||||||
|
|
||||||
|
with self.assertRaises(OSError) as exception_manager:
|
||||||
|
adapter.get_ip()
|
||||||
|
|
||||||
|
exception = exception_manager.exception
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(exception),
|
||||||
|
f"Unable to determine IP from response from {adapter.service}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OpenDNSAdapterTestCase(TestCase):
|
||||||
|
def setUp(self) -> None:
|
||||||
|
patcher = patch("transip_client.adapters.subprocess.check_output")
|
||||||
|
|
||||||
|
self.mocked_check_output = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
self.mocked_check_output.return_value = "8.8.8.8\n"
|
||||||
|
|
||||||
|
adapter = OpenDNSAdapter()
|
||||||
|
|
||||||
|
self.assertEqual(adapter.get_ip(), "8.8.8.8")
|
||||||
|
|
||||||
|
def test_retry_next_resolvers(self):
|
||||||
|
self.mocked_check_output.side_effect = (
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver1.opendns.com"),
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver2.opendns.com"),
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver3.opendns.com"),
|
||||||
|
"9.9.9.9\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
adapter = OpenDNSAdapter()
|
||||||
|
|
||||||
|
self.assertEqual(adapter.get_ip(), "9.9.9.9")
|
||||||
|
|
||||||
|
def test_resolvers_exhausted(self):
|
||||||
|
self.mocked_check_output.side_effect = (
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver1.opendns.com"),
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver2.opendns.com"),
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver3.opendns.com"),
|
||||||
|
CalledProcessError(9, "dig +short myip.opendns.com @resolver4.opendns.com"),
|
||||||
|
)
|
||||||
|
|
||||||
|
adapter = OpenDNSAdapter()
|
||||||
|
|
||||||
|
with self.assertRaises(OSError) as exception_manager:
|
||||||
|
adapter.get_ip()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(exception_manager.exception),
|
||||||
|
"Exhausted all known IP resolvers, unable to retrieve IP",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_command_error(self):
|
||||||
|
self.mocked_check_output.side_effect = (
|
||||||
|
CalledProcessError(1, "dig +short myip.opendns.com @resolver1.opendns.com"),
|
||||||
|
)
|
||||||
|
|
||||||
|
adapter = OpenDNSAdapter()
|
||||||
|
|
||||||
|
with self.assertRaises(OSError) as exception_manager:
|
||||||
|
adapter.get_ip()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
str(exception_manager.exception), "Unable to retrieve current IP"
|
||||||
|
)
|
||||||
359
transip_client/tests/test_cli.py
Normal file
359
transip_client/tests/test_cli.py
Normal file
|
|
@ -0,0 +1,359 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest import TestCase
|
||||||
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
|
from click.testing import CliRunner
|
||||||
|
from requests import HTTPError
|
||||||
|
|
||||||
|
from transip_client.cli import run
|
||||||
|
from transip_client.main import API_URL
|
||||||
|
|
||||||
|
|
||||||
|
class RunTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
patcher = patch("transip_client.main.requests.get")
|
||||||
|
self.mocked_get = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
patcher = patch("transip_client.main.requests.put")
|
||||||
|
self.mocked_put = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
patcher = patch("transip_client.main.requests.Session.send")
|
||||||
|
self.mocked_session = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
patcher = patch("transip_client.main.import_string")
|
||||||
|
self.mocked_import_string = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
self.runner = CliRunner()
|
||||||
|
|
||||||
|
self.private_key_path = (
|
||||||
|
Path(__file__).resolve().parent / "files" / "test-private-key.pem"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
mocked_adapter = MagicMock(get_ip=lambda: "111.420")
|
||||||
|
self.mocked_import_string.return_value = MagicMock(return_value=mocked_adapter)
|
||||||
|
|
||||||
|
self.mocked_get.side_effect = [
|
||||||
|
MagicMock(
|
||||||
|
json=lambda: {
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.421",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "domain",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.mocked_session.return_value.json.return_value = {"token": "token"}
|
||||||
|
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str(self.private_key_path), "foobar.com"],
|
||||||
|
catch_exceptions=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 0)
|
||||||
|
|
||||||
|
self.mocked_get.assert_called_with(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_json = json.dumps(
|
||||||
|
{
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.420",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mocked_put.assert_called_with(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
data=expected_json,
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_error_response(self):
|
||||||
|
mocked_adapter = MagicMock(get_ip=lambda: "111.420")
|
||||||
|
self.mocked_import_string.return_value = MagicMock(return_value=mocked_adapter)
|
||||||
|
|
||||||
|
self.mocked_session.return_value.json.return_value = {"token": "token"}
|
||||||
|
self.mocked_get.side_effect = [HTTPError]
|
||||||
|
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str(self.private_key_path), "foobar.com"],
|
||||||
|
catch_exceptions=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 0)
|
||||||
|
|
||||||
|
self.mocked_get.assert_called_with(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mocked_put.assert_not_called()
|
||||||
|
|
||||||
|
def test_update_error_response(self):
|
||||||
|
mocked_adapter = MagicMock(get_ip=lambda: "111.420")
|
||||||
|
self.mocked_import_string.return_value = MagicMock(return_value=mocked_adapter)
|
||||||
|
|
||||||
|
self.mocked_session.return_value.json.return_value = {"token": "token"}
|
||||||
|
|
||||||
|
self.mocked_get.side_effect = [
|
||||||
|
MagicMock(
|
||||||
|
json=lambda: {
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.421",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "domain",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
MagicMock(
|
||||||
|
json=lambda: {
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.421",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/boofar.com/dns",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "domain",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/boofar.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
def raise_exception() -> None:
|
||||||
|
raise HTTPError
|
||||||
|
|
||||||
|
self.mocked_put.side_effect = (
|
||||||
|
MagicMock(raise_for_status=raise_exception),
|
||||||
|
MagicMock(status=200),
|
||||||
|
)
|
||||||
|
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str(self.private_key_path), "foobar.com", "boofar.com"],
|
||||||
|
catch_exceptions=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 0)
|
||||||
|
|
||||||
|
self.mocked_get.assert_has_calls(
|
||||||
|
(
|
||||||
|
call(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
f"{API_URL}/domains/boofar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertCountEqual(
|
||||||
|
self.mocked_put.mock_calls,
|
||||||
|
(
|
||||||
|
call(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
data=json.dumps(
|
||||||
|
{
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.420",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
f"{API_URL}/domains/boofar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
data=json.dumps(
|
||||||
|
{
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.420",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_matching_ip(self):
|
||||||
|
mocked_adapter = MagicMock(get_ip=lambda: "111.420")
|
||||||
|
self.mocked_import_string.return_value = MagicMock(return_value=mocked_adapter)
|
||||||
|
|
||||||
|
self.mocked_get.side_effect = [
|
||||||
|
MagicMock(
|
||||||
|
json=lambda: {
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.420",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "domain",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.mocked_session.return_value.json.return_value = {"token": "token"}
|
||||||
|
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str(self.private_key_path), "foobar.com"],
|
||||||
|
catch_exceptions=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 0)
|
||||||
|
|
||||||
|
self.mocked_get.assert_called_with(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mocked_put.assert_not_called()
|
||||||
|
|
||||||
|
def test_readonly(self):
|
||||||
|
mocked_adapter = MagicMock(get_ip=lambda: "111.420")
|
||||||
|
self.mocked_import_string.return_value = MagicMock(return_value=mocked_adapter)
|
||||||
|
|
||||||
|
self.mocked_get.side_effect = [
|
||||||
|
MagicMock(
|
||||||
|
json=lambda: {
|
||||||
|
"dnsEntries": [
|
||||||
|
{
|
||||||
|
"name": "@",
|
||||||
|
"expire": 60,
|
||||||
|
"type": "A",
|
||||||
|
"content": "111.421",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "domain",
|
||||||
|
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.mocked_session.return_value.json.return_value = {"token": "token"}
|
||||||
|
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str(self.private_key_path), "foobar.com", "--read-only"],
|
||||||
|
catch_exceptions=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 0)
|
||||||
|
|
||||||
|
self.mocked_get.assert_called_with(
|
||||||
|
f"{API_URL}/domains/foobar.com/dns",
|
||||||
|
headers={"Authorization": "Bearer token"},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mocked_put.assert_not_called()
|
||||||
|
|
||||||
|
def test_no_domains(self):
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str(self.private_key_path)],
|
||||||
|
catch_exceptions=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 1)
|
||||||
|
self.assertEqual(str(result.exception), "No domain(s) specified")
|
||||||
|
|
||||||
|
self.mocked_get.assert_not_called()
|
||||||
|
self.mocked_put.assert_not_called()
|
||||||
|
|
||||||
|
def test_unknown_private_key_path(self):
|
||||||
|
result = self.runner.invoke(
|
||||||
|
run,
|
||||||
|
["my-user", str("/tmp/foo"), "foobar.com"],
|
||||||
|
catch_exceptions=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(result.exit_code, 1)
|
||||||
|
self.assertEqual(str(result.exception), "Unknown private key path: /tmp/foo")
|
||||||
|
|
||||||
|
self.mocked_get.assert_not_called()
|
||||||
|
self.mocked_put.assert_not_called()
|
||||||
|
|
@ -1,528 +0,0 @@
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import Mock, call, patch
|
|
||||||
|
|
||||||
from click.testing import CliRunner
|
|
||||||
from requests import HTTPError
|
|
||||||
|
|
||||||
from transip_client.cli import DEFAULT_API_URL, DEFAULT_SERVICE, run
|
|
||||||
|
|
||||||
|
|
||||||
class RunTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
patcher = patch("transip_client.main.requests.get")
|
|
||||||
self.mocked_get = patcher.start()
|
|
||||||
|
|
||||||
patcher = patch("transip_client.main.requests.put")
|
|
||||||
self.mocked_put = patcher.start()
|
|
||||||
|
|
||||||
patcher = patch("transip_client.main.requests.Session.send")
|
|
||||||
self.mocked_session = patcher.start()
|
|
||||||
|
|
||||||
self.runner = CliRunner()
|
|
||||||
|
|
||||||
def test_simple(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
with self.assertLogs("transip_client.main", level="INFO") as logger:
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run, "foobar.com", env={"TOKEN": "token"}, catch_exceptions=False
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
logger.output, ["INFO:transip_client.main:Updated domain foobar.com"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
expected_json = json.dumps(
|
|
||||||
{
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.420",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
data=expected_json,
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_error_response(self):
|
|
||||||
self.mocked_get.side_effect = [Mock(text="111.420"), HTTPError]
|
|
||||||
|
|
||||||
with self.assertLogs("transip_client.main", level="INFO") as logger:
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run, ["foobar.com"], env={"TOKEN": "token"}, catch_exceptions=False
|
|
||||||
)
|
|
||||||
|
|
||||||
error_log = logger.output[0]
|
|
||||||
|
|
||||||
self.assertIn("Failed retrieving information for foobar.com", error_log)
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_not_called()
|
|
||||||
|
|
||||||
def test_matching_ip(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.420",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
result = self.runner.invoke(run, ["foobar.com"], env={"TOKEN": "token"})
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_not_called()
|
|
||||||
|
|
||||||
def test_readonly(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run, ["foobar.com", "--read-only"], env={"TOKEN": "token"}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_not_called()
|
|
||||||
|
|
||||||
def test_different_api_url(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
with self.assertLogs("transip_client.main", level="INFO") as logger:
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run,
|
|
||||||
["foobar.com", "--api-url", "https://other-provider.com"],
|
|
||||||
env={"TOKEN": "token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
logger.output, ["INFO:transip_client.main:Updated domain foobar.com"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
"https://other-provider.com/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
expected_json = json.dumps(
|
|
||||||
{
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.420",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_called_with(
|
|
||||||
"https://other-provider.com/domains/foobar.com/dns",
|
|
||||||
data=expected_json,
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_env_var(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
with self.assertLogs("transip_client.main", level="INFO") as logger:
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run,
|
|
||||||
["foobar.com"],
|
|
||||||
env={
|
|
||||||
"TOKEN": "token",
|
|
||||||
"API_URL": "https://new-api.com",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
logger.output, ["INFO:transip_client.main:Updated domain foobar.com"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
"https://new-api.com/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
expected_json = json.dumps(
|
|
||||||
{
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.420",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_called_with(
|
|
||||||
"https://new-api.com/domains/foobar.com/dns",
|
|
||||||
data=expected_json,
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_multi_arg_env_var(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foofoo.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foofoo.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
with self.assertLogs("transip_client.main", level="INFO") as logger:
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run, [], env={"TOKEN": "token", "DOMAINS": "foobar.com foofoo.com"}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertIsNone(result.exception)
|
|
||||||
self.assertEqual(
|
|
||||||
logger.output,
|
|
||||||
[
|
|
||||||
"INFO:transip_client.main:Updated domain foobar.com",
|
|
||||||
"INFO:transip_client.main:Updated domain foofoo.com",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
expected_calls = [
|
|
||||||
call(DEFAULT_SERVICE, timeout=10),
|
|
||||||
call(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foofoo.com/dns",
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
# use any_order because of the asynchronous requests
|
|
||||||
self.mocked_get.assert_has_calls(expected_calls, any_order=True)
|
|
||||||
|
|
||||||
expected_json = json.dumps(
|
|
||||||
{
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.420",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
expected_calls = [
|
|
||||||
call(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
data=expected_json,
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
),
|
|
||||||
call(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foofoo.com/dns",
|
|
||||||
data=expected_json,
|
|
||||||
headers={"Authorization": "Bearer token"},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.mocked_put.assert_has_calls(expected_calls, any_order=True)
|
|
||||||
|
|
||||||
def test_no_domains(self):
|
|
||||||
result = self.runner.invoke(run, [], env={"TOKEN": "token"})
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 1)
|
|
||||||
self.assertEqual(str(result.exception), "No domain(s) specified")
|
|
||||||
|
|
||||||
self.mocked_get.assert_not_called()
|
|
||||||
self.mocked_put.assert_not_called()
|
|
||||||
|
|
||||||
def test_no_token_or_login_with_private_key_path(self):
|
|
||||||
result = self.runner.invoke(run, ["foobar.com"])
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 1)
|
|
||||||
self.assertEqual(
|
|
||||||
str(result.exception),
|
|
||||||
"Either a token or a login name with a path to a private key need"
|
|
||||||
" to be specified",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_get.assert_not_called()
|
|
||||||
self.mocked_put.assert_not_called()
|
|
||||||
|
|
||||||
def test_login_without_private_key_path(self):
|
|
||||||
result = self.runner.invoke(run, ["foobar.com"], env={"LOGIN": "foo"})
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 1)
|
|
||||||
self.assertEqual(
|
|
||||||
str(result.exception),
|
|
||||||
"Both a login name and the path to a private key need to be specified",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_get.assert_not_called()
|
|
||||||
self.mocked_put.assert_not_called()
|
|
||||||
|
|
||||||
def test_login_with_private_key_path(self):
|
|
||||||
self.mocked_get.side_effect = [
|
|
||||||
Mock(text="111.420"),
|
|
||||||
Mock(
|
|
||||||
json=lambda: {
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.421",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com/dns",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel": "domain",
|
|
||||||
"link": "https://api.transip.nl/v6/domains/foobar.com",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.mocked_session.return_value.json.return_value = {"token": "FOOBAR"}
|
|
||||||
|
|
||||||
private_key_path = (
|
|
||||||
Path(os.path.dirname(__file__)) / "files" / "test-private-key.pem"
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertLogs("transip_client.main", level="INFO") as logger:
|
|
||||||
result = self.runner.invoke(
|
|
||||||
run,
|
|
||||||
["foobar.com"],
|
|
||||||
env={"LOGIN": "foo", "PRIVATE_KEY_PATH": str(private_key_path)},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
logger.output, ["INFO:transip_client.main:Updated domain foobar.com"]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result.exit_code, 0)
|
|
||||||
|
|
||||||
self.mocked_get.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
headers={"Authorization": "Bearer FOOBAR"},
|
|
||||||
)
|
|
||||||
|
|
||||||
expected_json = json.dumps(
|
|
||||||
{
|
|
||||||
"dnsEntries": [
|
|
||||||
{
|
|
||||||
"name": "@",
|
|
||||||
"expire": 60,
|
|
||||||
"type": "A",
|
|
||||||
"content": "111.420",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mocked_put.assert_called_with(
|
|
||||||
f"{DEFAULT_API_URL}/domains/foobar.com/dns",
|
|
||||||
data=expected_json,
|
|
||||||
headers={"Authorization": "Bearer FOOBAR"},
|
|
||||||
)
|
|
||||||
10
transip_client/utils.py
Normal file
10
transip_client/utils.py
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
from importlib import import_module
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
|
from transip_client.adapters import Adapter
|
||||||
|
|
||||||
|
|
||||||
|
def import_string(path: str) -> Type[Adapter]:
|
||||||
|
module_path, class_name = path.rsplit(".", 1)
|
||||||
|
module = import_module(module_path)
|
||||||
|
return getattr(module, class_name)
|
||||||
290
uv.lock
generated
290
uv.lock
generated
|
|
@ -1,5 +1,5 @@
|
||||||
version = 1
|
version = 1
|
||||||
revision = 1
|
revision = 2
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"sys_platform == 'linux'",
|
"sys_platform == 'linux'",
|
||||||
|
|
@ -12,9 +12,9 @@ supported-markers = [
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2024.12.14"
|
version = "2024.12.14"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 }
|
sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010, upload_time = "2024-12-14T13:52:38.02Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 },
|
{ url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927, upload_time = "2024-12-14T13:52:36.114Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -24,110 +24,110 @@ source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pycparser", marker = "sys_platform == 'linux'" },
|
{ name = "pycparser", marker = "sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 }
|
sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload_time = "2024-09-04T20:45:21.852Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 },
|
{ url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload_time = "2024-09-04T20:43:56.123Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 },
|
{ url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload_time = "2024-09-04T20:43:57.891Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 },
|
{ url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload_time = "2024-09-04T20:44:00.18Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 },
|
{ url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload_time = "2024-09-04T20:44:01.585Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 },
|
{ url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload_time = "2024-09-04T20:44:03.467Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 },
|
{ url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload_time = "2024-09-04T20:44:05.023Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 },
|
{ url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload_time = "2024-09-04T20:44:06.444Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 },
|
{ url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload_time = "2024-09-04T20:44:08.206Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 },
|
{ url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload_time = "2024-09-04T20:44:15.231Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 },
|
{ url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload_time = "2024-09-04T20:44:17.188Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 },
|
{ url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload_time = "2024-09-04T20:44:18.688Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 },
|
{ url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload_time = "2024-09-04T20:44:20.248Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 },
|
{ url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload_time = "2024-09-04T20:44:21.673Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 },
|
{ url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload_time = "2024-09-04T20:44:23.245Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 },
|
{ url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload_time = "2024-09-04T20:44:24.757Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 },
|
{ url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload_time = "2024-09-04T20:44:32.01Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 },
|
{ url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload_time = "2024-09-04T20:44:33.606Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 },
|
{ url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload_time = "2024-09-04T20:44:35.191Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 },
|
{ url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload_time = "2024-09-04T20:44:36.743Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 },
|
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload_time = "2024-09-04T20:44:38.492Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 },
|
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload_time = "2024-09-04T20:44:40.046Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 },
|
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload_time = "2024-09-04T20:44:41.616Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "charset-normalizer"
|
name = "charset-normalizer"
|
||||||
version = "3.4.1"
|
version = "3.4.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 }
|
sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188, upload_time = "2024-12-24T18:12:35.43Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 },
|
{ url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471, upload_time = "2024-12-24T18:10:14.101Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 },
|
{ url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831, upload_time = "2024-12-24T18:10:15.512Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 },
|
{ url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335, upload_time = "2024-12-24T18:10:18.369Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 },
|
{ url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862, upload_time = "2024-12-24T18:10:19.743Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 },
|
{ url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673, upload_time = "2024-12-24T18:10:21.139Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 },
|
{ url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211, upload_time = "2024-12-24T18:10:22.382Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 },
|
{ url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039, upload_time = "2024-12-24T18:10:24.802Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 },
|
{ url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939, upload_time = "2024-12-24T18:10:26.124Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 },
|
{ url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075, upload_time = "2024-12-24T18:10:30.027Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 },
|
{ url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340, upload_time = "2024-12-24T18:10:32.679Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 },
|
{ url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404, upload_time = "2024-12-24T18:10:44.272Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 },
|
{ url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423, upload_time = "2024-12-24T18:10:45.492Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 },
|
{ url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184, upload_time = "2024-12-24T18:10:47.898Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 },
|
{ url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268, upload_time = "2024-12-24T18:10:50.589Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 },
|
{ url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601, upload_time = "2024-12-24T18:10:52.541Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 },
|
{ url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098, upload_time = "2024-12-24T18:10:53.789Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 },
|
{ url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520, upload_time = "2024-12-24T18:10:55.048Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 },
|
{ url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852, upload_time = "2024-12-24T18:10:57.647Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 },
|
{ url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488, upload_time = "2024-12-24T18:10:59.43Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 },
|
{ url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192, upload_time = "2024-12-24T18:11:00.676Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 },
|
{ url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162, upload_time = "2024-12-24T18:11:07.064Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 },
|
{ url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263, upload_time = "2024-12-24T18:11:08.374Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 },
|
{ url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966, upload_time = "2024-12-24T18:11:09.831Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 },
|
{ url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992, upload_time = "2024-12-24T18:11:12.03Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 },
|
{ url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162, upload_time = "2024-12-24T18:11:13.372Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 },
|
{ url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972, upload_time = "2024-12-24T18:11:14.628Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 },
|
{ url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095, upload_time = "2024-12-24T18:11:17.672Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 },
|
{ url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668, upload_time = "2024-12-24T18:11:18.989Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 },
|
{ url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073, upload_time = "2024-12-24T18:11:21.507Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 },
|
{ url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732, upload_time = "2024-12-24T18:11:22.774Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 },
|
{ url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767, upload_time = "2024-12-24T18:12:32.852Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.8"
|
version = "8.1.8"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
|
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload_time = "2024-12-21T18:38:44.339Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
|
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload_time = "2024-12-21T18:38:41.666Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coverage"
|
name = "coverage"
|
||||||
version = "7.6.10"
|
version = "7.6.10"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 }
|
sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868, upload_time = "2024-12-26T16:59:18.734Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 },
|
{ url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474, upload_time = "2024-12-26T16:57:28.659Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 },
|
{ url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880, upload_time = "2024-12-26T16:57:30.095Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 },
|
{ url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750, upload_time = "2024-12-26T16:57:31.48Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 },
|
{ url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642, upload_time = "2024-12-26T16:57:34.09Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 },
|
{ url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266, upload_time = "2024-12-26T16:57:35.48Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 },
|
{ url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045, upload_time = "2024-12-26T16:57:36.952Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 },
|
{ url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537, upload_time = "2024-12-26T16:57:48.647Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 },
|
{ url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572, upload_time = "2024-12-26T16:57:51.668Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 },
|
{ url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639, upload_time = "2024-12-26T16:57:53.175Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 },
|
{ url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072, upload_time = "2024-12-26T16:57:56.087Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 },
|
{ url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386, upload_time = "2024-12-26T16:57:57.572Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 },
|
{ url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054, upload_time = "2024-12-26T16:57:58.967Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 },
|
{ url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083, upload_time = "2024-12-26T16:58:10.27Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 },
|
{ url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235, upload_time = "2024-12-26T16:58:12.497Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 },
|
{ url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220, upload_time = "2024-12-26T16:58:15.619Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 },
|
{ url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847, upload_time = "2024-12-26T16:58:17.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 },
|
{ url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922, upload_time = "2024-12-26T16:58:20.198Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 },
|
{ url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783, upload_time = "2024-12-26T16:58:23.614Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 },
|
{ url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039, upload_time = "2024-12-26T16:58:36.072Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 },
|
{ url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758, upload_time = "2024-12-26T16:58:39.458Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 },
|
{ url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119, upload_time = "2024-12-26T16:58:41.018Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 },
|
{ url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597, upload_time = "2024-12-26T16:58:42.827Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 },
|
{ url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473, upload_time = "2024-12-26T16:58:44.486Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 },
|
{ url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737, upload_time = "2024-12-26T16:58:45.919Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -137,49 +137,49 @@ source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cffi", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'linux'" },
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 }
|
sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657, upload_time = "2024-11-27T18:07:10.168Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710 },
|
{ url = "https://files.pythonhosted.org/packages/7e/5b/3759e30a103144e29632e7cb72aec28cedc79e514b2ea8896bb17163c19b/cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092", size = 3922710, upload_time = "2024-11-27T18:05:58.621Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546 },
|
{ url = "https://files.pythonhosted.org/packages/5f/58/3b14bf39f1a0cfd679e753e8647ada56cddbf5acebffe7db90e184c76168/cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f", size = 4137546, upload_time = "2024-11-27T18:06:01.062Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420 },
|
{ url = "https://files.pythonhosted.org/packages/98/65/13d9e76ca19b0ba5603d71ac8424b5694415b348e719db277b5edc985ff5/cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb", size = 3915420, upload_time = "2024-11-27T18:06:03.487Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498 },
|
{ url = "https://files.pythonhosted.org/packages/b1/07/40fe09ce96b91fc9276a9ad272832ead0fddedcba87f1190372af8e3039c/cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b", size = 4154498, upload_time = "2024-11-27T18:06:05.763Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569 },
|
{ url = "https://files.pythonhosted.org/packages/75/ea/af65619c800ec0a7e4034207aec543acdf248d9bffba0533342d1bd435e1/cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543", size = 3932569, upload_time = "2024-11-27T18:06:07.489Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721 },
|
{ url = "https://files.pythonhosted.org/packages/c7/af/d1deb0c04d59612e3d5e54203159e284d3e7a6921e565bb0eeb6269bdd8a/cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e", size = 4016721, upload_time = "2024-11-27T18:06:11.57Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915 },
|
{ url = "https://files.pythonhosted.org/packages/bd/69/7ca326c55698d0688db867795134bdfac87136b80ef373aaa42b225d6dd5/cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e", size = 4240915, upload_time = "2024-11-27T18:06:13.515Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613 },
|
{ url = "https://files.pythonhosted.org/packages/1a/07/5f165b6c65696ef75601b781a280fc3b33f1e0cd6aa5a92d9fb96c410e97/cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7", size = 3922613, upload_time = "2024-11-27T18:06:24.314Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925 },
|
{ url = "https://files.pythonhosted.org/packages/28/34/6b3ac1d80fc174812486561cf25194338151780f27e438526f9c64e16869/cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc", size = 4137925, upload_time = "2024-11-27T18:06:27.079Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417 },
|
{ url = "https://files.pythonhosted.org/packages/d0/c7/c656eb08fd22255d21bc3129625ed9cd5ee305f33752ef2278711b3fa98b/cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289", size = 3915417, upload_time = "2024-11-27T18:06:28.959Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160 },
|
{ url = "https://files.pythonhosted.org/packages/ef/82/72403624f197af0db6bac4e58153bc9ac0e6020e57234115db9596eee85d/cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7", size = 4155160, upload_time = "2024-11-27T18:06:30.866Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331 },
|
{ url = "https://files.pythonhosted.org/packages/a2/cd/2f3c440913d4329ade49b146d74f2e9766422e1732613f57097fea61f344/cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c", size = 3932331, upload_time = "2024-11-27T18:06:33.432Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372 },
|
{ url = "https://files.pythonhosted.org/packages/7f/df/8be88797f0a1cca6e255189a57bb49237402b1880d6e8721690c5603ac23/cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64", size = 4017372, upload_time = "2024-11-27T18:06:38.343Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657 },
|
{ url = "https://files.pythonhosted.org/packages/af/36/5ccc376f025a834e72b8e52e18746b927f34e4520487098e283a719c205e/cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285", size = 4239657, upload_time = "2024-11-27T18:06:41.045Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.10"
|
version = "3.10"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
|
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload_time = "2024-09-15T18:07:39.745Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
|
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload_time = "2024-09-15T18:07:37.964Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pycparser"
|
name = "pycparser"
|
||||||
version = "2.22"
|
version = "2.22"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 }
|
sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload_time = "2024-03-30T13:22:22.564Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 },
|
{ url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload_time = "2024-03-30T13:22:20.476Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 }
|
sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115, upload_time = "2024-01-23T06:33:00.505Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
|
{ url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863, upload_time = "2024-01-23T06:32:58.246Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -192,29 +192,67 @@ dependencies = [
|
||||||
{ name = "idna", marker = "sys_platform == 'linux'" },
|
{ name = "idna", marker = "sys_platform == 'linux'" },
|
||||||
{ name = "urllib3", marker = "sys_platform == 'linux'" },
|
{ name = "urllib3", marker = "sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 }
|
sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload_time = "2024-05-29T15:37:49.536Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
|
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload_time = "2024-05-29T15:37:47.027Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruamel-yaml"
|
||||||
|
version = "0.18.10"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "ruamel-yaml-clib", marker = "python_full_version < '3.13' and platform_python_implementation == 'CPython' and sys_platform == 'linux'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ea/46/f44d8be06b85bc7c4d8c95d658be2b68f27711f279bf9dd0612a5e4794f5/ruamel.yaml-0.18.10.tar.gz", hash = "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58", size = 143447, upload_time = "2025-01-06T14:08:51.334Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/36/dfc1ebc0081e6d39924a2cc53654497f967a084a436bb64402dfce4254d9/ruamel.yaml-0.18.10-py3-none-any.whl", hash = "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1", size = 117729, upload_time = "2025-01-06T14:08:47.471Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruamel-yaml-clib"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/20/84/80203abff8ea4993a87d823a5f632e4d92831ef75d404c9fc78d0176d2b5/ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f", size = 225315, upload_time = "2024-10-20T10:10:56.22Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/d2/b79b7d695e2f21da020bd44c782490578f300dd44f0a4c57a92575758a76/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e", size = 641480, upload_time = "2024-10-20T10:12:46.758Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/6e/264c50ce2a31473a9fdbf4fa66ca9b2b17c7455b31ef585462343818bd6c/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e", size = 739068, upload_time = "2024-10-20T10:12:48.605Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/29/88c2567bc893c84d88b4c48027367c3562ae69121d568e8a3f3a8d363f4d/ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52", size = 703012, upload_time = "2024-10-20T10:12:51.124Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/46/879763c619b5470820f0cd6ca97d134771e502776bc2b844d2adb6e37753/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642", size = 704352, upload_time = "2024-10-21T11:26:41.438Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/80/ece7e6034256a4186bbe50dee28cd032d816974941a6abf6a9d65e4228a7/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2", size = 737344, upload_time = "2024-10-21T11:26:43.62Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/ca/e4106ac7e80efbabdf4bf91d3d32fc424e41418458251712f5672eada9ce/ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1492a6051dab8d912fc2adeef0e8c72216b24d57bd896ea607cb90bb0c4981d3", size = 714498, upload_time = "2024-12-11T19:58:15.592Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/b0/b850385604334c2ce90e3ee1013bd911aedf058a934905863a6ea95e9eb4/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d", size = 647362, upload_time = "2024-10-20T10:12:57.155Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/44/d0/3f68a86e006448fb6c005aee66565b9eb89014a70c491d70c08de597f8e4/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c", size = 754118, upload_time = "2024-10-20T10:12:58.501Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/a9/d39f3c5ada0a3bb2870d7db41901125dbe2434fa4f12ca8c5b83a42d7c53/ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd", size = 706497, upload_time = "2024-10-20T10:13:00.211Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/fa/097e38135dadd9ac25aecf2a54be17ddf6e4c23e43d538492a90ab3d71c6/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31", size = 698042, upload_time = "2024-10-21T11:26:46.038Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/d5/a659ca6f503b9379b930f13bc6b130c9f176469b73b9834296822a83a132/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680", size = 745831, upload_time = "2024-10-21T11:26:47.487Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/5d/36619b61ffa2429eeaefaab4f3374666adf36ad8ac6330d855848d7d36fd/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b82a7c94a498853aa0b272fd5bc67f29008da798d4f93a2f9f289feb8426a58d", size = 715692, upload_time = "2024-12-11T19:58:17.252Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/5e/212f473a93ae78c669ffa0cb051e3fee1139cb2d385d2ae1653d64281507/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", size = 642488, upload_time = "2024-10-20T10:13:05.906Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/8f/ecfbe2123ade605c49ef769788f79c38ddb1c8fa81e01f4dbf5cf1a44b16/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", size = 745066, upload_time = "2024-10-20T10:13:07.26Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/a9/28f60726d29dfc01b8decdb385de4ced2ced9faeb37a847bd5cf26836815/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", size = 701785, upload_time = "2024-10-20T10:13:08.504Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/7e/8e7ec45920daa7f76046578e4f677a3215fe8f18ee30a9cb7627a19d9b4c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", size = 693017, upload_time = "2024-10-21T11:26:48.866Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/b3/d650eaade4ca225f02a648321e1ab835b9d361c60d51150bac49063b83fa/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", size = 741270, upload_time = "2024-10-21T11:26:50.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/b8/01c29b924dcbbed75cc45b30c30d565d763b9c4d540545a0eeecffb8f09c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f6f3eac23941b32afccc23081e1f50612bdbe4e982012ef4f5797986828cd01", size = 709059, upload_time = "2024-12-11T19:58:18.846Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/da/00/089db7890ea3be5709e3ece6e46408d6f1e876026ec3fd081ee585fef209/ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", size = 3473116 }
|
sdist = { url = "https://files.pythonhosted.org/packages/da/00/089db7890ea3be5709e3ece6e46408d6f1e876026ec3fd081ee585fef209/ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", size = 3473116, upload_time = "2025-01-04T12:23:00.794Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/28/aa07903694637c2fa394a9f4fe93cf861ad8b09f1282fa650ef07ff9fe97/ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", size = 10628735 },
|
{ url = "https://files.pythonhosted.org/packages/d7/28/aa07903694637c2fa394a9f4fe93cf861ad8b09f1282fa650ef07ff9fe97/ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", size = 10628735, upload_time = "2025-01-04T12:21:53.632Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/e9/e0ed4af1794335fb280c4fac180f2bf40f6a3b859cae93a5a3ada27325ae/ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", size = 10861031 },
|
{ url = "https://files.pythonhosted.org/packages/94/e9/e0ed4af1794335fb280c4fac180f2bf40f6a3b859cae93a5a3ada27325ae/ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", size = 10861031, upload_time = "2025-01-04T12:22:09.252Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/68/da0db02f5ecb2ce912c2bef2aa9fcb8915c31e9bc363969cfaaddbc4c1c2/ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", size = 10388246 },
|
{ url = "https://files.pythonhosted.org/packages/82/68/da0db02f5ecb2ce912c2bef2aa9fcb8915c31e9bc363969cfaaddbc4c1c2/ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", size = 10388246, upload_time = "2025-01-04T12:22:12.63Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/1d/b85383db181639019b50eb277c2ee48f9f5168f4f7c287376f2b6e2a6dc2/ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", size = 11424693 },
|
{ url = "https://files.pythonhosted.org/packages/ac/1d/b85383db181639019b50eb277c2ee48f9f5168f4f7c287376f2b6e2a6dc2/ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", size = 11424693, upload_time = "2025-01-04T12:22:17.244Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/b7/30bc78a37648d31bfc7ba7105b108cb9091cd925f249aa533038ebc5a96f/ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", size = 12141921 },
|
{ url = "https://files.pythonhosted.org/packages/ac/b7/30bc78a37648d31bfc7ba7105b108cb9091cd925f249aa533038ebc5a96f/ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", size = 12141921, upload_time = "2025-01-04T12:22:20.456Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/60/b3/ee0a14cf6a1fbd6965b601c88d5625d250b97caf0534181e151504498f86/ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", size = 11692419 },
|
{ url = "https://files.pythonhosted.org/packages/60/b3/ee0a14cf6a1fbd6965b601c88d5625d250b97caf0534181e151504498f86/ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", size = 11692419, upload_time = "2025-01-04T12:22:23.62Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ef/d6/c597062b2931ba3e3861e80bd2b147ca12b3370afc3889af46f29209037f/ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", size = 12981648 },
|
{ url = "https://files.pythonhosted.org/packages/ef/d6/c597062b2931ba3e3861e80bd2b147ca12b3370afc3889af46f29209037f/ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", size = 12981648, upload_time = "2025-01-04T12:22:26.663Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/84/21f578c2a4144917985f1f4011171aeff94ab18dfa5303ac632da2f9af36/ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", size = 11251801 },
|
{ url = "https://files.pythonhosted.org/packages/68/84/21f578c2a4144917985f1f4011171aeff94ab18dfa5303ac632da2f9af36/ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", size = 11251801, upload_time = "2025-01-04T12:22:29.59Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/aa/1ac02537c8edeb13e0955b5db86b5c050a1dcba54f6d49ab567decaa59c1/ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", size = 10849857 },
|
{ url = "https://files.pythonhosted.org/packages/6c/aa/1ac02537c8edeb13e0955b5db86b5c050a1dcba54f6d49ab567decaa59c1/ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", size = 10849857, upload_time = "2025-01-04T12:22:33.536Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/eb/00/020cb222252d833956cb3b07e0e40c9d4b984fbb2dc3923075c8f944497d/ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", size = 10470852 },
|
{ url = "https://files.pythonhosted.org/packages/eb/00/020cb222252d833956cb3b07e0e40c9d4b984fbb2dc3923075c8f944497d/ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", size = 10470852, upload_time = "2025-01-04T12:22:36.374Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/56/e6d6578202a0141cd52299fe5acb38b2d873565f4670c7a5373b637cf58d/ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", size = 10972997 },
|
{ url = "https://files.pythonhosted.org/packages/00/56/e6d6578202a0141cd52299fe5acb38b2d873565f4670c7a5373b637cf58d/ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", size = 10972997, upload_time = "2025-01-04T12:22:41.424Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/be/31/dd0db1f4796bda30dea7592f106f3a67a8f00bcd3a50df889fbac58e2786/ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", size = 11317760 },
|
{ url = "https://files.pythonhosted.org/packages/be/31/dd0db1f4796bda30dea7592f106f3a67a8f00bcd3a50df889fbac58e2786/ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", size = 11317760, upload_time = "2025-01-04T12:22:44.541Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -225,9 +263,9 @@ dependencies = [
|
||||||
{ name = "certifi", marker = "sys_platform == 'linux'" },
|
{ name = "certifi", marker = "sys_platform == 'linux'" },
|
||||||
{ name = "urllib3", marker = "sys_platform == 'linux'" },
|
{ name = "urllib3", marker = "sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/36/4a/eccdcb8c2649d53440ae1902447b86e2e2ad1bc84207c80af9696fa07614/sentry_sdk-2.19.2.tar.gz", hash = "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d", size = 299047 }
|
sdist = { url = "https://files.pythonhosted.org/packages/36/4a/eccdcb8c2649d53440ae1902447b86e2e2ad1bc84207c80af9696fa07614/sentry_sdk-2.19.2.tar.gz", hash = "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d", size = 299047, upload_time = "2024-12-06T08:23:30.762Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/31/4d/74597bb6bcc23abc774b8901277652c61331a9d4d0a8d1bdb20679b9bbcb/sentry_sdk-2.19.2-py2.py3-none-any.whl", hash = "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84", size = 322942 },
|
{ url = "https://files.pythonhosted.org/packages/31/4d/74597bb6bcc23abc774b8901277652c61331a9d4d0a8d1bdb20679b9bbcb/sentry_sdk-2.19.2-py2.py3-none-any.whl", hash = "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84", size = 322942, upload_time = "2024-12-06T08:23:28.842Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -239,6 +277,7 @@ dependencies = [
|
||||||
{ name = "cryptography", marker = "sys_platform == 'linux'" },
|
{ name = "cryptography", marker = "sys_platform == 'linux'" },
|
||||||
{ name = "python-dotenv", marker = "sys_platform == 'linux'" },
|
{ name = "python-dotenv", marker = "sys_platform == 'linux'" },
|
||||||
{ name = "requests", marker = "sys_platform == 'linux'" },
|
{ name = "requests", marker = "sys_platform == 'linux'" },
|
||||||
|
{ name = "ruamel-yaml", marker = "sys_platform == 'linux'" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.optional-dependencies]
|
[package.optional-dependencies]
|
||||||
|
|
@ -260,6 +299,7 @@ requires-dist = [
|
||||||
{ name = "cryptography", specifier = ">=3.4.7" },
|
{ name = "cryptography", specifier = ">=3.4.7" },
|
||||||
{ name = "python-dotenv", specifier = ">=0.15.0" },
|
{ name = "python-dotenv", specifier = ">=0.15.0" },
|
||||||
{ name = "requests", specifier = ">=2.25.1" },
|
{ name = "requests", specifier = ">=2.25.1" },
|
||||||
|
{ name = "ruamel-yaml", specifier = ">=0.18.10" },
|
||||||
{ name = "sentry-sdk", marker = "extra == 'sentry-enabled'", specifier = ">=0.19.5" },
|
{ name = "sentry-sdk", marker = "extra == 'sentry-enabled'", specifier = ">=0.19.5" },
|
||||||
]
|
]
|
||||||
provides-extras = ["sentry-enabled"]
|
provides-extras = ["sentry-enabled"]
|
||||||
|
|
@ -272,7 +312,7 @@ dev = [{ name = "ruff", specifier = ">=0.8.6" }]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 }
|
sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload_time = "2024-12-22T07:47:30.032Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 },
|
{ url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload_time = "2024-12-22T07:47:28.074Z" },
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue