diff --git a/.github/workflows/ruff.yaml b/.github/workflows/ruff.yaml index 889f6f06c..1972189d2 100644 --- a/.github/workflows/ruff.yaml +++ b/.github/workflows/ruff.yaml @@ -17,4 +17,6 @@ jobs: - uses: actions/checkout@v4 - name: Run ruff - uses: chartboost/ruff-action@v1 + uses: astral-sh/ruff-action@v3 + with: + version-file: "pyproject.toml" diff --git a/.gitignore b/.gitignore index 82f927558..d5d7484dd 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,6 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# Ruff cache +.ruff_cache/ \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9758601e5..a8cf4f29b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -default_stages: [commit] +default_stages: [pre-commit] repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.3.5 diff --git a/contrib/README.md b/CONTRIB.md similarity index 100% rename from contrib/README.md rename to CONTRIB.md diff --git a/Makefile b/Makefile index 49e271aa3..57269d280 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ -DRIVER_TARGETS = $(subst contrib/drivers/,driver-,$(wildcard contrib/drivers/*)) -LIB_TARGETS = $(subst contrib/libs/,lib-,$(wildcard contrib/libs/*)) +PKG_TARGETS = $(subst packages/,,$(wildcard packages/*)) EXAMPLE_TARGETS = $(subst examples/,example-,$(wildcard examples/*)) DOC_LISTEN ?= --host 127.0.0.1 @@ -14,16 +13,10 @@ serve-docs: clean-docs: uv run --isolated --all-packages --group docs $(MAKE) -C docs clean -test-jumpstarter: - uv run --isolated --package jumpstarter pytest jumpstarter tests - -test-driver-%: contrib/drivers/% - uv run --isolated --directory $< pytest - -test-lib-%: contrib/libs/% +test-%: packages/% uv run --isolated --directory $< pytest -test-contrib: $(addprefix test-,$(DRIVER_TARGETS)) +test-packages: $(addprefix test-,$(PKG_TARGETS)) clean-venv: -rm -rf ./.venv @@ -40,11 +33,14 @@ clean-test: sync: uv sync --all-packages --all-extras -test: test-jumpstarter test-contrib +test: test-packages + +generate: + buf generate build: uv build --all --out-dir dist clean: clean-docs clean-venv clean-build clean-test -.PHONY: sync docs test test-jumpstarter test-contrib build clean-test clean-docs clean-venv clean-build +.PHONY: sync docs test test-jumpstarter test-packages build clean-test clean-docs clean-venv clean-build diff --git a/contrib/__templates__/create_driver.sh b/__templates__/create_driver.sh similarity index 88% rename from contrib/__templates__/create_driver.sh rename to __templates__/create_driver.sh index 740bf787f..ea0040e23 100755 --- a/contrib/__templates__/create_driver.sh +++ b/__templates__/create_driver.sh @@ -21,7 +21,7 @@ export AUTHOR_NAME=$3 export AUTHOR_EMAIL=$4 # create the driver directory -DRIVER_DIRECTORY=contrib/drivers/${DRIVER_NAME} +DRIVER_DIRECTORY=packages/jumpstarter_driver_${DRIVER_NAME} MODULE_DIRECTORY=${DRIVER_DIRECTORY}/jumpstarter_driver_${DRIVER_NAME} # create the module directories mkdir -p ${MODULE_DIRECTORY} @@ -35,6 +35,5 @@ done for f in .gitignore pyproject.toml README.md examples/exporter.yaml; do echo "Creating: ${DRIVER_DIRECTORY}/${f}" - envsubst < contrib/__templates__/driver/${f}.tmpl > ${DRIVER_DIRECTORY}/${f} + envsubst < packages/__templates__/driver/${f}.tmpl > ${DRIVER_DIRECTORY}/${f} done - diff --git a/contrib/__templates__/driver/.gitignore.tmpl b/__templates__/driver/.gitignore.tmpl similarity index 100% rename from contrib/__templates__/driver/.gitignore.tmpl rename to __templates__/driver/.gitignore.tmpl diff --git a/contrib/__templates__/driver/README.md.tmpl b/__templates__/driver/README.md.tmpl similarity index 100% rename from contrib/__templates__/driver/README.md.tmpl rename to __templates__/driver/README.md.tmpl diff --git a/contrib/__templates__/driver/examples/exporter.yaml.tmpl b/__templates__/driver/examples/exporter.yaml.tmpl similarity index 100% rename from contrib/__templates__/driver/examples/exporter.yaml.tmpl rename to __templates__/driver/examples/exporter.yaml.tmpl diff --git a/contrib/__templates__/driver/jumpstarter_driver/__init__.py.tmpl b/__templates__/driver/jumpstarter_driver/__init__.py.tmpl similarity index 100% rename from contrib/__templates__/driver/jumpstarter_driver/__init__.py.tmpl rename to __templates__/driver/jumpstarter_driver/__init__.py.tmpl diff --git a/contrib/__templates__/driver/jumpstarter_driver/client.py.tmpl b/__templates__/driver/jumpstarter_driver/client.py.tmpl similarity index 100% rename from contrib/__templates__/driver/jumpstarter_driver/client.py.tmpl rename to __templates__/driver/jumpstarter_driver/client.py.tmpl diff --git a/contrib/__templates__/driver/jumpstarter_driver/driver.py.tmpl b/__templates__/driver/jumpstarter_driver/driver.py.tmpl similarity index 100% rename from contrib/__templates__/driver/jumpstarter_driver/driver.py.tmpl rename to __templates__/driver/jumpstarter_driver/driver.py.tmpl diff --git a/contrib/__templates__/driver/jumpstarter_driver/driver_test.py.tmpl b/__templates__/driver/jumpstarter_driver/driver_test.py.tmpl similarity index 100% rename from contrib/__templates__/driver/jumpstarter_driver/driver_test.py.tmpl rename to __templates__/driver/jumpstarter_driver/driver_test.py.tmpl diff --git a/contrib/__templates__/driver/pyproject.toml.tmpl b/__templates__/driver/pyproject.toml.tmpl similarity index 95% rename from contrib/__templates__/driver/pyproject.toml.tmpl rename to __templates__/driver/pyproject.toml.tmpl index 01c6b1323..4927c8275 100644 --- a/contrib/__templates__/driver/pyproject.toml.tmpl +++ b/__templates__/driver/pyproject.toml.tmpl @@ -14,7 +14,7 @@ dependencies = [ [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [tool.hatch.metadata.hooks.vcs.urls] Homepage = "https://jumpstarter.dev" diff --git a/buf.gen.yaml b/buf.gen.yaml index 6b153cb44..6b52d6ac1 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -3,9 +3,9 @@ managed: enabled: true plugins: - remote: buf.build/protocolbuffers/python - out: . + out: ./packages/jumpstarter_protocol/jumpstarter_protocol - remote: buf.build/grpc/python - out: . + out: ./packages/jumpstarter_protocol/jumpstarter_protocol inputs: - git_repo: https://github.com/jumpstarter-dev/jumpstarter-protocol.git subdir: proto diff --git a/contrib/drivers/http/.gitignore b/contrib/drivers/http/.gitignore deleted file mode 100644 index cbc5d672b..000000000 --- a/contrib/drivers/http/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -__pycache__/ -.coverage -coverage.xml diff --git a/contrib/drivers/http/.python-version b/contrib/drivers/http/.python-version deleted file mode 100644 index e4fba2183..000000000 --- a/contrib/drivers/http/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/contrib/drivers/tftp/.gitignore b/contrib/drivers/tftp/.gitignore deleted file mode 100644 index cbc5d672b..000000000 --- a/contrib/drivers/tftp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -__pycache__/ -.coverage -coverage.xml diff --git a/contrib/drivers/tftp/.python-version b/contrib/drivers/tftp/.python-version deleted file mode 100644 index e4fba2183..000000000 --- a/contrib/drivers/tftp/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py b/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py index 1221ad40b..9b40f1c02 100644 --- a/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py +++ b/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py @@ -6,10 +6,9 @@ import opendal import pexpect import pytest +from jumpstarter_driver_network.adapters import PexpectAdapter from jumpstarter_imagehash import ImageHash - -from jumpstarter.client.adapters import PexpectAdapter -from jumpstarter.testing.pytest import JumpstarterTest +from jumpstarter_testing.pytest import JumpstarterTest log = logging.getLogger(__file__) @@ -43,7 +42,7 @@ def test_setup_device(self, client, console): client.dutlink.storage.write_local_file("image/images/latest.raw") except opendal.exceptions.NotFound: pytest.exit( - "No image found, please enter the image directory and run `make`, " "more details in the README.md" + "No image found, please enter the image directory and run `make`, more details in the README.md" ) return client.dutlink.storage.dut() diff --git a/examples/soc-pytest/pyproject.toml b/examples/soc-pytest/pyproject.toml index c0e196a98..50667b9a2 100644 --- a/examples/soc-pytest/pyproject.toml +++ b/examples/soc-pytest/pyproject.toml @@ -11,16 +11,14 @@ readme = "README.md" license = { text = "Apache-2.0" } requires-python = ">=3.11" dependencies = [ + "pytest>=8.3.2", "jumpstarter", - "pytest>=8.3.2", - "jumpstarter_imagehash", - "jumpstarter_driver_dutlink", + "jumpstarter-testing", + "jumpstarter-imagehash", + "jumpstarter-driver-network", + "jumpstarter-driver-dutlink" ] -[tool.uv.sources] -jumpstarter-imagehash = { workspace = true } -jumpstarter-driver-dutlink = { workspace = true } - [tool.pytest.ini_options] addopts = "-s --ignore examples/pytest/test_on_rpi4.py" log_cli = 1 diff --git a/jumpstarter/__main__.py b/jumpstarter/__main__.py deleted file mode 100644 index d7892b385..000000000 --- a/jumpstarter/__main__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Allow running Jumpstarter through `python -m jumpstarter`.""" - -from jumpstarter.cli.jmp import jmp - -if __name__ == "__main__": - jmp(prog_name="jmp") diff --git a/jumpstarter/cli/client.py b/jumpstarter/cli/client.py deleted file mode 100644 index 65f39dd18..000000000 --- a/jumpstarter/cli/client.py +++ /dev/null @@ -1,239 +0,0 @@ -import logging -from typing import Optional - -import asyncclick as click - -from jumpstarter.common import MetadataFilter -from jumpstarter.common.utils import launch_shell -from jumpstarter.config import ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, UserConfigV1Alpha1 - -from .util import AliasedGroup, make_table -from .version import version - - -@click.group(cls=AliasedGroup, short_help="Manage and interact with clients.") -def client(): - logging.basicConfig(level=logging.INFO) - - -@client.group(short_help="Managed leases held by client.") -def lease(): - pass - -@lease.command("request") -@click.option("-l", "--label", "labels", type=(str, str), multiple=True) -@click.argument("name", type=str, default="") -def lease_request(name, labels): - """Request an exporter lease from the jumpstarter controller. - -The result of this command will be a lease ID that can be used to -connect to the remote exporter. - -This is useful for multi-step workflows where you want to hold a lease -for a specific exporter while performing multiple operations, or for -CI environments where one step will request the lease and other steps -will perform operations on the leased exporter. - -Example: - -.. code-block:: bash - - $ JMP_LEASE=$(jmp lease request -l label match) - $ jmp shell - $$ j --help - $$ exit - $ jmp lease release -l "${JMP_LEASE}" - -""" - try: - if name: - config = ClientConfigV1Alpha1.load(name) - else: - config = UserConfigV1Alpha1.load_or_create().config.current_client - if not config: - raise ValueError("No client specified") - lease = config.request_lease(metadata_filter=MetadataFilter(labels=dict(labels))) - print(lease.name) - except ValueError as e: - raise click.ClickException(str(e)) from e - except Exception as e: - raise e - -@lease.command("list") -@click.argument("name", type=str, default="") -def lease_list(name): - if name: - config = ClientConfigV1Alpha1.load(name) - else: - config = UserConfigV1Alpha1.load_or_create().config.current_client - if not config: - raise click.ClickException("no client specified") - - for lease in config.list_leases(): - print(lease) - - -@lease.command("release") -@click.argument("name", type=str, default="") -@click.option("-l", "--lease", "lease", type=str, default="") -@click.option("--all", "all_leases", is_flag=True) -def lease_release(name, lease, all_leases): - if name: - config = ClientConfigV1Alpha1.load(name) - else: - config = UserConfigV1Alpha1.load_or_create().config.current_client - if not config: - raise click.ClickException("no client specified") - - if all_leases: - for lease in config.list_leases(): - config.release_lease(lease) - else: - if not lease: - raise click.ClickException("no lease specified") - config.release_lease(lease) - - -@click.command("create", short_help="Create a client configuration.") -@click.argument("name") -@click.option( - "-o", - "--out", - type=click.Path(dir_okay=False, resolve_path=True, writable=True), - help="Specify an output file for the client config.", -) -@click.option( - "-e", - "--endpoint", - type=str, - help="Enter the Jumpstarter service endpoint.", - prompt="Enter a valid Jumpstarter service endpoint", -) -@click.option( - "-t", - "--token", - type=str, - help="A valid Jumpstarter auth token generated by the Jumpstarter service.", - prompt="Enter a Jumpstarter auth token (hidden)", - hide_input=True, -) -@click.option( - "-a", - "--allow", - type=str, - help="A comma-separated list of driver client packages to load.", - prompt="Enter a comma-separated list of allowed driver packages (optional)", - default="", -) -@click.option("--unsafe", is_flag=True, help="Should all driver client packages be allowed to load (UNSAFE!).") -def client_create( - name: str, - endpoint: str, - token: str, - allow: str, - unsafe: bool, - out: Optional[str], -): - """Create a Jumpstarter client configuration.""" - if out is None and ClientConfigV1Alpha1.exists(name): - raise click.ClickException(f"A client with the name '{name}' already exists.") - - config = ClientConfigV1Alpha1( - name=name, - endpoint=endpoint, - token=token, - drivers=ClientConfigV1Alpha1Drivers(allow=allow.split(","), unsafe=unsafe), - ) - ClientConfigV1Alpha1.save(config, out) - - # If this is the only client config, set it as default - if out is None and len(ClientConfigV1Alpha1.list()) == 1: - user_config = UserConfigV1Alpha1.load_or_create() - user_config.config.current_client = config - UserConfigV1Alpha1.save(user_config) - - -def set_next_client(name: str): - user_config = UserConfigV1Alpha1.load() if UserConfigV1Alpha1.exists() else None - if ( - user_config is not None - and user_config.config.current_client is not None - and user_config.config.current_client.name == name - ): - for c in ClientConfigV1Alpha1.list(): - if c.name != name: - # Use the next available client config - user_config.use_client(c.name) - return - # Otherwise, set client to none - user_config.use_client(None) - - -@click.command("delete", short_help="Delete a client configuration.") -@click.argument("name", type=str) -def client_delete(name: str): - """Delete a Jumpstarter client configuration.""" - set_next_client(name) - ClientConfigV1Alpha1.delete(name) - - -@click.command("list", short_help="List available client configurations.") -def client_list(): - # Allow listing if there is no user config defined - current_name = None - if UserConfigV1Alpha1.exists(): - current_client = UserConfigV1Alpha1.load().config.current_client - current_name = current_client.name if current_client is not None else None - - configs = ClientConfigV1Alpha1.list() - - columns = ["CURRENT", "NAME", "ENDPOINT", "PATH"] - - def make_row(c: ClientConfigV1Alpha1): - return { - "CURRENT": "*" if current_name == c.name else "", - "NAME": c.name, - "ENDPOINT": c.endpoint, - "PATH": str(c.path), - } - - rows = list(map(make_row, configs)) - click.echo(make_table(columns, rows)) - - -@click.command("use", short_help="Select the current client configuration.") -@click.argument("name", type=str) -def client_use(name: str): - """Select the current Jumpstarter client configuration to use.""" - user_config = UserConfigV1Alpha1.load_or_create() - user_config.use_client(name) - - -@click.command("shell", short_help="Spawns a shell connecting to a leased remote exporter") -@click.argument("name", type=str, default="") -@click.option("-l", "--label", "labels", type=(str, str), multiple=True) -@click.option("-n", "--lease", "lease_name", type=str) -def client_shell(name: str, labels, lease_name): - """Spawns a shell connecting to a leased remote exporter""" - if name: - config = ClientConfigV1Alpha1.load(name) - else: - config = UserConfigV1Alpha1.load_or_create().config.current_client - if not config: - raise ValueError("no client specified") - - with config.lease(metadata_filter=MetadataFilter(labels=dict(labels)), lease_name=lease_name) as lease: - with lease.serve_unix() as path: - launch_shell(path, config.drivers.allow, config.drivers.unsafe) - - -client.add_command(client_create) -client.add_command(client_delete) -client.add_command(client_list) -client.add_command(client_use) -client.add_command(client_shell) -client.add_command(version) - - -if __name__ == "__main__": - client() diff --git a/jumpstarter/cli/exporter.py b/jumpstarter/cli/exporter.py deleted file mode 100644 index 6bf8c8df6..000000000 --- a/jumpstarter/cli/exporter.py +++ /dev/null @@ -1,132 +0,0 @@ -import logging -import sys -import traceback -from pathlib import Path -from typing import Optional - -import asyncclick as click - -from jumpstarter.common.utils import launch_shell -from jumpstarter.config.exporter import ExporterConfigV1Alpha1 - -from .util import AliasedGroup, make_table, opt_log_level - -arg_alias = click.argument("alias", default="default") - -opt_config_path = click.option( - "-c", "--config", "config_path", type=click.Path(exists=True), help="Path of exporter config, overrides ALIAS" -) - -@click.group(cls=AliasedGroup) -@opt_log_level -def exporter(log_level: Optional[str]): - """Manage and run exporters""" - if log_level: - logging.basicConfig(level=log_level.upper()) - else: - logging.basicConfig(level=logging.INFO) - - -@exporter.command -@click.option("--endpoint", prompt=True) -@click.option("--token", prompt=True) -@arg_alias -def create(alias, endpoint, token): - """Create exporter""" - try: - ExporterConfigV1Alpha1.load(alias) - except FileNotFoundError: - pass - else: - raise click.ClickException(f'exporter "{alias}" exists') - - config = ExporterConfigV1Alpha1( - alias=alias, - endpoint=endpoint, - token=token, - ) - ExporterConfigV1Alpha1.save(config) - - -@exporter.command -@arg_alias -def delete(alias): - """Delete exporter""" - try: - ExporterConfigV1Alpha1.load(alias) - except FileNotFoundError as err: - raise click.ClickException(f'exporter "{alias}" does not exist') from err - ExporterConfigV1Alpha1.delete(alias) - - -@exporter.command -@arg_alias -def edit(alias): - """Edit exporter""" - try: - config = ExporterConfigV1Alpha1.load(alias) - except FileNotFoundError as err: - raise click.ClickException(f'exporter "{alias}" does not exist') from err - click.edit(filename=config.path) - - -@exporter.command -def list(): - """List exporters""" - exporters = ExporterConfigV1Alpha1.list() - columns = ["ALIAS", "PATH"] - rows = [ - { - "ALIAS": exporter.alias, - "PATH": str(exporter.path), - } - for exporter in exporters - ] - click.echo(make_table(columns, rows)) - - -async def _serve_with_exc_handling(exporter): - result = 0 - try: - await exporter.serve() - except* Exception as excgroup: - print(f"Exception while serving on the exporter: {excgroup.exceptions}", file=sys.stderr) - for exc in excgroup.exceptions: - traceback.print_exception(type(exc), exc, exc.__traceback__, file=sys.stderr) - result = 1 - return result - - -@exporter.command -@arg_alias -@opt_config_path -async def run(alias, config_path): - """Run exporter""" - try: - if config_path: - config = ExporterConfigV1Alpha1.load_path(Path(config_path)) - else: - config = ExporterConfigV1Alpha1.load(alias) - except FileNotFoundError as err: - raise click.ClickException(f'exporter "{alias}" does not exist') from err - - return await _serve_with_exc_handling(config) - - -@exporter.command -@arg_alias -@opt_config_path -def shell(alias, config_path): - """Spawns a shell connecting to a transient exporter""" - try: - if config_path: - config = ExporterConfigV1Alpha1.load_path(Path(config_path)) - else: - config = ExporterConfigV1Alpha1.load(alias) - except FileNotFoundError as err: - raise click.ClickException(f'exporter "{alias}" does not exist') from err - - with config.serve_unix() as path: - # SAFETY: the exporter config is local thus considered trusted - launch_shell(path, allow=[], unsafe=True) - diff --git a/jumpstarter/cli/jmp.py b/jumpstarter/cli/jmp.py deleted file mode 100644 index 29021ddd7..000000000 --- a/jumpstarter/cli/jmp.py +++ /dev/null @@ -1,32 +0,0 @@ -import asyncclick as click - -from .client import client -from .create import create -from .delete import delete -from .exporter import exporter -from .get import get -from .import_res import import_res -from .install import install -from .lease import lease -from .shell import shell -from .util import AliasedGroup -from .version import version - - -@click.group(cls=AliasedGroup) -def jmp(): - """The Jumpstarter CLI""" - -jmp.add_command(client) -jmp.add_command(exporter) -jmp.add_command(lease) -jmp.add_command(shell) -jmp.add_command(get) -jmp.add_command(create) -jmp.add_command(delete) -jmp.add_command(install) -jmp.add_command(import_res) -jmp.add_command(version) - -if __name__ == "__main__": - jmp() diff --git a/jumpstarter/cli/util/opt.py b/jumpstarter/cli/util/opt.py deleted file mode 100644 index cc33610f3..000000000 --- a/jumpstarter/cli/util/opt.py +++ /dev/null @@ -1,30 +0,0 @@ -import asyncclick as click - -opt_log_level = click.option( - "-l", "--log-level", "log_level", - type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]), - help="Set the log level" -) - -opt_kubeconfig = click.option( - "--kubeconfig", "kubeconfig", - type=click.File(), - default=None, - help="path to the kubeconfig file" -) - -opt_context = click.option( - "--context", - "context", - type=str, - default=None, - help="Kubernetes context to use" -) - -opt_namespace = click.option( - "-n", - "--namespace", - type=str, - help="Kubernetes namespace to use", - default="default" -) diff --git a/jumpstarter/client/adapters/__init__.py b/jumpstarter/client/adapters/__init__.py deleted file mode 100644 index 0bbfd7f59..000000000 --- a/jumpstarter/client/adapters/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .common import ClientAdapter -from .fabric import FabricAdapter -from .novnc import NovncAdapter -from .opendal import OpendalAdapter -from .pexpect import PexpectAdapter -from .portforward import PortforwardAdapter - -__all__ = ["ClientAdapter", "PortforwardAdapter", "NovncAdapter", "OpendalAdapter", "PexpectAdapter", "FabricAdapter"] diff --git a/jumpstarter/testing/pytest.py b/jumpstarter/testing/pytest.py deleted file mode 100644 index ebe71f911..000000000 --- a/jumpstarter/testing/pytest.py +++ /dev/null @@ -1,65 +0,0 @@ -import logging -import time -from typing import ClassVar - -import pytest - -from jumpstarter.common import MetadataFilter -from jumpstarter.common.utils import env -from jumpstarter.config.client import ClientConfigV1Alpha1 - -log = logging.getLogger(__name__) - -class JumpstarterTest: - """ Base class for Jumpstarter test cases in pytest - -This class provides a client fixture that can be used to interact with -Jumpstarter services in test cases. - -Looks for the `JUMPSTARTER_HOST` environment variable to connect to an -established Jumpstarter shell, otherwise it will try to acquire a lease -for a single exporter using the filter_labels annotation. -i.e.: - -.. code-block:: python - - import os - import pytest - import logging - - from jumpstarter.testing.pytest import JumpstarterTest - - log = logging.getLogger(__name__) - - class TestResource(JumpstarterTest): - filter_labels = {"board":"rpi4"} - - @pytest.fixture() - def console(self, client): - with PexpectAdapter(client=client.dutlink.console) as console: - yield console - - def test_setup_device(self, client, console): - client.dutlink.power.off() - log.info("Setting up device") - client.dutlink.storage.write_local_file("2024-07-04-raspios-bookworm-arm64-lite.img") - client.dutlink.storage.dut() - client.dutlink.power.on() - - """ - - filter_labels: ClassVar[dict[str, str]] - - @pytest.fixture(scope="class") - def client(self): - try: - with env() as client: - yield client - except RuntimeError: - labels = getattr(self, "filter_labels", {}) - config = ClientConfigV1Alpha1.load("default") - with config.lease(metadata_filter=MetadataFilter(labels=labels)) as lease: - with lease.connect() as client: - yield client - # BUG workaround: make sure that grpc servers get the client/lease release properly - time.sleep(1) diff --git a/packages/jumpstarter-cli-admin/README.md b/packages/jumpstarter-cli-admin/README.md new file mode 100644 index 000000000..912d85bfd --- /dev/null +++ b/packages/jumpstarter-cli-admin/README.md @@ -0,0 +1 @@ +# Jumpstarter Admin CLI \ No newline at end of file diff --git a/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/__init__.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/__init__.py new file mode 100644 index 000000000..7badfbcc7 --- /dev/null +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/__init__.py @@ -0,0 +1,24 @@ +import asyncclick as click +from jumpstarter_cli_common import AliasedGroup, version + +from .create import create +from .delete import delete +from .get import get +from .import_res import import_res +from .install import install + + +@click.group(cls=AliasedGroup) +def admin(): + """Jumpstarter Kubernetes cluster admin CLI tool""" + + +admin.add_command(get) +admin.add_command(create) +admin.add_command(delete) +admin.add_command(install) +admin.add_command(import_res) +admin.add_command(version) + +if __name__ == "__main__": + admin() diff --git a/jumpstarter/cli/create.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/create.py similarity index 97% rename from jumpstarter/cli/create.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/create.py index 751f67944..d5ebcf7aa 100644 --- a/jumpstarter/cli/create.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/create.py @@ -2,21 +2,22 @@ from typing import Optional import asyncclick as click -from kubernetes_asyncio.client.exceptions import ApiException -from kubernetes_asyncio.config.config_exception import ConfigException - from jumpstarter.config import ClientConfigV1Alpha1, ExporterConfigV1Alpha1, UserConfigV1Alpha1 -from jumpstarter.k8s import ClientsV1Alpha1Api, ExportersV1Alpha1Api - -from .util import ( +from jumpstarter_cli_common import ( AliasedGroup, - handle_k8s_api_exception, - handle_k8s_config_exception, opt_context, opt_kubeconfig, opt_log_level, opt_namespace, ) +from jumpstarter_kubernetes import ClientsV1Alpha1Api, ExportersV1Alpha1Api +from kubernetes_asyncio.client.exceptions import ApiException +from kubernetes_asyncio.config.config_exception import ConfigException + +from .k8s import ( + handle_k8s_api_exception, + handle_k8s_config_exception, +) @click.group(cls=AliasedGroup) diff --git a/jumpstarter/cli/create_test.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/create_test.py similarity index 99% rename from jumpstarter/cli/create_test.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/create_test.py index 3acb6882d..f7fd3ecff 100644 --- a/jumpstarter/cli/create_test.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/create_test.py @@ -3,14 +3,12 @@ import pytest from asyncclick.testing import CliRunner -from kubernetes_asyncio.client.models import V1ObjectMeta - from jumpstarter.config import ( ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, ExporterConfigV1Alpha1, ) -from jumpstarter.k8s import ( +from jumpstarter_kubernetes import ( ClientsV1Alpha1Api, ExportersV1Alpha1Api, V1Alpha1Client, @@ -18,6 +16,7 @@ V1Alpha1Exporter, V1Alpha1ExporterStatus, ) +from kubernetes_asyncio.client.models import V1ObjectMeta from .create import create diff --git a/jumpstarter/cli/delete.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/delete.py similarity index 96% rename from jumpstarter/cli/delete.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/delete.py index ae8852a22..3df7151f9 100644 --- a/jumpstarter/cli/delete.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/delete.py @@ -2,21 +2,22 @@ from typing import Optional import asyncclick as click -from kubernetes_asyncio.client.exceptions import ApiException -from kubernetes_asyncio.config.config_exception import ConfigException - from jumpstarter.config import ClientConfigV1Alpha1, ExporterConfigV1Alpha1, UserConfigV1Alpha1 -from jumpstarter.k8s import ClientsV1Alpha1Api, ExportersV1Alpha1Api - -from .util import ( +from jumpstarter_cli_common import ( AliasedGroup, - handle_k8s_api_exception, - handle_k8s_config_exception, opt_context, opt_kubeconfig, opt_log_level, opt_namespace, ) +from jumpstarter_kubernetes import ClientsV1Alpha1Api, ExportersV1Alpha1Api +from kubernetes_asyncio.client.exceptions import ApiException +from kubernetes_asyncio.config.config_exception import ConfigException + +from .k8s import ( + handle_k8s_api_exception, + handle_k8s_config_exception, +) @click.group(cls=AliasedGroup) diff --git a/jumpstarter/cli/delete_test.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/delete_test.py similarity index 99% rename from jumpstarter/cli/delete_test.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/delete_test.py index d8f3477c5..521966906 100644 --- a/jumpstarter/cli/delete_test.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/delete_test.py @@ -2,8 +2,6 @@ import pytest from asyncclick.testing import CliRunner -from kubernetes_asyncio.client.models import V1ObjectMeta - from jumpstarter.config import ( ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, @@ -11,12 +9,13 @@ UserConfigV1Alpha1, UserConfigV1Alpha1Config, ) -from jumpstarter.k8s import ( +from jumpstarter_kubernetes import ( ClientsV1Alpha1Api, ExportersV1Alpha1Api, V1Alpha1Exporter, V1Alpha1ExporterStatus, ) +from kubernetes_asyncio.client.models import V1ObjectMeta from .delete import delete diff --git a/jumpstarter/cli/get.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get.py similarity index 98% rename from jumpstarter/cli/get.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get.py index a48a2e3df..70cbfa510 100644 --- a/jumpstarter/cli/get.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get.py @@ -2,10 +2,16 @@ from typing import Optional import asyncclick as click -from kubernetes_asyncio.client.exceptions import ApiException -from kubernetes_asyncio.config.config_exception import ConfigException - -from jumpstarter.k8s import ( +from jumpstarter_cli_common import ( + AliasedGroup, + make_table, + opt_context, + opt_kubeconfig, + opt_log_level, + opt_namespace, + time_since, +) +from jumpstarter_kubernetes import ( ClientsV1Alpha1Api, ExportersV1Alpha1Api, LeasesV1Alpha1Api, @@ -13,17 +19,12 @@ V1Alpha1Exporter, V1Alpha1Lease, ) +from kubernetes_asyncio.client.exceptions import ApiException +from kubernetes_asyncio.config.config_exception import ConfigException -from .util import ( - AliasedGroup, +from .k8s import ( handle_k8s_api_exception, handle_k8s_config_exception, - make_table, - opt_context, - opt_kubeconfig, - opt_log_level, - opt_namespace, - time_since, ) @@ -151,6 +152,7 @@ async def get_exporter( LEASE_COLUMNS = ["NAME", "CLIENT", "SELECTOR", "EXPORTER", "STATUS", "REASON", "BEGIN", "END", "DURATION", "AGE"] + def get_reason(lease: V1Alpha1Lease): condition = lease.status.conditions[-1] if len(lease.status.conditions) > 0 else None reason = condition.reason if condition is not None else "Unknown" @@ -166,6 +168,7 @@ def get_reason(lease: V1Alpha1Lease): else: return "Complete" + def make_lease_row(lease: V1Alpha1Lease): selectors = [] for label in lease.spec.selector: diff --git a/jumpstarter/cli/get_test.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py similarity index 99% rename from jumpstarter/cli/get_test.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py index 07eb726d8..f4ce22bdb 100644 --- a/jumpstarter/cli/get_test.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/get_test.py @@ -2,10 +2,7 @@ import pytest from asyncclick.testing import CliRunner -from kubernetes_asyncio.client.exceptions import ApiException -from kubernetes_asyncio.client.models import V1Condition, V1ObjectMeta, V1ObjectReference - -from jumpstarter.k8s import ( +from jumpstarter_kubernetes import ( ClientsV1Alpha1Api, ExportersV1Alpha1Api, LeasesV1Alpha1Api, @@ -18,6 +15,8 @@ V1Alpha1LeaseSpec, V1Alpha1LeaseStatus, ) +from kubernetes_asyncio.client.exceptions import ApiException +from kubernetes_asyncio.client.models import V1Condition, V1ObjectMeta, V1ObjectReference from .get import get diff --git a/jumpstarter/cli/import_res.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/import_res.py similarity index 91% rename from jumpstarter/cli/import_res.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/import_res.py index 77853d058..10dd4aa8b 100644 --- a/jumpstarter/cli/import_res.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/import_res.py @@ -1,17 +1,24 @@ from typing import Optional import asyncclick as click -from kubernetes_asyncio.client.exceptions import ApiException -from kubernetes_asyncio.config.config_exception import ConfigException - from jumpstarter.config import ( ClientConfigV1Alpha1, UserConfigV1Alpha1, ) from jumpstarter.config.exporter import ExporterConfigV1Alpha1 -from jumpstarter.k8s import ClientsV1Alpha1Api, ExportersV1Alpha1Api +from jumpstarter_cli_common import ( + opt_context, + opt_kubeconfig, + opt_namespace, +) +from jumpstarter_kubernetes import ClientsV1Alpha1Api, ExportersV1Alpha1Api +from kubernetes_asyncio.client.exceptions import ApiException +from kubernetes_asyncio.config.config_exception import ConfigException -from .util import handle_k8s_api_exception, handle_k8s_config_exception, opt_context, opt_kubeconfig, opt_namespace +from .k8s import ( + handle_k8s_api_exception, + handle_k8s_config_exception, +) @click.group("import") @@ -37,9 +44,7 @@ def import_res(): help="A comma-separated list of driver client packages to load.", default=None, ) -@click.option( - "--unsafe", is_flag=True, help="Should all driver client packages be allowed to load (UNSAFE!)." -) +@click.option("--unsafe", is_flag=True, help="Should all driver client packages be allowed to load (UNSAFE!).") async def import_client( name: str, namespace: str, diff --git a/jumpstarter/cli/import_res_test.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/import_res_test.py similarity index 96% rename from jumpstarter/cli/import_res_test.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/import_res_test.py index 8aac5452d..da977d81a 100644 --- a/jumpstarter/cli/import_res_test.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/import_res_test.py @@ -3,13 +3,12 @@ import pytest from asyncclick.testing import CliRunner - from jumpstarter.config import ( ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, ExporterConfigV1Alpha1, ) -from jumpstarter.k8s import ( +from jumpstarter_kubernetes import ( ClientsV1Alpha1Api, ExportersV1Alpha1Api, ) @@ -95,9 +94,7 @@ async def test_import_client(_load_kube_config_mock, get_client_config_mock: Asy @patch.object(ExporterConfigV1Alpha1, "save") @patch.object(ExportersV1Alpha1Api, "get_exporter_config", return_value=EXPORTER_CONFIG) @patch.object(ExportersV1Alpha1Api, "_load_kube_config") -async def test_import_exporter( - _load_kube_config_mock, _get_exporter_config_mock, save_exporter_config_mock: Mock -): +async def test_import_exporter(_load_kube_config_mock, _get_exporter_config_mock, save_exporter_config_mock: Mock): runner = CliRunner() # Save with prompts diff --git a/jumpstarter/cli/install.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/install.py similarity index 93% rename from jumpstarter/cli/install.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/install.py index 9bf5ab73b..f52a98579 100644 --- a/jumpstarter/cli/install.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/install.py @@ -1,17 +1,14 @@ from typing import Literal, Optional import asyncclick as click - -from jumpstarter.k8s import get_ip_address, helm_installed, install_helm_chart - -from .util import opt_context, opt_kubeconfig -from .version import get_client_version +from jumpstarter_cli_common import get_client_version, opt_context, opt_kubeconfig +from jumpstarter_kubernetes import get_ip_address, helm_installed, install_helm_chart def get_chart_version() -> str: client_version = get_client_version() parts = client_version.split(".") - return f"{parts[0].replace("v", "")}.{parts[1]}.{parts[2]}" + return f"{parts[0].replace('v', '')}.{parts[1]}.{parts[2]}" @click.command diff --git a/jumpstarter/cli/util/k8s.py b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/k8s.py similarity index 93% rename from jumpstarter/cli/util/k8s.py rename to packages/jumpstarter-cli-admin/jumpstarter_cli_admin/k8s.py index 9cb21b4e2..8e3f622cd 100644 --- a/jumpstarter/cli/util/k8s.py +++ b/packages/jumpstarter-cli-admin/jumpstarter_cli_admin/k8s.py @@ -10,7 +10,7 @@ def handle_k8s_api_exception(e: ApiException): # Try to parse the JSON response try: json_body = json.loads(e.body) - raise click.ClickException(f"Error from server ({json_body["reason"]}): {json_body["message"]}") from e + raise click.ClickException(f"Error from server ({json_body['reason']}): {json_body['message']}") from e except json.decoder.JSONDecodeError: raise click.ClickException(f"Server error: {e.body}") from e diff --git a/packages/jumpstarter-cli-admin/pyproject.toml b/packages/jumpstarter-cli-admin/pyproject.toml new file mode 100644 index 000000000..bca898518 --- /dev/null +++ b/packages/jumpstarter-cli-admin/pyproject.toml @@ -0,0 +1,40 @@ +[project] +name = "jumpstarter-cli-admin" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter-cli-common", + "jumpstarter-kubernetes", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[project.scripts] +jmp-admin = "jumpstarter_cli_admin:admin" + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter_cli_admin"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-cli-client/README.md b/packages/jumpstarter-cli-client/README.md new file mode 100644 index 000000000..947a5b210 --- /dev/null +++ b/packages/jumpstarter-cli-client/README.md @@ -0,0 +1 @@ +# Jumpstarter Client CLI \ No newline at end of file diff --git a/packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py new file mode 100644 index 000000000..73a28d086 --- /dev/null +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/__init__.py @@ -0,0 +1,29 @@ +import asyncclick as click +from jumpstarter.common.utils import env +from jumpstarter_cli_common import AliasedGroup, version + +from .client_config import create_client_config, delete_client_config, list_client_configs, use_client_config +from .client_shell import client_shell +from .lease import lease + + +@click.group(cls=AliasedGroup) +def client(): + """Jumpstarter client CLI tool""" + + +def j(): + with env() as client: + client.cli()(standalone_mode=False) + + +client.add_command(create_client_config) +client.add_command(delete_client_config) +client.add_command(list_client_configs) +client.add_command(use_client_config) +client.add_command(lease) +client.add_command(client_shell) +client.add_command(version) + +if __name__ == "__main__": + client() diff --git a/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_config.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_config.py new file mode 100644 index 000000000..bed794ea0 --- /dev/null +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_config.py @@ -0,0 +1,120 @@ +from typing import Optional + +import asyncclick as click +from jumpstarter.config import ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, UserConfigV1Alpha1 +from jumpstarter_cli_common import make_table + + +@click.command("create-config", short_help="Create a client config.") +@click.argument("name") +@click.option( + "-o", + "--out", + type=click.Path(dir_okay=False, resolve_path=True, writable=True), + help="Specify an output file for the client config.", +) +@click.option( + "-e", + "--endpoint", + type=str, + help="Enter the Jumpstarter service endpoint.", + prompt="Enter a valid Jumpstarter service endpoint", +) +@click.option( + "-t", + "--token", + type=str, + help="A valid Jumpstarter auth token generated by the Jumpstarter service.", + prompt="Enter a Jumpstarter auth token (hidden)", + hide_input=True, +) +@click.option( + "-a", + "--allow", + type=str, + help="A comma-separated list of driver client packages to load.", + prompt="Enter a comma-separated list of allowed driver packages (optional)", + default="", +) +@click.option("--unsafe", is_flag=True, help="Should all driver client packages be allowed to load (UNSAFE!).") +def create_client_config( + name: str, + endpoint: str, + token: str, + allow: str, + unsafe: bool, + out: Optional[str], +): + """Create a Jumpstarter client configuration.""" + if out is None and ClientConfigV1Alpha1.exists(name): + raise click.ClickException(f"A client with the name '{name}' already exists.") + + config = ClientConfigV1Alpha1( + name=name, + endpoint=endpoint, + token=token, + drivers=ClientConfigV1Alpha1Drivers(allow=allow.split(","), unsafe=unsafe), + ) + ClientConfigV1Alpha1.save(config, out) + + # If this is the only client config, set it as default + if out is None and len(ClientConfigV1Alpha1.list()) == 1: + user_config = UserConfigV1Alpha1.load_or_create() + user_config.config.current_client = config + UserConfigV1Alpha1.save(user_config) + + +def set_next_client(name: str): + user_config = UserConfigV1Alpha1.load() if UserConfigV1Alpha1.exists() else None + if ( + user_config is not None + and user_config.config.current_client is not None + and user_config.config.current_client.name == name + ): + for c in ClientConfigV1Alpha1.list(): + if c.name != name: + # Use the next available client config + user_config.use_client(c.name) + return + # Otherwise, set client to none + user_config.use_client(None) + + +@click.command("delete-config", short_help="Delete a client config.") +@click.argument("name", type=str) +def delete_client_config(name: str): + """Delete a Jumpstarter client configuration.""" + set_next_client(name) + ClientConfigV1Alpha1.delete(name) + + +@click.command("list-configs", short_help="List available client configurations.") +def list_client_configs(): + # Allow listing if there is no user config defined + current_name = None + if UserConfigV1Alpha1.exists(): + current_client = UserConfigV1Alpha1.load().config.current_client + current_name = current_client.name if current_client is not None else None + + configs = ClientConfigV1Alpha1.list() + + columns = ["CURRENT", "NAME", "ENDPOINT", "PATH"] + + def make_row(c: ClientConfigV1Alpha1): + return { + "CURRENT": "*" if current_name == c.name else "", + "NAME": c.name, + "ENDPOINT": c.endpoint, + "PATH": str(c.path), + } + + rows = list(map(make_row, configs)) + click.echo(make_table(columns, rows)) + + +@click.command("use-config", short_help="Select the current client config.") +@click.argument("name", type=str) +def use_client_config(name: str): + """Select the current Jumpstarter client configuration to use.""" + user_config = UserConfigV1Alpha1.load_or_create() + user_config.use_client(name) diff --git a/jumpstarter/cli/shell.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py similarity index 95% rename from jumpstarter/cli/shell.py rename to packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py index ef5aa7ca5..fc1eb856c 100644 --- a/jumpstarter/cli/shell.py +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py @@ -1,5 +1,4 @@ import asyncclick as click - from jumpstarter.common import MetadataFilter from jumpstarter.common.utils import launch_shell from jumpstarter.config import ( @@ -12,7 +11,7 @@ @click.argument("name", type=str, default="") @click.option("-l", "--label", "labels", type=(str, str), multiple=True) @click.option("-n", "--lease", "lease_name", type=str) -def shell(name: str, labels, lease_name): +def client_shell(name: str, labels, lease_name): """Spawns a shell connecting to a leased remote exporter""" if name: config = ClientConfigV1Alpha1.load(name) diff --git a/jumpstarter/cli/client_test.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_test.py similarity index 71% rename from jumpstarter/cli/client_test.py rename to packages/jumpstarter-cli-client/jumpstarter_cli_client/client_test.py index f560dd663..1440e5adf 100644 --- a/jumpstarter/cli/client_test.py +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_test.py @@ -1,9 +1,8 @@ import pytest from asyncclick.testing import CliRunner - from jumpstarter.config import ClientConfigV1Alpha1, UserConfigV1Alpha1 -from .client import client +from . import client @pytest.fixture @@ -18,46 +17,48 @@ async def test_client(tmp_config_path): # create client non-interactively result = await runner.invoke( - client, ["create", "test1", "--endpoint", "example.com:443", "--token", "dummy", "--allow", "jumpstarter.*"] + client, + ["create-config", "test1", "--endpoint", "example.com:443", "--token", "dummy", "--allow", "jumpstarter.*"], ) assert result.exit_code == 0 # create duplicate client result = await runner.invoke( - client, ["create", "test1", "--endpoint", "example.com:443", "--token", "dummy", "--allow", "jumpstarter.*"] + client, + ["create-config", "test1", "--endpoint", "example.com:443", "--token", "dummy", "--allow", "jumpstarter.*"], ) assert result.exit_code != 0 # create client interactively result = await runner.invoke( client, - ["create", "test2"], + ["create-config", "test2"], input="example.org:443\ndummytoken\njumpstarter.*,com.example.*\n", ) assert result.exit_code == 0 # list clients - result = await runner.invoke(client, ["list"]) + result = await runner.invoke(client, ["list-configs"]) assert result.exit_code == 0 assert "* test1 example.com:443" in result.output assert " test2 example.org:443" in result.output # set default client - result = await runner.invoke(client, ["use", "test2"]) + result = await runner.invoke(client, ["use-config", "test2"]) assert result.exit_code == 0 # list clients - result = await runner.invoke(client, ["list"]) + result = await runner.invoke(client, ["list-configs"]) assert result.exit_code == 0 assert " test1 example.com:443" in result.output assert "* test2 example.org:443" in result.output # delete default client - result = await runner.invoke(client, ["delete", "test2"]) + result = await runner.invoke(client, ["delete-config", "test2"]) assert result.exit_code == 0 # list clients - result = await runner.invoke(client, ["list"]) + result = await runner.invoke(client, ["list-configs"]) assert result.exit_code == 0 assert "* test1 example.com:443" in result.output assert "* test2 example.org:443" not in result.output diff --git a/jumpstarter/cli/j.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/j.py similarity index 100% rename from jumpstarter/cli/j.py rename to packages/jumpstarter-cli-client/jumpstarter_cli_client/j.py diff --git a/jumpstarter/cli/lease.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/lease.py similarity index 96% rename from jumpstarter/cli/lease.py rename to packages/jumpstarter-cli-client/jumpstarter_cli_client/lease.py index 956dda56f..0ec567229 100644 --- a/jumpstarter/cli/lease.py +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/lease.py @@ -1,11 +1,9 @@ import asyncclick as click - from jumpstarter.config import ( ClientConfigV1Alpha1, UserConfigV1Alpha1, ) - -from .util import AliasedGroup +from jumpstarter_cli_common import AliasedGroup @click.group(cls=AliasedGroup, short_help="") diff --git a/packages/jumpstarter-cli-client/pyproject.toml b/packages/jumpstarter-cli-client/pyproject.toml new file mode 100644 index 000000000..e40329cf0 --- /dev/null +++ b/packages/jumpstarter-cli-client/pyproject.toml @@ -0,0 +1,42 @@ +[project] +name = "jumpstarter-cli-client" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Nick Cao", email = "ncao@redhat.com" }, + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter-cli-common", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[project.scripts] +jmp-client = "jumpstarter_cli_client:client" +j = "jumpstarter_cli_client:j" + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter_cli_client"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-cli-common/README.md b/packages/jumpstarter-cli-common/README.md new file mode 100644 index 000000000..7527686f9 --- /dev/null +++ b/packages/jumpstarter-cli-common/README.md @@ -0,0 +1 @@ +# Jumpstarter CLI Common Utils \ No newline at end of file diff --git a/jumpstarter/cli/util/__init__.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/__init__.py similarity index 70% rename from jumpstarter/cli/util/__init__.py rename to packages/jumpstarter-cli-common/jumpstarter_cli_common/__init__.py index a2e83e35f..445a88c04 100644 --- a/jumpstarter/cli/util/__init__.py +++ b/packages/jumpstarter-cli-common/jumpstarter_cli_common/__init__.py @@ -1,8 +1,8 @@ from .alias import AliasedGroup -from .k8s import handle_k8s_api_exception, handle_k8s_config_exception from .opt import opt_context, opt_kubeconfig, opt_log_level, opt_namespace from .table import make_table from .time import time_since +from .version import get_client_version, version __all__ = [ "AliasedGroup", @@ -12,6 +12,6 @@ "opt_kubeconfig", "opt_namespace", "time_since", - "handle_k8s_api_exception", - "handle_k8s_config_exception" + "version", + "get_client_version", ] diff --git a/jumpstarter/cli/util/alias.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/alias.py similarity index 66% rename from jumpstarter/cli/util/alias.py rename to packages/jumpstarter-cli-common/jumpstarter_cli_common/alias.py index 04550b6dc..2d5e4391d 100644 --- a/jumpstarter/cli/util/alias.py +++ b/packages/jumpstarter-cli-common/jumpstarter_cli_common/alias.py @@ -7,15 +7,23 @@ class AliasedGroup(click.Group): common_aliases: dict[str, list[str]] = { "remove": ["rm"], "list": ["ls"], - "create": ["cr"], + "create": ["c"], + "import": ["i"], + "get": ["g"], + "admin": ["a"], + "create-config": ["cc"], + "delete-config": ["dc"], + "edit-config": ["ec"], + "list-configs": ["lc"], + "use-config": ["uc"], "move": ["mv"], "config": ["conf"], - "delete": ["del"], - "shell": ["sh"], + "delete": ["del", "d"], + "shell": ["sh", "s"], "exporter": ["exporters", "e"], "client": ["clients", "c"], "lease": ["leases", "l"], - "version": ["ver", "v"] + "version": ["ver", "v"], } def get_command(self, ctx: click.Context, cmd_name: str): @@ -23,8 +31,9 @@ def get_command(self, ctx: click.Context, cmd_name: str): if rv is not None: return rv # Match if listed in the common aliases - matches = [x for x in self.list_commands(ctx) - if x in self.common_aliases and cmd_name in self.common_aliases[x]] + matches = [ + x for x in self.list_commands(ctx) if x in self.common_aliases and cmd_name in self.common_aliases[x] + ] if not matches: return None elif len(matches) == 1: diff --git a/packages/jumpstarter-cli-common/jumpstarter_cli_common/opt.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/opt.py new file mode 100644 index 000000000..e4136d8d7 --- /dev/null +++ b/packages/jumpstarter-cli-common/jumpstarter_cli_common/opt.py @@ -0,0 +1,17 @@ +import asyncclick as click + +opt_log_level = click.option( + "-l", + "--log-level", + "log_level", + type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]), + help="Set the log level", +) + +opt_kubeconfig = click.option( + "--kubeconfig", "kubeconfig", type=click.File(), default=None, help="path to the kubeconfig file" +) + +opt_context = click.option("--context", "context", type=str, default=None, help="Kubernetes context to use") + +opt_namespace = click.option("-n", "--namespace", type=str, help="Kubernetes namespace to use", default="default") diff --git a/jumpstarter/cli/util/table.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/table.py similarity index 100% rename from jumpstarter/cli/util/table.py rename to packages/jumpstarter-cli-common/jumpstarter_cli_common/table.py diff --git a/packages/jumpstarter-cli-common/jumpstarter_cli_common/table_test.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/table_test.py new file mode 100644 index 000000000..41efd2d87 --- /dev/null +++ b/packages/jumpstarter-cli-common/jumpstarter_cli_common/table_test.py @@ -0,0 +1,10 @@ +from .table import make_table + +EXPECTED_TABLE = "TEST HELLO \n123456 There " + + +def test_make_table(): + COLUMNS = ["TEST", "HELLO"] + DATA = [{"TEST": "123456", "HELLO": "There"}] + table = make_table(COLUMNS, DATA) + assert table == EXPECTED_TABLE diff --git a/jumpstarter/cli/util/time.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/time.py similarity index 100% rename from jumpstarter/cli/util/time.py rename to packages/jumpstarter-cli-common/jumpstarter_cli_common/time.py diff --git a/jumpstarter/cli/version.py b/packages/jumpstarter-cli-common/jumpstarter_cli_common/version.py similarity index 92% rename from jumpstarter/cli/version.py rename to packages/jumpstarter-cli-common/jumpstarter_cli_common/version.py index 8448740e7..0d78ef945 100644 --- a/jumpstarter/cli/version.py +++ b/packages/jumpstarter-cli-common/jumpstarter_cli_common/version.py @@ -11,7 +11,7 @@ def get_client_version(): def get_cli_path(): - """Get the path of the current Jumpstarter binary""" + """Get the path of the current Jumpstarter CLI binary""" return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/packages/jumpstarter-cli-common/pyproject.toml b/packages/jumpstarter-cli-common/pyproject.toml new file mode 100644 index 000000000..2b68995d6 --- /dev/null +++ b/packages/jumpstarter-cli-common/pyproject.toml @@ -0,0 +1,37 @@ +[project] +name = "jumpstarter-cli-common" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "asyncclick>=8.1.7.2", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter_cli_common"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-cli-exporter/README.md b/packages/jumpstarter-cli-exporter/README.md new file mode 100644 index 000000000..6f2310302 --- /dev/null +++ b/packages/jumpstarter-cli-exporter/README.md @@ -0,0 +1 @@ +# Jumpstarter Exporter CLI \ No newline at end of file diff --git a/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/__init__.py b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/__init__.py new file mode 100644 index 000000000..8d2c06d3e --- /dev/null +++ b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/__init__.py @@ -0,0 +1,30 @@ +import logging +from typing import Optional + +import asyncclick as click +from jumpstarter_cli_common import AliasedGroup, opt_log_level, version + +from .exporter import exporter_shell, run_exporter +from .exporter_config import create_exporter_config, delete_exporter_config, edit_exporter_config, list_exporter_configs + + +@click.group(cls=AliasedGroup) +@opt_log_level +def exporter(log_level: Optional[str]): + """Jumpstarter exporter CLI tool""" + if log_level: + logging.basicConfig(level=log_level.upper()) + else: + logging.basicConfig(level=logging.INFO) + + +exporter.add_command(create_exporter_config) +exporter.add_command(delete_exporter_config) +exporter.add_command(edit_exporter_config) +exporter.add_command(list_exporter_configs) +exporter.add_command(run_exporter) +exporter.add_command(exporter_shell) +exporter.add_command(version) + +if __name__ == "__main__": + exporter() diff --git a/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter.py b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter.py new file mode 100644 index 000000000..870ac78b2 --- /dev/null +++ b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter.py @@ -0,0 +1,59 @@ +import sys +import traceback +from pathlib import Path + +import asyncclick as click +from jumpstarter.common.utils import launch_shell +from jumpstarter.config.exporter import ExporterConfigV1Alpha1 + +arg_alias = click.argument("alias", default="default") + +opt_config_path = click.option( + "-c", "--config", "config_path", type=click.Path(exists=True), help="Path of exporter config, overrides ALIAS" +) + + +async def _serve_with_exc_handling(exporter): + result = 0 + try: + await exporter.serve() + except* Exception as excgroup: + print(f"Exception while serving on the exporter: {excgroup.exceptions}", file=sys.stderr) + for exc in excgroup.exceptions: + traceback.print_exception(type(exc), exc, exc.__traceback__, file=sys.stderr) + result = 1 + return result + + +@click.command("run") +@arg_alias +@opt_config_path +async def run_exporter(alias, config_path): + """Run an exporter locally.""" + try: + if config_path: + config = ExporterConfigV1Alpha1.load_path(Path(config_path)) + else: + config = ExporterConfigV1Alpha1.load(alias) + except FileNotFoundError as err: + raise click.ClickException(f'exporter "{alias}" does not exist') from err + + return await _serve_with_exc_handling(config) + + +@click.command("shell") +@arg_alias +@opt_config_path +def exporter_shell(alias, config_path): + """Spawns a shell connecting to a transient exporter""" + try: + if config_path: + config = ExporterConfigV1Alpha1.load_path(Path(config_path)) + else: + config = ExporterConfigV1Alpha1.load(alias) + except FileNotFoundError as err: + raise click.ClickException(f'exporter "{alias}" does not exist') from err + + with config.serve_unix() as path: + # SAFETY: the exporter config is local thus considered trusted + launch_shell(path, allow=[], unsafe=True) diff --git a/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_config.py b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_config.py new file mode 100644 index 000000000..074ec2662 --- /dev/null +++ b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_config.py @@ -0,0 +1,63 @@ +import asyncclick as click +from jumpstarter.config.exporter import ExporterConfigV1Alpha1 +from jumpstarter_cli_common import make_table + +arg_alias = click.argument("alias", default="default") + + +@click.command("create-config") +@click.option("--endpoint", prompt=True) +@click.option("--token", prompt=True) +@arg_alias +def create_exporter_config(alias, endpoint, token): + """Create an exporter config.""" + try: + ExporterConfigV1Alpha1.load(alias) + except FileNotFoundError: + pass + else: + raise click.ClickException(f'exporter "{alias}" exists') + + config = ExporterConfigV1Alpha1( + alias=alias, + endpoint=endpoint, + token=token, + ) + ExporterConfigV1Alpha1.save(config) + + +@click.command("delete-config") +@arg_alias +def delete_exporter_config(alias): + """Delete an exporter config.""" + try: + ExporterConfigV1Alpha1.load(alias) + except FileNotFoundError as err: + raise click.ClickException(f'exporter "{alias}" does not exist') from err + ExporterConfigV1Alpha1.delete(alias) + + +@click.command("edit-config") +@arg_alias +def edit_exporter_config(alias): + """Edit an exporter config.""" + try: + config = ExporterConfigV1Alpha1.load(alias) + except FileNotFoundError as err: + raise click.ClickException(f'exporter "{alias}" does not exist') from err + click.edit(filename=config.path) + + +@click.command("list-configs") +def list_exporter_configs(): + """List exporter configs.""" + exporters = ExporterConfigV1Alpha1.list() + columns = ["ALIAS", "PATH"] + rows = [ + { + "ALIAS": exporter.alias, + "PATH": str(exporter.path), + } + for exporter in exporters + ] + click.echo(make_table(columns, rows)) diff --git a/jumpstarter/cli/exporter_test.py b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_test.py similarity index 60% rename from jumpstarter/cli/exporter_test.py rename to packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_test.py index f7717121a..f3824fd21 100644 --- a/jumpstarter/cli/exporter_test.py +++ b/packages/jumpstarter-cli-exporter/jumpstarter_cli_exporter/exporter_test.py @@ -1,47 +1,52 @@ import pytest from asyncclick.testing import CliRunner - from jumpstarter.config.exporter import ExporterConfigV1Alpha1 -from .exporter import exporter +from . import exporter @pytest.fixture def tmp_config_path(tmp_path, monkeypatch): monkeypatch.setattr(ExporterConfigV1Alpha1, "BASE_PATH", tmp_path) + @pytest.mark.anyio async def test_exporter(tmp_config_path): runner = CliRunner() # create exporter non-interactively - result = await runner.invoke(exporter, ["create", "test1", "--endpoint", "example.com:443", "--token", "dummy"]) + result = await runner.invoke( + exporter, ["create-config", "test1", "--endpoint", "example.com:443", "--token", "dummy"] + ) assert result.exit_code == 0 # create duplicate exporter - result = await runner.invoke(exporter, ["create", "test1", "--endpoint", "example.com:443", "--token", "dummy"]) + result = await runner.invoke( + exporter, ["create-config", "test1", "--endpoint", "example.com:443", "--token", "dummy"] + ) assert result.exit_code != 0 # create exporter interactively - result = await runner.invoke(exporter, ["create", "test2"], input="example.org:443\ndummytoken\n") + result = await runner.invoke(exporter, ["create-config", "test2"], input="example.org:443\ndummytoken\n") assert result.exit_code == 0 # list exporters - result = await runner.invoke(exporter, ["list"]) + result = await runner.invoke(exporter, ["list-configs"]) assert result.exit_code == 0 assert "test1" in result.output assert "test2" in result.output # delete exporter - result = await runner.invoke(exporter, ["delete", "test2"]) + result = await runner.invoke(exporter, ["delete-config", "test2"]) assert result.exit_code == 0 ## list exporters - result = await runner.invoke(exporter, ["list"]) + result = await runner.invoke(exporter, ["list-configs"]) assert result.exit_code == 0 assert "test1" in result.output assert "test2" not in result.output + @pytest.fixture def anyio_backend(): return "asyncio" diff --git a/packages/jumpstarter-cli-exporter/pyproject.toml b/packages/jumpstarter-cli-exporter/pyproject.toml new file mode 100644 index 000000000..15fe94fc6 --- /dev/null +++ b/packages/jumpstarter-cli-exporter/pyproject.toml @@ -0,0 +1,42 @@ +[project] +name = "jumpstarter-cli-exporter" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Nick Cao", email = "ncao@redhat.com" }, + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter-cli-common", + "asyncclick>=8.1.7.2", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[project.scripts] +jmp-client = "jumpstarter_cli_exporter:exporter" + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter_cli_exporter"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-cli/README.md b/packages/jumpstarter-cli/README.md new file mode 100644 index 000000000..105e567fb --- /dev/null +++ b/packages/jumpstarter-cli/README.md @@ -0,0 +1 @@ +# The Jumpstarter CLI \ No newline at end of file diff --git a/packages/jumpstarter-cli/jumpstarter_cli/__init__.py b/packages/jumpstarter-cli/jumpstarter_cli/__init__.py new file mode 100644 index 000000000..a32f07830 --- /dev/null +++ b/packages/jumpstarter-cli/jumpstarter_cli/__init__.py @@ -0,0 +1,19 @@ +import asyncclick as click +from jumpstarter_cli_admin import admin +from jumpstarter_cli_client import client +from jumpstarter_cli_common import AliasedGroup, version +from jumpstarter_cli_exporter import exporter + + +@click.group(cls=AliasedGroup) +def jmp(): + """The Jumpstarter CLI""" + + +jmp.add_command(client) +jmp.add_command(exporter) +jmp.add_command(admin) +jmp.add_command(version) + +if __name__ == "__main__": + jmp() diff --git a/packages/jumpstarter-cli/jumpstarter_cli/__main__.py b/packages/jumpstarter-cli/jumpstarter_cli/__main__.py new file mode 100644 index 000000000..95a4f5ac9 --- /dev/null +++ b/packages/jumpstarter-cli/jumpstarter_cli/__main__.py @@ -0,0 +1,6 @@ +"""Allow running Jumpstarter through `python -m jumpstarter-cli`.""" + +from . import jmp + +if __name__ == "__main__": + jmp(prog_name="jmp") diff --git a/packages/jumpstarter-cli/jumpstarter_cli/cli_test.py b/packages/jumpstarter-cli/jumpstarter_cli/cli_test.py new file mode 100644 index 000000000..51c9d5084 --- /dev/null +++ b/packages/jumpstarter-cli/jumpstarter_cli/cli_test.py @@ -0,0 +1,19 @@ +import pytest +from asyncclick.testing import CliRunner + +from . import jmp + + +@pytest.mark.anyio +async def test_cli(): + runner = CliRunner() + result = await runner.invoke(jmp, []) + assert "admin" in result.output + assert "client" in result.output + assert "exporter" in result.output + assert "version" in result.output + + +@pytest.fixture +def anyio_backend(): + return "asyncio" diff --git a/packages/jumpstarter-cli/pyproject.toml b/packages/jumpstarter-cli/pyproject.toml new file mode 100644 index 000000000..97b3a63b5 --- /dev/null +++ b/packages/jumpstarter-cli/pyproject.toml @@ -0,0 +1,43 @@ +[project] +name = "jumpstarter-cli" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Nick Cao", email = "ncao@redhat.com" }, + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter-cli-admin", + "jumpstarter-cli-client", + "jumpstarter-cli-exporter", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[project.scripts] +jmp = "jumpstarter_cli:jmp" + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter_cli"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../' } + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/contrib/drivers/can/README.md b/packages/jumpstarter-driver-can/README.md similarity index 100% rename from contrib/drivers/can/README.md rename to packages/jumpstarter-driver-can/README.md diff --git a/contrib/drivers/can/jumpstarter_driver_can/__init__.py b/packages/jumpstarter-driver-can/jumpstarter_driver_can/__init__.py similarity index 100% rename from contrib/drivers/can/jumpstarter_driver_can/__init__.py rename to packages/jumpstarter-driver-can/jumpstarter_driver_can/__init__.py diff --git a/contrib/drivers/can/jumpstarter_driver_can/client.py b/packages/jumpstarter-driver-can/jumpstarter_driver_can/client.py similarity index 99% rename from contrib/drivers/can/jumpstarter_driver_can/client.py rename to packages/jumpstarter-driver-can/jumpstarter_driver_can/client.py index 3555ec0ce..bf86a2b3b 100644 --- a/contrib/drivers/can/jumpstarter_driver_can/client.py +++ b/packages/jumpstarter-driver-can/jumpstarter_driver_can/client.py @@ -8,9 +8,8 @@ import can import isotp from can.bus import _SelfRemovingCyclicTask -from pydantic import ConfigDict, validate_call - from jumpstarter.client import DriverClient +from pydantic import ConfigDict, validate_call from .common import CanMessage, IsoTpAddress, IsoTpAsymmetricAddress, IsoTpMessage diff --git a/contrib/drivers/can/jumpstarter_driver_can/client_test.py b/packages/jumpstarter-driver-can/jumpstarter_driver_can/client_test.py similarity index 100% rename from contrib/drivers/can/jumpstarter_driver_can/client_test.py rename to packages/jumpstarter-driver-can/jumpstarter_driver_can/client_test.py index fe73e8d0a..88c130af6 100644 --- a/contrib/drivers/can/jumpstarter_driver_can/client_test.py +++ b/packages/jumpstarter-driver-can/jumpstarter_driver_can/client_test.py @@ -6,8 +6,8 @@ import can import isotp import pytest - from jumpstarter.common.utils import serve + from jumpstarter_driver_can.common import IsoTpParams from jumpstarter_driver_can.driver import Can, IsoTpPython, IsoTpSocket diff --git a/contrib/drivers/can/jumpstarter_driver_can/common.py b/packages/jumpstarter-driver-can/jumpstarter_driver_can/common.py similarity index 100% rename from contrib/drivers/can/jumpstarter_driver_can/common.py rename to packages/jumpstarter-driver-can/jumpstarter_driver_can/common.py diff --git a/contrib/drivers/can/jumpstarter_driver_can/driver.py b/packages/jumpstarter-driver-can/jumpstarter_driver_can/driver.py similarity index 99% rename from contrib/drivers/can/jumpstarter_driver_can/driver.py rename to packages/jumpstarter-driver-can/jumpstarter_driver_can/driver.py index 177d341ee..96f2c06eb 100644 --- a/contrib/drivers/can/jumpstarter_driver_can/driver.py +++ b/packages/jumpstarter-driver-can/jumpstarter_driver_can/driver.py @@ -4,11 +4,10 @@ import can import isotp +from jumpstarter.driver import Driver, export from pydantic import ConfigDict, validate_call from pydantic.dataclasses import dataclass -from jumpstarter.driver import Driver, export - from .common import CanMessage, IsoTpAddress, IsoTpAsymmetricAddress, IsoTpMessage, IsoTpParams diff --git a/contrib/drivers/can/pyproject.toml b/packages/jumpstarter-driver-can/pyproject.toml similarity index 92% rename from contrib/drivers/can/pyproject.toml rename to packages/jumpstarter-driver-can/pyproject.toml index c41cf7247..a429a2aa9 100644 --- a/contrib/drivers/can/pyproject.toml +++ b/packages/jumpstarter-driver-can/pyproject.toml @@ -12,7 +12,7 @@ license = { text = "Apache-2.0" } requires-python = ">=3.11" dependencies = [ "jumpstarter", - "python-can>=4.4.2", + "python-can>=4.5.0", "can-isotp>=2.0.6", ] @@ -28,7 +28,8 @@ source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}. [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} + [build-system] requires = ["hatchling", "hatch-vcs"] build-backend = "hatchling.build" diff --git a/packages/jumpstarter-driver-composite/README.md b/packages/jumpstarter-driver-composite/README.md new file mode 100644 index 000000000..8b8344e69 --- /dev/null +++ b/packages/jumpstarter-driver-composite/README.md @@ -0,0 +1 @@ +# Jumpstarter Composite Driver \ No newline at end of file diff --git a/contrib/drivers/dutlink/jumpstarter_driver_dutlink/__init__.py b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/__init__.py similarity index 100% rename from contrib/drivers/dutlink/jumpstarter_driver_dutlink/__init__.py rename to packages/jumpstarter-driver-composite/jumpstarter_driver_composite/__init__.py diff --git a/jumpstarter/drivers/composite/client.py b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/client.py similarity index 99% rename from jumpstarter/drivers/composite/client.py rename to packages/jumpstarter-driver-composite/jumpstarter_driver_composite/client.py index fed7d169e..273e0434f 100644 --- a/jumpstarter/drivers/composite/client.py +++ b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/client.py @@ -1,7 +1,6 @@ from dataclasses import dataclass import asyncclick as click - from jumpstarter.client import DriverClient diff --git a/jumpstarter/drivers/composite/driver.py b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/driver.py similarity index 76% rename from jumpstarter/drivers/composite/driver.py rename to packages/jumpstarter-driver-composite/jumpstarter_driver_composite/driver.py index 57cdb878c..438ce317b 100644 --- a/jumpstarter/drivers/composite/driver.py +++ b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/driver.py @@ -1,12 +1,11 @@ -from pydantic.dataclasses import dataclass - from jumpstarter.driver import Driver +from pydantic.dataclasses import dataclass class CompositeInterface: @classmethod def client(cls) -> str: - return "jumpstarter.drivers.composite.client.CompositeClient" + return "jumpstarter_driver_composite.client.CompositeClient" @dataclass(kw_only=True) diff --git a/jumpstarter/drivers/composite/driver_test.py b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/driver_test.py similarity index 80% rename from jumpstarter/drivers/composite/driver_test.py rename to packages/jumpstarter-driver-composite/jumpstarter_driver_composite/driver_test.py index 05614c21b..b2adf6d02 100644 --- a/jumpstarter/drivers/composite/driver_test.py +++ b/packages/jumpstarter-driver-composite/jumpstarter_driver_composite/driver_test.py @@ -1,6 +1,7 @@ from jumpstarter.common.utils import serve -from jumpstarter.drivers.composite.driver import Composite -from jumpstarter.drivers.power.driver import MockPower +from jumpstarter_driver_power.driver import MockPower + +from .driver import Composite def test_drivers_composite(): diff --git a/contrib/drivers/dutlink/pyproject.toml b/packages/jumpstarter-driver-composite/pyproject.toml similarity index 79% rename from contrib/drivers/dutlink/pyproject.toml rename to packages/jumpstarter-driver-composite/pyproject.toml index 8b2d3a83a..e5e2015ef 100644 --- a/contrib/drivers/dutlink/pyproject.toml +++ b/packages/jumpstarter-driver-composite/pyproject.toml @@ -1,25 +1,24 @@ [project] -name = "jumpstarter-driver-dutlink" +name = "jumpstarter-driver-composite" dynamic = ["version", "urls"] description = "" authors = [ { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, { name = "Nick Cao", email = "ncao@redhat.com" }, - { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, ] readme = "README.md" license = { text = "Apache-2.0" } requires-python = ">=3.11" dependencies = [ "jumpstarter", - "pyudev>=0.24.3", - "pyusb>=1.2.1", + "asyncclick>=8.1.7.2" ] [dependency-groups] dev = [ "pytest>=8.3.2", "pytest-cov>=5.0.0", + "jumpstarter-driver-power" ] [tool.hatch.metadata.hooks.vcs.urls] @@ -28,7 +27,7 @@ source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}. [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [build-system] requires = ["hatchling", "hatch-vcs"] diff --git a/contrib/drivers/dutlink/README.md b/packages/jumpstarter-driver-dutlink/README.md similarity index 100% rename from contrib/drivers/dutlink/README.md rename to packages/jumpstarter-driver-dutlink/README.md diff --git a/contrib/drivers/dutlink/examples/dutlink.py b/packages/jumpstarter-driver-dutlink/examples/dutlink.py similarity index 96% rename from contrib/drivers/dutlink/examples/dutlink.py rename to packages/jumpstarter-driver-dutlink/examples/dutlink.py index 02cec55ec..b04840f40 100755 --- a/contrib/drivers/dutlink/examples/dutlink.py +++ b/packages/jumpstarter-driver-dutlink/examples/dutlink.py @@ -3,9 +3,8 @@ import time import asyncclick as click - -from jumpstarter.client.adapters import PexpectAdapter from jumpstarter.common.utils import env +from jumpstarter_driver_network.adapters import PexpectAdapter # initialize client from exporter config # from jumpstarter.common import MetadataFilter diff --git a/contrib/drivers/dutlink/examples/exporter.yaml b/packages/jumpstarter-driver-dutlink/examples/exporter.yaml similarity index 100% rename from contrib/drivers/dutlink/examples/exporter.yaml rename to packages/jumpstarter-driver-dutlink/examples/exporter.yaml diff --git a/contrib/drivers/http/src/jumpstarter_driver_http/__init__.py b/packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/__init__.py similarity index 100% rename from contrib/drivers/http/src/jumpstarter_driver_http/__init__.py rename to packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/__init__.py diff --git a/contrib/drivers/dutlink/jumpstarter_driver_dutlink/driver.py b/packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver.py similarity index 97% rename from contrib/drivers/dutlink/jumpstarter_driver_dutlink/driver.py rename to packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver.py index 3cda69e05..b8210de56 100644 --- a/contrib/drivers/dutlink/jumpstarter_driver_dutlink/driver.py +++ b/packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver.py @@ -11,13 +11,12 @@ import usb.util from anyio import fail_after, sleep from anyio.streams.file import FileReadStream, FileWriteStream -from serial.serialutil import SerialException - from jumpstarter.driver import Driver, export -from jumpstarter.drivers.composite.driver import CompositeInterface -from jumpstarter.drivers.power.driver import PowerInterface, PowerReading -from jumpstarter.drivers.pyserial.driver import PySerial -from jumpstarter.drivers.storage.driver import StorageMuxInterface +from jumpstarter_driver_composite.driver import CompositeInterface +from jumpstarter_driver_opendal.driver import StorageMuxInterface +from jumpstarter_driver_power.driver import PowerInterface, PowerReading +from jumpstarter_driver_pyserial.driver import PySerial +from serial.serialutil import SerialException log = logging.getLogger(__name__) diff --git a/contrib/drivers/dutlink/jumpstarter_driver_dutlink/driver_test.py b/packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver_test.py similarity index 94% rename from contrib/drivers/dutlink/jumpstarter_driver_dutlink/driver_test.py rename to packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver_test.py index c877bbb39..efab289d4 100644 --- a/contrib/drivers/dutlink/jumpstarter_driver_dutlink/driver_test.py +++ b/packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/driver_test.py @@ -1,8 +1,8 @@ import pytest import usb - -from jumpstarter.client.adapters import PexpectAdapter from jumpstarter.common.utils import serve +from jumpstarter_driver_network.adapters import PexpectAdapter + from jumpstarter_driver_dutlink.driver import Dutlink diff --git a/packages/jumpstarter-driver-dutlink/pyproject.toml b/packages/jumpstarter-driver-dutlink/pyproject.toml new file mode 100644 index 000000000..7878a2267 --- /dev/null +++ b/packages/jumpstarter-driver-dutlink/pyproject.toml @@ -0,0 +1,41 @@ +[project] +name = "jumpstarter-driver-dutlink" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Nick Cao", email = "ncao@redhat.com" }, + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "jumpstarter-driver-composite", + "jumpstarter-driver-pyserial", + "jumpstarter-driver-opendal", + "jumpstarter-driver-network", + "jumpstarter-driver-power", + "pyudev>=0.24.3", + "pyusb>=1.2.1", + "asyncclick>=8.1.7.2" +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=5.0.0", +] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/contrib/drivers/http/README.md b/packages/jumpstarter-driver-http/README.md similarity index 100% rename from contrib/drivers/http/README.md rename to packages/jumpstarter-driver-http/README.md diff --git a/contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/__init__.py b/packages/jumpstarter-driver-http/jumpstarter_driver_http/__init__.py similarity index 100% rename from contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/__init__.py rename to packages/jumpstarter-driver-http/jumpstarter_driver_http/__init__.py diff --git a/contrib/drivers/http/src/jumpstarter_driver_http/client.py b/packages/jumpstarter-driver-http/jumpstarter_driver_http/client.py similarity index 92% rename from contrib/drivers/http/src/jumpstarter_driver_http/client.py rename to packages/jumpstarter-driver-http/jumpstarter_driver_http/client.py index d718bc4a2..cf68516e0 100644 --- a/contrib/drivers/http/src/jumpstarter_driver_http/client.py +++ b/packages/jumpstarter-driver-http/jumpstarter_driver_http/client.py @@ -1,10 +1,9 @@ from dataclasses import dataclass from pathlib import Path -from opendal import Operator - from jumpstarter.client import DriverClient -from jumpstarter.client.adapters.opendal import OpendalAdapter +from jumpstarter_driver_opendal.adapter import OpendalAdapter +from opendal import Operator @dataclass(kw_only=True) @@ -68,12 +67,7 @@ def put_local_file(self, filepath: str) -> str: >>> client.put_local_file("/path/to/local/file.txt") """ absolute = Path(filepath).resolve() - with OpendalAdapter( - client=self, - operator=Operator("fs", root="/"), - path=str(absolute), - mode="rb" - ) as handle: + with OpendalAdapter(client=self, operator=Operator("fs", root="/"), path=str(absolute), mode="rb") as handle: return self.call("put_file", absolute.name, handle) def delete_file(self, filename: str) -> str: diff --git a/contrib/drivers/http/src/jumpstarter_driver_http/driver.py b/packages/jumpstarter-driver-http/jumpstarter_driver_http/driver.py similarity index 97% rename from contrib/drivers/http/src/jumpstarter_driver_http/driver.py rename to packages/jumpstarter-driver-http/jumpstarter_driver_http/driver.py index 060e1a5a9..08ba20308 100644 --- a/contrib/drivers/http/src/jumpstarter_driver_http/driver.py +++ b/packages/jumpstarter-driver-http/jumpstarter_driver_http/driver.py @@ -7,7 +7,6 @@ import anyio from aiohttp import web from anyio.streams.file import FileWriteStream - from jumpstarter.driver import Driver, export logger = logging.getLogger(__name__) @@ -48,9 +47,11 @@ class HttpServer(Driver): def __post_init__(self): super().__post_init__() os.makedirs(self.root_dir, exist_ok=True) - self.app.router.add_routes([ - web.get('/{filename}', self.get_file), - ]) + self.app.router.add_routes( + [ + web.get("/{filename}", self.get_file), + ] + ) @classmethod def client(cls) -> str: @@ -129,7 +130,7 @@ async def get_file(self, request) -> web.FileResponse: Raises: web.HTTPNotFound: If the requested file does not exist. """ - filename = request.match_info['filename'] + filename = request.match_info["filename"] file_path = os.path.join(self.root_dir, filename) if not os.path.isfile(file_path): logger.warning(f"File not found: {file_path}") @@ -170,7 +171,7 @@ async def start(self): self.runner = web.AppRunner(self.app) if self.runner: - await self.runner.setup() + await self.runner.setup() site = web.TCPSite(self.runner, self.host, self.port) await site.start() diff --git a/contrib/drivers/http/src/jumpstarter_driver_http/driver_test.py b/packages/jumpstarter-driver-http/jumpstarter_driver_http/driver_test.py similarity index 99% rename from contrib/drivers/http/src/jumpstarter_driver_http/driver_test.py rename to packages/jumpstarter-driver-http/jumpstarter_driver_http/driver_test.py index 2a47da734..519fce79a 100644 --- a/contrib/drivers/http/src/jumpstarter_driver_http/driver_test.py +++ b/packages/jumpstarter-driver-http/jumpstarter_driver_http/driver_test.py @@ -6,7 +6,6 @@ import anyio import pytest from anyio import create_memory_object_stream - from jumpstarter.common.resources import ClientStreamResource from .driver import HttpServer @@ -16,11 +15,13 @@ def anyio_backend(): return "asyncio" + @pytest.fixture def temp_dir(): with TemporaryDirectory() as tmpdir: yield tmpdir + @pytest.fixture async def server(temp_dir): server = HttpServer(root_dir=temp_dir) @@ -30,6 +31,7 @@ async def server(temp_dir): finally: await server.stop() + @pytest.mark.anyio async def test_http_server(server): filename = "test.txt" @@ -67,11 +69,13 @@ async def send_data(): files_after_deletion = server.list_files() assert filename not in files_after_deletion + def test_http_server_host_config(temp_dir): custom_host = "192.168.1.1" server = HttpServer(root_dir=temp_dir, host=custom_host) assert server.get_host() == custom_host + def test_http_server_root_directory_creation(temp_dir): new_dir = os.path.join(temp_dir, "new_http_root") _ = HttpServer(root_dir=new_dir) diff --git a/contrib/drivers/http/pyproject.toml b/packages/jumpstarter-driver-http/pyproject.toml similarity index 89% rename from contrib/drivers/http/pyproject.toml rename to packages/jumpstarter-driver-http/pyproject.toml index 07b0452d5..a1744e951 100644 --- a/contrib/drivers/http/pyproject.toml +++ b/packages/jumpstarter-driver-http/pyproject.toml @@ -10,11 +10,12 @@ requires-python = ">=3.12" dependencies = [ "anyio>=4.6.2.post1", "jumpstarter", + "jumpstarter-driver-opendal" ] [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [tool.hatch.metadata.hooks.vcs.urls] Homepage = "https://jumpstarter.dev" @@ -33,6 +34,7 @@ build-backend = "hatchling.build" dev = [ "pytest-cov>=6.0.0", "pytest>=8.3.3", + "pytest-asyncio>=0.0.0", "ruff>=0.7.1", "pytest-asyncio>=0.24.0", ] diff --git a/packages/jumpstarter-driver-network/README.md b/packages/jumpstarter-driver-network/README.md new file mode 100644 index 000000000..3de611b91 --- /dev/null +++ b/packages/jumpstarter-driver-network/README.md @@ -0,0 +1 @@ +# Jumpstarter Generic Network Driver \ No newline at end of file diff --git a/contrib/drivers/sdwire/jumpstarter_driver_sdwire/__init__.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/__init__.py similarity index 100% rename from contrib/drivers/sdwire/jumpstarter_driver_sdwire/__init__.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/__init__.py diff --git a/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/__init__.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/__init__.py new file mode 100644 index 000000000..cc043bced --- /dev/null +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/__init__.py @@ -0,0 +1,6 @@ +from .fabric import FabricAdapter +from .novnc import NovncAdapter +from .pexpect import PexpectAdapter +from .portforward import PortforwardAdapter + +__all__ = ["FabricAdapter", "NovncAdapter", "PexpectAdapter", "PortforwardAdapter"] diff --git a/jumpstarter/client/adapters/fabric.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/fabric.py similarity index 100% rename from jumpstarter/client/adapters/fabric.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/fabric.py diff --git a/jumpstarter/client/adapters/fabric_test.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/fabric_test.py similarity index 92% rename from jumpstarter/client/adapters/fabric_test.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/fabric_test.py index 4bb7cf79d..6845e257b 100644 --- a/jumpstarter/client/adapters/fabric_test.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/fabric_test.py @@ -2,12 +2,12 @@ from threading import Thread from time import sleep +from jumpstarter.common.utils import serve from paramiko import AUTH_SUCCESSFUL, OPEN_SUCCEEDED, ServerInterface, Transport from paramiko.rsakey import RSAKey -from jumpstarter.client.adapters import FabricAdapter -from jumpstarter.common.utils import serve -from jumpstarter.drivers.network.driver import TcpNetwork +from ..driver import TcpNetwork +from .fabric import FabricAdapter class SSHServer(ServerInterface): diff --git a/jumpstarter/client/adapters/novnc.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc.py similarity index 90% rename from jumpstarter/client/adapters/novnc.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc.py index fcde6108b..46cbcdb54 100644 --- a/jumpstarter/client/adapters/novnc.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc.py @@ -1,8 +1,9 @@ from dataclasses import dataclass from urllib.parse import urlencode, urlunparse -from jumpstarter.streams import WebsocketServerStream, forward_stream +from jumpstarter.streams import forward_stream +from ..streams import WebsocketServerStream from .portforward import PortforwardAdapter diff --git a/jumpstarter/client/adapters/novnc_test.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc_test.py similarity index 90% rename from jumpstarter/client/adapters/novnc_test.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc_test.py index e5ff861e7..f3b5deaab 100644 --- a/jumpstarter/client/adapters/novnc_test.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc_test.py @@ -2,12 +2,12 @@ from urllib.parse import parse_qsl, urlparse from anyio.from_thread import start_blocking_portal -from websocket import create_connection - -from jumpstarter.client.adapters import NovncAdapter from jumpstarter.common import TemporaryTcpListener from jumpstarter.common.utils import serve -from jumpstarter.drivers.network.driver import TcpNetwork +from websocket import create_connection + +from ..driver import TcpNetwork +from .novnc import NovncAdapter async def echo_handler(stream): diff --git a/jumpstarter/client/adapters/pexpect.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/pexpect.py similarity index 100% rename from jumpstarter/client/adapters/pexpect.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/pexpect.py diff --git a/jumpstarter/client/adapters/portforward.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/portforward.py similarity index 94% rename from jumpstarter/client/adapters/portforward.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/portforward.py index b4dca1c71..c180fb340 100644 --- a/jumpstarter/client/adapters/portforward.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/portforward.py @@ -1,10 +1,9 @@ from dataclasses import dataclass +from jumpstarter.client.adapters import ClientAdapter from jumpstarter.common import TemporaryTcpListener from jumpstarter.streams import forward_stream -from .common import ClientAdapter - @dataclass(kw_only=True) class PortforwardAdapter(ClientAdapter): diff --git a/jumpstarter/drivers/network/client.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/client.py similarity index 100% rename from jumpstarter/drivers/network/client.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/client.py diff --git a/jumpstarter/drivers/network/driver.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/driver.py similarity index 96% rename from jumpstarter/drivers/network/driver.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/driver.py index b88763606..8b2293ef7 100644 --- a/jumpstarter/drivers/network/driver.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/driver.py @@ -10,7 +10,6 @@ create_memory_object_stream, ) from anyio.streams.stapled import StapledObjectStream - from jumpstarter.driver import Driver, exportstream logger = logging.getLogger(__name__) @@ -19,7 +18,7 @@ class NetworkInterface(metaclass=ABCMeta): @classmethod def client(cls) -> str: - return "jumpstarter.drivers.network.client.NetworkClient" + return "jumpstarter_driver_network.client.NetworkClient" @abstractmethod @asynccontextmanager diff --git a/jumpstarter/drivers/network/driver_test.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/driver_test.py similarity index 95% rename from jumpstarter/drivers/network/driver_test.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/driver_test.py index 8dd41f083..647e229be 100644 --- a/jumpstarter/drivers/network/driver_test.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/driver_test.py @@ -5,11 +5,11 @@ import pytest from anyio.from_thread import start_blocking_portal - -from jumpstarter.client.adapters import PortforwardAdapter from jumpstarter.common import TemporaryTcpListener, TemporaryUnixListener from jumpstarter.common.utils import serve -from jumpstarter.drivers.network.driver import EchoNetwork, TcpNetwork, UdpNetwork, UnixNetwork + +from .adapters import PortforwardAdapter +from .driver import EchoNetwork, TcpNetwork, UdpNetwork, UnixNetwork def test_echo_network(): diff --git a/packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/__init__.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/__init__.py new file mode 100644 index 000000000..786b8e4e1 --- /dev/null +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/__init__.py @@ -0,0 +1,3 @@ +from .websocket import WebsocketServerStream + +__all__ = ["WebsocketServerStream"] diff --git a/jumpstarter/streams/websocket.py b/packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/websocket.py similarity index 95% rename from jumpstarter/streams/websocket.py rename to packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/websocket.py index 49beb43be..e79ed07c8 100644 --- a/jumpstarter/streams/websocket.py +++ b/packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/websocket.py @@ -1,5 +1,6 @@ from contextlib import suppress from dataclasses import dataclass, field +from typing import Tuple from anyio import BrokenResourceError, WouldBlock, create_memory_object_stream from anyio.abc import AnyByteStream, ObjectStream @@ -22,7 +23,7 @@ class WebsocketServerStream(ObjectStream[bytes]): stream: AnyByteStream ws: WSConnection = field(init=False, default_factory=lambda: WSConnection(ConnectionType.SERVER)) - queue: (MemoryObjectSendStream[bytes], MemoryObjectReceiveStream[bytes]) = field( + queue: Tuple[MemoryObjectSendStream[bytes], MemoryObjectReceiveStream[bytes]] = field( init=False, default_factory=lambda: create_memory_object_stream[bytes](32) ) diff --git a/packages/jumpstarter-driver-network/pyproject.toml b/packages/jumpstarter-driver-network/pyproject.toml new file mode 100644 index 000000000..1e01f85aa --- /dev/null +++ b/packages/jumpstarter-driver-network/pyproject.toml @@ -0,0 +1,36 @@ +[project] +name = "jumpstarter-driver-network" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Nick Cao", email = "ncao@redhat.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "pexpect>=4.9.0", + "fabric>=3.2.2", + "wsproto>=1.2.0" +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=5.0.0", + "websocket-client>=1.8.0" +] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-driver-opendal/README.md b/packages/jumpstarter-driver-opendal/README.md new file mode 100644 index 000000000..e361e0070 --- /dev/null +++ b/packages/jumpstarter-driver-opendal/README.md @@ -0,0 +1 @@ +# Jumpstarter OpenDAL Storage Driver \ No newline at end of file diff --git a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/__init__.py b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/__init__.py similarity index 100% rename from contrib/drivers/tftp/src/jumpstarter_driver_tftp/__init__.py rename to packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/__init__.py diff --git a/jumpstarter/client/adapters/opendal.py b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/adapter.py similarity index 97% rename from jumpstarter/client/adapters/opendal.py rename to packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/adapter.py index 82a5a7b8e..a94be7948 100644 --- a/jumpstarter/client/adapters/opendal.py +++ b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/adapter.py @@ -4,13 +4,11 @@ from anyio import BrokenResourceError, EndOfStream from anyio.abc import ObjectStream +from jumpstarter.client.adapters import ClientAdapter +from jumpstarter.common.resources import PresignedRequestResource from opendal import AsyncFile, Operator from opendal.exceptions import Error -from jumpstarter.common.resources import PresignedRequestResource - -from .common import ClientAdapter - @dataclass(frozen=True, kw_only=True, slots=True) class AsyncFileStream(ObjectStream[bytes]): diff --git a/jumpstarter/drivers/storage/client.py b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/client.py similarity index 97% rename from jumpstarter/drivers/storage/client.py rename to packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/client.py index 186a0e76c..261a86069 100644 --- a/jumpstarter/drivers/storage/client.py +++ b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/client.py @@ -1,10 +1,10 @@ from pathlib import Path import asyncclick as click +from jumpstarter.client import DriverClient from opendal import Operator -from jumpstarter.client import DriverClient -from jumpstarter.client.adapters import OpendalAdapter +from .adapter import OpendalAdapter class StorageMuxClient(DriverClient): diff --git a/jumpstarter/drivers/storage/driver.py b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/driver.py similarity index 95% rename from jumpstarter/drivers/storage/driver.py rename to packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/driver.py index cd72636f6..47d36f19b 100644 --- a/jumpstarter/drivers/storage/driver.py +++ b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/driver.py @@ -3,14 +3,13 @@ from tempfile import NamedTemporaryFile from anyio.streams.file import FileReadStream, FileWriteStream - from jumpstarter.driver import Driver, export class StorageMuxInterface(metaclass=ABCMeta): @classmethod def client(cls) -> str: - return "jumpstarter.drivers.storage.client.StorageMuxClient" + return "jumpstarter_driver_opendal.client.StorageMuxClient" @abstractmethod async def host(self): ... diff --git a/jumpstarter/drivers/storage/driver_test.py b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/driver_test.py similarity index 97% rename from jumpstarter/drivers/storage/driver_test.py rename to packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/driver_test.py index 2fe55a336..90221b443 100644 --- a/jumpstarter/drivers/storage/driver_test.py +++ b/packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/driver_test.py @@ -5,10 +5,10 @@ from threading import Thread import pytest +from jumpstarter.common.utils import serve from opendal import Operator -from jumpstarter.common.utils import serve -from jumpstarter.drivers.storage.driver import MockStorageMux +from .driver import MockStorageMux def test_drivers_mock_storage_mux_fs(monkeypatch: pytest.MonkeyPatch): diff --git a/packages/jumpstarter-driver-opendal/pyproject.toml b/packages/jumpstarter-driver-opendal/pyproject.toml new file mode 100644 index 000000000..2f89c3934 --- /dev/null +++ b/packages/jumpstarter-driver-opendal/pyproject.toml @@ -0,0 +1,34 @@ +[project] +name = "jumpstarter-driver-opendal" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Nick Cao", email = "ncao@redhat.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "opendal>=0.45.8", + "asyncclick>=8.1.7.2" +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=5.0.0", +] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-driver-power/README.md b/packages/jumpstarter-driver-power/README.md new file mode 100644 index 000000000..28e04653a --- /dev/null +++ b/packages/jumpstarter-driver-power/README.md @@ -0,0 +1 @@ +# Jumpstarter Power Driver Interface \ No newline at end of file diff --git a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/__init__.py b/packages/jumpstarter-driver-power/jumpstarter_driver_power/__init__.py similarity index 100% rename from contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/__init__.py rename to packages/jumpstarter-driver-power/jumpstarter_driver_power/__init__.py diff --git a/jumpstarter/drivers/power/client.py b/packages/jumpstarter-driver-power/jumpstarter_driver_power/client.py similarity index 99% rename from jumpstarter/drivers/power/client.py rename to packages/jumpstarter-driver-power/jumpstarter_driver_power/client.py index f9aa897d7..be2003773 100644 --- a/jumpstarter/drivers/power/client.py +++ b/packages/jumpstarter-driver-power/jumpstarter_driver_power/client.py @@ -1,7 +1,6 @@ from collections.abc import Generator import asyncclick as click - from jumpstarter.client import DriverClient from .common import PowerReading diff --git a/jumpstarter/drivers/power/client_test.py b/packages/jumpstarter-driver-power/jumpstarter_driver_power/client_test.py similarity index 83% rename from jumpstarter/drivers/power/client_test.py rename to packages/jumpstarter-driver-power/jumpstarter_driver_power/client_test.py index 7422f9196..d8dad4d9d 100644 --- a/jumpstarter/drivers/power/client_test.py +++ b/packages/jumpstarter-driver-power/jumpstarter_driver_power/client_test.py @@ -1,6 +1,7 @@ from jumpstarter.common.utils import serve -from jumpstarter.drivers.power.common import PowerReading -from jumpstarter.drivers.power.driver import MockPower, SyncMockPower + +from .common import PowerReading +from .driver import MockPower, SyncMockPower def test_client_mock_power(): diff --git a/jumpstarter/drivers/power/common.py b/packages/jumpstarter-driver-power/jumpstarter_driver_power/common.py similarity index 100% rename from jumpstarter/drivers/power/common.py rename to packages/jumpstarter-driver-power/jumpstarter_driver_power/common.py diff --git a/jumpstarter/drivers/power/driver.py b/packages/jumpstarter-driver-power/jumpstarter_driver_power/driver.py similarity index 86% rename from jumpstarter/drivers/power/driver.py rename to packages/jumpstarter-driver-power/jumpstarter_driver_power/driver.py index 21bf8a223..c31c9bd0c 100644 --- a/jumpstarter/drivers/power/driver.py +++ b/packages/jumpstarter-driver-power/jumpstarter_driver_power/driver.py @@ -1,5 +1,5 @@ from abc import ABCMeta, abstractmethod -from collections.abc import AsyncGenerator +from collections.abc import AsyncGenerator, Generator from jumpstarter.driver import Driver, export @@ -9,7 +9,7 @@ class PowerInterface(metaclass=ABCMeta): @classmethod def client(cls) -> str: - return "jumpstarter.drivers.power.client.PowerClient" + return "jumpstarter_driver_power.client.PowerClient" @abstractmethod async def on(self) -> str: ... @@ -46,6 +46,6 @@ def off(self) -> str: return "ok" @export - def read(self) -> AsyncGenerator[PowerReading, None]: + def read(self) -> Generator[PowerReading, None]: yield PowerReading(voltage=0.0, current=0.0) yield PowerReading(voltage=5.0, current=2.0) diff --git a/jumpstarter/drivers/power/driver_test.py b/packages/jumpstarter-driver-power/jumpstarter_driver_power/driver_test.py similarity index 82% rename from jumpstarter/drivers/power/driver_test.py rename to packages/jumpstarter-driver-power/jumpstarter_driver_power/driver_test.py index 06807deba..f0824ff47 100644 --- a/jumpstarter/drivers/power/driver_test.py +++ b/packages/jumpstarter-driver-power/jumpstarter_driver_power/driver_test.py @@ -1,7 +1,7 @@ import pytest -from jumpstarter.drivers.power.common import PowerReading -from jumpstarter.drivers.power.driver import MockPower, SyncMockPower +from .common import PowerReading +from .driver import MockPower, SyncMockPower pytestmark = pytest.mark.anyio diff --git a/packages/jumpstarter-driver-power/pyproject.toml b/packages/jumpstarter-driver-power/pyproject.toml new file mode 100644 index 000000000..19e7378a0 --- /dev/null +++ b/packages/jumpstarter-driver-power/pyproject.toml @@ -0,0 +1,35 @@ +[project] +name = "jumpstarter-driver-power" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Nick Cao", email = "ncao@redhat.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "pyserial>=3.5", + "asyncclick>=8.1.7.2" +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=5.0.0", + "trio>=0.28.0" +] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter-driver-pyserial/README.md b/packages/jumpstarter-driver-pyserial/README.md new file mode 100644 index 000000000..eeb22dae0 --- /dev/null +++ b/packages/jumpstarter-driver-pyserial/README.md @@ -0,0 +1 @@ +# Jumpstarter PySerial Driver \ No newline at end of file diff --git a/jumpstarter/cli/__init__.py b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/__init__.py similarity index 100% rename from jumpstarter/cli/__init__.py rename to packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/__init__.py diff --git a/jumpstarter/drivers/pyserial/client.py b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/client.py similarity index 95% rename from jumpstarter/drivers/pyserial/client.py rename to packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/client.py index 5acddd12f..f6640cc49 100644 --- a/jumpstarter/drivers/pyserial/client.py +++ b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/client.py @@ -1,16 +1,14 @@ from contextlib import contextmanager import asyncclick as click -from pexpect.fdpexpect import fdspawn - from jumpstarter.client import DriverClient -from jumpstarter.client.adapters import PexpectAdapter +from jumpstarter_driver_network.adapters import PexpectAdapter +from pexpect.fdpexpect import fdspawn from .console import Console class PySerialClient(DriverClient): - """ A client for handling serial communication using pexpect. diff --git a/jumpstarter/drivers/pyserial/console.py b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/console.py similarity index 93% rename from jumpstarter/drivers/pyserial/console.py rename to packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/console.py index 6934d440c..a022c0df7 100644 --- a/jumpstarter/drivers/pyserial/console.py +++ b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/console.py @@ -1,4 +1,3 @@ - import os import sys import termios @@ -9,7 +8,7 @@ class Console: - def __init__(self, serial_client:DriverClient): + def __init__(self, serial_client: DriverClient): self.serial_client = serial_client def run(self): @@ -28,7 +27,7 @@ def _run(self, stream): data = sys.stdin.buffer.read(1) if not data: continue - if data == b"\x02": # Ctrl-B + if data == b"\x02": # Ctrl-B ctrl_b_count += 1 if ctrl_b_count == 3: return @@ -51,4 +50,3 @@ def _copy_serial_to_stdout(self): sys.stdout.flush() finally: self._reset_terminal() - diff --git a/jumpstarter/drivers/pyserial/driver.py b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/driver.py similarity index 95% rename from jumpstarter/drivers/pyserial/driver.py rename to packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/driver.py index 7a0f60d67..69d4d0f88 100644 --- a/jumpstarter/drivers/pyserial/driver.py +++ b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/driver.py @@ -4,9 +4,8 @@ from anyio.abc import ObjectStream from anyio.to_thread import run_sync -from serial import Serial, serial_for_url - from jumpstarter.driver import Driver, exportstream +from serial import Serial, serial_for_url log = logging.getLogger(__name__) @@ -41,7 +40,7 @@ def __post_init__(self): @classmethod def client(cls) -> str: - return "jumpstarter.drivers.pyserial.client.PySerialClient" + return "jumpstarter_driver_pyserial.client.PySerialClient" @exportstream @asynccontextmanager diff --git a/jumpstarter/drivers/pyserial/driver_test.py b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/driver_test.py similarity index 84% rename from jumpstarter/drivers/pyserial/driver_test.py rename to packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/driver_test.py index 2394edb6d..87bf09872 100644 --- a/jumpstarter/drivers/pyserial/driver_test.py +++ b/packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/driver_test.py @@ -1,8 +1,9 @@ from typing import cast from jumpstarter.common.utils import serve -from jumpstarter.drivers.pyserial.client import PySerialClient -from jumpstarter.drivers.pyserial.driver import PySerial + +from .client import PySerialClient +from .driver import PySerial def test_bare_pyserial(): @@ -11,6 +12,7 @@ def test_bare_pyserial(): stream.send(b"hello") assert "hello".startswith(stream.receive().decode("utf-8")) + def test_bare_open_pyserial(): with serve(PySerial(url="loop://")) as client: client = cast(PySerialClient, client) @@ -19,13 +21,15 @@ def test_bare_open_pyserial(): assert "hello".startswith(stream.receive().decode("utf-8")) client.close() + def test_pexpect_open_pyserial_forget_close(): with serve(PySerial(url="loop://")) as client: - client = cast(PySerialClient, client) # this is only necessary for the editor to recognize the client methods + client = cast(PySerialClient, client) # this is only necessary for the editor to recognize the client methods pexpect = client.open() pexpect.sendline("hello") assert pexpect.expect("hello") == 0 + def test_pexpect_open_pyserial(): with serve(PySerial(url="loop://")) as client: client = cast(PySerialClient, client) @@ -34,6 +38,7 @@ def test_pexpect_open_pyserial(): assert pexpect.expect("hello") == 0 client.close() + def test_pexpect_context_pyserial(): with serve(PySerial(url="loop://")) as client: client = cast(PySerialClient, client) diff --git a/packages/jumpstarter-driver-pyserial/pyproject.toml b/packages/jumpstarter-driver-pyserial/pyproject.toml new file mode 100644 index 000000000..5330454c8 --- /dev/null +++ b/packages/jumpstarter-driver-pyserial/pyproject.toml @@ -0,0 +1,35 @@ +[project] +name = "jumpstarter-driver-pyserial" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Nick Cao", email = "ncao@redhat.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "jumpstarter-driver-network", + "pyserial>=3.5", + "asyncclick>=8.1.7.2" +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=5.0.0", +] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/contrib/drivers/raspberrypi/README.md b/packages/jumpstarter-driver-raspberrypi/README.md similarity index 100% rename from contrib/drivers/raspberrypi/README.md rename to packages/jumpstarter-driver-raspberrypi/README.md diff --git a/jumpstarter/drivers/composite/__init__.py b/packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/__init__.py similarity index 100% rename from jumpstarter/drivers/composite/__init__.py rename to packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/__init__.py diff --git a/contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/client.py b/packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/client.py similarity index 100% rename from contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/client.py rename to packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/client.py diff --git a/contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/driver.py b/packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/driver.py similarity index 97% rename from contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/driver.py rename to packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/driver.py index 4489f1ecb..1e86d5253 100644 --- a/contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/driver.py +++ b/packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/driver.py @@ -1,7 +1,6 @@ from dataclasses import dataclass, field from gpiozero import DigitalInputDevice, DigitalOutputDevice, InputDevice - from jumpstarter.driver import Driver, export @@ -20,7 +19,7 @@ def __post_init__(self): self.device = InputDevice(pin=self.pin) def close(self): - if hasattr(self, 'device'): + if hasattr(self, "device"): self.device.close() super().close() diff --git a/contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/driver_test.py b/packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/driver_test.py similarity index 99% rename from contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/driver_test.py rename to packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/driver_test.py index 79575ef90..a933ac17a 100644 --- a/contrib/drivers/raspberrypi/jumpstarter_driver_raspberrypi/driver_test.py +++ b/packages/jumpstarter-driver-raspberrypi/jumpstarter_driver_raspberrypi/driver_test.py @@ -2,8 +2,8 @@ from gpiozero import Device from gpiozero.pins.mock import MockFactory - from jumpstarter.common.utils import serve + from jumpstarter_driver_raspberrypi.driver import DigitalInput, DigitalOutput Device.pin_factory = MockFactory() @@ -31,6 +31,7 @@ def test_drivers_gpio_digital_output(): mock_pin.assert_states([False, True, False]) + def test_drivers_gpio_digital_input(): instance = DigitalInput(pin=4) diff --git a/contrib/drivers/raspberrypi/pyproject.toml b/packages/jumpstarter-driver-raspberrypi/pyproject.toml similarity index 95% rename from contrib/drivers/raspberrypi/pyproject.toml rename to packages/jumpstarter-driver-raspberrypi/pyproject.toml index 730287608..2d2665fbb 100644 --- a/contrib/drivers/raspberrypi/pyproject.toml +++ b/packages/jumpstarter-driver-raspberrypi/pyproject.toml @@ -27,7 +27,7 @@ source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}. [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [build-system] requires = ["hatchling", "hatch-vcs"] diff --git a/contrib/drivers/sdwire/README.md b/packages/jumpstarter-driver-sdwire/README.md similarity index 100% rename from contrib/drivers/sdwire/README.md rename to packages/jumpstarter-driver-sdwire/README.md diff --git a/jumpstarter/drivers/network/__init__.py b/packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/__init__.py similarity index 100% rename from jumpstarter/drivers/network/__init__.py rename to packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/__init__.py diff --git a/contrib/drivers/sdwire/jumpstarter_driver_sdwire/driver.py b/packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver.py similarity index 98% rename from contrib/drivers/sdwire/jumpstarter_driver_sdwire/driver.py rename to packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver.py index a73e7068a..ad5d94419 100644 --- a/contrib/drivers/sdwire/jumpstarter_driver_sdwire/driver.py +++ b/packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver.py @@ -8,9 +8,8 @@ import usb.util from anyio import fail_after, sleep from anyio.streams.file import FileReadStream, FileWriteStream - from jumpstarter.driver import Driver, export -from jumpstarter.drivers.storage.driver import StorageMuxInterface +from jumpstarter_driver_opendal.driver import StorageMuxInterface @dataclass(kw_only=True) diff --git a/contrib/drivers/sdwire/jumpstarter_driver_sdwire/driver_test.py b/packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver_test.py similarity index 100% rename from contrib/drivers/sdwire/jumpstarter_driver_sdwire/driver_test.py rename to packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver_test.py index d6d9c9aed..8f4434d0d 100644 --- a/contrib/drivers/sdwire/jumpstarter_driver_sdwire/driver_test.py +++ b/packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver_test.py @@ -1,7 +1,7 @@ import pytest import usb - from jumpstarter.common.utils import serve + from jumpstarter_driver_sdwire.driver import SDWire diff --git a/contrib/drivers/sdwire/pyproject.toml b/packages/jumpstarter-driver-sdwire/pyproject.toml similarity index 90% rename from contrib/drivers/sdwire/pyproject.toml rename to packages/jumpstarter-driver-sdwire/pyproject.toml index 317468cee..d373c0053 100644 --- a/contrib/drivers/sdwire/pyproject.toml +++ b/packages/jumpstarter-driver-sdwire/pyproject.toml @@ -10,6 +10,7 @@ license = { text = "Apache-2.0" } requires-python = ">=3.11" dependencies = [ "jumpstarter", + "jumpstarter-driver-opendal", "pyusb>=1.2.1", "pyudev>=0.24.3", ] @@ -26,7 +27,7 @@ source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}. [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [build-system] requires = ["hatchling", "hatch-vcs"] diff --git a/contrib/drivers/tftp/README.md b/packages/jumpstarter-driver-tftp/README.md similarity index 100% rename from contrib/drivers/tftp/README.md rename to packages/jumpstarter-driver-tftp/README.md diff --git a/contrib/drivers/tftp/examples/exporter.yaml b/packages/jumpstarter-driver-tftp/examples/exporter.yaml similarity index 86% rename from contrib/drivers/tftp/examples/exporter.yaml rename to packages/jumpstarter-driver-tftp/examples/exporter.yaml index 7b7645db6..fc5a2acf5 100644 --- a/contrib/drivers/tftp/examples/exporter.yaml +++ b/packages/jumpstarter-driver-tftp/examples/exporter.yaml @@ -4,7 +4,7 @@ endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 token: "" export: serial: - type: "jumpstarter.drivers.pyserial.driver.PySerial" + type: "jumpstarter_driver_pyserial.driver.PySerial" config: url: "/dev/ttyUSB0" baudrate: 1843200 diff --git a/contrib/drivers/tftp/examples/tftp_test.py b/packages/jumpstarter-driver-tftp/examples/tftp_test.py similarity index 83% rename from contrib/drivers/tftp/examples/tftp_test.py rename to packages/jumpstarter-driver-tftp/examples/tftp_test.py index 1108b9320..ba7b7067b 100644 --- a/contrib/drivers/tftp/examples/tftp_test.py +++ b/packages/jumpstarter-driver-tftp/examples/tftp_test.py @@ -1,12 +1,18 @@ +import logging import time +import pytest from jumpstarter_driver_tftp.driver import FileNotFound, TftpError +from jumpstarter_testing.pytest import JumpstarterTest -from jumpstarter.common.utils import env +log = logging.getLogger(__name__) -def test_tftp_upload(): - with env() as client: +class TestResource(JumpstarterTest): + filter_labels = {"board": "rpi4"} + + @pytest.fixture() + def test_tftp_upload(self, client): try: client.tftp.start() print("TFTP server started") @@ -43,7 +49,3 @@ def test_tftp_upload(): print("TFTP server stopped") except Exception as e: print(f"Error stopping server: {e}") - - -if __name__ == "__main__": - test_tftp_upload() diff --git a/jumpstarter/drivers/power/__init__.py b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/__init__.py similarity index 100% rename from jumpstarter/drivers/power/__init__.py rename to packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/__init__.py diff --git a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/client.py b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/client.py similarity index 98% rename from contrib/drivers/tftp/src/jumpstarter_driver_tftp/client.py rename to packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/client.py index b06ee7048..06c009c6f 100644 --- a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/client.py +++ b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/client.py @@ -1,10 +1,9 @@ from dataclasses import dataclass from pathlib import Path -from opendal import Operator - from jumpstarter.client import DriverClient -from jumpstarter.client.adapters import OpendalAdapter +from jumpstarter_driver_opendal.adapter import OpendalAdapter +from opendal import Operator @dataclass(kw_only=True) diff --git a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/driver.py b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver.py similarity index 96% rename from contrib/drivers/tftp/src/jumpstarter_driver_tftp/driver.py rename to packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver.py index bd4fb7580..2c917d596 100644 --- a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/driver.py +++ b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver.py @@ -8,12 +8,13 @@ from typing import Optional from anyio.streams.file import FileWriteStream - from jumpstarter.driver import Driver, export + from jumpstarter_driver_tftp.server import TftpServer logger = logging.getLogger(__name__) + def get_default_ip(): """Get the IP address of the default route interface""" try: @@ -24,18 +25,25 @@ def get_default_ip(): logger.warning("Could not determine default IP address, falling back to 0.0.0.0") return "0.0.0.0" + class TftpError(Exception): """Base exception for TFTP server errors""" + pass + class ServerNotRunning(TftpError): """Server is not running""" + pass + class FileNotFound(TftpError): """File not found""" + pass + @dataclass(kw_only=True) class Tftp(Driver): """TFTP Server driver for Jumpstarter""" @@ -43,7 +51,7 @@ class Tftp(Driver): root_dir: str = "/var/lib/tftpboot" host: str = field(default_factory=get_default_ip) port: int = 69 - server: Optional['TftpServer'] = field(init=False, default=None) + server: Optional["TftpServer"] = field(init=False, default=None) server_thread: Optional[threading.Thread] = field(init=False, default=None) _shutdown_event: threading.Event = field(init=False, default_factory=threading.Event) _loop_ready: threading.Event = field(init=False, default_factory=threading.Event) @@ -82,10 +90,7 @@ def _start_server(self): async def _run_server(self): try: server_task = asyncio.create_task(self.server.start()) - await asyncio.gather( - server_task, - self._wait_for_shutdown() - ) + await asyncio.gather(server_task, self._wait_for_shutdown()) except asyncio.CancelledError: logger.info("Server task cancelled") raise @@ -95,7 +100,7 @@ async def _wait_for_shutdown(self): await asyncio.sleep(0.1) logger.info("Shutdown event detected") if self.server is not None: - await self.server.shutdown() + await self.server.shutdown() @export def start(self): diff --git a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/driver_test.py b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver_test.py similarity index 98% rename from contrib/drivers/tftp/src/jumpstarter_driver_tftp/driver_test.py rename to packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver_test.py index 7cb9f2964..196cdb4b1 100644 --- a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/driver_test.py +++ b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver_test.py @@ -6,8 +6,8 @@ import anyio import pytest from anyio import create_memory_object_stream - from jumpstarter.common.resources import ClientStreamResource + from jumpstarter_driver_tftp.driver import ( FileNotFound, Tftp, @@ -19,12 +19,14 @@ def temp_dir(): with tempfile.TemporaryDirectory() as tmpdir: yield tmpdir + @pytest.fixture def server(temp_dir): server = Tftp(root_dir=temp_dir, host="127.0.0.1") yield server server.close() + @pytest.mark.anyio async def test_tftp_file_operations(server): filename = "test.txt" @@ -64,12 +66,14 @@ def test_tftp_host_config(temp_dir): server = Tftp(root_dir=temp_dir, host=custom_host) assert server.get_host() == custom_host + def test_tftp_root_directory_creation(temp_dir): new_dir = os.path.join(temp_dir, "new_tftp_root") server = Tftp(root_dir=new_dir) assert os.path.exists(new_dir) server.close() + @pytest.fixture def anyio_backend(): - return 'asyncio' + return "asyncio" diff --git a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/server.py b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/server.py similarity index 84% rename from contrib/drivers/tftp/src/jumpstarter_driver_tftp/server.py rename to packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/server.py index d602c0615..bf476f1fa 100644 --- a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/server.py +++ b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/server.py @@ -32,18 +32,19 @@ class TftpServer: TFTP Server that handles read requests (RRQ). """ - def __init__(self, host: str, port: int, root_dir: str, - block_size: int = 512, timeout: float = 5.0, retries: int = 3): + def __init__( + self, host: str, port: int, root_dir: str, block_size: int = 512, timeout: float = 5.0, retries: int = 3 + ): self.host = host self.port = port self.root_dir = pathlib.Path(os.path.abspath(root_dir)) self.block_size = block_size self.timeout = timeout self.retries = retries - self.active_transfers: Set['TftpTransfer'] = set() + self.active_transfers: Set["TftpTransfer"] = set() self.shutdown_event = asyncio.Event() self.transport: Optional[asyncio.DatagramTransport] = None - self.protocol: Optional['TftpServerProtocol'] = None + self.protocol: Optional["TftpServerProtocol"] = None self.logger = logging.getLogger(self.__class__.__name__) async def start(self): @@ -51,8 +52,7 @@ async def start(self): loop = asyncio.get_running_loop() self.transport, self.protocol = await loop.create_datagram_endpoint( - lambda: TftpServerProtocol(self), - local_addr=(self.host, self.port) + lambda: TftpServerProtocol(self), local_addr=(self.host, self.port) ) try: @@ -82,11 +82,11 @@ async def shutdown(self): self.logger.info("Shutdown signal received for TFTP server") self.shutdown_event.set() - def register_transfer(self, transfer: 'TftpTransfer'): + def register_transfer(self, transfer: "TftpTransfer"): self.active_transfers.add(transfer) self.logger.debug(f"Registered transfer: {transfer}") - def unregister_transfer(self, transfer: 'TftpTransfer'): + def unregister_transfer(self, transfer: "TftpTransfer"): self.active_transfers.discard(transfer) self.logger.debug(f"Unregistered transfer: {transfer}") @@ -120,7 +120,7 @@ def datagram_received(self, data: bytes, addr: Tuple[str, int]): return try: - opcode = Opcode(int.from_bytes(data[0:2], 'big')) + opcode = Opcode(int.from_bytes(data[0:2], "big")) except ValueError: self.logger.error(f"Unknown opcode from {addr}") self._send_error(addr, TftpErrorCode.ILLEGAL_OPERATION, "Unknown opcode") @@ -137,17 +137,17 @@ def datagram_received(self, data: bytes, addr: Tuple[str, int]): async def _handle_read_request(self, data: bytes, addr: Tuple[str, int]): try: # Parse filename and mode from request - parts = data[2:].split(b'\x00') + parts = data[2:].split(b"\x00") if len(parts) < 2: self.logger.error(f"Invalid RRQ format from {addr}") raise ValueError("Invalid RRQ format") - filename = parts[0].decode('utf-8') - mode = parts[1].decode('utf-8').lower() + filename = parts[0].decode("utf-8") + mode = parts[1].decode("utf-8").lower() self.logger.info(f"RRQ from {addr}: '{filename}' in mode '{mode}'") - if mode not in ('netascii', 'octet'): + if mode not in ("netascii", "octet"): self.logger.warning(f"Unsupported transfer mode '{mode}' from {addr}") self._send_error(addr, TftpErrorCode.ILLEGAL_OPERATION, "Unsupported transfer mode") return @@ -172,7 +172,7 @@ async def _handle_read_request(self, data: bytes, addr: Tuple[str, int]): client_addr=addr, block_size=self.server.block_size, timeout=self.server.timeout, - retries=self.server.retries + retries=self.server.retries, ) self.server.register_transfer(transfer) asyncio.create_task(transfer.start()) @@ -183,9 +183,7 @@ async def _handle_read_request(self, data: bytes, addr: Tuple[str, int]): def _send_error(self, addr: Tuple[str, int], error_code: TftpErrorCode, message: str): error_packet = ( - Opcode.ERROR.to_bytes(2, 'big') + - error_code.to_bytes(2, 'big') + - message.encode('utf-8') + b'\x00' + Opcode.ERROR.to_bytes(2, "big") + error_code.to_bytes(2, "big") + message.encode("utf-8") + b"\x00" ) if self.transport: self.transport.sendto(error_packet, addr) @@ -205,8 +203,15 @@ class TftpTransfer: Base class for TFTP transfers. """ - def __init__(self, server: TftpServer, filepath: pathlib.Path, client_addr: Tuple[str, int], - block_size: int, timeout: float, retries: int): + def __init__( + self, + server: TftpServer, + filepath: pathlib.Path, + client_addr: Tuple[str, int], + block_size: int, + timeout: float, + retries: int, + ): self.server = server self.filepath = filepath self.client_addr = client_addr @@ -214,7 +219,7 @@ def __init__(self, server: TftpServer, filepath: pathlib.Path, client_addr: Tupl self.timeout = timeout self.retries = retries self.transport: Optional[asyncio.DatagramTransport] = None - self.protocol: Optional['TftpTransferProtocol'] = None + self.protocol: Optional["TftpTransferProtocol"] = None self.cleanup_task: Optional[asyncio.Task] = None self.logger = logging.getLogger(self.__class__.__name__) @@ -236,8 +241,15 @@ class TftpReadTransfer(TftpTransfer): Handles a TFTP Read (RRQ) transfer. """ - def __init__(self, server: TftpServer, filepath: pathlib.Path, client_addr: Tuple[str, int], - block_size: int, timeout: float, retries: int): + def __init__( + self, + server: TftpServer, + filepath: pathlib.Path, + client_addr: Tuple[str, int], + block_size: int, + timeout: float, + retries: int, + ): super().__init__(server, filepath, client_addr, block_size, timeout, retries) self.block_num = 1 self.ack_received = asyncio.Event() @@ -248,26 +260,20 @@ async def start(self): loop = asyncio.get_running_loop() self.transport, self.protocol = await loop.create_datagram_endpoint( - lambda: TftpTransferProtocol(self), - local_addr=('0.0.0.0', 0), - remote_addr=self.client_addr + lambda: TftpTransferProtocol(self), local_addr=("0.0.0.0", 0), remote_addr=self.client_addr ) - local_addr = self.transport.get_extra_info('sockname') + local_addr = self.transport.get_extra_info("sockname") self.logger.debug(f"Transfer bound to local {local_addr}") try: - async with aiofiles.open(self.filepath, 'rb') as f: + async with aiofiles.open(self.filepath, "rb") as f: while True: if self.server.shutdown_event.is_set(): self.logger.info(f"Server shutdown detected, stopping transfer to {self.client_addr}") break data = await f.read(self.block_size) if data: - packet = ( - Opcode.DATA.to_bytes(2, 'big') + - self.block_num.to_bytes(2, 'big') + - data - ) + packet = Opcode.DATA.to_bytes(2, "big") + self.block_num.to_bytes(2, "big") + data success = await self._send_with_retries(packet) if not success: self.logger.error(f"Failed to send block {self.block_num} to {self.client_addr}") @@ -282,16 +288,11 @@ async def start(self): else: # If no data is returned, it means the file size is an exact multiple of block_size # Send an extra empty DATA packet to signal end of transfer - packet = ( - Opcode.DATA.to_bytes(2, 'big') + - self.block_num.to_bytes(2, 'big') + - b'' - ) + packet = Opcode.DATA.to_bytes(2, "big") + self.block_num.to_bytes(2, "big") + b"" success = await self._send_with_retries(packet) if not success: self.logger.error( - f"Failed to send final empty block {self.block_num} " - f"to {self.client_addr}" + f"Failed to send final empty block {self.block_num} to {self.client_addr}" ) break self.logger.info(f"Transfer complete to {self.client_addr}, final block {self.block_num}") @@ -327,7 +328,7 @@ def _send_packet(self, packet: bytes): Sends a DATA packet to the client. """ self.transport.sendto(packet) - block = int.from_bytes(packet[2:4], 'big') + block = int.from_bytes(packet[2:4], "big") data_length = len(packet) - 4 self.logger.debug(f"Sent DATA block {block} ({data_length} bytes) to {self.client_addr}") @@ -343,6 +344,7 @@ def handle_ack(self, block_num: int): else: self.logger.warning(f"Out of sequence ACK: expected {self.block_num}, got {block_num}") + class TftpTransferProtocol(asyncio.DatagramProtocol): """ Protocol for handling ACKs during a TFTP transfer. @@ -354,7 +356,7 @@ def __init__(self, transfer: TftpReadTransfer): def connection_made(self, transport: asyncio.DatagramTransport): self.transfer.transport = transport - local_addr = transport.get_extra_info('sockname') + local_addr = transport.get_extra_info("sockname") self.logger.debug(f"Transfer protocol connection established on {local_addr} for {self.transfer.client_addr}") def datagram_received(self, data: bytes, addr: Tuple[str, int]): @@ -368,7 +370,7 @@ def datagram_received(self, data: bytes, addr: Tuple[str, int]): return try: - opcode = Opcode(int.from_bytes(data[0:2], 'big')) + opcode = Opcode(int.from_bytes(data[0:2], "big")) except ValueError: self.logger.error(f"Unknown opcode in ACK from {addr}") self._send_error(addr, TftpErrorCode.ILLEGAL_OPERATION, "Unknown opcode in ACK") @@ -379,7 +381,7 @@ def datagram_received(self, data: bytes, addr: Tuple[str, int]): self._send_error(addr, TftpErrorCode.ILLEGAL_OPERATION, "Expected ACK") return - block_num = int.from_bytes(data[2:4], 'big') + block_num = int.from_bytes(data[2:4], "big") self.logger.debug(f"Received ACK for block {block_num} from {addr}") self.transfer.handle_ack(block_num) @@ -391,9 +393,7 @@ def connection_lost(self, exc): def _send_error(self, addr: Tuple[str, int], error_code: TftpErrorCode, message: str): error_packet = ( - Opcode.ERROR.to_bytes(2, 'big') + - error_code.to_bytes(2, 'big') + - message.encode('utf-8') + b'\x00' + Opcode.ERROR.to_bytes(2, "big") + error_code.to_bytes(2, "big") + message.encode("utf-8") + b"\x00" ) if self.transfer.transport: self.transfer.transport.sendto(error_packet) diff --git a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/server_test.py b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/server_test.py similarity index 79% rename from contrib/drivers/tftp/src/jumpstarter_driver_tftp/server_test.py rename to packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/server_test.py index 612f4a8b1..6ffa44534 100644 --- a/contrib/drivers/tftp/src/jumpstarter_driver_tftp/server_test.py +++ b/packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/server_test.py @@ -14,26 +14,23 @@ async def tftp_server(): test_file_path = Path(temp_dir) / "test.txt" test_file_path.write_text("Hello, TFTP!") - server = TftpServer( - host="127.0.0.1", - port=0, - root_dir=temp_dir - ) + server = TftpServer(host="127.0.0.1", port=0, root_dir=temp_dir) yield server, temp_dir await server.shutdown() + async def create_test_client(server_port): """Helper function to create a test UDP client.""" loop = asyncio.get_running_loop() transport, protocol = await loop.create_datagram_endpoint( - asyncio.DatagramProtocol, - remote_addr=('127.0.0.1', server_port) + asyncio.DatagramProtocol, remote_addr=("127.0.0.1", server_port) ) return transport, protocol -@pytest.mark.asyncio + +@pytest.mark.anyio async def test_server_startup_and_shutdown(tftp_server): """Test that server starts up and shuts down cleanly.""" server, _ = tftp_server @@ -48,7 +45,8 @@ async def test_server_startup_and_shutdown(tftp_server): assert True -@pytest.mark.asyncio + +@pytest.mark.anyio async def test_read_request_for_existing_file(tftp_server): """Test reading an existing file from the server.""" server, temp_dir = tftp_server @@ -60,9 +58,9 @@ async def test_read_request_for_existing_file(tftp_server): transport, _ = await create_test_client(server.port) rrq_packet = ( - Opcode.RRQ.to_bytes(2, 'big') + - b'test.txt\x00' + # Filename - b'octet\x00' # Mode + Opcode.RRQ.to_bytes(2, "big") + + b"test.txt\x00" # Filename + + b"octet\x00" # Mode ) transport.sendto(rrq_packet) @@ -75,7 +73,8 @@ async def test_read_request_for_existing_file(tftp_server): await server.shutdown() await server_task -@pytest.mark.asyncio + +@pytest.mark.anyio async def test_read_request_for_nonexistent_file(tftp_server): """Test reading a non-existent file returns appropriate error.""" server, _ = tftp_server @@ -86,11 +85,7 @@ async def test_read_request_for_nonexistent_file(tftp_server): try: transport, protocol = await create_test_client(server.port) - rrq_packet = ( - Opcode.RRQ.to_bytes(2, 'big') + - b'nonexistent.txt\x00' + - b'octet\x00' - ) + rrq_packet = Opcode.RRQ.to_bytes(2, "big") + b"nonexistent.txt\x00" + b"octet\x00" transport.sendto(rrq_packet) await asyncio.sleep(0.1) @@ -102,7 +97,8 @@ async def test_read_request_for_nonexistent_file(tftp_server): await server.shutdown() await server_task -@pytest.mark.asyncio + +@pytest.mark.anyio async def test_write_request_rejection(tftp_server): """Test that write requests are properly rejected (server is read-only).""" server, _ = tftp_server @@ -111,11 +107,7 @@ async def test_write_request_rejection(tftp_server): try: transport, _ = await create_test_client(server.port) - wrq_packet = ( - Opcode.WRQ.to_bytes(2, 'big') + - b'test.txt\x00' + - b'octet\x00' - ) + wrq_packet = Opcode.WRQ.to_bytes(2, "big") + b"test.txt\x00" + b"octet\x00" transport.sendto(wrq_packet) await asyncio.sleep(0.1) @@ -127,7 +119,8 @@ async def test_write_request_rejection(tftp_server): await server.shutdown() await server_task -@pytest.mark.asyncio + +@pytest.mark.anyio async def test_invalid_packet_handling(tftp_server): server, _ = tftp_server server_task = asyncio.create_task(server.start()) @@ -135,7 +128,7 @@ async def test_invalid_packet_handling(tftp_server): try: transport, _ = await create_test_client(server.port) - transport.sendto(b'\x00\x01') + transport.sendto(b"\x00\x01") await asyncio.sleep(0.1) assert server.transport is not None @@ -145,7 +138,8 @@ async def test_invalid_packet_handling(tftp_server): await server.shutdown() await server_task -@pytest.mark.asyncio + +@pytest.mark.anyio async def test_path_traversal_prevention(tftp_server): """Test that path traversal attempts are blocked.""" server, _ = tftp_server @@ -156,11 +150,7 @@ async def test_path_traversal_prevention(tftp_server): try: transport, _ = await create_test_client(server.port) - rrq_packet = ( - Opcode.RRQ.to_bytes(2, 'big') + - b'../../../etc/passwd\x00' + - b'octet\x00' - ) + rrq_packet = Opcode.RRQ.to_bytes(2, "big") + b"../../../etc/passwd\x00" + b"octet\x00" transport.sendto(rrq_packet) await asyncio.sleep(0.1) @@ -171,3 +161,8 @@ async def test_path_traversal_prevention(tftp_server): transport.close() await server.shutdown() await server_task + + +@pytest.fixture +def anyio_backend(): + return "asyncio" diff --git a/contrib/drivers/tftp/pyproject.toml b/packages/jumpstarter-driver-tftp/pyproject.toml similarity index 65% rename from contrib/drivers/tftp/pyproject.toml rename to packages/jumpstarter-driver-tftp/pyproject.toml index 2eec5eedc..830c47bb9 100644 --- a/contrib/drivers/tftp/pyproject.toml +++ b/packages/jumpstarter-driver-tftp/pyproject.toml @@ -10,33 +10,35 @@ requires-python = ">=3.12" dependencies = [ "anyio>=4.6.2.post1", "jumpstarter", + "jumpstarter-driver-opendal", "aiofiles>=24.1.0" ] +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=6.0.0", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "jumpstarter-testing" +] + + [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [tool.hatch.metadata.hooks.vcs.urls] Homepage = "https://jumpstarter.dev" source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" -[tool.pytest.ini_options] -#addopts = "--cov --cov-report=html --cov-report=xml" -log_cli = true -log_cli_level = "INFO" -testpaths = ["src"] -asyncio_mode = "auto" +# [tool.pytest.ini_options] +# #addopts = "--cov --cov-report=html --cov-report=xml" +# log_cli = true +# log_cli_level = "INFO" +# # testpaths = ["src"] +# asyncio_mode = "auto" [build-system] requires = ["hatchling", "hatch-vcs"] -build-backend = "hatchling.build" - -[dependency-groups] -dev = [ - "pytest-cov>=6.0.0", - "pytest>=8.3.3", - "pytest-asyncio>=0.0.0", - "ruff>=0.7.1", - -] +build-backend = "hatchling.build" \ No newline at end of file diff --git a/contrib/drivers/tftp/test.txt b/packages/jumpstarter-driver-tftp/test.txt similarity index 100% rename from contrib/drivers/tftp/test.txt rename to packages/jumpstarter-driver-tftp/test.txt diff --git a/contrib/drivers/ustreamer/README.md b/packages/jumpstarter-driver-ustreamer/README.md similarity index 100% rename from contrib/drivers/ustreamer/README.md rename to packages/jumpstarter-driver-ustreamer/README.md diff --git a/jumpstarter/drivers/pyserial/__init__.py b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/__init__.py similarity index 100% rename from jumpstarter/drivers/pyserial/__init__.py rename to packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/__init__.py diff --git a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/client.py b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/client.py similarity index 99% rename from contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/client.py rename to packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/client.py index 7f40da8ea..e2e8f5101 100644 --- a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/client.py +++ b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/client.py @@ -2,9 +2,8 @@ import logging from base64 import b64decode -from PIL import Image - from jumpstarter.client import DriverClient +from PIL import Image from .common import UStreamerState diff --git a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/common.py b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/common.py similarity index 100% rename from contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/common.py rename to packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/common.py diff --git a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/driver.py b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver.py similarity index 99% rename from contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/driver.py rename to packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver.py index e0a620989..24f21d724 100644 --- a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/driver.py +++ b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver.py @@ -10,7 +10,6 @@ from aiohttp import ClientSession, UnixConnector from anyio import connect_unix - from jumpstarter.driver import Driver, export, exportstream from .common import UStreamerState diff --git a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/driver_test.py b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver_test.py similarity index 100% rename from contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/driver_test.py rename to packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver_test.py index 7cbda2858..de52cd3bd 100644 --- a/contrib/drivers/ustreamer/jumpstarter_driver_ustreamer/driver_test.py +++ b/packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver_test.py @@ -1,6 +1,6 @@ import pytest - from jumpstarter.common.utils import serve + from jumpstarter_driver_ustreamer.driver import UStreamer diff --git a/contrib/drivers/ustreamer/pyproject.toml b/packages/jumpstarter-driver-ustreamer/pyproject.toml similarity index 95% rename from contrib/drivers/ustreamer/pyproject.toml rename to packages/jumpstarter-driver-ustreamer/pyproject.toml index 3b5238553..1d6d2f606 100644 --- a/contrib/drivers/ustreamer/pyproject.toml +++ b/packages/jumpstarter-driver-ustreamer/pyproject.toml @@ -27,7 +27,7 @@ source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}. [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [build-system] requires = ["hatchling", "hatch-vcs"] diff --git a/contrib/libs/imagehash/README.md b/packages/jumpstarter-imagehash/README.md similarity index 100% rename from contrib/libs/imagehash/README.md rename to packages/jumpstarter-imagehash/README.md diff --git a/contrib/libs/imagehash/jumpstarter_imagehash/__init__.py b/packages/jumpstarter-imagehash/jumpstarter_imagehash/__init__.py similarity index 100% rename from contrib/libs/imagehash/jumpstarter_imagehash/__init__.py rename to packages/jumpstarter-imagehash/jumpstarter_imagehash/__init__.py diff --git a/contrib/libs/imagehash/jumpstarter_imagehash/imagehash.py b/packages/jumpstarter-imagehash/jumpstarter_imagehash/imagehash.py similarity index 98% rename from contrib/libs/imagehash/jumpstarter_imagehash/imagehash.py rename to packages/jumpstarter-imagehash/jumpstarter_imagehash/imagehash.py index 8208b20c9..e7b747111 100644 --- a/contrib/libs/imagehash/jumpstarter_imagehash/imagehash.py +++ b/packages/jumpstarter-imagehash/jumpstarter_imagehash/imagehash.py @@ -5,9 +5,8 @@ from typing import Any import imagehash -from PIL import Image - from jumpstarter.client import DriverClient +from PIL import Image log = logging.getLogger("imagehash") @@ -68,7 +67,7 @@ def assert_snapshot(self, reference_img_file, tolerance=1): log.error(f"Image hashes are different, saving the actual image as {save_filename}") snapshot_img.save(save_filename) raise AssertionError( - f"{self.client.name}.assert_snapshot {reference_img_file}:" f" diff {diff} > tolerance {tolerance}" + f"{self.client.name}.assert_snapshot {reference_img_file}: diff {diff} > tolerance {tolerance}" ) def _snapshot_diff(self, reference_img_file, hash_func=imagehash.average_hash, hash_size=8): diff --git a/contrib/libs/imagehash/jumpstarter_imagehash/imagehash_test.py b/packages/jumpstarter-imagehash/jumpstarter_imagehash/imagehash_test.py similarity index 100% rename from contrib/libs/imagehash/jumpstarter_imagehash/imagehash_test.py rename to packages/jumpstarter-imagehash/jumpstarter_imagehash/imagehash_test.py diff --git a/contrib/libs/imagehash/jumpstarter_imagehash/test_image_a.jpeg b/packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_a.jpeg similarity index 100% rename from contrib/libs/imagehash/jumpstarter_imagehash/test_image_a.jpeg rename to packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_a.jpeg diff --git a/contrib/libs/imagehash/jumpstarter_imagehash/test_image_b.jpeg b/packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_b.jpeg similarity index 100% rename from contrib/libs/imagehash/jumpstarter_imagehash/test_image_b.jpeg rename to packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_b.jpeg diff --git a/contrib/libs/imagehash/pyproject.toml b/packages/jumpstarter-imagehash/pyproject.toml similarity index 95% rename from contrib/libs/imagehash/pyproject.toml rename to packages/jumpstarter-imagehash/pyproject.toml index ff3095349..d100c3d30 100644 --- a/contrib/libs/imagehash/pyproject.toml +++ b/packages/jumpstarter-imagehash/pyproject.toml @@ -27,7 +27,7 @@ source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}. [tool.hatch.version] source = "vcs" -raw-options = { 'root' = '../../../'} +raw-options = { 'root' = '../../'} [build-system] requires = ["hatchling", "hatch-vcs"] diff --git a/packages/jumpstarter-kubernetes/README.md b/packages/jumpstarter-kubernetes/README.md new file mode 100644 index 000000000..47affcc4e --- /dev/null +++ b/packages/jumpstarter-kubernetes/README.md @@ -0,0 +1 @@ +# Jumpstarter Kubernetes Library \ No newline at end of file diff --git a/jumpstarter/k8s/__init__.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py similarity index 100% rename from jumpstarter/k8s/__init__.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/__init__.py diff --git a/jumpstarter/k8s/clients.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/clients.py similarity index 99% rename from jumpstarter/k8s/clients.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/clients.py index cd3d69e37..34d80f356 100644 --- a/jumpstarter/k8s/clients.py +++ b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/clients.py @@ -4,9 +4,8 @@ from dataclasses import dataclass from typing import Literal, Optional -from kubernetes_asyncio.client.models import V1ObjectMeta, V1ObjectReference - from jumpstarter.config import ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers +from kubernetes_asyncio.client.models import V1ObjectMeta, V1ObjectReference from .util import AbstractAsyncCustomObjectApi diff --git a/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/clients_test.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/clients_test.py new file mode 100644 index 000000000..7641b8e6e --- /dev/null +++ b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/clients_test.py @@ -0,0 +1,2 @@ +def test_client(): + pass diff --git a/jumpstarter/k8s/exporters.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/exporters.py similarity index 99% rename from jumpstarter/k8s/exporters.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/exporters.py index 27b115e2c..ff23bb216 100644 --- a/jumpstarter/k8s/exporters.py +++ b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/exporters.py @@ -3,9 +3,8 @@ from dataclasses import dataclass from typing import Literal -from kubernetes_asyncio.client.models import V1ObjectMeta, V1ObjectReference - from jumpstarter.config import ExporterConfigV1Alpha1 +from kubernetes_asyncio.client.models import V1ObjectMeta, V1ObjectReference from .util import AbstractAsyncCustomObjectApi diff --git a/jumpstarter/k8s/install.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/install.py similarity index 95% rename from jumpstarter/k8s/install.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/install.py index 090e03488..42a538bad 100644 --- a/jumpstarter/k8s/install.py +++ b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/install.py @@ -54,7 +54,7 @@ async def install_helm_chart( "--set", "global.metrics.enabled=false", "--set", - f"jumpstarter-controller.grpc.nodeport.enabled={"true" if mode == "nodeport" else "false"}", + f"jumpstarter-controller.grpc.nodeport.enabled={'true' if mode == 'nodeport' else 'false'}", "--set", f"jumpstarter-controller.grpc.nodeport.port={grpc_port}", "--set", diff --git a/jumpstarter/k8s/leases.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py similarity index 100% rename from jumpstarter/k8s/leases.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/leases.py diff --git a/jumpstarter/k8s/util/__init__.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/util/__init__.py similarity index 100% rename from jumpstarter/k8s/util/__init__.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/util/__init__.py diff --git a/jumpstarter/k8s/util/async_custom_object_api.py b/packages/jumpstarter-kubernetes/jumpstarter_kubernetes/util/async_custom_object_api.py similarity index 100% rename from jumpstarter/k8s/util/async_custom_object_api.py rename to packages/jumpstarter-kubernetes/jumpstarter_kubernetes/util/async_custom_object_api.py diff --git a/packages/jumpstarter-kubernetes/pyproject.toml b/packages/jumpstarter-kubernetes/pyproject.toml new file mode 100644 index 000000000..fd1d4045e --- /dev/null +++ b/packages/jumpstarter-kubernetes/pyproject.toml @@ -0,0 +1,35 @@ +[project] +name = "jumpstarter-kubernetes" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "kubernetes>=31.0.0", + "kubernetes-asyncio>=31.1.0", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/jumpstarter/drivers/storage/__init__.py b/packages/jumpstarter-protocol/README.md similarity index 100% rename from jumpstarter/drivers/storage/__init__.py rename to packages/jumpstarter-protocol/README.md diff --git a/packages/jumpstarter-protocol/jumpstarter_protocol/__init__.py b/packages/jumpstarter-protocol/jumpstarter_protocol/__init__.py new file mode 100644 index 000000000..f94433757 --- /dev/null +++ b/packages/jumpstarter-protocol/jumpstarter_protocol/__init__.py @@ -0,0 +1,17 @@ +from .jumpstarter.v1 import ( + jumpstarter_pb2, + jumpstarter_pb2_grpc, + kubernetes_pb2, + kubernetes_pb2_grpc, + router_pb2, + router_pb2_grpc, +) + +__all__ = [ + "jumpstarter_pb2", + "jumpstarter_pb2_grpc", + "kubernetes_pb2", + "kubernetes_pb2_grpc", + "router_pb2", + "router_pb2_grpc" +] diff --git a/jumpstarter/v1/jumpstarter_pb2.py b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/jumpstarter_pb2.py similarity index 99% rename from jumpstarter/v1/jumpstarter_pb2.py rename to packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/jumpstarter_pb2.py index 156eb2840..d8b4bcf55 100644 --- a/jumpstarter/v1/jumpstarter_pb2.py +++ b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/jumpstarter_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: jumpstarter/v1/jumpstarter.proto -# Protobuf Python Version: 5.28.2 +# Protobuf Python Version: 5.29.3 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 5, - 28, - 2, + 29, + 3, '', 'jumpstarter/v1/jumpstarter.proto' ) @@ -26,7 +26,7 @@ from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 -from jumpstarter.v1 import kubernetes_pb2 as jumpstarter_dot_v1_dot_kubernetes__pb2 +from . import kubernetes_pb2 as jumpstarter_dot_v1_dot_kubernetes__pb2 DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n jumpstarter/v1/jumpstarter.proto\x12\x0ejumpstarter.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1fjumpstarter/v1/kubernetes.proto\"\xd1\x01\n\x0fRegisterRequest\x12\x43\n\x06labels\x18\x01 \x03(\x0b\x32+.jumpstarter.v1.RegisterRequest.LabelsEntryR\x06labels\x12>\n\x07reports\x18\x02 \x03(\x0b\x32$.jumpstarter.v1.DriverInstanceReportR\x07reports\x1a\x39\n\x0bLabelsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\"\xe5\x01\n\x14\x44riverInstanceReport\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12$\n\x0bparent_uuid\x18\x02 \x01(\tH\x00R\nparentUuid\x88\x01\x01\x12H\n\x06labels\x18\x03 \x03(\x0b\x32\x30.jumpstarter.v1.DriverInstanceReport.LabelsEntryR\x06labels\x1a\x39\n\x0bLabelsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\x42\x0e\n\x0c_parent_uuid\"&\n\x10RegisterResponse\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\"+\n\x11UnregisterRequest\x12\x16\n\x06reason\x18\x02 \x01(\tR\x06reason\"\x14\n\x12UnregisterResponse\".\n\rListenRequest\x12\x1d\n\nlease_name\x18\x01 \x01(\tR\tleaseName\"\\\n\x0eListenResponse\x12\'\n\x0frouter_endpoint\x18\x01 \x01(\tR\x0erouterEndpoint\x12!\n\x0crouter_token\x18\x02 \x01(\tR\x0brouterToken\"\x0f\n\rStatusRequest\"\x91\x01\n\x0eStatusResponse\x12\x16\n\x06leased\x18\x01 \x01(\x08R\x06leased\x12\"\n\nlease_name\x18\x02 \x01(\tH\x00R\tleaseName\x88\x01\x01\x12$\n\x0b\x63lient_name\x18\x03 \x01(\tH\x01R\nclientName\x88\x01\x01\x42\r\n\x0b_lease_nameB\x0e\n\x0c_client_name\",\n\x0b\x44ialRequest\x12\x1d\n\nlease_name\x18\x01 \x01(\tR\tleaseName\"Z\n\x0c\x44ialResponse\x12\'\n\x0frouter_endpoint\x18\x01 \x01(\tR\x0erouterEndpoint\x12!\n\x0crouter_token\x18\x02 \x01(\tR\x0brouterToken\"\xa1\x01\n\x12\x41uditStreamRequest\x12#\n\rexporter_uuid\x18\x01 \x01(\tR\x0c\x65xporterUuid\x12\x30\n\x14\x64river_instance_uuid\x18\x02 \x01(\tR\x12\x64riverInstanceUuid\x12\x1a\n\x08severity\x18\x03 \x01(\tR\x08severity\x12\x18\n\x07message\x18\x04 \x01(\tR\x07message\"\xe9\x01\n\x11GetReportResponse\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x45\n\x06labels\x18\x02 \x03(\x0b\x32-.jumpstarter.v1.GetReportResponse.LabelsEntryR\x06labels\x12>\n\x07reports\x18\x03 \x03(\x0b\x32$.jumpstarter.v1.DriverInstanceReportR\x07reports\x1a\x39\n\x0bLabelsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\"k\n\x11\x44riverCallRequest\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x16\n\x06method\x18\x02 \x01(\tR\x06method\x12*\n\x04\x61rgs\x18\x03 \x03(\x0b\x32\x16.google.protobuf.ValueR\x04\x61rgs\"X\n\x12\x44riverCallResponse\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12.\n\x06result\x18\x02 \x01(\x0b\x32\x16.google.protobuf.ValueR\x06result\"t\n\x1aStreamingDriverCallRequest\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x16\n\x06method\x18\x02 \x01(\tR\x06method\x12*\n\x04\x61rgs\x18\x03 \x03(\x0b\x32\x16.google.protobuf.ValueR\x04\x61rgs\"a\n\x1bStreamingDriverCallResponse\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12.\n\x06result\x18\x02 \x01(\x0b\x32\x16.google.protobuf.ValueR\x06result\"]\n\x11LogStreamResponse\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x1a\n\x08severity\x18\x02 \x01(\tR\x08severity\x12\x18\n\x07message\x18\x03 \x01(\tR\x07message\"\x0e\n\x0cResetRequest\"\x0f\n\rResetResponse\"\x9b\x01\n\x14ListExportersRequest\x12H\n\x06labels\x18\x01 \x03(\x0b\x32\x30.jumpstarter.v1.ListExportersRequest.LabelsEntryR\x06labels\x1a\x39\n\x0bLabelsEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\"X\n\x15ListExportersResponse\x12?\n\texporters\x18\x01 \x03(\x0b\x32!.jumpstarter.v1.GetReportResponseR\texporters\"(\n\x12GetExporterRequest\x12\x12\n\x04uuid\x18\x01 \x01(\tR\x04uuid\"T\n\x13GetExporterResponse\x12=\n\x08\x65xporter\x18\x01 \x01(\x0b\x32!.jumpstarter.v1.GetReportResponseR\x08\x65xporter\"%\n\x0fGetLeaseRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\"\x93\x03\n\x10GetLeaseResponse\x12\x35\n\x08\x64uration\x18\x01 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x39\n\x08selector\x18\x02 \x01(\x0b\x32\x1d.jumpstarter.v1.LabelSelectorR\x08selector\x12>\n\nbegin_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00R\tbeginTime\x88\x01\x01\x12:\n\x08\x65nd_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x01R\x07\x65ndTime\x88\x01\x01\x12(\n\rexporter_uuid\x18\x05 \x01(\tH\x02R\x0c\x65xporterUuid\x88\x01\x01\x12\x39\n\nconditions\x18\x06 \x03(\x0b\x32\x19.jumpstarter.v1.ConditionR\nconditionsB\r\n\x0b_begin_timeB\x0b\n\t_end_timeB\x10\n\x0e_exporter_uuid\"\x87\x01\n\x13RequestLeaseRequest\x12\x35\n\x08\x64uration\x18\x01 \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12\x39\n\x08selector\x18\x02 \x01(\x0b\x32\x1d.jumpstarter.v1.LabelSelectorR\x08selector\"*\n\x14RequestLeaseResponse\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\")\n\x13ReleaseLeaseRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\"\x16\n\x14ReleaseLeaseResponse\"\x13\n\x11ListLeasesRequest\"*\n\x12ListLeasesResponse\x12\x14\n\x05names\x18\x01 \x03(\tR\x05names2\xed\x07\n\x11\x43ontrollerService\x12M\n\x08Register\x12\x1f.jumpstarter.v1.RegisterRequest\x1a .jumpstarter.v1.RegisterResponse\x12S\n\nUnregister\x12!.jumpstarter.v1.UnregisterRequest\x1a\".jumpstarter.v1.UnregisterResponse\x12I\n\x06Listen\x12\x1d.jumpstarter.v1.ListenRequest\x1a\x1e.jumpstarter.v1.ListenResponse0\x01\x12I\n\x06Status\x12\x1d.jumpstarter.v1.StatusRequest\x1a\x1e.jumpstarter.v1.StatusResponse0\x01\x12\x41\n\x04\x44ial\x12\x1b.jumpstarter.v1.DialRequest\x1a\x1c.jumpstarter.v1.DialResponse\x12K\n\x0b\x41uditStream\x12\".jumpstarter.v1.AuditStreamRequest\x1a\x16.google.protobuf.Empty(\x01\x12\\\n\rListExporters\x12$.jumpstarter.v1.ListExportersRequest\x1a%.jumpstarter.v1.ListExportersResponse\x12V\n\x0bGetExporter\x12\".jumpstarter.v1.GetExporterRequest\x1a#.jumpstarter.v1.GetExporterResponse\x12M\n\x08GetLease\x12\x1f.jumpstarter.v1.GetLeaseRequest\x1a .jumpstarter.v1.GetLeaseResponse\x12Y\n\x0cRequestLease\x12#.jumpstarter.v1.RequestLeaseRequest\x1a$.jumpstarter.v1.RequestLeaseResponse\x12Y\n\x0cReleaseLease\x12#.jumpstarter.v1.ReleaseLeaseRequest\x1a$.jumpstarter.v1.ReleaseLeaseResponse\x12S\n\nListLeases\x12!.jumpstarter.v1.ListLeasesRequest\x1a\".jumpstarter.v1.ListLeasesResponse2\xb0\x03\n\x0f\x45xporterService\x12\x46\n\tGetReport\x12\x16.google.protobuf.Empty\x1a!.jumpstarter.v1.GetReportResponse\x12S\n\nDriverCall\x12!.jumpstarter.v1.DriverCallRequest\x1a\".jumpstarter.v1.DriverCallResponse\x12p\n\x13StreamingDriverCall\x12*.jumpstarter.v1.StreamingDriverCallRequest\x1a+.jumpstarter.v1.StreamingDriverCallResponse0\x01\x12H\n\tLogStream\x12\x16.google.protobuf.Empty\x1a!.jumpstarter.v1.LogStreamResponse0\x01\x12\x44\n\x05Reset\x12\x1c.jumpstarter.v1.ResetRequest\x1a\x1d.jumpstarter.v1.ResetResponseB\x7f\n\x12\x63om.jumpstarter.v1B\x10JumpstarterProtoP\x01\xa2\x02\x03JXX\xaa\x02\x0eJumpstarter.V1\xca\x02\x0eJumpstarter\\V1\xe2\x02\x1aJumpstarter\\V1\\GPBMetadata\xea\x02\x0fJumpstarter::V1b\x06proto3') diff --git a/jumpstarter/v1/jumpstarter_pb2_grpc.py b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/jumpstarter_pb2_grpc.py similarity index 99% rename from jumpstarter/v1/jumpstarter_pb2_grpc.py rename to packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/jumpstarter_pb2_grpc.py index ac199a432..227d63404 100644 --- a/jumpstarter/v1/jumpstarter_pb2_grpc.py +++ b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/jumpstarter_pb2_grpc.py @@ -3,7 +3,7 @@ import grpc from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 -from jumpstarter.v1 import jumpstarter_pb2 as jumpstarter_dot_v1_dot_jumpstarter__pb2 +from . import jumpstarter_pb2 as jumpstarter_dot_v1_dot_jumpstarter__pb2 class ControllerServiceStub(object): diff --git a/jumpstarter/v1/kubernetes_pb2.py b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/kubernetes_pb2.py similarity index 98% rename from jumpstarter/v1/kubernetes_pb2.py rename to packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/kubernetes_pb2.py index 5f4e60dcc..bfeeae908 100644 --- a/jumpstarter/v1/kubernetes_pb2.py +++ b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/kubernetes_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: jumpstarter/v1/kubernetes.proto -# Protobuf Python Version: 5.28.2 +# Protobuf Python Version: 5.29.3 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 5, - 28, - 2, + 29, + 3, '', 'jumpstarter/v1/kubernetes.proto' ) diff --git a/jumpstarter/v1/kubernetes_pb2_grpc.py b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/kubernetes_pb2_grpc.py similarity index 100% rename from jumpstarter/v1/kubernetes_pb2_grpc.py rename to packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/kubernetes_pb2_grpc.py diff --git a/jumpstarter/v1/router_pb2.py b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/router_pb2.py similarity index 98% rename from jumpstarter/v1/router_pb2.py rename to packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/router_pb2.py index 66b8ae110..eff53189e 100644 --- a/jumpstarter/v1/router_pb2.py +++ b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/router_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: jumpstarter/v1/router.proto -# Protobuf Python Version: 5.28.2 +# Protobuf Python Version: 5.29.3 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 5, - 28, - 2, + 29, + 3, '', 'jumpstarter/v1/router.proto' ) diff --git a/jumpstarter/v1/router_pb2_grpc.py b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/router_pb2_grpc.py similarity index 97% rename from jumpstarter/v1/router_pb2_grpc.py rename to packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/router_pb2_grpc.py index 8f3995c0d..81393a572 100644 --- a/jumpstarter/v1/router_pb2_grpc.py +++ b/packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/router_pb2_grpc.py @@ -2,7 +2,7 @@ """Client and server classes corresponding to protobuf-defined services.""" import grpc -from jumpstarter.v1 import router_pb2 as jumpstarter_dot_v1_dot_router__pb2 +from . import router_pb2 as jumpstarter_dot_v1_dot_router__pb2 class RouterServiceStub(object): diff --git a/packages/jumpstarter-protocol/protocol_test.py b/packages/jumpstarter-protocol/protocol_test.py new file mode 100644 index 000000000..a097381b7 --- /dev/null +++ b/packages/jumpstarter-protocol/protocol_test.py @@ -0,0 +1,2 @@ +def test_protocol(): + pass diff --git a/packages/jumpstarter-protocol/pyproject.toml b/packages/jumpstarter-protocol/pyproject.toml new file mode 100644 index 000000000..45c7e562b --- /dev/null +++ b/packages/jumpstarter-protocol/pyproject.toml @@ -0,0 +1,37 @@ +[project] +name = "jumpstarter-protocol" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "grpcio>=1.66.1", + "protobuf>=5.29.3", +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0", +] + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter_protocol"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/jumpstarter/testing/__init__.py b/packages/jumpstarter-testing/README.md similarity index 100% rename from jumpstarter/testing/__init__.py rename to packages/jumpstarter-testing/README.md diff --git a/packages/jumpstarter-testing/conftest.py b/packages/jumpstarter-testing/conftest.py new file mode 100644 index 000000000..4d2c99857 --- /dev/null +++ b/packages/jumpstarter-testing/conftest.py @@ -0,0 +1,8 @@ +import pytest + +pytest_plugins = ["pytester"] + + +@pytest.fixture +def anyio_backend(): + return "asyncio" diff --git a/packages/jumpstarter-testing/jumpstarter_testing/__init__.py b/packages/jumpstarter-testing/jumpstarter_testing/__init__.py new file mode 100644 index 000000000..8975fd655 --- /dev/null +++ b/packages/jumpstarter-testing/jumpstarter_testing/__init__.py @@ -0,0 +1,3 @@ +from .pytest import JumpstarterTest + +__all__ = ["JumpstarterTest"] diff --git a/packages/jumpstarter-testing/jumpstarter_testing/pytest.py b/packages/jumpstarter-testing/jumpstarter_testing/pytest.py new file mode 100644 index 000000000..512abcd1c --- /dev/null +++ b/packages/jumpstarter-testing/jumpstarter_testing/pytest.py @@ -0,0 +1,65 @@ +import logging +import time +from typing import ClassVar + +import pytest +from jumpstarter.common import MetadataFilter +from jumpstarter.common.utils import env +from jumpstarter.config.client import ClientConfigV1Alpha1 + +log = logging.getLogger(__name__) + + +class JumpstarterTest: + """Base class for Jumpstarter test cases in pytest + + This class provides a client fixture that can be used to interact with + Jumpstarter services in test cases. + + Looks for the `JUMPSTARTER_HOST` environment variable to connect to an + established Jumpstarter shell, otherwise it will try to acquire a lease + for a single exporter using the filter_labels annotation. + i.e.: + + .. code-block:: python + + import os + import pytest + import logging + + from jumpstarter_testing.pytest import JumpstarterTest + + log = logging.getLogger(__name__) + + class TestResource(JumpstarterTest): + filter_labels = {"board":"rpi4"} + + @pytest.fixture() + def console(self, client): + with PexpectAdapter(client=client.dutlink.console) as console: + yield console + + def test_setup_device(self, client, console): + client.dutlink.power.off() + log.info("Setting up device") + client.dutlink.storage.write_local_file("2024-07-04-raspios-bookworm-arm64-lite.img") + client.dutlink.storage.dut() + client.dutlink.power.on() + + """ + + filter_labels: ClassVar[dict[str, str]] + + @pytest.fixture(scope="class") + def client(self): + try: + with env() as client: + yield client + except RuntimeError: + labels = getattr(self, "filter_labels", {}) + config = ClientConfigV1Alpha1.load("default") + with config.lease(metadata_filter=MetadataFilter(labels=labels)) as lease: + with lease.connect() as client: + yield client + # BUG workaround: make sure that grpc servers get the client/lease release properly + time.sleep(1) diff --git a/jumpstarter/testing/pytest_test.py b/packages/jumpstarter-testing/jumpstarter_testing/pytest_test.py similarity index 76% rename from jumpstarter/testing/pytest_test.py rename to packages/jumpstarter-testing/jumpstarter_testing/pytest_test.py index 0cee1b2b7..60be99a0d 100644 --- a/jumpstarter/testing/pytest_test.py +++ b/packages/jumpstarter-testing/jumpstarter_testing/pytest_test.py @@ -1,12 +1,13 @@ from jumpstarter.config.env import JMP_DRIVERS_ALLOW, JUMPSTARTER_HOST -from jumpstarter.drivers.power.driver import MockPower from jumpstarter.exporter import Session +from jumpstarter_driver_power.driver import MockPower +from pytest import Pytester -def test_env(pytester, monkeypatch): +def test_env(pytester: Pytester, monkeypatch): pytester.makepyfile( """ - from jumpstarter.testing.pytest import JumpstarterTest + from jumpstarter_testing import JumpstarterTest class TestSample(JumpstarterTest): def test_simple(self, client): diff --git a/packages/jumpstarter-testing/pyproject.toml b/packages/jumpstarter-testing/pyproject.toml new file mode 100644 index 000000000..a77b5cb30 --- /dev/null +++ b/packages/jumpstarter-testing/pyproject.toml @@ -0,0 +1,30 @@ +[project] +name = "jumpstarter-testing" +dynamic = ["version", "urls"] +description = "" +authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter", + "pytest>=8.3.2", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "pytest-cov>=5.0.0" +] + +[dependency-groups] +dev = ["jumpstarter-driver-power"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../' } + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/packages/jumpstarter/README.md b/packages/jumpstarter/README.md new file mode 100644 index 000000000..ae4322f2c --- /dev/null +++ b/packages/jumpstarter/README.md @@ -0,0 +1 @@ +# Jumpstarter Core \ No newline at end of file diff --git a/conftest.py b/packages/jumpstarter/conftest.py similarity index 96% rename from conftest.py rename to packages/jumpstarter/conftest.py index 1ba8d1d47..159b28ab1 100644 --- a/conftest.py +++ b/packages/jumpstarter/conftest.py @@ -2,6 +2,7 @@ from dataclasses import dataclass, field from datetime import datetime, timedelta from ipaddress import IPv4Address +from typing import Tuple from uuid import uuid4 import grpc @@ -13,9 +14,8 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa - from jumpstarter.streams import RouterStream, forward_stream -from jumpstarter.v1 import ( +from jumpstarter_protocol import ( jumpstarter_pb2, jumpstarter_pb2_grpc, kubernetes_pb2, @@ -44,11 +44,11 @@ async def Stream(self, _request_iterator, context): @dataclass(kw_only=True) class MockController(jumpstarter_pb2_grpc.ControllerServiceServicer): router_endpoint: str - status: ( + status: Tuple[ MemoryObjectSendStream[jumpstarter_pb2.StatusResponse], MemoryObjectReceiveStream[jumpstarter_pb2.StatusResponse], - ) = field(init=False, default_factory=lambda: create_memory_object_stream[jumpstarter_pb2.StatusResponse](32)) - queue: (MemoryObjectSendStream[str], MemoryObjectReceiveStream[str]) = field( + ] = field(init=False, default_factory=lambda: create_memory_object_stream[jumpstarter_pb2.StatusResponse](32)) + queue: Tuple[MemoryObjectSendStream[str], MemoryObjectReceiveStream[str]] = field( init=False, default_factory=lambda: create_memory_object_stream[str](32) ) leases: dict[str, int | str] = field(init=False, default_factory=dict) diff --git a/jumpstarter/client/__init__.py b/packages/jumpstarter/jumpstarter/client/__init__.py similarity index 100% rename from jumpstarter/client/__init__.py rename to packages/jumpstarter/jumpstarter/client/__init__.py diff --git a/jumpstarter/client/adapters/common.py b/packages/jumpstarter/jumpstarter/client/adapters.py similarity index 100% rename from jumpstarter/client/adapters/common.py rename to packages/jumpstarter/jumpstarter/client/adapters.py diff --git a/jumpstarter/client/base.py b/packages/jumpstarter/jumpstarter/client/base.py similarity index 99% rename from jumpstarter/client/base.py rename to packages/jumpstarter/jumpstarter/client/base.py index 5b4e7cfd1..22f236447 100644 --- a/jumpstarter/client/base.py +++ b/packages/jumpstarter/jumpstarter/client/base.py @@ -8,11 +8,10 @@ from dataclasses import field from anyio.from_thread import BlockingPortal +from jumpstarter.streams import BlockingStream from pydantic import ConfigDict from pydantic.dataclasses import dataclass -from jumpstarter.streams import BlockingStream - from .core import AsyncDriverClient diff --git a/jumpstarter/client/client.py b/packages/jumpstarter/jumpstarter/client/client.py similarity index 96% rename from jumpstarter/client/client.py rename to packages/jumpstarter/jumpstarter/client/client.py index 7a3387512..64730330b 100644 --- a/jumpstarter/client/client.py +++ b/packages/jumpstarter/jumpstarter/client/client.py @@ -6,12 +6,9 @@ import grpc from anyio.from_thread import BlockingPortal from google.protobuf import empty_pb2 - from jumpstarter.client import DriverClient from jumpstarter.common.importlib import import_class -from jumpstarter.v1 import ( - jumpstarter_pb2_grpc, -) +from jumpstarter_protocol import jumpstarter_pb2_grpc @asynccontextmanager diff --git a/jumpstarter/client/core.py b/packages/jumpstarter/jumpstarter/client/core.py similarity index 97% rename from jumpstarter/client/core.py rename to packages/jumpstarter/jumpstarter/client/core.py index eba4fdb4e..f7deaae52 100644 --- a/jumpstarter/client/core.py +++ b/packages/jumpstarter/jumpstarter/client/core.py @@ -7,7 +7,6 @@ from grpc import StatusCode from grpc.aio import AioRpcError, Channel - from jumpstarter.common import Metadata from jumpstarter.common.resources import ResourceMetadata from jumpstarter.common.serde import decode_value, encode_value @@ -23,7 +22,7 @@ RouterStream, forward_stream, ) -from jumpstarter.v1 import jumpstarter_pb2, jumpstarter_pb2_grpc, router_pb2_grpc +from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc, router_pb2_grpc @dataclass(kw_only=True) diff --git a/jumpstarter/client/lease.py b/packages/jumpstarter/jumpstarter/client/lease.py similarity index 95% rename from jumpstarter/client/lease.py rename to packages/jumpstarter/jumpstarter/client/lease.py index fccce10c0..3a3f96e4e 100644 --- a/jumpstarter/client/lease.py +++ b/packages/jumpstarter/jumpstarter/client/lease.py @@ -6,13 +6,12 @@ from anyio.from_thread import BlockingPortal from google.protobuf import duration_pb2 from grpc.aio import Channel - from jumpstarter.client import client_from_path from jumpstarter.common import MetadataFilter, TemporaryUnixListener from jumpstarter.common.condition import condition_false, condition_present_and_equal, condition_true from jumpstarter.common.streams import connect_router_stream from jumpstarter.config.tls import TLSConfigV1Alpha1 -from jumpstarter.v1 import jumpstarter_pb2, jumpstarter_pb2_grpc, kubernetes_pb2 +from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc, kubernetes_pb2 logger = logging.getLogger(__name__) @@ -26,7 +25,7 @@ class Lease(AbstractContextManager, AbstractAsyncContextManager): name: str | None = field(default=None) allow: list[str] unsafe: bool - release: bool = True # release on contexts exit + release: bool = True # release on contexts exit controller: jumpstarter_pb2_grpc.ControllerServiceStub = field(init=False) tls_config: TLSConfigV1Alpha1 = field(default_factory=TLSConfigV1Alpha1) @@ -53,7 +52,7 @@ def request(self): return self.portal.call(self.request_async) async def request_async(self): - """ Request a lease, or verifies a lease which was already created. + """Request a lease, or verifies a lease which was already created. :return: lease :rtype: Lease @@ -68,7 +67,7 @@ async def request_async(self): return await self._acquire() async def _acquire(self): - """ Acquire a lease. + """Acquire a lease. Makes sure the lease is ready, and returns the lease object. """ diff --git a/jumpstarter/common/__init__.py b/packages/jumpstarter/jumpstarter/common/__init__.py similarity index 100% rename from jumpstarter/common/__init__.py rename to packages/jumpstarter/jumpstarter/common/__init__.py diff --git a/jumpstarter/common/condition.py b/packages/jumpstarter/jumpstarter/common/condition.py similarity index 74% rename from jumpstarter/common/condition.py rename to packages/jumpstarter/jumpstarter/common/condition.py index 4199b5553..1fdb7c0ad 100644 --- a/jumpstarter/common/condition.py +++ b/packages/jumpstarter/jumpstarter/common/condition.py @@ -1,10 +1,11 @@ # Ported from https://github.com/kubernetes/apimachinery/blob/v0.31.1/pkg/api/meta/conditions.go -from jumpstarter.v1 import kubernetes_pb2 +from jumpstarter_protocol import kubernetes_pb2 -def condition_present_and_equal(conditions: list[kubernetes_pb2.Condition], - condition_type: str, status: str, reason: str | None=None) -> bool: +def condition_present_and_equal( + conditions: list[kubernetes_pb2.Condition], condition_type: str, status: str, reason: str | None = None +) -> bool: for condition in conditions: if condition.type == condition_type: if reason is None or condition.reason == reason: diff --git a/jumpstarter/common/grpc.py b/packages/jumpstarter/jumpstarter/common/grpc.py similarity index 100% rename from jumpstarter/common/grpc.py rename to packages/jumpstarter/jumpstarter/common/grpc.py diff --git a/jumpstarter/common/importlib.py b/packages/jumpstarter/jumpstarter/common/importlib.py similarity index 100% rename from jumpstarter/common/importlib.py rename to packages/jumpstarter/jumpstarter/common/importlib.py diff --git a/jumpstarter/common/importlib_test.py b/packages/jumpstarter/jumpstarter/common/importlib_test.py similarity index 100% rename from jumpstarter/common/importlib_test.py rename to packages/jumpstarter/jumpstarter/common/importlib_test.py diff --git a/jumpstarter/common/metadata.py b/packages/jumpstarter/jumpstarter/common/metadata.py similarity index 100% rename from jumpstarter/common/metadata.py rename to packages/jumpstarter/jumpstarter/common/metadata.py diff --git a/jumpstarter/common/resources.py b/packages/jumpstarter/jumpstarter/common/resources.py similarity index 100% rename from jumpstarter/common/resources.py rename to packages/jumpstarter/jumpstarter/common/resources.py diff --git a/jumpstarter/common/serde.py b/packages/jumpstarter/jumpstarter/common/serde.py similarity index 100% rename from jumpstarter/common/serde.py rename to packages/jumpstarter/jumpstarter/common/serde.py diff --git a/jumpstarter/common/streams.py b/packages/jumpstarter/jumpstarter/common/streams.py similarity index 95% rename from jumpstarter/common/streams.py rename to packages/jumpstarter/jumpstarter/common/streams.py index f1ed59750..e2a9db6ad 100644 --- a/jumpstarter/common/streams.py +++ b/packages/jumpstarter/jumpstarter/common/streams.py @@ -3,11 +3,10 @@ from uuid import UUID import grpc -from pydantic import BaseModel, Field, Json - from jumpstarter.common.grpc import aio_secure_channel, ssl_channel_credentials from jumpstarter.streams import RouterStream, forward_stream -from jumpstarter.v1 import router_pb2_grpc +from jumpstarter_protocol.jumpstarter.v1 import router_pb2_grpc +from pydantic import BaseModel, Field, Json class ResourceStreamRequest(BaseModel): diff --git a/jumpstarter/common/tempfile.py b/packages/jumpstarter/jumpstarter/common/tempfile.py similarity index 100% rename from jumpstarter/common/tempfile.py rename to packages/jumpstarter/jumpstarter/common/tempfile.py diff --git a/jumpstarter/common/utils.py b/packages/jumpstarter/jumpstarter/common/utils.py similarity index 93% rename from jumpstarter/common/utils.py rename to packages/jumpstarter/jumpstarter/common/utils.py index cb41d4bc7..20e91c46c 100644 --- a/jumpstarter/common/utils.py +++ b/packages/jumpstarter/jumpstarter/common/utils.py @@ -4,7 +4,6 @@ from subprocess import Popen from anyio.from_thread import BlockingPortal, start_blocking_portal - from jumpstarter.client import client_from_path from jumpstarter.config.client import _allow_from_env from jumpstarter.config.env import JMP_DRIVERS_ALLOW, JUMPSTARTER_HOST @@ -23,7 +22,6 @@ async def serve_async(root_device: Driver, portal: BlockingPortal): client.close() - @contextmanager def serve(root_device: Driver): with start_blocking_portal() as portal: @@ -35,7 +33,7 @@ def serve(root_device: Driver): @asynccontextmanager async def env_async(portal): - """ Provide a client for an existing JUMPSTARTER_HOST environment variable. + """Provide a client for an existing JUMPSTARTER_HOST environment variable. Async version of env() @@ -56,7 +54,7 @@ async def env_async(portal): @contextmanager def env(): - """ Provide a client for an existing JUMPSTARTER_HOST environment variable. + """Provide a client for an existing JUMPSTARTER_HOST environment variable. This is useful when interacting with an already established Jumpstarter shell, to either a local exporter or a remote one. diff --git a/jumpstarter/config/__init__.py b/packages/jumpstarter/jumpstarter/config/__init__.py similarity index 94% rename from jumpstarter/config/__init__.py rename to packages/jumpstarter/jumpstarter/config/__init__.py index e0d00a6f7..c81ab2f02 100644 --- a/jumpstarter/config/__init__.py +++ b/packages/jumpstarter/jumpstarter/config/__init__.py @@ -20,5 +20,5 @@ "ClientConfigV1Alpha1", "ClientConfigV1Alpha1Drivers", "ExporterConfigV1Alpha1", - "ExporterConfigV1Alpha1DriverInstance" + "ExporterConfigV1Alpha1DriverInstance", ] diff --git a/jumpstarter/config/client.py b/packages/jumpstarter/jumpstarter/config/client.py similarity index 96% rename from jumpstarter/config/client.py rename to packages/jumpstarter/jumpstarter/config/client.py index 64ad20b6c..633d36ad1 100644 --- a/jumpstarter/config/client.py +++ b/packages/jumpstarter/jumpstarter/config/client.py @@ -6,11 +6,10 @@ import grpc import yaml from anyio.from_thread import BlockingPortal, start_blocking_portal -from pydantic import BaseModel, Field, ValidationError - from jumpstarter.common import MetadataFilter from jumpstarter.common.grpc import aio_secure_channel, ssl_channel_credentials -from jumpstarter.v1 import jumpstarter_pb2, jumpstarter_pb2_grpc +from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc +from pydantic import BaseModel, Field, ValidationError from .common import CONFIG_PATH from .env import JMP_DRIVERS_ALLOW, JMP_ENDPOINT, JMP_LEASE, JMP_TOKEN @@ -27,6 +26,7 @@ def _allow_from_env(): case _: return allow.split(","), False + class ClientConfigV1Alpha1Drivers(BaseModel): allow: list[str] = Field(default_factory=[]) unsafe: bool = Field(default=False) @@ -58,8 +58,7 @@ async def channel(self): @contextmanager def lease(self, metadata_filter: MetadataFilter, lease_name: str | None = None): with start_blocking_portal() as portal: - with portal.wrap_async_context_manager( - self.lease_async(metadata_filter, lease_name, portal)) as lease: + with portal.wrap_async_context_manager(self.lease_async(metadata_filter, lease_name, portal)) as lease: yield lease def request_lease(self, metadata_filter: MetadataFilter): @@ -74,9 +73,10 @@ def release_lease(self, name): with start_blocking_portal() as portal: portal.call(self.release_lease_async, name) - async def request_lease_async(self, metadata_filter: MetadataFilter, portal:BlockingPortal): + async def request_lease_async(self, metadata_filter: MetadataFilter, portal: BlockingPortal): # dynamically import to avoid circular imports from jumpstarter.client import Lease + lease = Lease( channel=await self.channel(), name=None, diff --git a/tests/test_client_config.py b/packages/jumpstarter/jumpstarter/config/client_config_test.py similarity index 99% rename from tests/test_client_config.py rename to packages/jumpstarter/jumpstarter/config/client_config_test.py index fbdc1e9ae..325873477 100644 --- a/tests/test_client_config.py +++ b/packages/jumpstarter/jumpstarter/config/client_config_test.py @@ -5,13 +5,12 @@ import pytest import yaml -from pydantic import ValidationError - from jumpstarter.config import ( ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, ) from jumpstarter.config.env import JMP_DRIVERS_ALLOW, JMP_ENDPOINT, JMP_TOKEN +from pydantic import ValidationError def test_client_ensure_exists_makes_dir(monkeypatch: pytest.MonkeyPatch): diff --git a/jumpstarter/config/common.py b/packages/jumpstarter/jumpstarter/config/common.py similarity index 100% rename from jumpstarter/config/common.py rename to packages/jumpstarter/jumpstarter/config/common.py diff --git a/jumpstarter/config/env.py b/packages/jumpstarter/jumpstarter/config/env.py similarity index 90% rename from jumpstarter/config/env.py rename to packages/jumpstarter/jumpstarter/config/env.py index 62c46f2eb..1cde72093 100644 --- a/jumpstarter/config/env.py +++ b/packages/jumpstarter/jumpstarter/config/env.py @@ -4,4 +4,4 @@ JMP_TOKEN = "JMP_TOKEN" JMP_DRIVERS_ALLOW = "JMP_DRIVERS_ALLOW" JUMPSTARTER_HOST = "JUMPSTARTER_HOST" -JMP_LEASE ="JMP_LEASE" +JMP_LEASE = "JMP_LEASE" diff --git a/jumpstarter/config/exporter.py b/packages/jumpstarter/jumpstarter/config/exporter.py similarity index 98% rename from jumpstarter/config/exporter.py rename to packages/jumpstarter/jumpstarter/config/exporter.py index ab1ce0126..a241d81da 100644 --- a/jumpstarter/config/exporter.py +++ b/packages/jumpstarter/jumpstarter/config/exporter.py @@ -7,17 +7,16 @@ import grpc import yaml from anyio.from_thread import start_blocking_portal -from pydantic import BaseModel, Field - from jumpstarter.common.grpc import aio_secure_channel, ssl_channel_credentials from jumpstarter.common.importlib import import_class from jumpstarter.driver import Driver +from pydantic import BaseModel, Field from .tls import TLSConfigV1Alpha1 class ExporterConfigV1Alpha1DriverInstance(BaseModel): - type: str = Field(default="jumpstarter.drivers.composite.driver.Composite") + type: str = Field(default="jumpstarter_driver_composite.driver.Composite") children: dict[str, ExporterConfigV1Alpha1DriverInstance] = Field(default_factory=dict) config: dict[str, Any] = Field(default_factory=dict) @@ -28,6 +27,7 @@ def instantiate(self) -> Driver: return driver_class(children=children, **self.config) + class ExporterConfigV1Alpha1(BaseModel): BASE_PATH: ClassVar[Path] = Path("/etc/jumpstarter/exporters") @@ -96,6 +96,7 @@ def delete(cls, alias: str): async def serve_unix_async(self): # dynamic import to avoid circular imports from jumpstarter.exporter import Session + with Session( root_device=ExporterConfigV1Alpha1DriverInstance(children=self.export).instantiate(), ) as session: @@ -111,6 +112,7 @@ def serve_unix(self): async def serve(self): # dynamic import to avoid circular imports from jumpstarter.exporter import Exporter + def channel_factory(): credentials = grpc.composite_channel_credentials( ssl_channel_credentials(self.endpoint, self.tls), diff --git a/jumpstarter/config/exporter_test.py b/packages/jumpstarter/jumpstarter/config/exporter_test.py similarity index 90% rename from jumpstarter/config/exporter_test.py rename to packages/jumpstarter/jumpstarter/config/exporter_test.py index d3a521e76..92e00319a 100644 --- a/jumpstarter/config/exporter_test.py +++ b/packages/jumpstarter/jumpstarter/config/exporter_test.py @@ -3,7 +3,6 @@ import pytest from anyio import create_task_group from anyio.from_thread import start_blocking_portal - from jumpstarter.common import MetadataFilter from .client import ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers @@ -21,12 +20,12 @@ async def test_exporter_serve(mock_controller): token="dummy-exporter-token", export={ "power": ExporterConfigV1Alpha1DriverInstance( - type="jumpstarter.drivers.power.driver.MockPower", + type="jumpstarter_driver_power.driver.MockPower", ), "nested": ExporterConfigV1Alpha1DriverInstance( children={ "tcp": ExporterConfigV1Alpha1DriverInstance( - type="jumpstarter.drivers.network.driver.TcpNetwork", + type="jumpstarter_driver_network.driver.TcpNetwork", config={ "host": "127.0.0.1", "port": 8080, @@ -72,7 +71,7 @@ def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): export: power: - type: "jumpstarter.drivers.power.PduPower" + type: "jumpstarter_driver_power.driver.PduPower" config: host: "192.168.1.111" port: 1234 @@ -80,7 +79,7 @@ def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): username: "admin" password: "secret" serial: - type: "jumpstarter.drivers.serial.Pyserial" + type: "jumpstarter_driver_pyserial.driver.Pyserial" config: port: "/dev/ttyUSB0" baudrate: 115200 @@ -107,7 +106,7 @@ def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): tls=TLSConfigV1Alpha1(ca="cacertificatedata", insecure=True), export={ "power": ExporterConfigV1Alpha1DriverInstance( - type="jumpstarter.drivers.power.PduPower", + type="jumpstarter_driver_power.driver.PduPower", children={}, # missing children defaults to empty config={ "host": "192.168.1.111", @@ -119,7 +118,7 @@ def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): }, ), "serial": ExporterConfigV1Alpha1DriverInstance( - type="jumpstarter.drivers.serial.Pyserial", + type="jumpstarter_driver_pyserial.driver.Pyserial", children={}, config={ "port": "/dev/ttyUSB0", @@ -127,7 +126,7 @@ def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): }, ), "nested": ExporterConfigV1Alpha1DriverInstance( - type="jumpstarter.drivers.composite.driver.Composite", + type="jumpstarter_driver_composite.driver.Composite", children={ "custom": ExporterConfigV1Alpha1DriverInstance( type="vendorpackage.CustomDriver", @@ -141,7 +140,7 @@ def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path): ), }, config={}, - path=path + path=path, ) path.unlink() diff --git a/jumpstarter/config/tls.py b/packages/jumpstarter/jumpstarter/config/tls.py similarity index 100% rename from jumpstarter/config/tls.py rename to packages/jumpstarter/jumpstarter/config/tls.py diff --git a/jumpstarter/config/user.py b/packages/jumpstarter/jumpstarter/config/user.py similarity index 100% rename from jumpstarter/config/user.py rename to packages/jumpstarter/jumpstarter/config/user.py diff --git a/tests/test_user_config.py b/packages/jumpstarter/jumpstarter/config/user_config_test.py similarity index 99% rename from tests/test_user_config.py rename to packages/jumpstarter/jumpstarter/config/user_config_test.py index d7daa9d06..2504ab94b 100644 --- a/tests/test_user_config.py +++ b/packages/jumpstarter/jumpstarter/config/user_config_test.py @@ -3,7 +3,6 @@ from unittest.mock import patch import pytest - from jumpstarter.config import ( ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers, diff --git a/jumpstarter/driver/__init__.py b/packages/jumpstarter/jumpstarter/driver/__init__.py similarity index 100% rename from jumpstarter/driver/__init__.py rename to packages/jumpstarter/jumpstarter/driver/__init__.py diff --git a/jumpstarter/driver/base.py b/packages/jumpstarter/jumpstarter/driver/base.py similarity index 98% rename from jumpstarter/driver/base.py rename to packages/jumpstarter/jumpstarter/driver/base.py index 651e03f8e..712b21a12 100644 --- a/jumpstarter/driver/base.py +++ b/packages/jumpstarter/jumpstarter/driver/base.py @@ -15,9 +15,6 @@ import aiohttp from anyio import to_thread from grpc import StatusCode -from pydantic import TypeAdapter -from pydantic.dataclasses import dataclass - from jumpstarter.common import Metadata from jumpstarter.common.resources import ClientStreamResource, PresignedRequestResource, Resource, ResourceMetadata from jumpstarter.common.serde import decode_value, encode_value @@ -26,7 +23,9 @@ ResourceStreamRequest, ) from jumpstarter.streams import AiohttpStreamReaderStream, MetadataStream, create_memory_stream -from jumpstarter.v1 import jumpstarter_pb2, jumpstarter_pb2_grpc, router_pb2_grpc +from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc, router_pb2_grpc +from pydantic import TypeAdapter +from pydantic.dataclasses import dataclass from .decorators import ( MARKER_DRIVERCALL, diff --git a/jumpstarter/driver/decorators.py b/packages/jumpstarter/jumpstarter/driver/decorators.py similarity index 100% rename from jumpstarter/driver/decorators.py rename to packages/jumpstarter/jumpstarter/driver/decorators.py diff --git a/jumpstarter/driver/decorators_test.py b/packages/jumpstarter/jumpstarter/driver/decorators_test.py similarity index 100% rename from jumpstarter/driver/decorators_test.py rename to packages/jumpstarter/jumpstarter/driver/decorators_test.py diff --git a/jumpstarter/exporter/__init__.py b/packages/jumpstarter/jumpstarter/exporter/__init__.py similarity index 100% rename from jumpstarter/exporter/__init__.py rename to packages/jumpstarter/jumpstarter/exporter/__init__.py diff --git a/jumpstarter/exporter/exporter.py b/packages/jumpstarter/jumpstarter/exporter/exporter.py similarity index 99% rename from jumpstarter/exporter/exporter.py rename to packages/jumpstarter/jumpstarter/exporter/exporter.py index 6b5cb59b9..1420215cb 100644 --- a/jumpstarter/exporter/exporter.py +++ b/packages/jumpstarter/jumpstarter/exporter/exporter.py @@ -6,13 +6,12 @@ import grpc from anyio import connect_unix, create_task_group from google.protobuf import empty_pb2 - from jumpstarter.common import Metadata from jumpstarter.common.streams import connect_router_stream from jumpstarter.config.tls import TLSConfigV1Alpha1 from jumpstarter.driver import Driver from jumpstarter.exporter.session import Session -from jumpstarter.v1 import ( +from jumpstarter_protocol import ( jumpstarter_pb2, jumpstarter_pb2_grpc, ) diff --git a/jumpstarter/exporter/session.py b/packages/jumpstarter/jumpstarter/exporter/session.py similarity index 99% rename from jumpstarter/exporter/session.py rename to packages/jumpstarter/jumpstarter/exporter/session.py index 037d8a01c..892e9585b 100644 --- a/jumpstarter/exporter/session.py +++ b/packages/jumpstarter/jumpstarter/exporter/session.py @@ -6,12 +6,11 @@ import grpc from anyio import Event, TypedAttributeLookupError from anyio.from_thread import start_blocking_portal - from jumpstarter.common import Metadata, TemporarySocket from jumpstarter.common.streams import StreamRequestMetadata from jumpstarter.driver import Driver from jumpstarter.streams import MetadataStreamAttributes, RouterStream, forward_stream -from jumpstarter.v1 import ( +from jumpstarter_protocol import ( jumpstarter_pb2, jumpstarter_pb2_grpc, router_pb2_grpc, diff --git a/tests/test_listener.py b/packages/jumpstarter/jumpstarter/listener_test.py similarity index 98% rename from tests/test_listener.py rename to packages/jumpstarter/jumpstarter/listener_test.py index 28d6d9b81..73c3e8b5b 100644 --- a/tests/test_listener.py +++ b/packages/jumpstarter/jumpstarter/listener_test.py @@ -7,14 +7,13 @@ import pytest from anyio import create_task_group from anyio.from_thread import start_blocking_portal - from jumpstarter.client import Lease from jumpstarter.common import MetadataFilter from jumpstarter.common.grpc import aio_secure_channel, ssl_channel_credentials from jumpstarter.common.streams import connect_router_stream from jumpstarter.config.tls import TLSConfigV1Alpha1 -from jumpstarter.drivers.power.driver import MockPower from jumpstarter.exporter import Exporter, Session +from jumpstarter_driver_power.driver import MockPower pytestmark = pytest.mark.anyio diff --git a/jumpstarter/streams/__init__.py b/packages/jumpstarter/jumpstarter/streams/__init__.py similarity index 86% rename from jumpstarter/streams/__init__.py rename to packages/jumpstarter/jumpstarter/streams/__init__.py index f4779f47b..6fa9c68d7 100644 --- a/jumpstarter/streams/__init__.py +++ b/packages/jumpstarter/jumpstarter/streams/__init__.py @@ -4,14 +4,12 @@ from .metadata import MetadataStream, MetadataStreamAttributes from .progress import ProgressStream from .router import RouterStream -from .websocket import WebsocketServerStream __all__ = [ "create_memory_stream", "forward_stream", "BlockingStream", "RouterStream", - "WebsocketServerStream", "ProgressStream", "MetadataStream", "MetadataStreamAttributes", diff --git a/jumpstarter/streams/aiohttp.py b/packages/jumpstarter/jumpstarter/streams/aiohttp.py similarity index 100% rename from jumpstarter/streams/aiohttp.py rename to packages/jumpstarter/jumpstarter/streams/aiohttp.py diff --git a/jumpstarter/streams/blocking.py b/packages/jumpstarter/jumpstarter/streams/blocking.py similarity index 100% rename from jumpstarter/streams/blocking.py rename to packages/jumpstarter/jumpstarter/streams/blocking.py diff --git a/jumpstarter/streams/common.py b/packages/jumpstarter/jumpstarter/streams/common.py similarity index 100% rename from jumpstarter/streams/common.py rename to packages/jumpstarter/jumpstarter/streams/common.py diff --git a/jumpstarter/streams/metadata.py b/packages/jumpstarter/jumpstarter/streams/metadata.py similarity index 100% rename from jumpstarter/streams/metadata.py rename to packages/jumpstarter/jumpstarter/streams/metadata.py diff --git a/jumpstarter/streams/progress.py b/packages/jumpstarter/jumpstarter/streams/progress.py similarity index 100% rename from jumpstarter/streams/progress.py rename to packages/jumpstarter/jumpstarter/streams/progress.py diff --git a/jumpstarter/streams/router.py b/packages/jumpstarter/jumpstarter/streams/router.py similarity index 98% rename from jumpstarter/streams/router.py rename to packages/jumpstarter/jumpstarter/streams/router.py index 9ef735636..b626ad6b3 100644 --- a/jumpstarter/streams/router.py +++ b/packages/jumpstarter/jumpstarter/streams/router.py @@ -9,8 +9,7 @@ EndOfStream, ) from anyio.abc import ObjectStream - -from jumpstarter.v1 import router_pb2 +from jumpstarter_protocol import router_pb2 logger = logging.getLogger(__name__) diff --git a/packages/jumpstarter/pyproject.toml b/packages/jumpstarter/pyproject.toml new file mode 100644 index 000000000..36d995918 --- /dev/null +++ b/packages/jumpstarter/pyproject.toml @@ -0,0 +1,47 @@ +[project] +name = "jumpstarter" +dynamic = ["version", "urls"] +description = "" +authors = [ + { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, + { name = "Nick Cao", email = "ncao@redhat.com" }, + { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, +] +readme = "README.md" +license = { text = "Apache-2.0" } +requires-python = ">=3.11" +dependencies = [ + "jumpstarter-protocol", + "pyyaml>=6.0.2", + "anyio>=4.4.0,!=4.6.2", + "aiohttp>=3.10.5", + "tqdm>=4.66.5", + "pydantic>=2.8.2" +] + +[dependency-groups] +dev = [ + "pytest>=8.3.2", + "pytest-cov>=6.0.0", + "pytest-anyio>=0.0.0", + "pytest-asyncio>=0.0.0", + "cryptography>=43.0.3", + "jumpstarter-driver-power", + "jumpstarter-driver-network", + "jumpstarter-driver-composite" +] + +[tool.hatch.build.targets.wheel] +packages = ["jumpstarter"] + +[tool.hatch.metadata.hooks.vcs.urls] +Homepage = "https://jumpstarter.dev" +source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" + +[tool.hatch.version] +source = "vcs" +raw-options = { 'root' = '../../'} + +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" diff --git a/pyproject.toml b/pyproject.toml index 5287a4f0a..2745c2cb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,33 +1,29 @@ -[project] -name = "jumpstarter" -dynamic = ["version", "urls"] -description = "" -authors = [ - { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, - { name = "Nick Cao", email = "ncao@redhat.com" }, - { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, -] -readme = "README.md" -license = { text = "Apache-2.0" } -requires-python = ">=3.11" -dependencies = [ - "pexpect>=4.9.0", - "httpx>=0.27.0", - "pyyaml>=6.0.2", - "anyio>=4.4.0,!=4.6.2", - "aiohttp>=3.10.5", - "tqdm>=4.66.5", - "opendal>=0.45.8", - "pydantic>=2.8.2", - "pyserial>=3.5", - "wsproto>=1.2.0", - "fabric>=3.2.2", - "grpcio>=1.66.1", - "protobuf>=5.28.0", - "kubernetes>=31.0.0", - "kubernetes-asyncio>=31.1.0", - "asyncclick>=8.1.7.2", -] +[tool.uv.workspace] +members = ["packages/*", "examples/*"] + +[tool.uv.sources] +jumpstarter = { workspace = true } +jumpstarter-cli = { workspace = true } +jumpstarter-cli-admin = { workspace = true } +jumpstarter-cli-client = { workspace = true } +jumpstarter-cli-common = { workspace = true } +jumpstarter-cli-exporter = { workspace = true } +jumpstarter-driver-can = { workspace = true } +jumpstarter-driver-composite = { workspace = true } +jumpstarter-driver-dutlink = { workspace = true } +jumpstarter-driver-http = { workspace = true } +jumpstarter-driver-raspberrypi = { workspace = true } +jumpstarter-driver-network = { workspace = true } +jumpstarter-driver-opendal = { workspace = true } +jumpstarter-driver-power = { workspace = true } +jumpstarter-driver-pyserial = { workspace = true } +jumpstarter-driver-sdwire = { workspace = true } +jumpstarter-driver-tftp = { workspace = true } +jumpstarter-driver-ustreamer = { workspace = true } +jumpstarter-imagehash = { workspace = true } +jumpstarter-kubernetes = { workspace = true } +jumpstarter-protocol = { workspace = true } +jumpstarter-testing = { workspace = true } [dependency-groups] docs = [ @@ -40,45 +36,14 @@ docs = [ "sphinx-click>=6.0.0", "sphinx-substitution-extensions>=2024.10.17", ] -dev = [ - "pytest>=8.3.2", - "pytest-anyio>=0.0.0", - "pytest-asyncio>=0.0.0", - "pytest-cov>=5.0.0", - "ruff>=0.6.1", - "typos>=1.23.6", - "pre-commit>=3.8.0", - "cryptography>=43.0.1", - "websocket-client>=1.8.0", - "esbonio>=0.16.5", -] - -[project.scripts] -jmp = "jumpstarter.cli.jmp:jmp" -j = "jumpstarter.cli.j:main" - -[tool.hatch.version] -source = "vcs" - -[tool.hatch.build.targets.wheel] -packages = ["jumpstarter"] - -[tool.hatch.metadata.hooks.vcs.urls] -Homepage = "https://jumpstarter.dev" -source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" - -[tool.uv.workspace] -members = ["contrib/drivers/*", "contrib/libs/*", "examples/*"] - -[tool.uv.sources] -jumpstarter = { workspace = true } +dev = ["ruff>=0.9.2", "typos>=1.23.6", "pre-commit>=3.8.0", "esbonio>=0.16.5"] [tool.ruff] -exclude = ["jumpstarter/v1"] +exclude = ["packages/jumpstarter-protocol"] line-length = 120 [tool.ruff.lint] -exclude = ["jumpstarter/v1"] +exclude = ["packages/jumpstarter-protocol"] extend-select = ["I", "C", "E", "F", "W", "B"] [tool.typos.default] @@ -86,10 +51,7 @@ locale = "en-us" [tool.coverage.run] omit = ["conftest.py", "test_*.py", "*_test.py", "*_pb2.py", "*_pb2_grpc.py"] +skip_empty = true [tool.pytest.ini_options] -addopts = "--capture=no --verbose --cov --cov-report=html --cov-report=xml --cov-append" - -[build-system] -requires = ["hatchling", "hatch-vcs"] -build-backend = "hatchling.build" +addopts = "--capture=no --cov --cov-report=html --cov-report=xml --cov-append" diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/uv.lock b/uv.lock index 3417f33d4..cc960ee23 100644 --- a/uv.lock +++ b/uv.lock @@ -1,12 +1,26 @@ version = 1 requires-python = ">=3.12" +resolution-markers = [ + "python_full_version < '3.13'", + "python_full_version >= '3.13'", +] [manifest] members = [ "jumpstarter", + "jumpstarter-cli", + "jumpstarter-cli-admin", + "jumpstarter-cli-client", + "jumpstarter-cli-common", + "jumpstarter-cli-exporter", "jumpstarter-driver-can", + "jumpstarter-driver-composite", "jumpstarter-driver-dutlink", "jumpstarter-driver-http", + "jumpstarter-driver-network", + "jumpstarter-driver-opendal", + "jumpstarter-driver-power", + "jumpstarter-driver-pyserial", "jumpstarter-driver-raspberrypi", "jumpstarter-driver-sdwire", "jumpstarter-driver-tftp", @@ -14,6 +28,27 @@ members = [ "jumpstarter-example-automotive", "jumpstarter-example-soc-pytest", "jumpstarter-imagehash", + "jumpstarter-kubernetes", + "jumpstarter-protocol", + "jumpstarter-testing", +] + +[manifest.dependency-groups] +dev = [ + { name = "esbonio", specifier = ">=0.16.5" }, + { name = "pre-commit", specifier = ">=3.8.0" }, + { name = "ruff", specifier = ">=0.9.2" }, + { name = "typos", specifier = ">=1.23.6" }, +] +docs = [ + { name = "esbonio", specifier = ">=0.16.4" }, + { name = "furo", specifier = ">=2024.8.6" }, + { name = "myst-parser", specifier = ">=4.0.0" }, + { name = "sphinx", specifier = "<8.1.0" }, + { name = "sphinx-autobuild", specifier = ">=2024.4.16" }, + { name = "sphinx-click", specifier = ">=6.0.0" }, + { name = "sphinx-substitution-extensions", specifier = ">=2024.10.17" }, + { name = "sphinxcontrib-mermaid", specifier = ">=0.9.2" }, ] [[package]] @@ -27,16 +62,16 @@ wheels = [ [[package]] name = "aiohappyeyeballs" -version = "2.4.4" +version = "2.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/55/e4373e888fdacb15563ef6fa9fa8c8252476ea071e96fb46defac9f18bf2/aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", size = 21977 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8", size = 14756 }, + { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 }, ] [[package]] name = "aiohttp" -version = "3.11.11" +version = "3.10.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -44,53 +79,52 @@ dependencies = [ { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, - { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/ed/f26db39d29cd3cb2f5a3374304c713fe5ab5a0e4c8ee25a0c45cc6adf844/aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e", size = 7669618 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/cf/4bda538c502f9738d6b95ada11603c05ec260807246e15e869fc3ec5de97/aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886", size = 704666 }, - { url = "https://files.pythonhosted.org/packages/46/7b/87fcef2cad2fad420ca77bef981e815df6904047d0a1bd6aeded1b0d1d66/aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2", size = 464057 }, - { url = "https://files.pythonhosted.org/packages/5a/a6/789e1f17a1b6f4a38939fbc39d29e1d960d5f89f73d0629a939410171bc0/aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c", size = 455996 }, - { url = "https://files.pythonhosted.org/packages/b7/dd/485061fbfef33165ce7320db36e530cd7116ee1098e9c3774d15a732b3fd/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a", size = 1682367 }, - { url = "https://files.pythonhosted.org/packages/e9/d7/9ec5b3ea9ae215c311d88b2093e8da17e67b8856673e4166c994e117ee3e/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231", size = 1736989 }, - { url = "https://files.pythonhosted.org/packages/d6/fb/ea94927f7bfe1d86178c9d3e0a8c54f651a0a655214cce930b3c679b8f64/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e", size = 1793265 }, - { url = "https://files.pythonhosted.org/packages/40/7f/6de218084f9b653026bd7063cd8045123a7ba90c25176465f266976d8c82/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8", size = 1691841 }, - { url = "https://files.pythonhosted.org/packages/77/e2/992f43d87831cbddb6b09c57ab55499332f60ad6fdbf438ff4419c2925fc/aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8", size = 1619317 }, - { url = "https://files.pythonhosted.org/packages/96/74/879b23cdd816db4133325a201287c95bef4ce669acde37f8f1b8669e1755/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c", size = 1641416 }, - { url = "https://files.pythonhosted.org/packages/30/98/b123f6b15d87c54e58fd7ae3558ff594f898d7f30a90899718f3215ad328/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab", size = 1646514 }, - { url = "https://files.pythonhosted.org/packages/d7/38/257fda3dc99d6978ab943141d5165ec74fd4b4164baa15e9c66fa21da86b/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da", size = 1702095 }, - { url = "https://files.pythonhosted.org/packages/0c/f4/ddab089053f9fb96654df5505c0a69bde093214b3c3454f6bfdb1845f558/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853", size = 1734611 }, - { url = "https://files.pythonhosted.org/packages/c3/d6/f30b2bc520c38c8aa4657ed953186e535ae84abe55c08d0f70acd72ff577/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e", size = 1694576 }, - { url = "https://files.pythonhosted.org/packages/bc/97/b0a88c3f4c6d0020b34045ee6d954058abc870814f6e310c4c9b74254116/aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600", size = 411363 }, - { url = "https://files.pythonhosted.org/packages/7f/23/cc36d9c398980acaeeb443100f0216f50a7cfe20c67a9fd0a2f1a5a846de/aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d", size = 437666 }, - { url = "https://files.pythonhosted.org/packages/49/d1/d8af164f400bad432b63e1ac857d74a09311a8334b0481f2f64b158b50eb/aiohttp-3.11.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:541d823548ab69d13d23730a06f97460f4238ad2e5ed966aaf850d7c369782d9", size = 697982 }, - { url = "https://files.pythonhosted.org/packages/92/d1/faad3bf9fa4bfd26b95c69fc2e98937d52b1ff44f7e28131855a98d23a17/aiohttp-3.11.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:929f3ed33743a49ab127c58c3e0a827de0664bfcda566108989a14068f820194", size = 460662 }, - { url = "https://files.pythonhosted.org/packages/db/61/0d71cc66d63909dabc4590f74eba71f91873a77ea52424401c2498d47536/aiohttp-3.11.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0882c2820fd0132240edbb4a51eb8ceb6eef8181db9ad5291ab3332e0d71df5f", size = 452950 }, - { url = "https://files.pythonhosted.org/packages/07/db/6d04bc7fd92784900704e16b745484ef45b77bd04e25f58f6febaadf7983/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63de12e44935d5aca7ed7ed98a255a11e5cb47f83a9fded7a5e41c40277d104", size = 1665178 }, - { url = "https://files.pythonhosted.org/packages/54/5c/e95ade9ae29f375411884d9fd98e50535bf9fe316c9feb0f30cd2ac8f508/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa54f8ef31d23c506910c21163f22b124facb573bff73930735cf9fe38bf7dff", size = 1717939 }, - { url = "https://files.pythonhosted.org/packages/6f/1c/1e7d5c5daea9e409ed70f7986001b8c9e3a49a50b28404498d30860edab6/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344d5dc18074e3872777b62f5f7d584ae4344cd6006c17ba12103759d407af3", size = 1775125 }, - { url = "https://files.pythonhosted.org/packages/5d/66/890987e44f7d2f33a130e37e01a164168e6aff06fce15217b6eaf14df4f6/aiohttp-3.11.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7fb429ab1aafa1f48578eb315ca45bd46e9c37de11fe45c7f5f4138091e2f1", size = 1677176 }, - { url = "https://files.pythonhosted.org/packages/8f/dc/e2ba57d7a52df6cdf1072fd5fa9c6301a68e1cd67415f189805d3eeb031d/aiohttp-3.11.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c341c7d868750e31961d6d8e60ff040fb9d3d3a46d77fd85e1ab8e76c3e9a5c4", size = 1603192 }, - { url = "https://files.pythonhosted.org/packages/6c/9e/8d08a57de79ca3a358da449405555e668f2c8871a7777ecd2f0e3912c272/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed9ee95614a71e87f1a70bc81603f6c6760128b140bc4030abe6abaa988f1c3d", size = 1618296 }, - { url = "https://files.pythonhosted.org/packages/56/51/89822e3ec72db352c32e7fc1c690370e24e231837d9abd056490f3a49886/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de8d38f1c2810fa2a4f1d995a2e9c70bb8737b18da04ac2afbf3971f65781d87", size = 1616524 }, - { url = "https://files.pythonhosted.org/packages/2c/fa/e2e6d9398f462ffaa095e84717c1732916a57f1814502929ed67dd7568ef/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a9b7371665d4f00deb8f32208c7c5e652059b0fda41cf6dbcac6114a041f1cc2", size = 1685471 }, - { url = "https://files.pythonhosted.org/packages/ae/5f/6bb976e619ca28a052e2c0ca7b0251ccd893f93d7c24a96abea38e332bf6/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:620598717fce1b3bd14dd09947ea53e1ad510317c85dda2c9c65b622edc96b12", size = 1715312 }, - { url = "https://files.pythonhosted.org/packages/79/c1/756a7e65aa087c7fac724d6c4c038f2faaa2a42fe56dbc1dd62a33ca7213/aiohttp-3.11.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf8d9bfee991d8acc72d060d53860f356e07a50f0e0d09a8dfedea1c554dd0d5", size = 1672783 }, - { url = "https://files.pythonhosted.org/packages/73/ba/a6190ebb02176c7f75e6308da31f5d49f6477b651a3dcfaaaca865a298e2/aiohttp-3.11.11-cp313-cp313-win32.whl", hash = "sha256:9d73ee3725b7a737ad86c2eac5c57a4a97793d9f442599bea5ec67ac9f4bdc3d", size = 410229 }, - { url = "https://files.pythonhosted.org/packages/b8/62/c9fa5bafe03186a0e4699150a7fed9b1e73240996d0d2f0e5f70f3fdf471/aiohttp-3.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:c7a06301c2fb096bdb0bd25fe2011531c1453b9f2c163c8031600ec73af1cc99", size = 436081 }, +sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, + { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, + { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, + { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, + { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, + { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, + { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, + { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, + { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, + { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, + { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, + { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, + { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, + { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, + { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, + { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, + { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, + { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, + { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, + { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, + { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, + { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, + { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, + { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, + { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, + { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, + { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, + { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, + { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, + { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, ] [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, + { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] [[package]] @@ -113,16 +147,15 @@ wheels = [ [[package]] name = "anyio" -version = "4.8.0" +version = "4.6.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } +sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, + { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, ] [[package]] @@ -141,11 +174,11 @@ wheels = [ [[package]] name = "attrs" -version = "24.3.0" +version = "24.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, ] [[package]] @@ -159,32 +192,32 @@ wheels = [ [[package]] name = "bcrypt" -version = "4.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/8c/dd696962612e4cd83c40a9e6b3db77bfe65a830f4b9af44098708584686c/bcrypt-4.2.1.tar.gz", hash = "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe", size = 24427 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/ca/e17b08c523adb93d5f07a226b2bd45a7c6e96b359e31c1e99f9db58cb8c3/bcrypt-4.2.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17", size = 489982 }, - { url = "https://files.pythonhosted.org/packages/6a/be/e7c6e0fd6087ee8fc6d77d8d9e817e9339d879737509019b9a9012a1d96f/bcrypt-4.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f", size = 273108 }, - { url = "https://files.pythonhosted.org/packages/d6/53/ac084b7d985aee1a5f2b086d501f550862596dbf73220663b8c17427e7f2/bcrypt-4.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad", size = 278733 }, - { url = "https://files.pythonhosted.org/packages/8e/ab/b8710a3d6231c587e575ead0b1c45bb99f5454f9f579c9d7312c17b069cc/bcrypt-4.2.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea", size = 273856 }, - { url = "https://files.pythonhosted.org/packages/9d/e5/2fd1ea6395358ffdfd4afe370d5b52f71408f618f781772a48971ef3b92b/bcrypt-4.2.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396", size = 279067 }, - { url = "https://files.pythonhosted.org/packages/4e/ef/f2cb7a0f7e1ed800a604f8ab256fb0afcf03c1540ad94ff771ce31e794aa/bcrypt-4.2.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425", size = 306851 }, - { url = "https://files.pythonhosted.org/packages/de/cb/578b0023c6a5ca16a177b9044ba6bd6032277bd3ef020fb863eccd22e49b/bcrypt-4.2.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685", size = 310793 }, - { url = "https://files.pythonhosted.org/packages/98/bc/9d501ee9d754f63d4b1086b64756c284facc3696de9b556c146279a124a5/bcrypt-4.2.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6", size = 320957 }, - { url = "https://files.pythonhosted.org/packages/a1/25/2ec4ce5740abc43182bfc064b9acbbf5a493991246985e8b2bfe231ead64/bcrypt-4.2.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139", size = 339958 }, - { url = "https://files.pythonhosted.org/packages/6d/64/fd67788f64817727897d31e9cdeeeba3941eaad8540733c05c7eac4aa998/bcrypt-4.2.1-cp37-abi3-win32.whl", hash = "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005", size = 160912 }, - { url = "https://files.pythonhosted.org/packages/00/8f/fe834eaa54abbd7cab8607e5020fa3a0557e929555b9e4ca404b4adaab06/bcrypt-4.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526", size = 152981 }, - { url = "https://files.pythonhosted.org/packages/4a/57/23b46933206daf5384b5397d9878746d2249fe9d45efaa8e1467c87d3048/bcrypt-4.2.1-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413", size = 489842 }, - { url = "https://files.pythonhosted.org/packages/fd/28/3ea8a39ddd4938b6c6b6136816d72ba5e659e2d82b53d843c8c53455ac4d/bcrypt-4.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a", size = 272500 }, - { url = "https://files.pythonhosted.org/packages/77/7f/b43622999f5d4de06237a195ac5501ac83516adf571b907228cd14bac8fe/bcrypt-4.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c", size = 278368 }, - { url = "https://files.pythonhosted.org/packages/50/68/f2e3959014b4d8874c747e6e171d46d3e63a3a39aaca8417a8d837eda0a8/bcrypt-4.2.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99", size = 273335 }, - { url = "https://files.pythonhosted.org/packages/d6/c3/4b4bad4da852924427c651589d464ad1aa624f94dd904ddda8493b0a35e5/bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54", size = 278614 }, - { url = "https://files.pythonhosted.org/packages/6e/5a/ee107961e84c41af2ac201d0460f962b6622ff391255ffd46429e9e09dc1/bcrypt-4.2.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837", size = 306464 }, - { url = "https://files.pythonhosted.org/packages/5c/72/916e14fa12d2b1d1fc6c26ea195337419da6dd23d0bf53ac61ef3739e5c5/bcrypt-4.2.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331", size = 310674 }, - { url = "https://files.pythonhosted.org/packages/97/92/3dc76d8bfa23300591eec248e950f85bd78eb608c96bd4747ce4cc06acdb/bcrypt-4.2.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84", size = 320577 }, - { url = "https://files.pythonhosted.org/packages/5d/ab/a6c0da5c2cf86600f74402a72b06dfe365e1a1d30783b1bbeec460fd57d1/bcrypt-4.2.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d", size = 339836 }, - { url = "https://files.pythonhosted.org/packages/b4/b4/e75b6e9a72a030a04362034022ebe317c5b735d04db6ad79237101ae4a5c/bcrypt-4.2.1-cp39-abi3-win32.whl", hash = "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf", size = 160911 }, - { url = "https://files.pythonhosted.org/packages/76/b9/d51d34e6cd6d887adddb28a8680a1d34235cc45b9d6e238ce39b98199ca0/bcrypt-4.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c", size = 153078 }, +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/7e/d95e7d96d4828e965891af92e43b52a4cd3395dc1c1ef4ee62748d0471d0/bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", size = 24294 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/81/4e8f5bc0cd947e91fb720e1737371922854da47a94bc9630454e7b2845f8/bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", size = 471568 }, + { url = "https://files.pythonhosted.org/packages/05/d2/1be1e16aedec04bcf8d0156e01b987d16a2063d38e64c3f28030a3427d61/bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", size = 277372 }, + { url = "https://files.pythonhosted.org/packages/e3/96/7a654027638ad9b7589effb6db77eb63eba64319dfeaf9c0f4ca953e5f76/bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", size = 273488 }, + { url = "https://files.pythonhosted.org/packages/46/54/dc7b58abeb4a3d95bab653405935e27ba32f21b812d8ff38f271fb6f7f55/bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", size = 277759 }, + { url = "https://files.pythonhosted.org/packages/ac/be/da233c5f11fce3f8adec05e8e532b299b64833cc962f49331cdd0e614fa9/bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", size = 273796 }, + { url = "https://files.pythonhosted.org/packages/b0/b8/8b4add88d55a263cf1c6b8cf66c735280954a04223fcd2880120cc767ac3/bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", size = 311082 }, + { url = "https://files.pythonhosted.org/packages/7b/76/2aa660679abbdc7f8ee961552e4bb6415a81b303e55e9374533f22770203/bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", size = 305912 }, + { url = "https://files.pythonhosted.org/packages/00/03/2af7c45034aba6002d4f2b728c1a385676b4eab7d764410e34fd768009f2/bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", size = 325185 }, + { url = "https://files.pythonhosted.org/packages/dc/5d/6843443ce4ab3af40bddb6c7c085ed4a8418b3396f7a17e60e6d9888416c/bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", size = 335188 }, + { url = "https://files.pythonhosted.org/packages/cb/4c/ff8ca83d816052fba36def1d24e97d9a85739b9bbf428c0d0ecd296a07c8/bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", size = 156481 }, + { url = "https://files.pythonhosted.org/packages/65/f1/e09626c88a56cda488810fb29d5035f1662873777ed337880856b9d204ae/bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", size = 151336 }, + { url = "https://files.pythonhosted.org/packages/96/86/8c6a84daed4dd878fbab094400c9174c43d9b838ace077a2f8ee8bc3ae12/bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", size = 472414 }, + { url = "https://files.pythonhosted.org/packages/f6/05/e394515f4e23c17662e5aeb4d1859b11dc651be01a3bd03c2e919a155901/bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", size = 277599 }, + { url = "https://files.pythonhosted.org/packages/4b/3b/ad784eac415937c53da48983756105d267b91e56aa53ba8a1b2014b8d930/bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", size = 273491 }, + { url = "https://files.pythonhosted.org/packages/cc/14/b9ff8e0218bee95e517b70e91130effb4511e8827ac1ab00b4e30943a3f6/bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", size = 277934 }, + { url = "https://files.pythonhosted.org/packages/3e/d0/31938bb697600a04864246acde4918c4190a938f891fd11883eaaf41327a/bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", size = 273804 }, + { url = "https://files.pythonhosted.org/packages/e7/c3/dae866739989e3f04ae304e1201932571708cb292a28b2f1b93283e2dcd8/bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", size = 311275 }, + { url = "https://files.pythonhosted.org/packages/5d/2c/019bc2c63c6125ddf0483ee7d914a405860327767d437913942b476e9c9b/bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", size = 306355 }, + { url = "https://files.pythonhosted.org/packages/75/fe/9e137727f122bbe29771d56afbf4e0dbc85968caa8957806f86404a5bfe1/bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", size = 325381 }, + { url = "https://files.pythonhosted.org/packages/1a/d4/586b9c18a327561ea4cd336ff4586cca1a7aa0f5ee04e23a8a8bb9ca64f1/bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", size = 335685 }, + { url = "https://files.pythonhosted.org/packages/24/55/1a7127faf4576138bb278b91e9c75307490178979d69c8e6e273f74b974f/bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", size = 155857 }, + { url = "https://files.pythonhosted.org/packages/1c/2a/c74052e54162ec639266d91539cca7cbf3d1d3b8b36afbfeaee0ea6a1702/bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", size = 151717 }, ] [[package]] @@ -240,11 +273,11 @@ wheels = [ [[package]] name = "certifi" -version = "2024.12.14" +version = "2024.8.30" 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/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } 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/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, ] [[package]] @@ -291,49 +324,53 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.1" -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 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, - { 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/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/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/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/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/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/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/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/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/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/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, - { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, - { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, - { 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/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/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/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/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/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/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/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/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/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/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, - { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, - { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] [[package]] name = "click" -version = "8.1.8" +version = "8.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -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/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } 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/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, ] [[package]] @@ -359,71 +396,69 @@ wheels = [ [[package]] name = "coverage" -version = "7.6.10" -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 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 }, - { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 }, - { 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/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/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/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/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/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/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 }, - { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 }, - { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 }, - { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 }, - { 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/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/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/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/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/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/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 }, - { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 }, - { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 }, - { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 }, - { 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/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/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/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/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/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/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 }, - { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 }, +version = "7.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/12/3669b6382792783e92046730ad3327f53b2726f0603f4c311c4da4824222/coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", size = 798716 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/e7/9291de916d084f41adddfd4b82246e68d61d6a75747f075f7e64628998d2/coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", size = 207013 }, + { url = "https://files.pythonhosted.org/packages/27/03/932c2c5717a7fa80cd43c6a07d3177076d97b79f12f40f882f9916db0063/coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", size = 207251 }, + { url = "https://files.pythonhosted.org/packages/d5/3f/0af47dcb9327f65a45455fbca846fe96eb57c153af46c4754a3ba678938a/coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", size = 240268 }, + { url = "https://files.pythonhosted.org/packages/8a/3c/37a9d81bbd4b23bc7d46ca820e16174c613579c66342faa390a271d2e18b/coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", size = 237298 }, + { url = "https://files.pythonhosted.org/packages/c0/70/6b0627e5bd68204ee580126ed3513140b2298995c1233bd67404b4e44d0e/coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", size = 239367 }, + { url = "https://files.pythonhosted.org/packages/3c/eb/634d7dfab24ac3b790bebaf9da0f4a5352cbc125ce6a9d5c6cf4c6cae3c7/coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", size = 238853 }, + { url = "https://files.pythonhosted.org/packages/d9/0d/8e3ed00f1266ef7472a4e33458f42e39492e01a64281084fb3043553d3f1/coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", size = 237160 }, + { url = "https://files.pythonhosted.org/packages/ce/9c/4337f468ef0ab7a2e0887a9c9da0e58e2eada6fc6cbee637a4acd5dfd8a9/coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", size = 238824 }, + { url = "https://files.pythonhosted.org/packages/5e/09/3e94912b8dd37251377bb02727a33a67ee96b84bbbe092f132b401ca5dd9/coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", size = 209639 }, + { url = "https://files.pythonhosted.org/packages/01/69/d4f3a4101171f32bc5b3caec8ff94c2c60f700107a6aaef7244b2c166793/coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", size = 210428 }, + { url = "https://files.pythonhosted.org/packages/c2/4d/2dede4f7cb5a70fb0bb40a57627fddf1dbdc6b9c1db81f7c4dcdcb19e2f4/coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", size = 207039 }, + { url = "https://files.pythonhosted.org/packages/3f/f9/d86368ae8c79e28f1fb458ebc76ae9ff3e8bd8069adc24e8f2fed03c58b7/coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", size = 207298 }, + { url = "https://files.pythonhosted.org/packages/64/c5/b4cc3c3f64622c58fbfd4d8b9a7a8ce9d355f172f91fcabbba1f026852f6/coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", size = 239813 }, + { url = "https://files.pythonhosted.org/packages/8a/86/14c42e60b70a79b26099e4d289ccdfefbc68624d096f4481163085aa614c/coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", size = 236959 }, + { url = "https://files.pythonhosted.org/packages/7f/f8/4436a643631a2fbab4b44d54f515028f6099bfb1cd95b13cfbf701e7f2f2/coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", size = 238950 }, + { url = "https://files.pythonhosted.org/packages/49/50/1571810ddd01f99a0a8be464a4ac8b147f322cd1e8e296a1528984fc560b/coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", size = 238610 }, + { url = "https://files.pythonhosted.org/packages/f3/8c/6312d241fe7cbd1f0cade34a62fea6f333d1a261255d76b9a87074d8703c/coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", size = 236697 }, + { url = "https://files.pythonhosted.org/packages/ce/5f/fef33dfd05d87ee9030f614c857deb6df6556b8f6a1c51bbbb41e24ee5ac/coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", size = 238541 }, + { url = "https://files.pythonhosted.org/packages/a9/64/6a984b6e92e1ea1353b7ffa08e27f707a5e29b044622445859200f541e8c/coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", size = 209707 }, + { url = "https://files.pythonhosted.org/packages/5c/60/ce5a9e942e9543783b3db5d942e0578b391c25cdd5e7f342d854ea83d6b7/coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", size = 210439 }, + { url = "https://files.pythonhosted.org/packages/78/53/6719677e92c308207e7f10561a1b16ab8b5c00e9328efc9af7cfd6fb703e/coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", size = 207784 }, + { url = "https://files.pythonhosted.org/packages/fa/dd/7054928930671fcb39ae6a83bb71d9ab5f0afb733172543ced4b09a115ca/coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", size = 208058 }, + { url = "https://files.pythonhosted.org/packages/b5/7d/fd656ddc2b38301927b9eb3aae3fe827e7aa82e691923ed43721fd9423c9/coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", size = 250772 }, + { url = "https://files.pythonhosted.org/packages/90/d0/eb9a3cc2100b83064bb086f18aedde3afffd7de6ead28f69736c00b7f302/coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", size = 246490 }, + { url = "https://files.pythonhosted.org/packages/45/44/3f64f38f6faab8a0cfd2c6bc6eb4c6daead246b97cf5f8fc23bf3788f841/coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", size = 248848 }, + { url = "https://files.pythonhosted.org/packages/5d/11/4c465a5f98656821e499f4b4619929bd5a34639c466021740ecdca42aa30/coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", size = 248340 }, + { url = "https://files.pythonhosted.org/packages/f1/96/ebecda2d016cce9da812f404f720ca5df83c6b29f65dc80d2000d0078741/coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", size = 246229 }, + { url = "https://files.pythonhosted.org/packages/16/d9/3d820c00066ae55d69e6d0eae11d6149a5ca7546de469ba9d597f01bf2d7/coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", size = 247510 }, + { url = "https://files.pythonhosted.org/packages/8f/c3/4fa1eb412bb288ff6bfcc163c11700ff06e02c5fad8513817186e460ed43/coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", size = 210353 }, + { url = "https://files.pythonhosted.org/packages/7e/77/03fc2979d1538884d921c2013075917fc927f41cd8526909852fe4494112/coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", size = 211502 }, ] [[package]] name = "cryptography" -version = "44.0.0" +version = "43.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/4c/45dfa6829acffa344e3967d6006ee4ae8be57af746ae2eba1c431949b32c/cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02", size = 710657 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/09/8cc67f9b84730ad330b3b72cf867150744bf07ff113cda21a15a1c6d2c7c/cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123", size = 6541833 }, - { 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/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/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/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/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/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/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/ef/d4/cae11bf68c0f981e0413906c6dd03ae7fa864347ed5fac40021df1ef467c/cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053", size = 2757925 }, - { url = "https://files.pythonhosted.org/packages/64/b1/50d7739254d2002acae64eed4fc43b24ac0cc44bf0a0d388d1ca06ec5bb1/cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd", size = 3202055 }, - { url = "https://files.pythonhosted.org/packages/11/18/61e52a3d28fc1514a43b0ac291177acd1b4de00e9301aaf7ef867076ff8a/cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591", size = 6542801 }, - { 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/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/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/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/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/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/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/46/b0/f4f7d0d0bcfbc8dd6296c1449be326d04217c57afb8b2594f017eed95533/cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417", size = 2758672 }, - { url = "https://files.pythonhosted.org/packages/97/9b/443270b9210f13f6ef240eff73fd32e02d381e7103969dc66ce8e89ee901/cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede", size = 3202071 }, +sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 }, + { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 }, + { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 }, + { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 }, + { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 }, + { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 }, + { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 }, + { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 }, + { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 }, + { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 }, + { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 }, + { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 }, + { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 }, + { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 }, + { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 }, + { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 }, + { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 }, + { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, ] [[package]] @@ -437,14 +472,14 @@ wheels = [ [[package]] name = "deprecated" -version = "1.2.15" +version = "1.2.14" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/a3/53e7d78a6850ffdd394d7048a31a6f14e44900adedf190f9a165f6b69439/deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d", size = 2977612 } +sdist = { url = "https://files.pythonhosted.org/packages/92/14/1e41f504a246fc224d2ac264c227975427a85caf37c3979979edb9b1b232/Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3", size = 2974416 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/8f/c7f227eb42cfeaddce3eb0c96c60cbca37797fa7b34f8e1aeadf6c5c0983/Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", size = 9941 }, + { url = "https://files.pythonhosted.org/packages/20/8d/778b7d51b981a96554f29136cd59ca7880bf58094338085bcf2a979a0e6a/Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c", size = 9561 }, ] [[package]] @@ -628,41 +663,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, ] -[[package]] -name = "httpcore" -version = "1.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, -] - [[package]] name = "identify" -version = "2.6.6" +version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/bf/c68c46601bacd4c6fb4dd751a42b6e7087240eaabc6487f2ef7a48e0e8fc/identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251", size = 99217 } +sdist = { url = "https://files.pythonhosted.org/packages/29/bb/25024dbcc93516c492b75919e76f389bac754a3e4248682fba32b250c880/identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98", size = 99097 } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/a1/68a395c17eeefb04917034bd0a1bfa765e7654fa150cca473d669aa3afb5/identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881", size = 99083 }, + { url = "https://files.pythonhosted.org/packages/7d/0c/4ef72754c050979fdcc06c744715ae70ea37e734816bb6514f79df77a42f/identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", size = 98972 }, ] [[package]] @@ -718,111 +725,220 @@ wheels = [ [[package]] name = "jinja2" -version = "3.1.5" +version = "3.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } +sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, + { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, ] [[package]] name = "jumpstarter" -version = "0.5.1.dev117+gaa5a151.d20250123" -source = { editable = "." } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter" } dependencies = [ { name = "aiohttp" }, { name = "anyio" }, - { name = "asyncclick" }, - { name = "fabric" }, - { name = "grpcio" }, - { name = "httpx" }, - { name = "kubernetes" }, - { name = "kubernetes-asyncio" }, - { name = "opendal" }, - { name = "pexpect" }, - { name = "protobuf" }, + { name = "jumpstarter-protocol" }, { name = "pydantic" }, - { name = "pyserial" }, { name = "pyyaml" }, { name = "tqdm" }, - { name = "wsproto" }, ] [package.dev-dependencies] dev = [ { name = "cryptography" }, - { name = "esbonio" }, - { name = "pre-commit" }, + { name = "jumpstarter-driver-composite" }, + { name = "jumpstarter-driver-network" }, + { name = "jumpstarter-driver-power" }, { name = "pytest" }, { name = "pytest-anyio" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, - { name = "ruff" }, - { name = "typos" }, - { name = "websocket-client" }, -] -docs = [ - { name = "esbonio" }, - { name = "furo" }, - { name = "myst-parser" }, - { name = "sphinx" }, - { name = "sphinx-autobuild" }, - { name = "sphinx-click" }, - { name = "sphinx-substitution-extensions" }, - { name = "sphinxcontrib-mermaid" }, ] [package.metadata] requires-dist = [ { name = "aiohttp", specifier = ">=3.10.5" }, { name = "anyio", specifier = ">=4.4.0,!=4.6.2" }, - { name = "asyncclick", specifier = ">=8.1.7.2" }, - { name = "fabric", specifier = ">=3.2.2" }, - { name = "grpcio", specifier = ">=1.66.1" }, - { name = "httpx", specifier = ">=0.27.0" }, - { name = "kubernetes", specifier = ">=31.0.0" }, - { name = "kubernetes-asyncio", specifier = ">=31.1.0" }, - { name = "opendal", specifier = ">=0.45.8" }, - { name = "pexpect", specifier = ">=4.9.0" }, - { name = "protobuf", specifier = ">=5.28.0" }, + { name = "jumpstarter-protocol", editable = "packages/jumpstarter-protocol" }, { name = "pydantic", specifier = ">=2.8.2" }, - { name = "pyserial", specifier = ">=3.5" }, { name = "pyyaml", specifier = ">=6.0.2" }, { name = "tqdm", specifier = ">=4.66.5" }, - { name = "wsproto", specifier = ">=1.2.0" }, ] [package.metadata.requires-dev] dev = [ - { name = "cryptography", specifier = ">=43.0.1" }, - { name = "esbonio", specifier = ">=0.16.5" }, - { name = "pre-commit", specifier = ">=3.8.0" }, + { name = "cryptography", specifier = ">=43.0.3" }, + { name = "jumpstarter-driver-composite", editable = "packages/jumpstarter-driver-composite" }, + { name = "jumpstarter-driver-network", editable = "packages/jumpstarter-driver-network" }, + { name = "jumpstarter-driver-power", editable = "packages/jumpstarter-driver-power" }, + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, +] + +[[package]] +name = "jumpstarter-cli" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-cli" } +dependencies = [ + { name = "jumpstarter-cli-admin" }, + { name = "jumpstarter-cli-client" }, + { name = "jumpstarter-cli-exporter" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "jumpstarter-cli-admin", editable = "packages/jumpstarter-cli-admin" }, + { name = "jumpstarter-cli-client", editable = "packages/jumpstarter-cli-client" }, + { name = "jumpstarter-cli-exporter", editable = "packages/jumpstarter-cli-exporter" }, +] + +[package.metadata.requires-dev] +dev = [ { name = "pytest", specifier = ">=8.3.2" }, { name = "pytest-anyio", specifier = ">=0.0.0" }, { name = "pytest-asyncio", specifier = ">=0.0.0" }, { name = "pytest-cov", specifier = ">=5.0.0" }, - { name = "ruff", specifier = ">=0.6.1" }, - { name = "typos", specifier = ">=1.23.6" }, - { name = "websocket-client", specifier = ">=1.8.0" }, ] -docs = [ - { name = "esbonio", specifier = ">=0.16.4" }, - { name = "furo", specifier = ">=2024.8.6" }, - { name = "myst-parser", specifier = ">=4.0.0" }, - { name = "sphinx", specifier = "<8.1.0" }, - { name = "sphinx-autobuild", specifier = ">=2024.4.16" }, - { name = "sphinx-click", specifier = ">=6.0.0" }, - { name = "sphinx-substitution-extensions", specifier = ">=2024.10.17" }, - { name = "sphinxcontrib-mermaid", specifier = ">=0.9.2" }, + +[[package]] +name = "jumpstarter-cli-admin" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-cli-admin" } +dependencies = [ + { name = "jumpstarter-cli-common" }, + { name = "jumpstarter-kubernetes" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "jumpstarter-cli-common", editable = "packages/jumpstarter-cli-common" }, + { name = "jumpstarter-kubernetes", editable = "packages/jumpstarter-kubernetes" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-cli-client" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-cli-client" } +dependencies = [ + { name = "jumpstarter-cli-common" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [{ name = "jumpstarter-cli-common", editable = "packages/jumpstarter-cli-common" }] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-cli-common" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-cli-common" } +dependencies = [ + { name = "asyncclick" }, + { name = "jumpstarter" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-cli-exporter" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-cli-exporter" } +dependencies = [ + { name = "asyncclick" }, + { name = "jumpstarter-cli-common" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter-cli-common", editable = "packages/jumpstarter-cli-common" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, ] [[package]] name = "jumpstarter-driver-can" -version = "0.5.1.dev117+gaa5a151.d20250123" -source = { editable = "contrib/drivers/can" } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-can" } dependencies = [ { name = "can-isotp" }, { name = "jumpstarter" }, @@ -838,22 +954,57 @@ dev = [ [package.metadata] requires-dist = [ { name = "can-isotp", specifier = ">=2.0.6" }, - { name = "jumpstarter", editable = "." }, - { name = "python-can", specifier = ">=4.4.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "python-can", specifier = ">=4.5.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-driver-composite" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-composite" } +dependencies = [ + { name = "asyncclick" }, + { name = "jumpstarter" }, +] + +[package.dev-dependencies] +dev = [ + { name = "jumpstarter-driver-power" }, + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, ] [package.metadata.requires-dev] dev = [ + { name = "jumpstarter-driver-power", editable = "packages/jumpstarter-driver-power" }, { name = "pytest", specifier = ">=8.3.2" }, { name = "pytest-cov", specifier = ">=5.0.0" }, ] [[package]] name = "jumpstarter-driver-dutlink" -version = "0.5.1.dev117+gaa5a151.d20250123" -source = { editable = "contrib/drivers/dutlink" } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-dutlink" } dependencies = [ + { name = "asyncclick" }, { name = "jumpstarter" }, + { name = "jumpstarter-driver-composite" }, + { name = "jumpstarter-driver-network" }, + { name = "jumpstarter-driver-opendal" }, + { name = "jumpstarter-driver-power" }, + { name = "jumpstarter-driver-pyserial" }, { name = "pyudev" }, { name = "pyusb" }, ] @@ -866,7 +1017,13 @@ dev = [ [package.metadata] requires-dist = [ - { name = "jumpstarter", editable = "." }, + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "jumpstarter-driver-composite", editable = "packages/jumpstarter-driver-composite" }, + { name = "jumpstarter-driver-network", editable = "packages/jumpstarter-driver-network" }, + { name = "jumpstarter-driver-opendal", editable = "packages/jumpstarter-driver-opendal" }, + { name = "jumpstarter-driver-power", editable = "packages/jumpstarter-driver-power" }, + { name = "jumpstarter-driver-pyserial", editable = "packages/jumpstarter-driver-pyserial" }, { name = "pyudev", specifier = ">=0.24.3" }, { name = "pyusb", specifier = ">=1.2.1" }, ] @@ -880,10 +1037,11 @@ dev = [ [[package]] name = "jumpstarter-driver-http" version = "0.1.0" -source = { editable = "contrib/drivers/http" } +source = { editable = "packages/jumpstarter-driver-http" } dependencies = [ { name = "anyio" }, { name = "jumpstarter" }, + { name = "jumpstarter-driver-opendal" }, ] [package.dev-dependencies] @@ -897,20 +1055,147 @@ dev = [ [package.metadata] requires-dist = [ { name = "anyio", specifier = ">=4.6.2.post1" }, - { name = "jumpstarter", editable = "." }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "jumpstarter-driver-opendal", editable = "packages/jumpstarter-driver-opendal" }, ] [package.metadata.requires-dev] dev = [ { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, { name = "pytest-asyncio", specifier = ">=0.24.0" }, { name = "pytest-cov", specifier = ">=6.0.0" }, { name = "ruff", specifier = ">=0.7.1" }, ] +[[package]] +name = "jumpstarter-driver-network" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-network" } +dependencies = [ + { name = "fabric" }, + { name = "jumpstarter" }, + { name = "pexpect" }, + { name = "wsproto" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "websocket-client" }, +] + +[package.metadata] +requires-dist = [ + { name = "fabric", specifier = ">=3.2.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "pexpect", specifier = ">=4.9.0" }, + { name = "wsproto", specifier = ">=1.2.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, + { name = "websocket-client", specifier = ">=1.8.0" }, +] + +[[package]] +name = "jumpstarter-driver-opendal" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-opendal" } +dependencies = [ + { name = "asyncclick" }, + { name = "jumpstarter" }, + { name = "opendal" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "opendal", specifier = ">=0.45.8" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-driver-power" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-power" } +dependencies = [ + { name = "asyncclick" }, + { name = "jumpstarter" }, + { name = "pyserial" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "trio" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "pyserial", specifier = ">=3.5" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, + { name = "trio", specifier = ">=0.28.0" }, +] + +[[package]] +name = "jumpstarter-driver-pyserial" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-pyserial" } +dependencies = [ + { name = "asyncclick" }, + { name = "jumpstarter" }, + { name = "jumpstarter-driver-network" }, + { name = "pyserial" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncclick", specifier = ">=8.1.7.2" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "jumpstarter-driver-network", editable = "packages/jumpstarter-driver-network" }, + { name = "pyserial", specifier = ">=3.5" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + [[package]] name = "jumpstarter-driver-raspberrypi" -source = { editable = "contrib/drivers/raspberrypi" } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-raspberrypi" } dependencies = [ { name = "gpiozero" }, { name = "jumpstarter" }, @@ -925,7 +1210,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "gpiozero", specifier = ">=2.0.1" }, - { name = "jumpstarter", editable = "." }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, ] [package.metadata.requires-dev] @@ -936,10 +1221,11 @@ dev = [ [[package]] name = "jumpstarter-driver-sdwire" -version = "0.5.1.dev117+gaa5a151.d20250123" -source = { editable = "contrib/drivers/sdwire" } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-sdwire" } dependencies = [ { name = "jumpstarter" }, + { name = "jumpstarter-driver-opendal" }, { name = "pyudev" }, { name = "pyusb" }, ] @@ -952,7 +1238,8 @@ dev = [ [package.metadata] requires-dist = [ - { name = "jumpstarter", editable = "." }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "jumpstarter-driver-opendal", editable = "packages/jumpstarter-driver-opendal" }, { name = "pyudev", specifier = ">=0.24.3" }, { name = "pyusb", specifier = ">=1.2.1" }, ] @@ -966,40 +1253,44 @@ dev = [ [[package]] name = "jumpstarter-driver-tftp" version = "0.1.0" -source = { editable = "contrib/drivers/tftp" } +source = { editable = "packages/jumpstarter-driver-tftp" } dependencies = [ { name = "aiofiles" }, { name = "anyio" }, { name = "jumpstarter" }, + { name = "jumpstarter-driver-opendal" }, ] [package.dev-dependencies] dev = [ + { name = "jumpstarter-testing" }, { name = "pytest" }, + { name = "pytest-anyio" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, - { name = "ruff" }, ] [package.metadata] requires-dist = [ { name = "aiofiles", specifier = ">=24.1.0" }, { name = "anyio", specifier = ">=4.6.2.post1" }, - { name = "jumpstarter", editable = "." }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "jumpstarter-driver-opendal", editable = "packages/jumpstarter-driver-opendal" }, ] [package.metadata.requires-dev] dev = [ - { name = "pytest", specifier = ">=8.3.3" }, + { name = "jumpstarter-testing", editable = "packages/jumpstarter-testing" }, + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, { name = "pytest-asyncio", specifier = ">=0.0.0" }, { name = "pytest-cov", specifier = ">=6.0.0" }, - { name = "ruff", specifier = ">=0.7.1" }, ] [[package]] name = "jumpstarter-driver-ustreamer" -version = "0.5.1.dev117+gaa5a151.d20250123" -source = { editable = "contrib/drivers/ustreamer" } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-driver-ustreamer" } dependencies = [ { name = "jumpstarter" }, { name = "pillow" }, @@ -1013,7 +1304,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "jumpstarter", editable = "." }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, { name = "pillow", specifier = ">=10.4.0" }, ] @@ -1032,7 +1323,7 @@ dependencies = [ ] [package.metadata] -requires-dist = [{ name = "jumpstarter", editable = "." }] +requires-dist = [{ name = "jumpstarter", editable = "packages/jumpstarter" }] [[package]] name = "jumpstarter-example-soc-pytest" @@ -1041,22 +1332,26 @@ source = { virtual = "examples/soc-pytest" } dependencies = [ { name = "jumpstarter" }, { name = "jumpstarter-driver-dutlink" }, + { name = "jumpstarter-driver-network" }, { name = "jumpstarter-imagehash" }, + { name = "jumpstarter-testing" }, { name = "pytest" }, ] [package.metadata] requires-dist = [ - { name = "jumpstarter", editable = "." }, - { name = "jumpstarter-driver-dutlink", editable = "contrib/drivers/dutlink" }, - { name = "jumpstarter-imagehash", editable = "contrib/libs/imagehash" }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "jumpstarter-driver-dutlink", editable = "packages/jumpstarter-driver-dutlink" }, + { name = "jumpstarter-driver-network", editable = "packages/jumpstarter-driver-network" }, + { name = "jumpstarter-imagehash", editable = "packages/jumpstarter-imagehash" }, + { name = "jumpstarter-testing", editable = "packages/jumpstarter-testing" }, { name = "pytest", specifier = ">=8.3.2" }, ] [[package]] name = "jumpstarter-imagehash" -version = "0.5.1.dev117+gaa5a151.d20250123" -source = { editable = "contrib/libs/imagehash" } +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-imagehash" } dependencies = [ { name = "imagehash" }, { name = "jumpstarter" }, @@ -1071,15 +1366,108 @@ dev = [ [package.metadata] requires-dist = [ { name = "imagehash", specifier = ">=4.3.1" }, - { name = "jumpstarter", editable = "." }, + { name = "jumpstarter", editable = "packages/jumpstarter" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-kubernetes" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-kubernetes" } +dependencies = [ + { name = "jumpstarter" }, + { name = "kubernetes" }, + { name = "kubernetes-asyncio" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "kubernetes", specifier = ">=31.0.0" }, + { name = "kubernetes-asyncio", specifier = ">=31.1.0" }, ] [package.metadata.requires-dev] dev = [ { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, { name = "pytest-cov", specifier = ">=5.0.0" }, ] +[[package]] +name = "jumpstarter-protocol" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-protocol" } +dependencies = [ + { name = "grpcio" }, + { name = "protobuf" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.metadata] +requires-dist = [ + { name = "grpcio", specifier = ">=1.66.1" }, + { name = "protobuf", specifier = ">=5.29.3" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[[package]] +name = "jumpstarter-testing" +version = "0.5.1.dev125+g41e837e.d20250124" +source = { editable = "packages/jumpstarter-testing" } +dependencies = [ + { name = "jumpstarter" }, + { name = "pytest" }, + { name = "pytest-anyio" }, + { name = "pytest-asyncio" }, + { name = "pytest-cov" }, +] + +[package.dev-dependencies] +dev = [ + { name = "jumpstarter-driver-power" }, +] + +[package.metadata] +requires-dist = [ + { name = "jumpstarter", editable = "packages/jumpstarter" }, + { name = "pytest", specifier = ">=8.3.2" }, + { name = "pytest-anyio", specifier = ">=0.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.0.0" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, +] + +[package.metadata.requires-dev] +dev = [{ name = "jumpstarter-driver-power", editable = "packages/jumpstarter-driver-power" }] + [[package]] name = "kubernetes" version = "31.0.0" @@ -1296,40 +1684,40 @@ wheels = [ [[package]] name = "numpy" -version = "2.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/d0/c12ddfd3a02274be06ffc71f3efc6d0e457b0409c4481596881e748cb264/numpy-2.2.2.tar.gz", hash = "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f", size = 20233295 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/e6/847d15770ab7a01e807bdfcd4ead5bdae57c0092b7dc83878171b6af97bb/numpy-2.2.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467", size = 20912636 }, - { url = "https://files.pythonhosted.org/packages/d1/af/f83580891577b13bd7e261416120e036d0d8fb508c8a43a73e38928b794b/numpy-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a", size = 14098403 }, - { url = "https://files.pythonhosted.org/packages/2b/86/d019fb60a9d0f1d4cf04b014fe88a9135090adfadcc31c1fadbb071d7fa7/numpy-2.2.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825", size = 5128938 }, - { url = "https://files.pythonhosted.org/packages/7a/1b/50985edb6f1ec495a1c36452e860476f5b7ecdc3fc59ea89ccad3c4926c5/numpy-2.2.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37", size = 6661937 }, - { url = "https://files.pythonhosted.org/packages/f4/1b/17efd94cad1b9d605c3f8907fb06bcffc4ce4d1d14d46b95316cccccf2b9/numpy-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748", size = 14049518 }, - { url = "https://files.pythonhosted.org/packages/5b/73/65d2f0b698df1731e851e3295eb29a5ab8aa06f763f7e4188647a809578d/numpy-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0", size = 16099146 }, - { url = "https://files.pythonhosted.org/packages/d5/69/308f55c0e19d4b5057b5df286c5433822e3c8039ede06d4051d96f1c2c4e/numpy-2.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278", size = 15246336 }, - { url = "https://files.pythonhosted.org/packages/f0/d8/d8d333ad0d8518d077a21aeea7b7c826eff766a2b1ce1194dea95ca0bacf/numpy-2.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba", size = 17863507 }, - { url = "https://files.pythonhosted.org/packages/82/6e/0b84ad3103ffc16d6673e63b5acbe7901b2af96c2837174c6318c98e27ab/numpy-2.2.2-cp312-cp312-win32.whl", hash = "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283", size = 6276491 }, - { url = "https://files.pythonhosted.org/packages/fc/84/7f801a42a67b9772a883223a0a1e12069a14626c81a732bd70aac57aebc1/numpy-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb", size = 12616372 }, - { url = "https://files.pythonhosted.org/packages/e1/fe/df5624001f4f5c3e0b78e9017bfab7fdc18a8d3b3d3161da3d64924dd659/numpy-2.2.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", size = 20899188 }, - { url = "https://files.pythonhosted.org/packages/a9/80/d349c3b5ed66bd3cb0214be60c27e32b90a506946857b866838adbe84040/numpy-2.2.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", size = 14113972 }, - { url = "https://files.pythonhosted.org/packages/9d/50/949ec9cbb28c4b751edfa64503f0913cbfa8d795b4a251e7980f13a8a655/numpy-2.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", size = 5114294 }, - { url = "https://files.pythonhosted.org/packages/8d/f3/399c15629d5a0c68ef2aa7621d430b2be22034f01dd7f3c65a9c9666c445/numpy-2.2.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", size = 6648426 }, - { url = "https://files.pythonhosted.org/packages/2c/03/c72474c13772e30e1bc2e558cdffd9123c7872b731263d5648b5c49dd459/numpy-2.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", size = 14045990 }, - { url = "https://files.pythonhosted.org/packages/83/9c/96a9ab62274ffafb023f8ee08c88d3d31ee74ca58869f859db6845494fa6/numpy-2.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", size = 16096614 }, - { url = "https://files.pythonhosted.org/packages/d5/34/cd0a735534c29bec7093544b3a509febc9b0df77718a9b41ffb0809c9f46/numpy-2.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", size = 15242123 }, - { url = "https://files.pythonhosted.org/packages/5e/6d/541717a554a8f56fa75e91886d9b79ade2e595918690eb5d0d3dbd3accb9/numpy-2.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", size = 17859160 }, - { url = "https://files.pythonhosted.org/packages/b9/a5/fbf1f2b54adab31510728edd06a05c1b30839f37cf8c9747cb85831aaf1b/numpy-2.2.2-cp313-cp313-win32.whl", hash = "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", size = 6273337 }, - { url = "https://files.pythonhosted.org/packages/56/e5/01106b9291ef1d680f82bc47d0c5b5e26dfed15b0754928e8f856c82c881/numpy-2.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", size = 12609010 }, - { url = "https://files.pythonhosted.org/packages/9f/30/f23d9876de0f08dceb707c4dcf7f8dd7588266745029debb12a3cdd40be6/numpy-2.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", size = 20924451 }, - { url = "https://files.pythonhosted.org/packages/6a/ec/6ea85b2da9d5dfa1dbb4cb3c76587fc8ddcae580cb1262303ab21c0926c4/numpy-2.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", size = 14122390 }, - { url = "https://files.pythonhosted.org/packages/68/05/bfbdf490414a7dbaf65b10c78bc243f312c4553234b6d91c94eb7c4b53c2/numpy-2.2.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", size = 5156590 }, - { url = "https://files.pythonhosted.org/packages/f7/ec/fe2e91b2642b9d6544518388a441bcd65c904cea38d9ff998e2e8ebf808e/numpy-2.2.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", size = 6671958 }, - { url = "https://files.pythonhosted.org/packages/b1/6f/6531a78e182f194d33ee17e59d67d03d0d5a1ce7f6be7343787828d1bd4a/numpy-2.2.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", size = 14019950 }, - { url = "https://files.pythonhosted.org/packages/e1/fb/13c58591d0b6294a08cc40fcc6b9552d239d773d520858ae27f39997f2ae/numpy-2.2.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", size = 16079759 }, - { url = "https://files.pythonhosted.org/packages/2c/f2/f2f8edd62abb4b289f65a7f6d1f3650273af00b91b7267a2431be7f1aec6/numpy-2.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", size = 15226139 }, - { url = "https://files.pythonhosted.org/packages/aa/29/14a177f1a90b8ad8a592ca32124ac06af5eff32889874e53a308f850290f/numpy-2.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", size = 17856316 }, - { url = "https://files.pythonhosted.org/packages/95/03/242ae8d7b97f4e0e4ab8dd51231465fb23ed5e802680d629149722e3faf1/numpy-2.2.2-cp313-cp313t-win32.whl", hash = "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", size = 6329134 }, - { url = "https://files.pythonhosted.org/packages/80/94/cd9e9b04012c015cb6320ab3bf43bc615e248dddfeb163728e800a5d96f0/numpy-2.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", size = 12696208 }, +version = "2.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/25/ca/1166b75c21abd1da445b97bf1fa2f14f423c6cfb4fc7c4ef31dccf9f6a94/numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761", size = 20166090 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/f0/385eb9970309643cbca4fc6eebc8bb16e560de129c91258dfaa18498da8b/numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e", size = 20849658 }, + { url = "https://files.pythonhosted.org/packages/54/4a/765b4607f0fecbb239638d610d04ec0a0ded9b4951c56dc68cef79026abf/numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958", size = 13492258 }, + { url = "https://files.pythonhosted.org/packages/bd/a7/2332679479c70b68dccbf4a8eb9c9b5ee383164b161bee9284ac141fbd33/numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8", size = 5090249 }, + { url = "https://files.pythonhosted.org/packages/c1/67/4aa00316b3b981a822c7a239d3a8135be2a6945d1fd11d0efb25d361711a/numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564", size = 6621704 }, + { url = "https://files.pythonhosted.org/packages/5e/da/1a429ae58b3b6c364eeec93bf044c532f2ff7b48a52e41050896cf15d5b1/numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512", size = 13606089 }, + { url = "https://files.pythonhosted.org/packages/9e/3e/3757f304c704f2f0294a6b8340fcf2be244038be07da4cccf390fa678a9f/numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b", size = 16043185 }, + { url = "https://files.pythonhosted.org/packages/43/97/75329c28fea3113d00c8d2daf9bc5828d58d78ed661d8e05e234f86f0f6d/numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc", size = 16410751 }, + { url = "https://files.pythonhosted.org/packages/ad/7a/442965e98b34e0ae9da319f075b387bcb9a1e0658276cc63adb8c9686f7b/numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0", size = 14082705 }, + { url = "https://files.pythonhosted.org/packages/ac/b6/26108cf2cfa5c7e03fb969b595c93131eab4a399762b51ce9ebec2332e80/numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9", size = 6239077 }, + { url = "https://files.pythonhosted.org/packages/a6/84/fa11dad3404b7634aaab50733581ce11e5350383311ea7a7010f464c0170/numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a", size = 12566858 }, + { url = "https://files.pythonhosted.org/packages/4d/0b/620591441457e25f3404c8057eb924d04f161244cb8a3680d529419aa86e/numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f", size = 20836263 }, + { url = "https://files.pythonhosted.org/packages/45/e1/210b2d8b31ce9119145433e6ea78046e30771de3fe353f313b2778142f34/numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598", size = 13507771 }, + { url = "https://files.pythonhosted.org/packages/55/44/aa9ee3caee02fa5a45f2c3b95cafe59c44e4b278fbbf895a93e88b308555/numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57", size = 5075805 }, + { url = "https://files.pythonhosted.org/packages/78/d6/61de6e7e31915ba4d87bbe1ae859e83e6582ea14c6add07c8f7eefd8488f/numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe", size = 6608380 }, + { url = "https://files.pythonhosted.org/packages/3e/46/48bdf9b7241e317e6cf94276fe11ba673c06d1fdf115d8b4ebf616affd1a/numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43", size = 13602451 }, + { url = "https://files.pythonhosted.org/packages/70/50/73f9a5aa0810cdccda9c1d20be3cbe4a4d6ea6bfd6931464a44c95eef731/numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56", size = 16039822 }, + { url = "https://files.pythonhosted.org/packages/ad/cd/098bc1d5a5bc5307cfc65ee9369d0ca658ed88fbd7307b0d49fab6ca5fa5/numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a", size = 16411822 }, + { url = "https://files.pythonhosted.org/packages/83/a2/7d4467a2a6d984549053b37945620209e702cf96a8bc658bc04bba13c9e2/numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef", size = 14079598 }, + { url = "https://files.pythonhosted.org/packages/e9/6a/d64514dcecb2ee70bfdfad10c42b76cab657e7ee31944ff7a600f141d9e9/numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f", size = 6236021 }, + { url = "https://files.pythonhosted.org/packages/bb/f9/12297ed8d8301a401e7d8eb6b418d32547f1d700ed3c038d325a605421a4/numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed", size = 12560405 }, + { url = "https://files.pythonhosted.org/packages/a7/45/7f9244cd792e163b334e3a7f02dff1239d2890b6f37ebf9e82cbe17debc0/numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f", size = 20859062 }, + { url = "https://files.pythonhosted.org/packages/b1/b4/a084218e7e92b506d634105b13e27a3a6645312b93e1c699cc9025adb0e1/numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4", size = 13515839 }, + { url = "https://files.pythonhosted.org/packages/27/45/58ed3f88028dcf80e6ea580311dc3edefdd94248f5770deb980500ef85dd/numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e", size = 5116031 }, + { url = "https://files.pythonhosted.org/packages/37/a8/eb689432eb977d83229094b58b0f53249d2209742f7de529c49d61a124a0/numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0", size = 6629977 }, + { url = "https://files.pythonhosted.org/packages/42/a3/5355ad51ac73c23334c7caaed01adadfda49544f646fcbfbb4331deb267b/numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408", size = 13575951 }, + { url = "https://files.pythonhosted.org/packages/c4/70/ea9646d203104e647988cb7d7279f135257a6b7e3354ea6c56f8bafdb095/numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6", size = 16022655 }, + { url = "https://files.pythonhosted.org/packages/14/ce/7fc0612903e91ff9d0b3f2eda4e18ef9904814afcae5b0f08edb7f637883/numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f", size = 16399902 }, + { url = "https://files.pythonhosted.org/packages/ef/62/1d3204313357591c913c32132a28f09a26357e33ea3c4e2fe81269e0dca1/numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17", size = 14067180 }, + { url = "https://files.pythonhosted.org/packages/24/d7/78a40ed1d80e23a774cb8a34ae8a9493ba1b4271dde96e56ccdbab1620ef/numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48", size = 6291907 }, + { url = "https://files.pythonhosted.org/packages/86/09/a5ab407bd7f5f5599e6a9261f964ace03a73e7c6928de906981c31c38082/numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4", size = 12644098 }, ] [[package]] @@ -1343,19 +1731,27 @@ wheels = [ [[package]] name = "opendal" -version = "0.45.14" +version = "0.45.12" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/3d/59fc8da8191fd68f2750543b13d6fb29e0857b81ce10f11c6942c9ce248f/opendal-0.45.14.tar.gz", hash = "sha256:6efa48efc77ff24ccbdc310c2252f92d90a626e065ce4bb659ec20a3a84d8b1e", size = 782347 } +sdist = { url = "https://files.pythonhosted.org/packages/4d/d4/c6a035463c8f79f6acf0ae895be72c14b79a4889f933c295a1a17cb728d7/opendal-0.45.12.tar.gz", hash = "sha256:5b35a1abf6a30a6dc82e343a5c8403f245c89125cc037c2b89ed7803409c717c", size = 742731 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/3a/9aa73a26b6a5f22aeb380c2ebbeb09f4eff8483730de92cd2f3a25fd09db/opendal-0.45.14-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:036309db35765fadb22602c02dff718da77788ce08a291714aa0aa454e0dbff2", size = 30561568 }, - { url = "https://files.pythonhosted.org/packages/f4/c0/1bd48e513dbf74db6ee31088a1252986c7730896a5272b89b8eb2705b97f/opendal-0.45.14-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d51bb62384af1959306bb5750ec9fab53c4f9b0d4737e270d704c90dd62bcdaf", size = 15629929 }, - { url = "https://files.pythonhosted.org/packages/70/bd/aa7d809f4f3584c2a69225266e9af14dacd00017084a885cc419d4a28642/opendal-0.45.14-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f828bd163abfdf2d68935ce47ce9a7f22ee0e2f352e1dd3dcb26f4ee3259800", size = 16594782 }, - { url = "https://files.pythonhosted.org/packages/ed/e4/c542e8424bc44d5a36fa9c5000afa97b042f0d26a0d3b0754e63216e981f/opendal-0.45.14-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2961f1478d3419767fb8c42e97093afbbbed9ff339bf25e3bc05c18f39127356", size = 16066025 }, - { url = "https://files.pythonhosted.org/packages/9c/f8/13c9466a25de0d935aec6102264c8e49fabdd1775e86ab382960d5cdf3b8/opendal-0.45.14-cp311-abi3-win_amd64.whl", hash = "sha256:47d41e1a412b82fd772ba4e0dd29c8848345a4312d630e0753a4330a6b5f9681", size = 15043508 }, - { url = "https://files.pythonhosted.org/packages/4e/7c/55ac8535d37c95aab89e1c24426ddb857c5e8209d8433978df1d0ff9f630/opendal-0.45.14-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7cf22ac17d5693348e066e9cf23bff7d1a23cac1f7de59a5fca08b66712a846e", size = 30549906 }, - { url = "https://files.pythonhosted.org/packages/ce/e4/bb7778f79b9be1b6197abd05f54d38520e9a514b68be33e0778f0d07c217/opendal-0.45.14-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:901bd4edd011bf6fe262d7b920dd70176e37037bd74da62cc0862fba5b9da7be", size = 15627471 }, - { url = "https://files.pythonhosted.org/packages/b2/37/2a2be7bdcb1594ad48863bfaa20091ff88ad74890dc19a852bf335d0338a/opendal-0.45.14-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6485a504ea1cdc90829c8c66bce339549f900470e384a35fb5de2fdb151ea42", size = 16596285 }, - { url = "https://files.pythonhosted.org/packages/4b/82/f328b2160692339fdb83939cdde0f1ca300d648ace10fd84ce26db9aae68/opendal-0.45.14-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:de76bfba28a9fa296fcdaad10ef5da72b23b387c5012239b43514d656068335b", size = 16065367 }, + { url = "https://files.pythonhosted.org/packages/42/3b/6c067f5910c360cb6e98e2f64569f394abc9a48db775738b154dff2d742e/opendal-0.45.12-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:fd6551780194870867ed205135d5e7e2d411145d3cc4faa63830f54bbf48acdb", size = 29971380 }, + { url = "https://files.pythonhosted.org/packages/e9/23/ce63b7afe24ec1de350f0140ff9480c53f0a654755a8cdc5e20a9fc70f4e/opendal-0.45.12-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6fb9dc5021c5a62785fdf81a2d6ab97b65b8ef86ccded119fe242a10655263", size = 16092588 }, + { url = "https://files.pythonhosted.org/packages/d8/bc/29766fd6ecf50a8178346a3ff21d583193a65d86b9541144b6f6c244d014/opendal-0.45.12-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6803edda7c0936722ecc5c2cf01fd84dcb520f11e1643f285605451df6b7c20b", size = 15689529 }, + { url = "https://files.pythonhosted.org/packages/18/05/01655f602edd4525f0bfb9e2437a916a8a857e954eaa44f7f45379778452/opendal-0.45.12-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:389908b68845991f5bf4e75fbf1b415f14b02fab3201d01f5b3a9ae0030ee164", size = 16623321 }, + { url = "https://files.pythonhosted.org/packages/ad/63/1bf0426289ef07cc27afb570653669a6a7d57d988d6f877ff852483b38cd/opendal-0.45.12-cp311-abi3-win_amd64.whl", hash = "sha256:c87f488c547e17174d53f98da1c25135595bf93c29bab731d732f55d993534e0", size = 14809759 }, +] + +[[package]] +name = "outcome" +version = "1.3.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692 }, ] [[package]] @@ -1395,40 +1791,40 @@ wheels = [ [[package]] name = "pillow" -version = "11.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/20/9ce6ed62c91c073fcaa23d216e68289e19d95fb8188b9fb7a63d36771db8/pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a", size = 3226818 }, - { url = "https://files.pythonhosted.org/packages/b9/d8/f6004d98579a2596c098d1e30d10b248798cceff82d2b77aa914875bfea1/pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b", size = 3101662 }, - { url = "https://files.pythonhosted.org/packages/08/d9/892e705f90051c7a2574d9f24579c9e100c828700d78a63239676f960b74/pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3", size = 4329317 }, - { url = "https://files.pythonhosted.org/packages/8c/aa/7f29711f26680eab0bcd3ecdd6d23ed6bce180d82e3f6380fb7ae35fcf3b/pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a", size = 4412999 }, - { url = "https://files.pythonhosted.org/packages/c8/c4/8f0fe3b9e0f7196f6d0bbb151f9fba323d72a41da068610c4c960b16632a/pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1", size = 4368819 }, - { url = "https://files.pythonhosted.org/packages/38/0d/84200ed6a871ce386ddc82904bfadc0c6b28b0c0ec78176871a4679e40b3/pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f", size = 4496081 }, - { url = "https://files.pythonhosted.org/packages/84/9c/9bcd66f714d7e25b64118e3952d52841a4babc6d97b6d28e2261c52045d4/pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91", size = 4296513 }, - { url = "https://files.pythonhosted.org/packages/db/61/ada2a226e22da011b45f7104c95ebda1b63dcbb0c378ad0f7c2a710f8fd2/pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c", size = 4431298 }, - { url = "https://files.pythonhosted.org/packages/e7/c4/fc6e86750523f367923522014b821c11ebc5ad402e659d8c9d09b3c9d70c/pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6", size = 2291630 }, - { url = "https://files.pythonhosted.org/packages/08/5c/2104299949b9d504baf3f4d35f73dbd14ef31bbd1ddc2c1b66a5b7dfda44/pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf", size = 2626369 }, - { url = "https://files.pythonhosted.org/packages/37/f3/9b18362206b244167c958984b57c7f70a0289bfb59a530dd8af5f699b910/pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5", size = 2375240 }, - { url = "https://files.pythonhosted.org/packages/b3/31/9ca79cafdce364fd5c980cd3416c20ce1bebd235b470d262f9d24d810184/pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", size = 3226640 }, - { url = "https://files.pythonhosted.org/packages/ac/0f/ff07ad45a1f172a497aa393b13a9d81a32e1477ef0e869d030e3c1532521/pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", size = 3101437 }, - { url = "https://files.pythonhosted.org/packages/08/2f/9906fca87a68d29ec4530be1f893149e0cb64a86d1f9f70a7cfcdfe8ae44/pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", size = 4326605 }, - { url = "https://files.pythonhosted.org/packages/b0/0f/f3547ee15b145bc5c8b336401b2d4c9d9da67da9dcb572d7c0d4103d2c69/pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", size = 4411173 }, - { url = "https://files.pythonhosted.org/packages/b1/df/bf8176aa5db515c5de584c5e00df9bab0713548fd780c82a86cba2c2fedb/pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", size = 4369145 }, - { url = "https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", size = 4496340 }, - { url = "https://files.pythonhosted.org/packages/25/46/dd94b93ca6bd555588835f2504bd90c00d5438fe131cf01cfa0c5131a19d/pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", size = 4296906 }, - { url = "https://files.pythonhosted.org/packages/a8/28/2f9d32014dfc7753e586db9add35b8a41b7a3b46540e965cb6d6bc607bd2/pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", size = 4431759 }, - { url = "https://files.pythonhosted.org/packages/33/48/19c2cbe7403870fbe8b7737d19eb013f46299cdfe4501573367f6396c775/pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", size = 2291657 }, - { url = "https://files.pythonhosted.org/packages/3b/ad/285c556747d34c399f332ba7c1a595ba245796ef3e22eae190f5364bb62b/pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", size = 2626304 }, - { url = "https://files.pythonhosted.org/packages/e5/7b/ef35a71163bf36db06e9c8729608f78dedf032fc8313d19bd4be5c2588f3/pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", size = 2375117 }, - { url = "https://files.pythonhosted.org/packages/79/30/77f54228401e84d6791354888549b45824ab0ffde659bafa67956303a09f/pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", size = 3230060 }, - { url = "https://files.pythonhosted.org/packages/ce/b1/56723b74b07dd64c1010fee011951ea9c35a43d8020acd03111f14298225/pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", size = 3106192 }, - { url = "https://files.pythonhosted.org/packages/e1/cd/7bf7180e08f80a4dcc6b4c3a0aa9e0b0ae57168562726a05dc8aa8fa66b0/pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", size = 4446805 }, - { url = "https://files.pythonhosted.org/packages/97/42/87c856ea30c8ed97e8efbe672b58c8304dee0573f8c7cab62ae9e31db6ae/pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", size = 4530623 }, - { url = "https://files.pythonhosted.org/packages/ff/41/026879e90c84a88e33fb00cc6bd915ac2743c67e87a18f80270dfe3c2041/pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", size = 4465191 }, - { url = "https://files.pythonhosted.org/packages/e5/fb/a7960e838bc5df57a2ce23183bfd2290d97c33028b96bde332a9057834d3/pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", size = 2295494 }, - { url = "https://files.pythonhosted.org/packages/d7/6c/6ec83ee2f6f0fda8d4cf89045c6be4b0373ebfc363ba8538f8c999f63fcd/pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", size = 2631595 }, - { url = "https://files.pythonhosted.org/packages/cf/6c/41c21c6c8af92b9fea313aa47c75de49e2f9a467964ee33eb0135d47eb64/pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", size = 2377651 }, +version = "11.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, + { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, + { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, + { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, + { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, + { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, + { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, + { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, + { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, + { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, + { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, + { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, + { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, + { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, + { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, + { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, + { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, + { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, + { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, + { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, + { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, + { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, + { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, + { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, + { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, + { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, + { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, + { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, + { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, + { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, ] [[package]] @@ -1451,7 +1847,7 @@ wheels = [ [[package]] name = "pre-commit" -version = "4.1.0" +version = "4.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -1460,50 +1856,50 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", size = 193330 } +sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678 } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560 }, + { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713 }, ] [[package]] name = "propcache" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/28/1d205fe49be8b1b4df4c50024e62480a442b1a7b818e734308bb0d17e7fb/propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", size = 79588 }, - { url = "https://files.pythonhosted.org/packages/21/ee/fc4d893f8d81cd4971affef2a6cb542b36617cd1d8ce56b406112cb80bf7/propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", size = 45825 }, - { url = "https://files.pythonhosted.org/packages/4a/de/bbe712f94d088da1d237c35d735f675e494a816fd6f54e9db2f61ef4d03f/propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", size = 45357 }, - { url = "https://files.pythonhosted.org/packages/7f/14/7ae06a6cf2a2f1cb382586d5a99efe66b0b3d0c6f9ac2f759e6f7af9d7cf/propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", size = 241869 }, - { url = "https://files.pythonhosted.org/packages/cc/59/227a78be960b54a41124e639e2c39e8807ac0c751c735a900e21315f8c2b/propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", size = 247884 }, - { url = "https://files.pythonhosted.org/packages/84/58/f62b4ffaedf88dc1b17f04d57d8536601e4e030feb26617228ef930c3279/propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", size = 248486 }, - { url = "https://files.pythonhosted.org/packages/1c/07/ebe102777a830bca91bbb93e3479cd34c2ca5d0361b83be9dbd93104865e/propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", size = 243649 }, - { url = "https://files.pythonhosted.org/packages/ed/bc/4f7aba7f08f520376c4bb6a20b9a981a581b7f2e385fa0ec9f789bb2d362/propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", size = 229103 }, - { url = "https://files.pythonhosted.org/packages/fe/d5/04ac9cd4e51a57a96f78795e03c5a0ddb8f23ec098b86f92de028d7f2a6b/propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", size = 226607 }, - { url = "https://files.pythonhosted.org/packages/e3/f0/24060d959ea41d7a7cc7fdbf68b31852331aabda914a0c63bdb0e22e96d6/propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", size = 221153 }, - { url = "https://files.pythonhosted.org/packages/77/a7/3ac76045a077b3e4de4859a0753010765e45749bdf53bd02bc4d372da1a0/propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", size = 222151 }, - { url = "https://files.pythonhosted.org/packages/e7/af/5e29da6f80cebab3f5a4dcd2a3240e7f56f2c4abf51cbfcc99be34e17f0b/propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", size = 233812 }, - { url = "https://files.pythonhosted.org/packages/8c/89/ebe3ad52642cc5509eaa453e9f4b94b374d81bae3265c59d5c2d98efa1b4/propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", size = 238829 }, - { url = "https://files.pythonhosted.org/packages/e9/2f/6b32f273fa02e978b7577159eae7471b3cfb88b48563b1c2578b2d7ca0bb/propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", size = 230704 }, - { url = "https://files.pythonhosted.org/packages/5c/2e/f40ae6ff5624a5f77edd7b8359b208b5455ea113f68309e2b00a2e1426b6/propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", size = 40050 }, - { url = "https://files.pythonhosted.org/packages/3b/77/a92c3ef994e47180862b9d7d11e37624fb1c00a16d61faf55115d970628b/propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", size = 44117 }, - { url = "https://files.pythonhosted.org/packages/0f/2a/329e0547cf2def8857157f9477669043e75524cc3e6251cef332b3ff256f/propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", size = 77002 }, - { url = "https://files.pythonhosted.org/packages/12/2d/c4df5415e2382f840dc2ecbca0eeb2293024bc28e57a80392f2012b4708c/propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", size = 44639 }, - { url = "https://files.pythonhosted.org/packages/d0/5a/21aaa4ea2f326edaa4e240959ac8b8386ea31dedfdaa636a3544d9e7a408/propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", size = 44049 }, - { url = "https://files.pythonhosted.org/packages/4e/3e/021b6cd86c0acc90d74784ccbb66808b0bd36067a1bf3e2deb0f3845f618/propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", size = 224819 }, - { url = "https://files.pythonhosted.org/packages/3c/57/c2fdeed1b3b8918b1770a133ba5c43ad3d78e18285b0c06364861ef5cc38/propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", size = 229625 }, - { url = "https://files.pythonhosted.org/packages/9d/81/70d4ff57bf2877b5780b466471bebf5892f851a7e2ca0ae7ffd728220281/propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", size = 232934 }, - { url = "https://files.pythonhosted.org/packages/3c/b9/bb51ea95d73b3fb4100cb95adbd4e1acaf2cbb1fd1083f5468eeb4a099a8/propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", size = 227361 }, - { url = "https://files.pythonhosted.org/packages/f1/20/3c6d696cd6fd70b29445960cc803b1851a1131e7a2e4ee261ee48e002bcd/propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", size = 213904 }, - { url = "https://files.pythonhosted.org/packages/a1/cb/1593bfc5ac6d40c010fa823f128056d6bc25b667f5393781e37d62f12005/propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", size = 212632 }, - { url = "https://files.pythonhosted.org/packages/6d/5c/e95617e222be14a34c709442a0ec179f3207f8a2b900273720501a70ec5e/propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", size = 207897 }, - { url = "https://files.pythonhosted.org/packages/8e/3b/56c5ab3dc00f6375fbcdeefdede5adf9bee94f1fab04adc8db118f0f9e25/propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", size = 208118 }, - { url = "https://files.pythonhosted.org/packages/86/25/d7ef738323fbc6ebcbce33eb2a19c5e07a89a3df2fded206065bd5e868a9/propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", size = 217851 }, - { url = "https://files.pythonhosted.org/packages/b3/77/763e6cef1852cf1ba740590364ec50309b89d1c818e3256d3929eb92fabf/propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", size = 222630 }, - { url = "https://files.pythonhosted.org/packages/4f/e9/0f86be33602089c701696fbed8d8c4c07b6ee9605c5b7536fd27ed540c5b/propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", size = 216269 }, - { url = "https://files.pythonhosted.org/packages/cc/02/5ac83217d522394b6a2e81a2e888167e7ca629ef6569a3f09852d6dcb01a/propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", size = 39472 }, - { url = "https://files.pythonhosted.org/packages/f4/33/d6f5420252a36034bc8a3a01171bc55b4bff5df50d1c63d9caa50693662f/propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", size = 43363 }, - { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 }, +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/4d/5e5a60b78dbc1d464f8a7bbaeb30957257afdc8512cbb9dfd5659304f5cd/propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", size = 40951 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/46/a41ca1097769fc548fc9216ec4c1471b772cc39720eb47ed7e38ef0006a9/propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", size = 80800 }, + { url = "https://files.pythonhosted.org/packages/75/4f/93df46aab9cc473498ff56be39b5f6ee1e33529223d7a4d8c0a6101a9ba2/propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", size = 46443 }, + { url = "https://files.pythonhosted.org/packages/0b/17/308acc6aee65d0f9a8375e36c4807ac6605d1f38074b1581bd4042b9fb37/propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", size = 45676 }, + { url = "https://files.pythonhosted.org/packages/65/44/626599d2854d6c1d4530b9a05e7ff2ee22b790358334b475ed7c89f7d625/propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", size = 246191 }, + { url = "https://files.pythonhosted.org/packages/f2/df/5d996d7cb18df076debae7d76ac3da085c0575a9f2be6b1f707fe227b54c/propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", size = 251791 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/9f91e5dde8b1f662f6dd4dff36098ed22a1ef4e08e1316f05f4758f1576c/propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", size = 253434 }, + { url = "https://files.pythonhosted.org/packages/3c/e9/1b54b7e26f50b3e0497cd13d3483d781d284452c2c50dd2a615a92a087a3/propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", size = 248150 }, + { url = "https://files.pythonhosted.org/packages/a7/ef/a35bf191c8038fe3ce9a414b907371c81d102384eda5dbafe6f4dce0cf9b/propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", size = 233568 }, + { url = "https://files.pythonhosted.org/packages/97/d9/d00bb9277a9165a5e6d60f2142cd1a38a750045c9c12e47ae087f686d781/propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", size = 229874 }, + { url = "https://files.pythonhosted.org/packages/8e/78/c123cf22469bdc4b18efb78893e69c70a8b16de88e6160b69ca6bdd88b5d/propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", size = 225857 }, + { url = "https://files.pythonhosted.org/packages/31/1b/fd6b2f1f36d028820d35475be78859d8c89c8f091ad30e377ac49fd66359/propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", size = 227604 }, + { url = "https://files.pythonhosted.org/packages/99/36/b07be976edf77a07233ba712e53262937625af02154353171716894a86a6/propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", size = 238430 }, + { url = "https://files.pythonhosted.org/packages/0d/64/5822f496c9010e3966e934a011ac08cac8734561842bc7c1f65586e0683c/propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", size = 244814 }, + { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 }, + { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 }, + { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 }, + { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 }, + { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 }, + { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 }, + { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 }, + { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 }, + { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 }, + { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 }, + { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 }, + { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 }, + { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 }, + { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 }, + { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 }, + { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 }, + { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 }, + { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 }, + { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 }, + { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 }, ] [[package]] @@ -1561,55 +1957,51 @@ wheels = [ [[package]] name = "pydantic" -version = "2.10.5" +version = "2.9.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6a/c7/ca334c2ef6f2e046b1144fe4bb2a5da8a4c574e7f2ebf7e16b34a6a2fa92/pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", size = 761287 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/26/82663c79010b28eddf29dcdd0ea723439535fa917fce5905885c0e9ba562/pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53", size = 431426 }, + { url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 }, ] [[package]] name = "pydantic-core" -version = "2.27.2" +version = "2.23.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, +sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 }, + { url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 }, + { url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 }, + { url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 }, + { url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 }, + { url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 }, + { url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 }, + { url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 }, + { url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 }, + { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, + { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, + { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, + { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, + { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, + { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, + { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, + { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, + { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, + { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, + { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, + { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, + { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, + { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, + { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, ] [[package]] @@ -1627,11 +2019,11 @@ wheels = [ [[package]] name = "pygments" -version = "2.19.1" +version = "2.18.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, ] [[package]] @@ -1665,16 +2057,16 @@ wheels = [ [[package]] name = "pyspellchecker" -version = "0.8.2" +version = "0.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/5d/86d94aceb9c0813f27004ec71c036d8ec6a6324d989854ff0fe13fe036dc/pyspellchecker-0.8.2.tar.gz", hash = "sha256:2b026be14a162ba810bdda8e5454c56e364f42d3b9e14aeff31706e5ebcdc78f", size = 7149207 } +sdist = { url = "https://files.pythonhosted.org/packages/5d/f4/5ed7eefd94df484406d2ff29af54daa940ea4cfc265e5add3d2150ff0640/pyspellchecker-0.8.1.tar.gz", hash = "sha256:3478ca8484d1c2db0c93d12b3c986cd17958c69f47b3ed7ef4d3f4201e591776", size = 6773020 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/8e/7c79443d302a80cfd59bc365938d51e36e7e9aa7ce8ab1d8a0ca0c8e6065/pyspellchecker-0.8.2-py3-none-any.whl", hash = "sha256:4fee22e1859c5153c3bc3953ac3041bf07d4541520b7e01901e955062022290a", size = 7147898 }, + { url = "https://files.pythonhosted.org/packages/e1/d2/c7e3b3a61a34b9320399fa731d1f9f0c73db8a1f28c6764e9e11efa68a29/pyspellchecker-0.8.1-py3-none-any.whl", hash = "sha256:d91e9e1064793ae1ee8e71b06ca40eeb8e5923437c54291a8e041b447792b640", size = 6771060 }, ] [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1682,9 +2074,9 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, + { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, ] [[package]] @@ -1702,14 +2094,14 @@ wheels = [ [[package]] name = "pytest-asyncio" -version = "0.25.2" +version = "0.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950 } +sdist = { url = "https://files.pythonhosted.org/packages/94/18/82fcb4ee47d66d99f6cd1efc0b11b2a25029f303c599a5afda7c1bca4254/pytest_asyncio-0.25.0.tar.gz", hash = "sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609", size = 53298 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400 }, + { url = "https://files.pythonhosted.org/packages/88/56/2ee0cab25c11d4e38738a2a98c645a8f002e2ecf7b5ed774c70d53b92bb1/pytest_asyncio-0.25.0-py3-none-any.whl", hash = "sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3", size = 19245 }, ] [[package]] @@ -1763,43 +2155,41 @@ wheels = [ [[package]] name = "pyusb" -version = "1.3.1" +version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/6b/ce3727395e52b7b76dfcf0c665e37d223b680b9becc60710d4bc08b7b7cb/pyusb-1.3.1.tar.gz", hash = "sha256:3af070b607467c1c164f49d5b0caabe8ac78dbed9298d703a8dbf9df4052d17e", size = 77281 } +sdist = { url = "https://files.pythonhosted.org/packages/d9/6e/433a5614132576289b8643fe598dd5d51b16e130fd591564be952e15bb45/pyusb-1.2.1.tar.gz", hash = "sha256:a4cc7404a203144754164b8b40994e2849fde1cfff06b08492f12fff9d9de7b9", size = 75292 } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/b8/27e6312e86408a44fe16bd28ee12dd98608b39f7e7e57884a24e8f29b573/pyusb-1.3.1-py3-none-any.whl", hash = "sha256:bf9b754557af4717fe80c2b07cc2b923a9151f5c08d17bdb5345dac09d6a0430", size = 58465 }, + { url = "https://files.pythonhosted.org/packages/15/a8/4982498b2ab44d1fcd5c49f07ea3795eab01601dc143b009d333fcace3b9/pyusb-1.2.1-py3-none-any.whl", hash = "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36", size = 58439 }, ] [[package]] name = "pywavelets" -version = "1.8.0" +version = "1.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/48/45/bfaaab38545a33a9f06c61211fc3bea2e23e8a8e00fedeb8e57feda722ff/pywavelets-1.8.0.tar.gz", hash = "sha256:f3800245754840adc143cbc29534a1b8fc4b8cff6e9d403326bd52b7bb5c35aa", size = 3935274 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/8b/4870f11559307416470158a5aa6f61e5c2a910f1645a7a836ffae580b7ad/pywavelets-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3f431c9e2aff1a2240765eff5e804975d0fcc24c82d6f3d4271243f228e5963b", size = 4326187 }, - { url = "https://files.pythonhosted.org/packages/c4/35/66835d889fd7fbf3119c7a9bd9d9bd567fc0bb603dfba408e9226db7cb44/pywavelets-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e39b0e2314e928cb850ee89b9042733a10ea044176a495a54dc84d2c98407a51", size = 4295428 }, - { url = "https://files.pythonhosted.org/packages/63/1c/42e5130226538c70d4bbbaee00eb1bc06ec3287f7ea43d5fcf85bfc761ce/pywavelets-1.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cae701117f5c7244b7c8d48b9e92a0289637cdc02a9c205e8be83361f0c11fae", size = 4421259 }, - { url = "https://files.pythonhosted.org/packages/6f/c5/1ce93657432e22a5debc21e8b52ec6980f819ecb7fa727bb86744224d967/pywavelets-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649936baee933e80083788e0adc4d8bc2da7cdd8b10464d3b113475be2cc5308", size = 4447650 }, - { url = "https://files.pythonhosted.org/packages/b9/d6/b54ef30daca71824f811f9d2322a978b0a58d27674b8e3af6520f67e9ec6/pywavelets-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8c68e9d072c536bc646e8bdce443bb1826eeb9aa21b2cb2479a43954dea692a3", size = 4448538 }, - { url = "https://files.pythonhosted.org/packages/ce/8c/1688b790e55674667ad644262f174405c2c9873cb13e773432e78b1b33e4/pywavelets-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:63f67fa2ee1610445de64f746fb9c1df31980ad13d896ea2331fc3755f49b3ae", size = 4485228 }, - { url = "https://files.pythonhosted.org/packages/c9/9b/69de31c3b663dadd76d1da6bf8af68d8cefff55df8e880fe96a94bb8c9ac/pywavelets-1.8.0-cp312-cp312-win32.whl", hash = "sha256:4b3c2ab669c91e3474fd63294355487b7dd23f0b51d32f811327ddf3546f4f3d", size = 4134850 }, - { url = "https://files.pythonhosted.org/packages/1c/88/9e2aa9d5fde08bfc0fb18ffb1b5307c1ed49c24930b4147e5f48571a7251/pywavelets-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:810a23a631da596fef7196ddec49b345b1aab13525bb58547eeebe1769edbbc1", size = 4210786 }, - { url = "https://files.pythonhosted.org/packages/94/73/7ff347d77c6bda11330565050c3346c54bc210086380abeb84e402c1c9cd/pywavelets-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:441ba45c8dff8c6916dbe706958d0d7f91da675695ca0c0d75e483f6f52d0a12", size = 4321474 }, - { url = "https://files.pythonhosted.org/packages/b0/70/c58937ebbca1aba3475ca5ee63c7bcebf09f3c93891ae5942eaec7e95707/pywavelets-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:24bb282bab09349d9d128ed0536fa50fff5c2147891971a69c2c36155dfeeeac", size = 4291502 }, - { url = "https://files.pythonhosted.org/packages/da/55/87b4ad6128b2e85985908e958e856e0b680cdcc03cc490e2cc995164b13a/pywavelets-1.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:426ff3799446cb4da1db04c2084e6e58edfe24225596805665fd39c14f53dece", size = 4412669 }, - { url = "https://files.pythonhosted.org/packages/bf/1a/bfca9eab23bd7b27843b0ce95c47796033a7b2c93048315f5fc5d6ac6428/pywavelets-1.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0607a9c085b8285bc0d04e33d461a6c80f8c325389221ffb1a45141861138e", size = 4454604 }, - { url = "https://files.pythonhosted.org/packages/c3/23/9ce38829f57159e812c469c4f9d7b5a16c1ba922c1802985e8c504468206/pywavelets-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d31c36a39110e8fcc7b1a4a11cfed7d22b610c285d3e7f4fe73ec777aa49fa39", size = 4445507 }, - { url = "https://files.pythonhosted.org/packages/e5/d2/e78a976b0600a6ef7a70f4430122d6ad11b3e1cbda3c8b3565661d094678/pywavelets-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa7c68ed1e5bab23b1bafe60ccbcf709b878652d03de59e961baefa5210fcd0a", size = 4479078 }, - { url = "https://files.pythonhosted.org/packages/85/4d/1c4f870010368f3aeb0bdd72929376a1988e4a122e76545bd8c56e549c96/pywavelets-1.8.0-cp313-cp313-win32.whl", hash = "sha256:2c6b359b55d713ef683e9da1529181b865a80d759881ceb9adc1c5742e4da4d8", size = 4133763 }, - { url = "https://files.pythonhosted.org/packages/c9/4f/0a709a5732e6cf9297fc87bf545cb879997cde204115f8c0cbc296c5bdd3/pywavelets-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:4dbebcfd55ea8a85b7fc8802d411e75337170422abf6e96019d7e46c394e80e5", size = 4209548 }, - { url = "https://files.pythonhosted.org/packages/de/2a/4cac0bba67d3bc0ad697d0680539864db0a6964c7ad953d8d9d887f360b3/pywavelets-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:2e1c79784bebeafd3715c1bea6621daa2e2e6ed37b687719322e2078fb35bb70", size = 4335183 }, - { url = "https://files.pythonhosted.org/packages/58/d1/3abe4cf34a35b09ad847f0e9a85f340c1988611222926d295fa8710659e7/pywavelets-1.8.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f489380c95013cc8fb3ef338f6d8c1a907125db453cc4dc739e2cca06fcd8b6", size = 4454723 }, - { url = "https://files.pythonhosted.org/packages/d5/62/f05dd191232ae94e0b48509bb0ee65c9d45abf5e8f3612b09fd309b41384/pywavelets-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:06786201a91b5e74540f4f3c115c49a29190de2eb424823abbd3a1fd75ea3e28", size = 4472192 }, - { url = "https://files.pythonhosted.org/packages/20/6a/257c95ad1e0fd395cbccd4ffec0d01cc9b51a3bb91e67d8fa10ffebc9c72/pywavelets-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:f2877fb7b58c94211257dcf364b204d6ed259146fc87d5a90bf9d93c97af6226", size = 4183968 }, - { url = "https://files.pythonhosted.org/packages/6c/58/7179fd6f87153f2e339171e8cfe9bf901398a89045eefd7a3911bb9b47ad/pywavelets-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ec5d723c3335ff8aa630fd4b14097077f12cc02893c91cafd60dd7b1730e780f", size = 4265431 }, +sdist = { url = "https://files.pythonhosted.org/packages/94/0a/c235e7dd60d136b14cd8793c440e8d22e7880df5588162feb02d6d6118a3/pywavelets-1.7.0.tar.gz", hash = "sha256:b47250e5bb853e37db5db423bafc82847f4cde0ffdf7aebb06336a993bc174f6", size = 3934767 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/48/b6dbb1124bfa15e2d16dc2c199562d0a9c3d7e7333348b29d05f68cdf146/pywavelets-1.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:badb7dc70ecd8042ddd98fdd41803d5e5b28bf7c90910bb1751906812326ab54", size = 4317328 }, + { url = "https://files.pythonhosted.org/packages/9c/cf/b5b1706d7054d792bdf678c894f4ad8f8cdaa789f82b7eaa48b80aa45ba0/pywavelets-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:74e838e0225783f37ae346e60a9f783b4a31adc5731b9cb6d687ee5c93bd87b7", size = 4287220 }, + { url = "https://files.pythonhosted.org/packages/05/a3/90cad7bfbd765f39bcd96af3efdefcf6fd05a49b7e81fc281f1be7a8e637/pywavelets-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ad14d8b5a412a621406276b8ae8ee1e369ba7a7f8e517fb87355bcb8106820f", size = 4420514 }, + { url = "https://files.pythonhosted.org/packages/53/b6/08d5ea524a5ed25e1f94fba428ac605f0f774bea4a8cf14dbdc7947a2bc5/pywavelets-1.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bd2611076f5d2c4ad940421bbb3c450b6a53d8ca24bde02662455dc67c70dac", size = 4453780 }, + { url = "https://files.pythonhosted.org/packages/f3/34/ad1502dc37295249000d3644c5bd183f5c063e9cebb3a37a9422121d77c1/pywavelets-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:40ebb994b332d48db3b0564e3c335c4f8ba236283939f5167de099766cf16517", size = 4448531 }, + { url = "https://files.pythonhosted.org/packages/f5/52/8e756c9783e7e7c43058cc3e9e9633935206ac77ff13580d489669d84b98/pywavelets-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a8cc39901f09d82fc94007026f9aed63876e334ae043eb26caa601aee2551", size = 4477268 }, + { url = "https://files.pythonhosted.org/packages/ce/74/15942502ec146c0e06d3f62ebeeeb2cfa873b57413a44238171cc3658387/pywavelets-1.7.0-cp312-cp312-win32.whl", hash = "sha256:0cd599c78fc240cbadb63344d73912fc79e8dccbb0db8a8bd5143df400c3a519", size = 4171601 }, + { url = "https://files.pythonhosted.org/packages/d6/bf/dc8836f983876a43cb15791f0ff15dab6631f423ca6ba55c068d8764ddf8/pywavelets-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:29a912c074977db6adf3782dfbd414945805039b755d0c23979bc823f1b4e9c3", size = 4247115 }, + { url = "https://files.pythonhosted.org/packages/52/0f/daedf2516c22cdb3ef208de286e77ebbf69da1c08cca3e086ecec057c738/pywavelets-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a322607b8c2985997ea45317d36cab58f0223ccf4c5b6540b612ed067d099ff", size = 4312598 }, + { url = "https://files.pythonhosted.org/packages/e9/68/eb5a02ec3ade3076af47a4236f744ec6859506036976b93072bbf47cc8a3/pywavelets-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f402424288178fd105a5cb76e1818649dc67e4a08d1b9974c8c7ef01dc5feb3", size = 4283781 }, + { url = "https://files.pythonhosted.org/packages/84/d0/3b839e6f05db4b6834fcc83f37e8bb6d7abdccfb8899000a2898c62d0c53/pywavelets-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ff81dd8288afdd5f2eae6c44f963152b41e14e2e5fc647b608c97bd6f8270fe", size = 4412092 }, + { url = "https://files.pythonhosted.org/packages/c0/3c/55137ea3b137b9e7a72822275f51214b91f3c368c9eb3ea671e1e3bb0786/pywavelets-1.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:259ccf233879cf0ed66052ffd174dcabe6314e92b53aa2de25f4ae50b08ea1e3", size = 4444608 }, + { url = "https://files.pythonhosted.org/packages/88/63/2fce3368cca2cc988723e6d48e68ce1056825675841fc1a9042629f8d1a9/pywavelets-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:105249d2bf824bddfb286e4e08934ff1e8829aa3077dab74ce3b2921a09caa43", size = 4445280 }, + { url = "https://files.pythonhosted.org/packages/5e/84/8d385d4a1e5ea79e166c3f65d6a58c76e5fa63106fa29c7c2c9deb03ddbb/pywavelets-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eac60fdb28bd421f72eb18824bd2e4f36c3dab0d7f4802ebfe4bbf68744a524a", size = 4478438 }, + { url = "https://files.pythonhosted.org/packages/2d/f0/35ae951344e3a5a7e6824aff9476032f4f2ebab3ef050c4d2d91321a7669/pywavelets-1.7.0-cp313-cp313-win32.whl", hash = "sha256:097bd03ee1b687942fa2f82ad0d35849879eef0ac82fc6f757d6ef881c53db6d", size = 4170479 }, + { url = "https://files.pythonhosted.org/packages/19/11/e0b349efd034a40cc086e166edbed5c9fa59f27f298b42be4fb6004a82dc/pywavelets-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:71918b973950c013c17ff28c3fc2958dfff68ec767ef60cd927a3ac4ff5a7345", size = 4246094 }, + { url = "https://files.pythonhosted.org/packages/f9/39/8e39c95a7d99e731ab5bcb43ba40778b091a740178000823b56e19d90dcb/pywavelets-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5b7e1a212269d3e48318388744684b702c6a649a70758e35e9a88614316e9b91", size = 4326062 }, + { url = "https://files.pythonhosted.org/packages/8a/74/036d4a80a48d847161fb3f967239fcd49901809fc93cd25eab3a051f5300/pywavelets-1.7.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d8c641aa26e040d62166cbe2052dd3cd575e3e0c78c00c52770be6d7dd386b", size = 4441602 }, + { url = "https://files.pythonhosted.org/packages/d7/76/a5ff1f1afe1e84c961c7e4b541684c2515ba4c529359f0ee2d9305cb9cd9/pywavelets-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e0611ffb6ceeee1b677bd224e657895193eec03ad39538f5263ce61db465f836", size = 4466593 }, ] [[package]] @@ -1895,45 +2285,38 @@ wheels = [ [[package]] name = "scipy" -version = "1.15.1" +version = "1.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/c6/8eb0654ba0c7d0bb1bf67bf8fbace101a8e4f250f7722371105e8b6f68fc/scipy-1.15.1.tar.gz", hash = "sha256:033a75ddad1463970c96a88063a1df87ccfddd526437136b6ee81ff0312ebdf6", size = 59407493 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/6e/a9c42d0d39e09ed7fd203d0ac17adfea759cba61ab457671fe66e523dbec/scipy-1.15.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c09aa9d90f3500ea4c9b393ee96f96b0ccb27f2f350d09a47f533293c78ea776", size = 41478318 }, - { url = "https://files.pythonhosted.org/packages/04/ee/e3e535c81828618878a7433992fecc92fa4df79393f31a8fea1d05615091/scipy-1.15.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0ac102ce99934b162914b1e4a6b94ca7da0f4058b6d6fd65b0cef330c0f3346f", size = 32596696 }, - { url = "https://files.pythonhosted.org/packages/c4/5e/b1b0124be8e76f87115f16b8915003eec4b7060298117715baf13f51942c/scipy-1.15.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:09c52320c42d7f5c7748b69e9f0389266fd4f82cf34c38485c14ee976cb8cb04", size = 24870366 }, - { url = "https://files.pythonhosted.org/packages/14/36/c00cb73eefda85946172c27913ab995c6ad4eee00fa4f007572e8c50cd51/scipy-1.15.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:cdde8414154054763b42b74fe8ce89d7f3d17a7ac5dd77204f0e142cdc9239e9", size = 28007461 }, - { url = "https://files.pythonhosted.org/packages/68/94/aff5c51b3799349a9d1e67a056772a0f8a47db371e83b498d43467806557/scipy-1.15.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c9d8fc81d6a3b6844235e6fd175ee1d4c060163905a2becce8e74cb0d7554ce", size = 38068174 }, - { url = "https://files.pythonhosted.org/packages/b0/3c/0de11ca154e24a57b579fb648151d901326d3102115bc4f9a7a86526ce54/scipy-1.15.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fb57b30f0017d4afa5fe5f5b150b8f807618819287c21cbe51130de7ccdaed2", size = 40249869 }, - { url = "https://files.pythonhosted.org/packages/15/09/472e8d0a6b33199d1bb95e49bedcabc0976c3724edd9b0ef7602ccacf41e/scipy-1.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:491d57fe89927fa1aafbe260f4cfa5ffa20ab9f1435025045a5315006a91b8f5", size = 42629068 }, - { url = "https://files.pythonhosted.org/packages/ff/ba/31c7a8131152822b3a2cdeba76398ffb404d81d640de98287d236da90c49/scipy-1.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:900f3fa3db87257510f011c292a5779eb627043dd89731b9c461cd16ef76ab3d", size = 43621992 }, - { url = "https://files.pythonhosted.org/packages/2b/bf/dd68965a4c5138a630eeed0baec9ae96e5d598887835bdde96cdd2fe4780/scipy-1.15.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:100193bb72fbff37dbd0bf14322314fc7cbe08b7ff3137f11a34d06dc0ee6b85", size = 41441136 }, - { url = "https://files.pythonhosted.org/packages/ef/5e/4928581312922d7e4d416d74c416a660addec4dd5ea185401df2269ba5a0/scipy-1.15.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:2114a08daec64980e4b4cbdf5bee90935af66d750146b1d2feb0d3ac30613692", size = 32533699 }, - { url = "https://files.pythonhosted.org/packages/32/90/03f99c43041852837686898c66767787cd41c5843d7a1509c39ffef683e9/scipy-1.15.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6b3e71893c6687fc5e29208d518900c24ea372a862854c9888368c0b267387ab", size = 24807289 }, - { url = "https://files.pythonhosted.org/packages/9d/52/bfe82b42ae112eaba1af2f3e556275b8727d55ac6e4932e7aef337a9d9d4/scipy-1.15.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:837299eec3d19b7e042923448d17d95a86e43941104d33f00da7e31a0f715d3c", size = 27929844 }, - { url = "https://files.pythonhosted.org/packages/f6/77/54ff610bad600462c313326acdb035783accc6a3d5f566d22757ad297564/scipy-1.15.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82add84e8a9fb12af5c2c1a3a3f1cb51849d27a580cb9e6bd66226195142be6e", size = 38031272 }, - { url = "https://files.pythonhosted.org/packages/f1/26/98585cbf04c7cf503d7eb0a1966df8a268154b5d923c5fe0c1ed13154c49/scipy-1.15.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070d10654f0cb6abd295bc96c12656f948e623ec5f9a4eab0ddb1466c000716e", size = 40210217 }, - { url = "https://files.pythonhosted.org/packages/fd/3f/3d2285eb6fece8bc5dbb2f9f94d61157d61d155e854fd5fea825b8218f12/scipy-1.15.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55cc79ce4085c702ac31e49b1e69b27ef41111f22beafb9b49fea67142b696c4", size = 42587785 }, - { url = "https://files.pythonhosted.org/packages/48/7d/5b5251984bf0160d6533695a74a5fddb1fa36edd6f26ffa8c871fbd4782a/scipy-1.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:c352c1b6d7cac452534517e022f8f7b8d139cd9f27e6fbd9f3cbd0bfd39f5bef", size = 43640439 }, - { url = "https://files.pythonhosted.org/packages/e7/b8/0e092f592d280496de52e152582030f8a270b194f87f890e1a97c5599b81/scipy-1.15.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0458839c9f873062db69a03de9a9765ae2e694352c76a16be44f93ea45c28d2b", size = 41619862 }, - { url = "https://files.pythonhosted.org/packages/f6/19/0b6e1173aba4db9e0b7aa27fe45019857fb90d6904038b83927cbe0a6c1d/scipy-1.15.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:af0b61c1de46d0565b4b39c6417373304c1d4f5220004058bdad3061c9fa8a95", size = 32610387 }, - { url = "https://files.pythonhosted.org/packages/e7/02/754aae3bd1fa0f2479ade3cfdf1732ecd6b05853f63eee6066a32684563a/scipy-1.15.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:71ba9a76c2390eca6e359be81a3e879614af3a71dfdabb96d1d7ab33da6f2364", size = 24883814 }, - { url = "https://files.pythonhosted.org/packages/1f/ac/d7906201604a2ea3b143bb0de51b3966f66441ba50b7dc182c4505b3edf9/scipy-1.15.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14eaa373c89eaf553be73c3affb11ec6c37493b7eaaf31cf9ac5dffae700c2e0", size = 27944865 }, - { url = "https://files.pythonhosted.org/packages/84/9d/8f539002b5e203723af6a6f513a45e0a7671e9dabeedb08f417ac17e4edc/scipy-1.15.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f735bc41bd1c792c96bc426dece66c8723283695f02df61dcc4d0a707a42fc54", size = 39883261 }, - { url = "https://files.pythonhosted.org/packages/97/c0/62fd3bab828bcccc9b864c5997645a3b86372a35941cdaf677565c25c98d/scipy-1.15.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2722a021a7929d21168830790202a75dbb20b468a8133c74a2c0230c72626b6c", size = 42093299 }, - { url = "https://files.pythonhosted.org/packages/e4/1f/5d46a8d94e9f6d2c913cbb109e57e7eed914de38ea99e2c4d69a9fc93140/scipy-1.15.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc7136626261ac1ed988dca56cfc4ab5180f75e0ee52e58f1e6aa74b5f3eacd5", size = 43181730 }, +sdist = { url = "https://files.pythonhosted.org/packages/62/11/4d44a1f274e002784e4dbdb81e0ea96d2de2d1045b2132d5af62cc31fd28/scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417", size = 58620554 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/04/2bdacc8ac6387b15db6faa40295f8bd25eccf33f1f13e68a72dc3c60a99e/scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d", size = 39128781 }, + { url = "https://files.pythonhosted.org/packages/c8/53/35b4d41f5fd42f5781dbd0dd6c05d35ba8aa75c84ecddc7d44756cd8da2e/scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07", size = 29939542 }, + { url = "https://files.pythonhosted.org/packages/66/67/6ef192e0e4d77b20cc33a01e743b00bc9e68fb83b88e06e636d2619a8767/scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5", size = 23148375 }, + { url = "https://files.pythonhosted.org/packages/f6/32/3a6dedd51d68eb7b8e7dc7947d5d841bcb699f1bf4463639554986f4d782/scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc", size = 25578573 }, + { url = "https://files.pythonhosted.org/packages/f0/5a/efa92a58dc3a2898705f1dc9dbaf390ca7d4fba26d6ab8cfffb0c72f656f/scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310", size = 35319299 }, + { url = "https://files.pythonhosted.org/packages/8e/ee/8a26858ca517e9c64f84b4c7734b89bda8e63bec85c3d2f432d225bb1886/scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066", size = 40849331 }, + { url = "https://files.pythonhosted.org/packages/a5/cd/06f72bc9187840f1c99e1a8750aad4216fc7dfdd7df46e6280add14b4822/scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1", size = 42544049 }, + { url = "https://files.pythonhosted.org/packages/aa/7d/43ab67228ef98c6b5dd42ab386eae2d7877036970a0d7e3dd3eb47a0d530/scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f", size = 44521212 }, + { url = "https://files.pythonhosted.org/packages/50/ef/ac98346db016ff18a6ad7626a35808f37074d25796fd0234c2bb0ed1e054/scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79", size = 39091068 }, + { url = "https://files.pythonhosted.org/packages/b9/cc/70948fe9f393b911b4251e96b55bbdeaa8cca41f37c26fd1df0232933b9e/scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e", size = 29875417 }, + { url = "https://files.pythonhosted.org/packages/3b/2e/35f549b7d231c1c9f9639f9ef49b815d816bf54dd050da5da1c11517a218/scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73", size = 23084508 }, + { url = "https://files.pythonhosted.org/packages/3f/d6/b028e3f3e59fae61fb8c0f450db732c43dd1d836223a589a8be9f6377203/scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e", size = 25503364 }, + { url = "https://files.pythonhosted.org/packages/a7/2f/6c142b352ac15967744d62b165537a965e95d557085db4beab2a11f7943b/scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d", size = 35292639 }, + { url = "https://files.pythonhosted.org/packages/56/46/2449e6e51e0d7c3575f289f6acb7f828938eaab8874dbccfeb0cd2b71a27/scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e", size = 40798288 }, + { url = "https://files.pythonhosted.org/packages/32/cd/9d86f7ed7f4497c9fd3e39f8918dd93d9f647ba80d7e34e4946c0c2d1a7c/scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06", size = 42524647 }, + { url = "https://files.pythonhosted.org/packages/f5/1b/6ee032251bf4cdb0cc50059374e86a9f076308c1512b61c4e003e241efb7/scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84", size = 44469524 }, ] [[package]] name = "setuptools" -version = "75.8.0" +version = "75.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 } +sdist = { url = "https://files.pythonhosted.org/packages/ed/22/a438e0caa4576f8c383fa4d35f1cc01655a46c75be358960d815bfbb12bd/setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686", size = 1351577 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 }, + { url = "https://files.pythonhosted.org/packages/90/12/282ee9bce8b58130cb762fbc9beabd531549952cac11fc56add11dcb7ea0/setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", size = 1251070 }, ] [[package]] @@ -1963,6 +2346,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, ] +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, +] + [[package]] name = "soupsieve" version = "2.6" @@ -2044,16 +2436,16 @@ wheels = [ [[package]] name = "sphinx-substitution-extensions" -version = "2025.1.2" +version = "2024.10.17" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beartype" }, { name = "docutils" }, { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/77cbca5489ddd6530c4c9804f56fdf3efbac49808ee7267434f7a1558750/sphinx_substitution_extensions-2025.1.2.tar.gz", hash = "sha256:53b8d394d5098a09aef36bc687fa310aeb28466319d2c750e996e46400fb2474", size = 28037 } +sdist = { url = "https://files.pythonhosted.org/packages/76/84/dd9f95819e8fb5b799cb3e6269ebab2e1ff734e0c09e1223c3d1231ba9e0/sphinx_substitution_extensions-2024.10.17.tar.gz", hash = "sha256:30fa723bb44afe23adc5187601dcf0c1955dcd1b26f588773b395e852076179d", size = 27754 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/20/81502ff9e5d814818cb3623e04b3b61c7fd3245914d9a18b54d50d86f789/sphinx_substitution_extensions-2025.1.2-py2.py3-none-any.whl", hash = "sha256:ff14f40e4393bd7434a196badb8d47983355d9755af884b902e3023fb456b958", size = 13533 }, + { url = "https://files.pythonhosted.org/packages/54/95/dd46a2ef9ad26d7e4c2e889bc714d744deb7b4b069d2264412716ee2db33/sphinx_substitution_extensions-2024.10.17-py2.py3-none-any.whl", hash = "sha256:6c1aae08edea616c5602f30368e6c15205220aa2d0b37bc47569322bce5e1271", size = 13583 }, ] [[package]] @@ -2125,26 +2517,43 @@ wheels = [ [[package]] name = "starlette" -version = "0.45.2" +version = "0.41.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/4f/e1c9f4ec3dae67a94c9285ed275355d5f7cf0f3a5c34538c8ae5412af550/starlette-0.45.2.tar.gz", hash = "sha256:bba1831d15ae5212b22feab2f218bab6ed3cd0fc2dc1d4442443bb1ee52260e0", size = 2574026 } +sdist = { url = "https://files.pythonhosted.org/packages/3e/da/1fb4bdb72ae12b834becd7e1e7e47001d32f91ec0ce8d7bc1b618d9f0bd9/starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", size = 2573867 } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/ab/fe4f57c83620b39dfc9e7687ebad59129ff05170b99422105019d9a65eec/starlette-0.45.2-py3-none-any.whl", hash = "sha256:4daec3356fb0cb1e723a5235e5beaf375d2259af27532958e2d79df549dad9da", size = 71505 }, + { url = "https://files.pythonhosted.org/packages/54/43/f185bfd0ca1d213beb4293bed51d92254df23d8ceaf6c0e17146d508a776/starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d", size = 73259 }, ] [[package]] name = "tqdm" -version = "4.67.1" +version = "4.67.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/4f/0153c21dc5779a49a0598c445b1978126b1344bab9ee71e53e44877e14e0/tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a", size = 169739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, + { url = "https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be", size = 78590 }, +] + +[[package]] +name = "trio" +version = "0.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, + { name = "idna" }, + { name = "outcome" }, + { name = "sniffio" }, + { name = "sortedcontainers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/73/57efab729506a8d4b89814f1e356ec8f3369de0ed4fd7e7616974d09646d/trio-0.28.0.tar.gz", hash = "sha256:4e547896fe9e8a5658e54e4c7c5fa1db748cbbbaa7c965e7d40505b928c73c05", size = 580318 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/04/9954a59e1fb6732f5436225c9af963811d7b24ea62a8bf96991f2cb8c26e/trio-0.28.0-py3-none-any.whl", hash = "sha256:56d58977acc1635735a96581ec70513cc781b8b6decd299c487d3be2a721cd94", size = 486317 }, ] [[package]] @@ -2158,91 +2567,91 @@ wheels = [ [[package]] name = "typos" -version = "1.29.4" +version = "1.27.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/17/bc/58050dbc50c2effc0a0a00f49eaeb0779c595b415b4d1544dafcac99394c/typos-1.29.4.tar.gz", hash = "sha256:590d776448d634e2437a326ff7f2218d53439f2d4e478337bb17ff627caaa2cd", size = 1484737 } +sdist = { url = "https://files.pythonhosted.org/packages/19/93/a26a423fa5d9feaee0f10f1b5ed5ba1629a9cbf311e56498033ec7732441/typos-1.27.3.tar.gz", hash = "sha256:971948dcb8658ca54a9540eeb3e98e70fde0567be270211ea777e6a48f097a0d", size = 1121142 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4e/5fcc4777326b2b12217233f51339e42d5f71bfd739a3c357fd2bc938181e/typos-1.29.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3825b4b6f6deec99b78c998ae5d1681334920a0519fe6ae4a3fdc6c041834728", size = 3057434 }, - { url = "https://files.pythonhosted.org/packages/d7/a5/5bf0f007476b13ffc2a99a81edec6baee6720381927765224a25449a4dec/typos-1.29.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f7a318f65bbea371f24ea3f5ab1ba1953d5f5ad7c1115582b4f6992ed79dcfcb", size = 2931341 }, - { url = "https://files.pythonhosted.org/packages/11/35/6bd1009dca9297063d96b7c1e29d66bea5f8c1e5aad64a33c7dd67f208c3/typos-1.29.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5e3aedf4d99055b27b70f472abb694cc420d03b003e71ab8877acf2a24a945e", size = 4271641 }, - { url = "https://files.pythonhosted.org/packages/77/2b/6458d18b2a9882d0ed0229ba7cc2197476a996a05589d151ad600a91cccb/typos-1.29.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59b134bad893e0611a0c0212750c0e49503552b600033b8c2c5cc2b8222e75de", size = 3417769 }, - { url = "https://files.pythonhosted.org/packages/bb/2e/8fbcde73fb4c6c826bd5d2c39d16d883915240cbdc693f5d99191574e11b/typos-1.29.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7dac616eacae037e71e6c1089b82dc296c1a5b4621b132eba5c79b7044b1a74", size = 4124138 }, - { url = "https://files.pythonhosted.org/packages/29/c6/6d66f554b4425f1bdd2220dbe5626e80db814ac4ac2a635e5c72ba75ec61/typos-1.29.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fdf9d2550796d36120e464f6dac4e525d397204728dc87be0c749f4a3746ce37", size = 3356751 }, - { url = "https://files.pythonhosted.org/packages/b2/0c/ff2dac645ec184518aeb78585b5e97d096f28278c78db762f78c81cba95a/typos-1.29.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:564a39c4803d2285c9756069ca0a4490e4ccecedeea568b085421cd9e035a865", size = 4180122 }, - { url = "https://files.pythonhosted.org/packages/2d/df/46177b00c22183bd4b0f9e10adbf2cb74c025ddac55f574b2f2045e09d7b/typos-1.29.4-py3-none-win32.whl", hash = "sha256:f66f292fe88c2ffe537373654c5e157a930f4ba302400916e0b9d802ad6e5932", size = 2735883 }, - { url = "https://files.pythonhosted.org/packages/90/54/063bf78200373b0ad7ab291fbb79a845e17df1a4cac9a58c8bd2dfdc4491/typos-1.29.4-py3-none-win_amd64.whl", hash = "sha256:937cd4ef6576f1d5a5f5473ea9ac789b332fb62bee7f6e4f6cfb1cfdd2e9e618", size = 2883074 }, + { url = "https://files.pythonhosted.org/packages/71/c7/c7fd35cacd427248cc22469d34a116a4b10d2fe8f10dfb17b0478f4f6896/typos-1.27.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:baded84708fb2a26af211f5b3b254cac57fafec00d08b5a0e6fef028265207de", size = 3004823 }, + { url = "https://files.pythonhosted.org/packages/bf/17/3285b1bc6484a453bddad48fedd07a74d7caa0d8404ba0d0ead01c4b7585/typos-1.27.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:04b065ee1e543d93dbee0fd9983aecc6510eee13864127782965e6ba9f117af2", size = 2907620 }, + { url = "https://files.pythonhosted.org/packages/ed/51/8ec8b4c3ecb5616c25865f3e75f77b979ee320455bcd7ae22928ec10791b/typos-1.27.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0adb86304e661e5e1a19f3cf5a7b45e424213373d548c71b7b066ba3bc50fce", size = 4309062 }, + { url = "https://files.pythonhosted.org/packages/a8/fd/48bcfd63bafd17b7c87215dd45e2feb539f75bdc80038951ca1274740556/typos-1.27.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c45235fdd7a3feef0e9760e1ecb3a1decb59daa16bbb8b66e1eba42cf6db001e", size = 3379419 }, + { url = "https://files.pythonhosted.org/packages/5d/a1/2fae2db480b9a5066dec7e07d8dc7ae4d89da0b037b39bfd18419d84e234/typos-1.27.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbdf22be5af91a6c7e6861d39e2ade680995d8ae8d8a0d2926a176da02dbd953", size = 4093355 }, + { url = "https://files.pythonhosted.org/packages/ca/6e/0bdf03999a7e966ca93f559ff3987bf7ac6906b588fa80764b7565a57029/typos-1.27.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:cb6e7358da27be68fdd668f8cce15e5528349914384935fbfc321973764f493a", size = 3912093 }, + { url = "https://files.pythonhosted.org/packages/b6/c8/4d4fc0785f489b811824da905905bc10d4f5ae95cdc384cda1c41f9b8730/typos-1.27.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:360faa9967ca60685f403db564005117223cae7611325202f6c7c5cdd9dae57c", size = 4096772 }, + { url = "https://files.pythonhosted.org/packages/3f/ef/9ac8bd186ecb304e5e43d4000dee362d3eb637f1215abbd2fa79155149c9/typos-1.27.3-py3-none-win32.whl", hash = "sha256:f48ab60939701ca4cb5749fea9654184a6bdb6a80a715f7bf7894bd434983ee8", size = 2431969 }, + { url = "https://files.pythonhosted.org/packages/9a/40/61626f683fabb0778553ee5e5d489c48c820064c3470389251e79fa64f81/typos-1.27.3-py3-none-win_amd64.whl", hash = "sha256:29cda6c1d3e68f419ee31b60f23e4c66bfa3be9e30e5df72df24566289da2852", size = 2562657 }, ] [[package]] name = "urllib3" -version = "2.3.0" +version = "2.2.3" 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/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } 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/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, ] [[package]] name = "uvicorn" -version = "0.34.0" +version = "0.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/fc/1d785078eefd6945f3e5bab5c076e4230698046231eb0f3747bc5c8fa992/uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e", size = 77564 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 }, + { url = "https://files.pythonhosted.org/packages/eb/14/78bd0e95dd2444b6caacbca2b730671d4295ccb628ef58b81bee903629df/uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", size = 63723 }, ] [[package]] name = "virtualenv" -version = "20.29.1" +version = "20.27.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/ca/f23dcb02e161a9bba141b1c08aa50e8da6ea25e6d780528f1d385a3efe25/virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35", size = 7658028 } +sdist = { url = "https://files.pythonhosted.org/packages/8c/b3/7b6a79c5c8cf6d90ea681310e169cf2db2884f4d583d16c6e1d5a75a4e04/virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba", size = 6491145 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/9b/599bcfc7064fbe5740919e78c5df18e5dceb0887e676256a1061bb5ae232/virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779", size = 4282379 }, + { url = "https://files.pythonhosted.org/packages/ae/92/78324ff89391e00c8f4cf6b8526c41c6ef36b4ea2d2c132250b1a6fc2b8d/virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4", size = 3117838 }, ] [[package]] name = "watchfiles" -version = "1.0.4" +version = "0.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/26/c705fc77d0a9ecdb9b66f1e2976d95b81df3cae518967431e7dbf9b5e219/watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205", size = 94625 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/1a/8f4d9a1461709756ace48c98f07772bc6d4519b1e48b5fa24a4061216256/watchfiles-1.0.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2", size = 391345 }, - { url = "https://files.pythonhosted.org/packages/bc/d2/6750b7b3527b1cdaa33731438432e7238a6c6c40a9924049e4cebfa40805/watchfiles-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9", size = 381515 }, - { url = "https://files.pythonhosted.org/packages/4e/17/80500e42363deef1e4b4818729ed939aaddc56f82f4e72b2508729dd3c6b/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712", size = 449767 }, - { url = "https://files.pythonhosted.org/packages/10/37/1427fa4cfa09adbe04b1e97bced19a29a3462cc64c78630787b613a23f18/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12", size = 455677 }, - { url = "https://files.pythonhosted.org/packages/c5/7a/39e9397f3a19cb549a7d380412fd9e507d4854eddc0700bfad10ef6d4dba/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844", size = 482219 }, - { url = "https://files.pythonhosted.org/packages/45/2d/7113931a77e2ea4436cad0c1690c09a40a7f31d366f79c6f0a5bc7a4f6d5/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733", size = 518830 }, - { url = "https://files.pythonhosted.org/packages/f9/1b/50733b1980fa81ef3c70388a546481ae5fa4c2080040100cd7bf3bf7b321/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af", size = 497997 }, - { url = "https://files.pythonhosted.org/packages/2b/b4/9396cc61b948ef18943e7c85ecfa64cf940c88977d882da57147f62b34b1/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a", size = 452249 }, - { url = "https://files.pythonhosted.org/packages/fb/69/0c65a5a29e057ad0dc691c2fa6c23b2983c7dabaa190ba553b29ac84c3cc/watchfiles-1.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff", size = 614412 }, - { url = "https://files.pythonhosted.org/packages/7f/b9/319fcba6eba5fad34327d7ce16a6b163b39741016b1996f4a3c96b8dd0e1/watchfiles-1.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e", size = 611982 }, - { url = "https://files.pythonhosted.org/packages/f1/47/143c92418e30cb9348a4387bfa149c8e0e404a7c5b0585d46d2f7031b4b9/watchfiles-1.0.4-cp312-cp312-win32.whl", hash = "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94", size = 271822 }, - { url = "https://files.pythonhosted.org/packages/ea/94/b0165481bff99a64b29e46e07ac2e0df9f7a957ef13bec4ceab8515f44e3/watchfiles-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c", size = 285441 }, - { url = "https://files.pythonhosted.org/packages/11/de/09fe56317d582742d7ca8c2ca7b52a85927ebb50678d9b0fa8194658f536/watchfiles-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90", size = 277141 }, - { url = "https://files.pythonhosted.org/packages/08/98/f03efabec64b5b1fa58c0daab25c68ef815b0f320e54adcacd0d6847c339/watchfiles-1.0.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8012bd820c380c3d3db8435e8cf7592260257b378b649154a7948a663b5f84e9", size = 390954 }, - { url = "https://files.pythonhosted.org/packages/16/09/4dd49ba0a32a45813debe5fb3897955541351ee8142f586303b271a02b40/watchfiles-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa216f87594f951c17511efe5912808dfcc4befa464ab17c98d387830ce07b60", size = 381133 }, - { url = "https://files.pythonhosted.org/packages/76/59/5aa6fc93553cd8d8ee75c6247763d77c02631aed21551a97d94998bf1dae/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c9953cf85529c05b24705639ffa390f78c26449e15ec34d5339e8108c7c407", size = 449516 }, - { url = "https://files.pythonhosted.org/packages/4c/aa/df4b6fe14b6317290b91335b23c96b488d365d65549587434817e06895ea/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cf684aa9bba4cd95ecb62c822a56de54e3ae0598c1a7f2065d51e24637a3c5d", size = 454820 }, - { url = "https://files.pythonhosted.org/packages/5e/71/185f8672f1094ce48af33252c73e39b48be93b761273872d9312087245f6/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f44a39aee3cbb9b825285ff979ab887a25c5d336e5ec3574f1506a4671556a8d", size = 481550 }, - { url = "https://files.pythonhosted.org/packages/85/d7/50ebba2c426ef1a5cb17f02158222911a2e005d401caf5d911bfca58f4c4/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38320582736922be8c865d46520c043bff350956dfc9fbaee3b2df4e1740a4b", size = 518647 }, - { url = "https://files.pythonhosted.org/packages/f0/7a/4c009342e393c545d68987e8010b937f72f47937731225b2b29b7231428f/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39f4914548b818540ef21fd22447a63e7be6e24b43a70f7642d21f1e73371590", size = 497547 }, - { url = "https://files.pythonhosted.org/packages/0f/7c/1cf50b35412d5c72d63b2bf9a4fffee2e1549a245924960dd087eb6a6de4/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f12969a3765909cf5dc1e50b2436eb2c0e676a3c75773ab8cc3aa6175c16e902", size = 452179 }, - { url = "https://files.pythonhosted.org/packages/d6/a9/3db1410e1c1413735a9a472380e4f431ad9a9e81711cda2aaf02b7f62693/watchfiles-1.0.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0986902677a1a5e6212d0c49b319aad9cc48da4bd967f86a11bde96ad9676ca1", size = 614125 }, - { url = "https://files.pythonhosted.org/packages/f2/e1/0025d365cf6248c4d1ee4c3d2e3d373bdd3f6aff78ba4298f97b4fad2740/watchfiles-1.0.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:308ac265c56f936636e3b0e3f59e059a40003c655228c131e1ad439957592303", size = 611911 }, - { url = "https://files.pythonhosted.org/packages/55/55/035838277d8c98fc8c917ac9beeb0cd6c59d675dc2421df5f9fcf44a0070/watchfiles-1.0.4-cp313-cp313-win32.whl", hash = "sha256:aee397456a29b492c20fda2d8961e1ffb266223625346ace14e4b6d861ba9c80", size = 271152 }, - { url = "https://files.pythonhosted.org/packages/f0/e5/96b8e55271685ddbadc50ce8bc53aa2dff278fb7ac4c2e473df890def2dc/watchfiles-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:d6097538b0ae5c1b88c3b55afa245a66793a8fec7ada6755322e465fb1a0e8cc", size = 285216 }, +sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 }, + { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 }, + { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 }, + { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 }, + { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 }, + { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 }, + { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 }, + { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 }, + { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 }, + { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 }, + { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 }, + { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 }, + { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 }, + { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 }, + { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 }, + { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 }, + { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 }, + { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 }, + { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 }, + { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 }, + { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 }, + { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 }, + { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 }, + { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 }, + { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, ] [[package]] @@ -2256,75 +2665,52 @@ wheels = [ [[package]] name = "websockets" -version = "14.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/54/8359678c726243d19fae38ca14a334e740782336c9f19700858c4eb64a1e/websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5", size = 164394 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/81/04f7a397653dc8bec94ddc071f34833e8b99b13ef1a3804c149d59f92c18/websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c", size = 163096 }, - { url = "https://files.pythonhosted.org/packages/ec/c5/de30e88557e4d70988ed4d2eabd73fd3e1e52456b9f3a4e9564d86353b6d/websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967", size = 160758 }, - { url = "https://files.pythonhosted.org/packages/e5/8c/d130d668781f2c77d106c007b6c6c1d9db68239107c41ba109f09e6c218a/websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990", size = 160995 }, - { url = "https://files.pythonhosted.org/packages/a6/bc/f6678a0ff17246df4f06765e22fc9d98d1b11a258cc50c5968b33d6742a1/websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda", size = 170815 }, - { url = "https://files.pythonhosted.org/packages/d8/b2/8070cb970c2e4122a6ef38bc5b203415fd46460e025652e1ee3f2f43a9a3/websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95", size = 169759 }, - { url = "https://files.pythonhosted.org/packages/81/da/72f7caabd94652e6eb7e92ed2d3da818626e70b4f2b15a854ef60bf501ec/websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3", size = 170178 }, - { url = "https://files.pythonhosted.org/packages/31/e0/812725b6deca8afd3a08a2e81b3c4c120c17f68c9b84522a520b816cda58/websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9", size = 170453 }, - { url = "https://files.pythonhosted.org/packages/66/d3/8275dbc231e5ba9bb0c4f93144394b4194402a7a0c8ffaca5307a58ab5e3/websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267", size = 169830 }, - { url = "https://files.pythonhosted.org/packages/a3/ae/e7d1a56755ae15ad5a94e80dd490ad09e345365199600b2629b18ee37bc7/websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe", size = 169824 }, - { url = "https://files.pythonhosted.org/packages/b6/32/88ccdd63cb261e77b882e706108d072e4f1c839ed723bf91a3e1f216bf60/websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205", size = 163981 }, - { url = "https://files.pythonhosted.org/packages/b3/7d/32cdb77990b3bdc34a306e0a0f73a1275221e9a66d869f6ff833c95b56ef/websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce", size = 164421 }, - { url = "https://files.pythonhosted.org/packages/82/94/4f9b55099a4603ac53c2912e1f043d6c49d23e94dd82a9ce1eb554a90215/websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e", size = 163102 }, - { url = "https://files.pythonhosted.org/packages/8e/b7/7484905215627909d9a79ae07070057afe477433fdacb59bf608ce86365a/websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad", size = 160766 }, - { url = "https://files.pythonhosted.org/packages/a3/a4/edb62efc84adb61883c7d2c6ad65181cb087c64252138e12d655989eec05/websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03", size = 160998 }, - { url = "https://files.pythonhosted.org/packages/f5/79/036d320dc894b96af14eac2529967a6fc8b74f03b83c487e7a0e9043d842/websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f", size = 170780 }, - { url = "https://files.pythonhosted.org/packages/63/75/5737d21ee4dd7e4b9d487ee044af24a935e36a9ff1e1419d684feedcba71/websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5", size = 169717 }, - { url = "https://files.pythonhosted.org/packages/2c/3c/bf9b2c396ed86a0b4a92ff4cdaee09753d3ee389be738e92b9bbd0330b64/websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a", size = 170155 }, - { url = "https://files.pythonhosted.org/packages/75/2d/83a5aca7247a655b1da5eb0ee73413abd5c3a57fc8b92915805e6033359d/websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20", size = 170495 }, - { url = "https://files.pythonhosted.org/packages/79/dd/699238a92761e2f943885e091486378813ac8f43e3c84990bc394c2be93e/websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2", size = 169880 }, - { url = "https://files.pythonhosted.org/packages/c8/c9/67a8f08923cf55ce61aadda72089e3ed4353a95a3a4bc8bf42082810e580/websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307", size = 169856 }, - { url = "https://files.pythonhosted.org/packages/17/b1/1ffdb2680c64e9c3921d99db460546194c40d4acbef999a18c37aa4d58a3/websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc", size = 163974 }, - { url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f", size = 164420 }, - { url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416 }, +version = "13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 }, + { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 }, + { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 }, + { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 }, + { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 }, + { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 }, + { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 }, + { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 }, + { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 }, + { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 }, + { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 }, + { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 }, + { url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 }, + { url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 }, + { url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 }, + { url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 }, + { url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 }, + { url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 }, + { url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 }, + { url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 }, + { url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 }, + { url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 }, + { url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 }, ] [[package]] name = "wrapt" -version = "1.17.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799 }, - { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821 }, - { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919 }, - { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721 }, - { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899 }, - { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222 }, - { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707 }, - { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685 }, - { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567 }, - { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672 }, - { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865 }, - { url = "https://files.pythonhosted.org/packages/ce/b9/0ffd557a92f3b11d4c5d5e0c5e4ad057bd9eb8586615cdaf901409920b14/wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", size = 53800 }, - { url = "https://files.pythonhosted.org/packages/c0/ef/8be90a0b7e73c32e550c73cfb2fa09db62234227ece47b0e80a05073b375/wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", size = 38824 }, - { url = "https://files.pythonhosted.org/packages/36/89/0aae34c10fe524cce30fe5fc433210376bce94cf74d05b0d68344c8ba46e/wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", size = 38920 }, - { url = "https://files.pythonhosted.org/packages/3b/24/11c4510de906d77e0cfb5197f1b1445d4fec42c9a39ea853d482698ac681/wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", size = 88690 }, - { url = "https://files.pythonhosted.org/packages/71/d7/cfcf842291267bf455b3e266c0c29dcb675b5540ee8b50ba1699abf3af45/wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", size = 80861 }, - { url = "https://files.pythonhosted.org/packages/d5/66/5d973e9f3e7370fd686fb47a9af3319418ed925c27d72ce16b791231576d/wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", size = 89174 }, - { url = "https://files.pythonhosted.org/packages/a7/d3/8e17bb70f6ae25dabc1aaf990f86824e4fd98ee9cadf197054e068500d27/wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", size = 86721 }, - { url = "https://files.pythonhosted.org/packages/6f/54/f170dfb278fe1c30d0ff864513cff526d624ab8de3254b20abb9cffedc24/wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", size = 79763 }, - { url = "https://files.pythonhosted.org/packages/4a/98/de07243751f1c4a9b15c76019250210dd3486ce098c3d80d5f729cba029c/wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", size = 87585 }, - { url = "https://files.pythonhosted.org/packages/f9/f0/13925f4bd6548013038cdeb11ee2cbd4e37c30f8bfd5db9e5a2a370d6e20/wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", size = 36676 }, - { url = "https://files.pythonhosted.org/packages/bf/ae/743f16ef8c2e3628df3ddfd652b7d4c555d12c84b53f3d8218498f4ade9b/wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", size = 38871 }, - { url = "https://files.pythonhosted.org/packages/3d/bc/30f903f891a82d402ffb5fda27ec1d621cc97cb74c16fea0b6141f1d4e87/wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", size = 56312 }, - { url = "https://files.pythonhosted.org/packages/8a/04/c97273eb491b5f1c918857cd26f314b74fc9b29224521f5b83f872253725/wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", size = 40062 }, - { url = "https://files.pythonhosted.org/packages/4e/ca/3b7afa1eae3a9e7fefe499db9b96813f41828b9fdb016ee836c4c379dadb/wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", size = 40155 }, - { url = "https://files.pythonhosted.org/packages/89/be/7c1baed43290775cb9030c774bc53c860db140397047cc49aedaf0a15477/wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", size = 113471 }, - { url = "https://files.pythonhosted.org/packages/32/98/4ed894cf012b6d6aae5f5cc974006bdeb92f0241775addad3f8cd6ab71c8/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", size = 101208 }, - { url = "https://files.pythonhosted.org/packages/ea/fd/0c30f2301ca94e655e5e057012e83284ce8c545df7661a78d8bfca2fac7a/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", size = 109339 }, - { url = "https://files.pythonhosted.org/packages/75/56/05d000de894c4cfcb84bcd6b1df6214297b8089a7bd324c21a4765e49b14/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", size = 110232 }, - { url = "https://files.pythonhosted.org/packages/53/f8/c3f6b2cf9b9277fb0813418e1503e68414cd036b3b099c823379c9575e6d/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", size = 100476 }, - { url = "https://files.pythonhosted.org/packages/a7/b1/0bb11e29aa5139d90b770ebbfa167267b1fc548d2302c30c8f7572851738/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", size = 106377 }, - { url = "https://files.pythonhosted.org/packages/6a/e1/0122853035b40b3f333bbb25f1939fc1045e21dd518f7f0922b60c156f7c/wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", size = 37986 }, - { url = "https://files.pythonhosted.org/packages/09/5e/1655cf481e079c1f22d0cabdd4e51733679932718dc23bf2db175f329b76/wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", size = 40750 }, - { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594 }, +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/4c/063a912e20bcef7124e0df97282a8af3ff3e4b603ce84c481d6d7346be0a/wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d", size = 53972 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/17/224132494c1e23521868cdd57cd1e903f3b6a7ba6996b7b8f077ff8ac7fe/wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b", size = 37614 }, + { url = "https://files.pythonhosted.org/packages/6a/d7/cfcd73e8f4858079ac59d9db1ec5a1349bc486ae8e9ba55698cc1f4a1dff/wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36", size = 38316 }, + { url = "https://files.pythonhosted.org/packages/7e/79/5ff0a5c54bda5aec75b36453d06be4f83d5cd4932cc84b7cb2b52cee23e2/wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73", size = 86322 }, + { url = "https://files.pythonhosted.org/packages/c4/81/e799bf5d419f422d8712108837c1d9bf6ebe3cb2a81ad94413449543a923/wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809", size = 79055 }, + { url = "https://files.pythonhosted.org/packages/62/62/30ca2405de6a20448ee557ab2cd61ab9c5900be7cbd18a2639db595f0b98/wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b", size = 87291 }, + { url = "https://files.pythonhosted.org/packages/49/4e/5d2f6d7b57fc9956bf06e944eb00463551f7d52fc73ca35cfc4c2cdb7aed/wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81", size = 90374 }, + { url = "https://files.pythonhosted.org/packages/a6/9b/c2c21b44ff5b9bf14a83252a8b973fb84923764ff63db3e6dfc3895cf2e0/wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9", size = 83896 }, + { url = "https://files.pythonhosted.org/packages/14/26/93a9fa02c6f257df54d7570dfe8011995138118d11939a4ecd82cb849613/wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c", size = 91738 }, + { url = "https://files.pythonhosted.org/packages/a2/5b/4660897233eb2c8c4de3dc7cefed114c61bacb3c28327e64150dc44ee2f6/wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc", size = 35568 }, + { url = "https://files.pythonhosted.org/packages/5c/cc/8297f9658506b224aa4bd71906447dea6bb0ba629861a758c28f67428b91/wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8", size = 37653 }, + { url = "https://files.pythonhosted.org/packages/ff/21/abdedb4cdf6ff41ebf01a74087740a709e2edb146490e4d9beea054b0b7a/wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1", size = 23362 }, ] [[package]] @@ -2341,46 +2727,46 @@ wheels = [ [[package]] name = "yarl" -version = "1.18.3" +version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/85/bd2e2729752ff4c77338e0102914897512e92496375e079ce0150a6dc306/yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", size = 142644 }, - { url = "https://files.pythonhosted.org/packages/ff/74/1178322cc0f10288d7eefa6e4a85d8d2e28187ccab13d5b844e8b5d7c88d/yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", size = 94962 }, - { url = "https://files.pythonhosted.org/packages/be/75/79c6acc0261e2c2ae8a1c41cf12265e91628c8c58ae91f5ff59e29c0787f/yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", size = 92795 }, - { url = "https://files.pythonhosted.org/packages/6b/32/927b2d67a412c31199e83fefdce6e645247b4fb164aa1ecb35a0f9eb2058/yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", size = 332368 }, - { url = "https://files.pythonhosted.org/packages/19/e5/859fca07169d6eceeaa4fde1997c91d8abde4e9a7c018e371640c2da2b71/yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", size = 342314 }, - { url = "https://files.pythonhosted.org/packages/08/75/76b63ccd91c9e03ab213ef27ae6add2e3400e77e5cdddf8ed2dbc36e3f21/yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", size = 341987 }, - { url = "https://files.pythonhosted.org/packages/1a/e1/a097d5755d3ea8479a42856f51d97eeff7a3a7160593332d98f2709b3580/yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", size = 336914 }, - { url = "https://files.pythonhosted.org/packages/0b/42/e1b4d0e396b7987feceebe565286c27bc085bf07d61a59508cdaf2d45e63/yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", size = 325765 }, - { url = "https://files.pythonhosted.org/packages/7e/18/03a5834ccc9177f97ca1bbb245b93c13e58e8225276f01eedc4cc98ab820/yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", size = 344444 }, - { url = "https://files.pythonhosted.org/packages/c8/03/a713633bdde0640b0472aa197b5b86e90fbc4c5bc05b727b714cd8a40e6d/yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", size = 340760 }, - { url = "https://files.pythonhosted.org/packages/eb/99/f6567e3f3bbad8fd101886ea0276c68ecb86a2b58be0f64077396cd4b95e/yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", size = 346484 }, - { url = "https://files.pythonhosted.org/packages/8e/a9/84717c896b2fc6cb15bd4eecd64e34a2f0a9fd6669e69170c73a8b46795a/yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", size = 359864 }, - { url = "https://files.pythonhosted.org/packages/1e/2e/d0f5f1bef7ee93ed17e739ec8dbcb47794af891f7d165fa6014517b48169/yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", size = 364537 }, - { url = "https://files.pythonhosted.org/packages/97/8a/568d07c5d4964da5b02621a517532adb8ec5ba181ad1687191fffeda0ab6/yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", size = 357861 }, - { url = "https://files.pythonhosted.org/packages/7d/e3/924c3f64b6b3077889df9a1ece1ed8947e7b61b0a933f2ec93041990a677/yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", size = 84097 }, - { url = "https://files.pythonhosted.org/packages/34/45/0e055320daaabfc169b21ff6174567b2c910c45617b0d79c68d7ab349b02/yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", size = 90399 }, - { url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789 }, - { url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144 }, - { url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974 }, - { url = "https://files.pythonhosted.org/packages/56/4e/d2563d8323a7e9a414b5b25341b3942af5902a2263d36d20fb17c40411e2/yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", size = 333587 }, - { url = "https://files.pythonhosted.org/packages/25/c9/cfec0bc0cac8d054be223e9f2c7909d3e8442a856af9dbce7e3442a8ec8d/yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", size = 344386 }, - { url = "https://files.pythonhosted.org/packages/ab/5d/4c532190113b25f1364d25f4c319322e86232d69175b91f27e3ebc2caf9a/yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", size = 345421 }, - { url = "https://files.pythonhosted.org/packages/23/d1/6cdd1632da013aa6ba18cee4d750d953104a5e7aac44e249d9410a972bf5/yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", size = 339384 }, - { url = "https://files.pythonhosted.org/packages/9a/c4/6b3c39bec352e441bd30f432cda6ba51681ab19bb8abe023f0d19777aad1/yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", size = 326689 }, - { url = "https://files.pythonhosted.org/packages/23/30/07fb088f2eefdc0aa4fc1af4e3ca4eb1a3aadd1ce7d866d74c0f124e6a85/yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", size = 345453 }, - { url = "https://files.pythonhosted.org/packages/63/09/d54befb48f9cd8eec43797f624ec37783a0266855f4930a91e3d5c7717f8/yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", size = 341872 }, - { url = "https://files.pythonhosted.org/packages/91/26/fd0ef9bf29dd906a84b59f0cd1281e65b0c3e08c6aa94b57f7d11f593518/yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", size = 347497 }, - { url = "https://files.pythonhosted.org/packages/d9/b5/14ac7a256d0511b2ac168d50d4b7d744aea1c1aa20c79f620d1059aab8b2/yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", size = 359981 }, - { url = "https://files.pythonhosted.org/packages/ca/b3/d493221ad5cbd18bc07e642894030437e405e1413c4236dd5db6e46bcec9/yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", size = 366229 }, - { url = "https://files.pythonhosted.org/packages/04/56/6a3e2a5d9152c56c346df9b8fb8edd2c8888b1e03f96324d457e5cf06d34/yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", size = 360383 }, - { url = "https://files.pythonhosted.org/packages/fd/b7/4b3c7c7913a278d445cc6284e59b2e62fa25e72758f888b7a7a39eb8423f/yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", size = 310152 }, - { url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723 }, - { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, +sdist = { url = "https://files.pythonhosted.org/packages/54/9c/9c0a9bfa683fc1be7fdcd9687635151544d992cccd48892dc5e0a5885a29/yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47", size = 178163 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/af/e25615c7920396219b943b9ff8b34636ae3e1ad30777649371317d7f05f8/yarl-1.17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61", size = 141839 }, + { url = "https://files.pythonhosted.org/packages/83/5e/363d9de3495c7c66592523f05d21576a811015579e0c87dd38c7b5788afd/yarl-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d", size = 94125 }, + { url = "https://files.pythonhosted.org/packages/e3/a2/b65447626227ebe36f18f63ac551790068bf42c69bb22dfa3ae986170728/yarl-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139", size = 92048 }, + { url = "https://files.pythonhosted.org/packages/a1/f5/2ef86458446f85cde10582054fd5113495ef8ce8477da35aaaf26d2970ef/yarl-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5", size = 331472 }, + { url = "https://files.pythonhosted.org/packages/f3/6b/1ba79758ba352cdf2ad4c20cab1b982dd369aa595bb0d7601fc89bf82bee/yarl-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac", size = 341260 }, + { url = "https://files.pythonhosted.org/packages/2d/41/4e07c2afca3f9ed3da5b0e38d43d0280d9b624a3d5c478c425e5ce17775c/yarl-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463", size = 340882 }, + { url = "https://files.pythonhosted.org/packages/c3/c0/cd8e94618983c1b811af082e1a7ad7764edb3a6af2bc6b468e0e686238ba/yarl-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147", size = 336648 }, + { url = "https://files.pythonhosted.org/packages/ac/fc/73ec4340d391ffbb8f34eb4c55429784ec9f5bd37973ce86d52d67135418/yarl-1.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7", size = 325019 }, + { url = "https://files.pythonhosted.org/packages/57/48/da3ebf418fc239d0a156b3bdec6b17a5446f8d2dea752299c6e47b143a85/yarl-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685", size = 342841 }, + { url = "https://files.pythonhosted.org/packages/5d/79/107272745a470a8167924e353a5312eb52b5a9bb58e22686adc46c94f7ec/yarl-1.17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172", size = 341433 }, + { url = "https://files.pythonhosted.org/packages/30/9c/6459668b3b8dcc11cd061fc53e12737e740fb6b1575b49c84cbffb387b3a/yarl-1.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7", size = 344927 }, + { url = "https://files.pythonhosted.org/packages/c5/0b/93a17ed733aca8164fc3a01cb7d47b3f08854ce4f957cce67a6afdb388a0/yarl-1.17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da", size = 355732 }, + { url = "https://files.pythonhosted.org/packages/9a/63/ead2ed6aec3c59397e135cadc66572330325a0c24cd353cd5c94f5e63463/yarl-1.17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c", size = 362123 }, + { url = "https://files.pythonhosted.org/packages/89/bf/f6b75b4c2fcf0e7bb56edc0ed74e33f37fac45dc40e5a52a3be66b02587a/yarl-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199", size = 356355 }, + { url = "https://files.pythonhosted.org/packages/45/1f/50a0257cd07eef65c8c65ad6a21f5fb230012d659e021aeb6ac8a7897bf6/yarl-1.17.1-cp312-cp312-win32.whl", hash = "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96", size = 83279 }, + { url = "https://files.pythonhosted.org/packages/bc/82/fafb2c1268d63d54ec08b3a254fbe51f4ef098211501df646026717abee3/yarl-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df", size = 89590 }, + { url = "https://files.pythonhosted.org/packages/06/1e/5a93e3743c20eefbc68bd89334d9c9f04f3f2334380f7bbf5e950f29511b/yarl-1.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488", size = 139974 }, + { url = "https://files.pythonhosted.org/packages/a1/be/4e0f6919013c7c5eaea5c31811c551ccd599d2fc80aa3dd6962f1bbdcddd/yarl-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374", size = 93364 }, + { url = "https://files.pythonhosted.org/packages/73/f0/650f994bc491d0cb85df8bb45392780b90eab1e175f103a5edc61445ff67/yarl-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac", size = 91177 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/9945ed555d14b43ede3ae8b1bd73e31068a694cad2b9d3cad0a28486c2eb/yarl-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170", size = 333086 }, + { url = "https://files.pythonhosted.org/packages/a6/c0/7d167e48e14d26639ca066825af8da7df1d2fcdba827e3fd6341aaf22a3b/yarl-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8", size = 343661 }, + { url = "https://files.pythonhosted.org/packages/fa/81/80a266517531d4e3553aecd141800dbf48d02e23ebd52909e63598a80134/yarl-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938", size = 345196 }, + { url = "https://files.pythonhosted.org/packages/b0/77/6adc482ba7f2dc6c0d9b3b492e7cd100edfac4cfc3849c7ffa26fd7beb1a/yarl-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e", size = 338743 }, + { url = "https://files.pythonhosted.org/packages/6d/cc/f0c4c0b92ff3ada517ffde2b127406c001504b225692216d969879ada89a/yarl-1.17.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556", size = 326719 }, + { url = "https://files.pythonhosted.org/packages/18/3b/7bfc80d3376b5fa162189993a87a5a6a58057f88315bd0ea00610055b57a/yarl-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67", size = 345826 }, + { url = "https://files.pythonhosted.org/packages/2e/66/cf0b0338107a5c370205c1a572432af08f36ca12ecce127f5b558398b4fd/yarl-1.17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8", size = 340335 }, + { url = "https://files.pythonhosted.org/packages/2f/52/b084b0eec0fd4d2490e1d33ace3320fad704c5f1f3deaa709f929d2d87fc/yarl-1.17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3", size = 345301 }, + { url = "https://files.pythonhosted.org/packages/ef/38/9e2036d948efd3bafcdb4976cb212166fded76615f0dfc6c1492c4ce4784/yarl-1.17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0", size = 354205 }, + { url = "https://files.pythonhosted.org/packages/81/c1/13dfe1e70b86811733316221c696580725ceb1c46d4e4db852807e134310/yarl-1.17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299", size = 360501 }, + { url = "https://files.pythonhosted.org/packages/91/87/756e05c74cd8bf9e71537df4a2cae7e8211a9ebe0d2350a3e26949e1e41c/yarl-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258", size = 359452 }, + { url = "https://files.pythonhosted.org/packages/06/b2/b2bb09c1e6d59e1c9b1b36a86caa473e22c3dbf26d1032c030e9bfb554dc/yarl-1.17.1-cp313-cp313-win32.whl", hash = "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2", size = 308904 }, + { url = "https://files.pythonhosted.org/packages/f3/27/f084d9a5668853c1f3b246620269b14ee871ef3c3cc4f3a1dd53645b68ec/yarl-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda", size = 314637 }, + { url = "https://files.pythonhosted.org/packages/52/ad/1fe7ff5f3e8869d4c5070f47b96bac2b4d15e67c100a8278d8e7876329fc/yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06", size = 44352 }, ]