From 9e57f292a676107f422721c1b06fafd49a99603a Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 11:50:25 -0800 Subject: [PATCH 01/24] Update integration tests --- justfile | 12 +-- scripts/integration.sh | 56 +++++++++++ tests/conftest.py | 92 +++++++++++++++++-- tests/helpers.py | 52 +++++++++++ .../test_client.py} | 0 5 files changed, 196 insertions(+), 16 deletions(-) create mode 100755 scripts/integration.sh create mode 100644 tests/helpers.py rename tests/{test_integration.py => integration/test_client.py} (100%) diff --git a/justfile b/justfile index 8c3aeda..73d14ed 100644 --- a/justfile +++ b/justfile @@ -79,18 +79,18 @@ check: uv run npx pyright@latest # Run tests with pytest -test: - uv run pytest -vvv ./tests --ignore=./tests/test_integration.py - @just clean-test +test *argv: + uv run pytest {{ argv }} ./tests --ignore-glob='./tests/integration/**' + @just _clean-test # Update snapshots snap: - uv run pytest --snapshot-update ./tests + uv run pytest --snapshot-update ./tests --ignore-glob='./tests/integration/**' @just clean-test # Run integration tests -integration: - uv run gaktest ./tests/test_integration.py +integration *argv: + ./scripts/integration.sh {{ argv }} clean-test: rm -f pytest_runner-*.egg diff --git a/scripts/integration.sh b/scripts/integration.sh new file mode 100755 index 0000000..6d8c12e --- /dev/null +++ b/scripts/integration.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -euo pipefail + +COMPONENTS=() +ARGV=() + +HELP='USAGE: ./scripts/integration.sh [OPTIONS] [COMPONENTS] + +Run integration tests for the supplied components. By default, runs cli tests. + +Components: + client Run plusdeck client integration tests + dbus Start plusdeck dbus integration tests + +Options: + --help Show this help text + --snapshot-update Update snapshots + --system Run any dbus tests against the system bus + + Other options are passed to pytest. + +Environment: + PLUSDECK_CONFIG_FILE Use an alternative config file. The default is + ./tests/fixtures/plusdeck.yaml. + PLUSDECK_LOG_LEVEL +' + +while [[ $# -gt 0 ]]; do + case "${1}" in + --help) + echo "${HELP}" + exit 0 + ;; + cli|dbus) + COMPONENTS+=("${1}") + shift + ;; + *) + ARGV+=("${1}") + shift + ;; + esac +done + +if [ ${#COMPONENTS[@]} -eq 0 ]; then + COMPONENTS=("client") +fi + +for component in "${COMPONENTS[@]}"; do + ARGV+=("./tests/integration/test_${component}.py") +done + +set -x + +exec uv run gaktest "${ARGV[@]}" diff --git a/tests/conftest.py b/tests/conftest.py index 0093d5c..c34fbab 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,24 @@ # -*- coding: utf-8 -*- +import logging import os -import os.path +from pathlib import Path from unittest.mock import Mock +from typing import Dict, Generator, List, Optional import pytest from plusdeck.client import Client, State import plusdeck.config +from tests.helpers import Cli, EnvFactory + +logger = logging.getLogger(__name__) + + +def pytest_addoption(parser: pytest.Parser) -> None: + parser.addoption( + "--system", action="store", default=False, help="Connect to the system bus" + ) @pytest.fixture @@ -19,28 +30,28 @@ async def client(): @pytest.fixture -def environment(monkeypatch, config_file): - environ = dict(PLUSDECK_CONFIG=config_file, PLUSDECK_PORT="/dev/ttyUSB1") +def environment(monkeypatch, config_file: str, port: str) -> Dict[str, str]: + environ = dict(PLUSDECK_CONFIG=config_file, PLUSDECK_PORT=port) monkeypatch.setattr(os, "environ", environ) return environ @pytest.fixture -def config_file(monkeypatch): - file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "fixtures", "config.yaml" - ) +def config_file(monkeypatch) -> str: + if "PLUSDECK_CONFIG_FILE" in os.environ: + return os.environ["PLUSDECK_CONFIG_FILE"] + path = Path(__file__).parent / "fixtures/crystalfontz.yaml" def default_file() -> str: - return file + return str(path) monkeypatch.setattr(plusdeck.config, "default_file", default_file) - return file + return str(path) @pytest.fixture -def port(monkeypatch): +def port(monkeypatch) -> str: port = "/dev/ttyUSB0" def default_port() -> str: @@ -49,3 +60,64 @@ def default_port() -> str: monkeypatch.setattr(plusdeck.config, "default_port", default_port) return port + + +@pytest.fixture +def log_level() -> str: + if "PLUSDECK_LOG_LEVEL" in os.environ: + return os.environ["PLUSDECK_LOG_LEVEL"] + return "INFO" + + +@pytest.fixture +def cli_env(config_file: str, port: str, log_level: str) -> EnvFactory: + def factory(env: Optional[Dict[str, str]] = None) -> Dict[str, str]: + _env: Dict[str, str] = dict(os.environ) + + if env: + _env.update(env) + + _env["PLUSDECK_CONFIG_FILE"] = config_file + _env["PLUSDECK_PORT"] = port + _env["PLUSDECK_LOG_LEVEL"] = log_level + + return _env + + return factory + + +@pytest.fixture +def cli(cli_env: EnvFactory) -> Cli: + return Cli(["python3", "-m", "plusdeck"], env=cli_env()) + + +@pytest.fixture +def dbus_service( + cli_env: EnvFactory, request: pytest.FixtureRequest +) -> Generator[None, None, None]: + cli = Cli(["python3", "-m", "plusdeck.dbus.service", "--user"], env=cli_env()) + + if request.config.getoption("--system"): + logger.info("Connecting to system bus") + yield + return + + with cli.bg(): + yield + + +@pytest.fixture +def dbus_cli( + cli_env: EnvFactory, dbus_service: None, request: pytest.FixtureRequest +) -> Cli: + argv: List[str] = [ + "python3", + "-m", + "plusdeck.dbus.client", + "--system" if request.config.getoption("--system") else "--user", + ] + + if not request.config.getoption("--system"): + argv.append("--user") + + return Cli(argv, env=cli_env()) diff --git a/tests/helpers.py b/tests/helpers.py new file mode 100644 index 0000000..f16fe4b --- /dev/null +++ b/tests/helpers.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +from contextlib import contextmanager +import os +import subprocess +from typing import Dict, Generator, List, Optional, Protocol, Self + +from crystalfontz.character import SpecialCharacter + + +class Cli: + """ + A fixture for running CLI commands + """ + + def __init__( + self: Self, + argv: List[str], + env: Optional[Dict[str, str]] = None, + ) -> None: + self.argv: List[str] = argv + self.env: Dict[str, str] = env or dict(os.environ) + + def __call__(self: Self, *argv: str) -> subprocess.CompletedProcess: + return subprocess.run( + self.argv + list(argv), + capture_output=True, + check=True, + env=self.env, + ) + + @contextmanager + def bg(self: Self, *argv: str, quiet: bool = True) -> Generator[None, None, None]: + proc = subprocess.Popen( + self.argv + list(argv), + stderr=subprocess.DEVNULL if quiet else None, + env=self.env, + ) + + yield + + proc.terminate() + + +class EnvFactory(Protocol): + def __call__( + self: Self, env: Optional[Dict[str, str]] = None + ) -> Dict[str, str]: ... + + +def special_character_as_rows(character: SpecialCharacter) -> List[str]: + return ["".join(["█" if p else " " for p in row]) for row in character.pixels] diff --git a/tests/test_integration.py b/tests/integration/test_client.py similarity index 100% rename from tests/test_integration.py rename to tests/integration/test_client.py From 142ea10601451564c34b0eb8afa05d50ec7af307 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 11:50:41 -0800 Subject: [PATCH 02/24] Remove cli scripts from python package --- bin/plusdeck | 3 +++ bin/plusdeck-dbus | 3 +++ bin/plusdeck-service | 3 +++ plusdeck.spec | 2 ++ plusdeck.spec.tmpl | 2 ++ pyproject.toml | 5 ----- 6 files changed, 13 insertions(+), 5 deletions(-) create mode 100755 bin/plusdeck create mode 100755 bin/plusdeck-dbus create mode 100755 bin/plusdeck-service diff --git a/bin/plusdeck b/bin/plusdeck new file mode 100755 index 0000000..4923445 --- /dev/null +++ b/bin/plusdeck @@ -0,0 +1,3 @@ +#!/usr/bin/sh + +exec python3 -m plusdeck "$@" diff --git a/bin/plusdeck-dbus b/bin/plusdeck-dbus new file mode 100755 index 0000000..a885418 --- /dev/null +++ b/bin/plusdeck-dbus @@ -0,0 +1,3 @@ +#!/usr/bin/sh + +exec python3 -m plusdeck.dbus.client "$@" diff --git a/bin/plusdeck-service b/bin/plusdeck-service new file mode 100755 index 0000000..00d6bd9 --- /dev/null +++ b/bin/plusdeck-service @@ -0,0 +1,3 @@ +#!/usr/bin/sh + +exec python3 -m plusdeck.dbus.service "$@" diff --git a/plusdeck.spec b/plusdeck.spec index 7e73c40..3e252b3 100644 --- a/plusdeck.spec +++ b/plusdeck.spec @@ -26,6 +26,7 @@ tar -xzf %{SOURCE0} mkdir -p %{buildroot}%{_prefix}/lib/systemd/system install -p -D -m 0644 systemd/plusdeck.service %{buildroot}%{_prefix}/lib/systemd/system/plusdeck.service install -p -D -m 0644 dbus/org.jfhbrook.plusdeck.conf %{buildroot}%{_prefix}/share/dbus-1/system.d/org.jfhbrook.plusdeck.conf +install -p -m 755 bin/plusdeck-dbus %{buildroot}%{_bindir}/plusdeck %check @@ -33,6 +34,7 @@ install -p -D -m 0644 dbus/org.jfhbrook.plusdeck.conf %{buildroot}%{_prefix}/sha %files %{_prefix}/lib/systemd/system/plusdeck.service %{_prefix}/share/dbus-1/system.d/org.jfhbrook.plusdeck.conf +%{_bindir}/plusdeck %changelog * Sun Feb 09 2025 Josh Holbrook 4.0.1-1 diff --git a/plusdeck.spec.tmpl b/plusdeck.spec.tmpl index ca10349..a1ab1c9 100644 --- a/plusdeck.spec.tmpl +++ b/plusdeck.spec.tmpl @@ -26,6 +26,7 @@ tar -xzf %{SOURCE0} mkdir -p %{buildroot}%{_prefix}/lib/systemd/system install -p -D -m 0644 systemd/plusdeck.service %{buildroot}%{_prefix}/lib/systemd/system/plusdeck.service install -p -D -m 0644 dbus/org.jfhbrook.plusdeck.conf %{buildroot}%{_prefix}/share/dbus-1/system.d/org.jfhbrook.plusdeck.conf +install -p -m 755 bin/plusdeck-dbus %{buildroot}%{_bindir}/plusdeck %check @@ -33,6 +34,7 @@ install -p -D -m 0644 dbus/org.jfhbrook.plusdeck.conf %{buildroot}%{_prefix}/sha %files %{_prefix}/lib/systemd/system/plusdeck.service %{_prefix}/share/dbus-1/system.d/org.jfhbrook.plusdeck.conf +%{_bindir}/plusdeck %changelog {{ .Env.CHANGELOG }} diff --git a/pyproject.toml b/pyproject.toml index a22975f..1bcb51f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,11 +50,6 @@ dbus = [ "sdbus", ] -[project.scripts] -plusdeck = "plusdeck.cli:main" -plusdeckd = "plusdeck.dbus.service:main" -plusdeckctl = "plusdeck.dbus.client:main" - [dependency-groups] dev = [ "flake8", From 03481009daa683e87ddbffb9f9f7c2cb81879c43 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 11:52:00 -0800 Subject: [PATCH 03/24] Do not manually bundle gh release --- justfile | 16 ++-------------- scripts/bundle-gh-release.sh | 23 ----------------------- scripts/gh-release.sh | 3 +-- 3 files changed, 3 insertions(+), 39 deletions(-) delete mode 100755 scripts/bundle-gh-release.sh diff --git a/justfile b/justfile index 73d14ed..9583713 100644 --- a/justfile +++ b/justfile @@ -175,14 +175,6 @@ check-main-branch: tag: ./scripts/tag.sh -# Bundle the package for GitHub release -bundle-gh-release: - ./scripts/bundle-gh-release.sh "$(./scripts/version.py)-$(./scripts/release-version.py)" - -# Clean up the release package -clean-release: - rm -f "plusdeck-*-*.tar.gz" - # Push main and tags push: git push origin main --follow-tags @@ -216,12 +208,8 @@ publish: # Tag and push @just tag @just push - # Build package and bundle release + # Build package and cut github release if [[ "$(./scripts/release-version.py)" == '1' ]]; then just clean-build; fi - @just clean-release - if [[ "$(./scripts/release-version.py)" == '1' ]]; then just build; fi - @just bundle-gh-release - # Publish package and release @just gh-release if [[ "$(./scripts/release-version.py)" == '1' ]]; then just publish-pypi; fi # Update packages on COPR @@ -231,7 +219,7 @@ publish: @just build-copr plusdeck # Clean up loose files -clean: clean-venv clean-compile clean-test clean-build clean-release +clean: clean-venv clean-compile clean-test clean-build rm -rf plusdeck.egg-info rm -f plusdeck/*.pyc rm -rf plusdeck/__pycache__ diff --git a/scripts/bundle-gh-release.sh b/scripts/bundle-gh-release.sh deleted file mode 100755 index 45f5654..0000000 --- a/scripts/bundle-gh-release.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -FULL_VERSION="${1}" - -tar -czf "plusdeck-${FULL_VERSION}.tar.gz" \ - CHANGELOG.md \ - LICENSE \ - Player.ipynb \ - README.md \ - docs \ - plusdeck \ - plusdeck.spec \ - pyproject.toml \ - pytest.ini \ - requirements.txt \ - requirements_dev.txt \ - setup.cfg \ - systemd \ - tests \ - typings \ - uv.lock diff --git a/scripts/gh-release.sh b/scripts/gh-release.sh index 990ae8f..97cd233 100755 --- a/scripts/gh-release.sh +++ b/scripts/gh-release.sh @@ -8,5 +8,4 @@ NOTES="$(./scripts/changelog-entry.py "${FULL_VERSION}")" gh release create "plusdeck-${FULL_VERSION}" \ -t "plusdeck v${FULL_VERSION}" \ - -n "${NOTES}" \ - "plusdeck-${FULL_VERSION}.tar.gz" + -n "${NOTES}" From 8e7d8bd70aa4d239d6b83ff6f4d296ddff6367ff Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 11:55:48 -0800 Subject: [PATCH 04/24] Fix QA --- .github/workflows/qa.yaml | 2 +- justfile | 2 +- plusdeck/cli.py | 8 +++++++- plusdeck/dbus/client.py | 6 +++++- plusdeck/dbus/error.py | 4 +++- scripts/version.py | 2 +- tests/__init__.py | 0 tests/conftest.py | 5 +++-- tests/helpers.py | 6 ------ 9 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 tests/__init__.py diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 49d6973..e60b5d0 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -31,4 +31,4 @@ jobs: npx pyright@latest - name: Run tests run: | - pytest ./tests --ignore=tests/test_integration.py + pytest ./tests --ignore-glob='./tests/integration/**' diff --git a/justfile b/justfile index 9583713..b02a717 100644 --- a/justfile +++ b/justfile @@ -81,7 +81,7 @@ check: # Run tests with pytest test *argv: uv run pytest {{ argv }} ./tests --ignore-glob='./tests/integration/**' - @just _clean-test + @just clean-test # Update snapshots snap: diff --git a/plusdeck/cli.py b/plusdeck/cli.py index 011174c..ff9f4cc 100644 --- a/plusdeck/cli.py +++ b/plusdeck/cli.py @@ -177,7 +177,13 @@ def wrapped(obj: Obj, *args, **kwargs) -> R: help=f"Load the global config file at {GLOBAL_FILE} " "(default true when called with sudo)", ) -@click.option("--config-file", "-C", envvar="PLUSDECK_CONFIG_FILE", type=click.Path(), help="A path to a config file") +@click.option( + "--config-file", + "-C", + envvar="PLUSDECK_CONFIG_FILE", + type=click.Path(), + help="A path to a config file", +) @click.option( "--log-level", envvar="PLUSDECK_LOG_LEVEL", diff --git a/plusdeck/dbus/client.py b/plusdeck/dbus/client.py index 8ef5d36..8a75dae 100644 --- a/plusdeck/dbus/client.py +++ b/plusdeck/dbus/client.py @@ -12,7 +12,11 @@ from unittest.mock import Mock import click -from sdbus import sd_bus_open_system, sd_bus_open_user, SdBus +from sdbus import ( #pyright: ignore [reportMissingModuleSource] + sd_bus_open_system, + sd_bus_open_user, + SdBus, +) from plusdeck.cli import async_command, AsyncCommand, echo, LogLevel, OutputMode, STATE from plusdeck.client import State diff --git a/plusdeck/dbus/error.py b/plusdeck/dbus/error.py index ce71bad..61be50b 100644 --- a/plusdeck/dbus/error.py +++ b/plusdeck/dbus/error.py @@ -5,7 +5,9 @@ from traceback import format_exc from typing import Any, AsyncGenerator, cast, List, Optional -from sdbus.sd_bus_internals import SdBusLibraryError +from sdbus.sd_bus_internals import ( #pyright: ignore [reportMissingModuleSource] + SdBusLibraryError, +) ERROR_NUMBER_RE = r"returned error number: (\d+)" diff --git a/scripts/version.py b/scripts/version.py index 2c57e6b..3751520 100755 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3 import tomllib diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py index c34fbab..cb18ea2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,14 +3,15 @@ import logging import os from pathlib import Path -from unittest.mock import Mock from typing import Dict, Generator, List, Optional +from unittest.mock import Mock import pytest +from tests.helpers import Cli, EnvFactory + from plusdeck.client import Client, State import plusdeck.config -from tests.helpers import Cli, EnvFactory logger = logging.getLogger(__name__) diff --git a/tests/helpers.py b/tests/helpers.py index f16fe4b..393b02d 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -5,8 +5,6 @@ import subprocess from typing import Dict, Generator, List, Optional, Protocol, Self -from crystalfontz.character import SpecialCharacter - class Cli: """ @@ -46,7 +44,3 @@ class EnvFactory(Protocol): def __call__( self: Self, env: Optional[Dict[str, str]] = None ) -> Dict[str, str]: ... - - -def special_character_as_rows(character: SpecialCharacter) -> List[str]: - return ["".join(["█" if p else " " for p in row]) for row in character.pixels] From c7cba515923d5f2ac99eeca744a70f3cd13ae204 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 12:00:51 -0800 Subject: [PATCH 05/24] REALLY basic dbus test --- tests/integration/test_dbus.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/integration/test_dbus.py diff --git a/tests/integration/test_dbus.py b/tests/integration/test_dbus.py new file mode 100644 index 0000000..5c25a65 --- /dev/null +++ b/tests/integration/test_dbus.py @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +import pytest + +from tests.helpers import Cli + + +def test_listen(dbus_cli, confirm) -> None: + with dbus_cli.bg("listen", quiet=False): + confirm("Mess with the Plusdeck. Are events showing up?") + + +def test_listen_for(dbus_cli: Cli) -> None: + dbus_cli("listen", "--for", "1.0") From 28b868f5e2e49075eab42448a01b9658ad3e8e3c Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 12:03:28 -0800 Subject: [PATCH 06/24] Actually fix QA --- plusdeck/dbus/client.py | 2 +- plusdeck/dbus/error.py | 2 +- tests/integration/test_dbus.py | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/plusdeck/dbus/client.py b/plusdeck/dbus/client.py index 8a75dae..9422624 100644 --- a/plusdeck/dbus/client.py +++ b/plusdeck/dbus/client.py @@ -12,7 +12,7 @@ from unittest.mock import Mock import click -from sdbus import ( #pyright: ignore [reportMissingModuleSource] +from sdbus import ( # pyright: ignore [reportMissingModuleSource] sd_bus_open_system, sd_bus_open_user, SdBus, diff --git a/plusdeck/dbus/error.py b/plusdeck/dbus/error.py index 61be50b..aecfb80 100644 --- a/plusdeck/dbus/error.py +++ b/plusdeck/dbus/error.py @@ -5,7 +5,7 @@ from traceback import format_exc from typing import Any, AsyncGenerator, cast, List, Optional -from sdbus.sd_bus_internals import ( #pyright: ignore [reportMissingModuleSource] +from sdbus.sd_bus_internals import ( # pyright: ignore [reportMissingModuleSource] SdBusLibraryError, ) diff --git a/tests/integration/test_dbus.py b/tests/integration/test_dbus.py index 5c25a65..fcd99a1 100644 --- a/tests/integration/test_dbus.py +++ b/tests/integration/test_dbus.py @@ -1,7 +1,5 @@ #!/usr/bin/env bash -import pytest - from tests.helpers import Cli From 6c48f6b67dbf03051f88de2cee9d01d96cfd53e0 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 12:29:14 -0800 Subject: [PATCH 07/24] Fix fixture --- tests/fixtures/{config.yaml => plusdeck.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/fixtures/{config.yaml => plusdeck.yaml} (100%) diff --git a/tests/fixtures/config.yaml b/tests/fixtures/plusdeck.yaml similarity index 100% rename from tests/fixtures/config.yaml rename to tests/fixtures/plusdeck.yaml From ac76d642643bf4bf5ac8c2cfcd9adb80ee256ca4 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 16:40:56 -0800 Subject: [PATCH 08/24] Update dependencies --- uv.lock | 584 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 306 insertions(+), 278 deletions(-) diff --git a/uv.lock b/uv.lock index f3eb6af..2794c5a 100644 --- a/uv.lock +++ b/uv.lock @@ -4,16 +4,16 @@ requires-python = ">=3.11" [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" 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/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 } 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/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 }, ] [[package]] @@ -91,46 +91,47 @@ wheels = [ [[package]] name = "async-lru" -version = "2.0.4" +version = "2.0.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/80/e2/2b4651eff771f6fd900d233e175ddc5e2be502c7eb62c0c42f975c6d36cd/async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627", size = 10019 } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/9f/3c3503693386c4b0f245eaf5ca6198e3b28879ca0a40bde6b0e319793453/async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224", size = 6111 }, + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069 }, ] [[package]] name = "attrs" -version = "25.1.0" +version = "25.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815 }, ] [[package]] name = "babel" -version = "2.16.0" +version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, ] [[package]] name = "beautifulsoup4" -version = "4.12.3" +version = "4.13.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/824b1195773ce6166d388573fc106ce56d4a805bd7427b624e063596ec58/beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", size = 581181 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/3c/adaf39ce1fb4afdd21b611e3d530b183bb7759c9b673d60db0e347fd4439/beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", size = 619516 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 }, + { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015 }, ] [[package]] name = "black" -version = "24.10.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -139,21 +140,21 @@ dependencies = [ { name = "pathspec" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } +sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, - { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, - { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, - { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, - { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, - { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, - { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, - { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, - { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, - { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, - { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, - { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, - { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, + { url = "https://files.pythonhosted.org/packages/7e/4f/87f596aca05c3ce5b94b8663dbfe242a12843caaa82dd3f85f1ffdc3f177/black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0", size = 1614372 }, + { url = "https://files.pythonhosted.org/packages/e7/d0/2c34c36190b741c59c901e56ab7f6e54dad8df05a6272a9747ecef7c6036/black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299", size = 1442865 }, + { url = "https://files.pythonhosted.org/packages/21/d4/7518c72262468430ead45cf22bd86c883a6448b9eb43672765d69a8f1248/black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096", size = 1749699 }, + { url = "https://files.pythonhosted.org/packages/58/db/4f5beb989b547f79096e035c4981ceb36ac2b552d0ac5f2620e941501c99/black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2", size = 1428028 }, + { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988 }, + { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985 }, + { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816 }, + { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860 }, + { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673 }, + { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190 }, + { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926 }, + { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613 }, + { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, ] [[package]] @@ -184,11 +185,11 @@ wheels = [ [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.1.31" 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/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } 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/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, ] [[package]] @@ -319,45 +320,46 @@ wheels = [ [[package]] name = "configurence" -version = "2.0.1" +version = "2.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appdirs" }, { name = "click" }, + { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/1b/d7291a15d8d66bfc7fdc2b4b0b95881b7c00b24b42026f2c1a31658ee322/configurence-2.0.1.tar.gz", hash = "sha256:4ff16e305b8e5f4f02fe99652909ed20e671e56468188d80477b450e49f16038", size = 46755 } +sdist = { url = "https://files.pythonhosted.org/packages/03/4c/99f5b39db827ef3bcbb77fe3fe636d6b9955d2997ef0986e835f0cd2229e/configurence-2.0.3.tar.gz", hash = "sha256:a40a8564bdeb2c905d7c1283b0974aae4c2378852033b66cbbae1facb0b4f065", size = 46872 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/ca/858b955b6572eeeff657d1d1ec1a0d32db3a16730130fc4541b639802b6b/configurence-2.0.1-py3-none-any.whl", hash = "sha256:7b84d5d7955ffd3c2f3d4de196550c758c20b6ee65c57d7c8d3999bacdb85dfd", size = 5018 }, + { url = "https://files.pythonhosted.org/packages/e3/b8/70aa8be08c721050f6e266c509064c67ded81a340b8d5e1c3082874b6315/configurence-2.0.3-py3-none-any.whl", hash = "sha256:df4d8f14f523c4e67bb8c77a08dcf43f9787c8f8a193715613515b32af795605", size = 5056 }, ] [[package]] name = "debugpy" -version = "1.8.12" +version = "1.8.13" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/25/c74e337134edf55c4dfc9af579eccb45af2393c40960e2795a94351e8140/debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce", size = 1641122 } +sdist = { url = "https://files.pythonhosted.org/packages/51/d4/f35f539e11c9344652f362c22413ec5078f677ac71229dc9b4f6f85ccaa3/debugpy-1.8.13.tar.gz", hash = "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce", size = 1641193 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/9f/5b8af282253615296264d4ef62d14a8686f0dcdebb31a669374e22fff0a4/debugpy-1.8.12-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:36f4829839ef0afdfdd208bb54f4c3d0eea86106d719811681a8627ae2e53dd5", size = 2174643 }, - { url = "https://files.pythonhosted.org/packages/ef/31/f9274dcd3b0f9f7d1e60373c3fa4696a585c55acb30729d313bb9d3bcbd1/debugpy-1.8.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a28ed481d530e3138553be60991d2d61103ce6da254e51547b79549675f539b7", size = 3133457 }, - { url = "https://files.pythonhosted.org/packages/ab/ca/6ee59e9892e424477e0c76e3798046f1fd1288040b927319c7a7b0baa484/debugpy-1.8.12-cp311-cp311-win32.whl", hash = "sha256:4ad9a94d8f5c9b954e0e3b137cc64ef3f579d0df3c3698fe9c3734ee397e4abb", size = 5106220 }, - { url = "https://files.pythonhosted.org/packages/d5/1a/8ab508ab05ede8a4eae3b139bbc06ea3ca6234f9e8c02713a044f253be5e/debugpy-1.8.12-cp311-cp311-win_amd64.whl", hash = "sha256:4703575b78dd697b294f8c65588dc86874ed787b7348c65da70cfc885efdf1e1", size = 5130481 }, - { url = "https://files.pythonhosted.org/packages/ba/e6/0f876ecfe5831ebe4762b19214364753c8bc2b357d28c5d739a1e88325c7/debugpy-1.8.12-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:7e94b643b19e8feb5215fa508aee531387494bf668b2eca27fa769ea11d9f498", size = 2500846 }, - { url = "https://files.pythonhosted.org/packages/19/64/33f41653a701f3cd2cbff8b41ebaad59885b3428b5afd0d93d16012ecf17/debugpy-1.8.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:086b32e233e89a2740c1615c2f775c34ae951508b28b308681dbbb87bba97d06", size = 4222181 }, - { url = "https://files.pythonhosted.org/packages/32/a6/02646cfe50bfacc9b71321c47dc19a46e35f4e0aceea227b6d205e900e34/debugpy-1.8.12-cp312-cp312-win32.whl", hash = "sha256:2ae5df899732a6051b49ea2632a9ea67f929604fd2b036613a9f12bc3163b92d", size = 5227017 }, - { url = "https://files.pythonhosted.org/packages/da/a6/10056431b5c47103474312cf4a2ec1001f73e0b63b1216706d5fef2531eb/debugpy-1.8.12-cp312-cp312-win_amd64.whl", hash = "sha256:39dfbb6fa09f12fae32639e3286112fc35ae976114f1f3d37375f3130a820969", size = 5267555 }, - { url = "https://files.pythonhosted.org/packages/cf/4d/7c3896619a8791effd5d8c31f0834471fc8f8fb3047ec4f5fc69dd1393dd/debugpy-1.8.12-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:696d8ae4dff4cbd06bf6b10d671e088b66669f110c7c4e18a44c43cf75ce966f", size = 2485246 }, - { url = "https://files.pythonhosted.org/packages/99/46/bc6dcfd7eb8cc969a5716d858e32485eb40c72c6a8dc88d1e3a4d5e95813/debugpy-1.8.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:898fba72b81a654e74412a67c7e0a81e89723cfe2a3ea6fcd3feaa3395138ca9", size = 4218616 }, - { url = "https://files.pythonhosted.org/packages/03/dd/d7fcdf0381a9b8094da1f6a1c9f19fed493a4f8576a2682349b3a8b20ec7/debugpy-1.8.12-cp313-cp313-win32.whl", hash = "sha256:22a11c493c70413a01ed03f01c3c3a2fc4478fc6ee186e340487b2edcd6f4180", size = 5226540 }, - { url = "https://files.pythonhosted.org/packages/25/bd/ecb98f5b5fc7ea0bfbb3c355bc1dd57c198a28780beadd1e19915bf7b4d9/debugpy-1.8.12-cp313-cp313-win_amd64.whl", hash = "sha256:fdb3c6d342825ea10b90e43d7f20f01535a72b3a1997850c0c3cefa5c27a4a2c", size = 5267134 }, - { url = "https://files.pythonhosted.org/packages/38/c4/5120ad36405c3008f451f94b8f92ef1805b1e516f6ff870f331ccb3c4cc0/debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6", size = 5229490 }, + { url = "https://files.pythonhosted.org/packages/31/90/dd2fcad8364f0964f476537481985198ce6e879760281ad1cec289f1aa71/debugpy-1.8.13-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:eee02b2ed52a563126c97bf04194af48f2fe1f68bb522a312b05935798e922ff", size = 2174802 }, + { url = "https://files.pythonhosted.org/packages/5c/c9/06ff65f15eb30dbdafd45d1575770b842ce3869ad5580a77f4e5590f1be7/debugpy-1.8.13-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4caca674206e97c85c034c1efab4483f33971d4e02e73081265ecb612af65377", size = 3133620 }, + { url = "https://files.pythonhosted.org/packages/3b/49/798a4092bde16a4650f17ac5f2301d4d37e1972d65462fb25c80a83b4790/debugpy-1.8.13-cp311-cp311-win32.whl", hash = "sha256:7d9a05efc6973b5aaf076d779cf3a6bbb1199e059a17738a2aa9d27a53bcc888", size = 5104764 }, + { url = "https://files.pythonhosted.org/packages/cd/d5/3684d7561c8ba2797305cf8259619acccb8d6ebe2117bb33a6897c235eee/debugpy-1.8.13-cp311-cp311-win_amd64.whl", hash = "sha256:62f9b4a861c256f37e163ada8cf5a81f4c8d5148fc17ee31fb46813bd658cdcc", size = 5129670 }, + { url = "https://files.pythonhosted.org/packages/79/ad/dff929b6b5403feaab0af0e5bb460fd723f9c62538b718a9af819b8fff20/debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1", size = 2501004 }, + { url = "https://files.pythonhosted.org/packages/d6/4f/b7d42e6679f0bb525888c278b0c0d2b6dff26ed42795230bb46eaae4f9b3/debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522", size = 4222346 }, + { url = "https://files.pythonhosted.org/packages/ec/18/d9b3e88e85d41f68f77235112adc31012a784e45a3fcdbb039777d570a0f/debugpy-1.8.13-cp312-cp312-win32.whl", hash = "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f", size = 5226639 }, + { url = "https://files.pythonhosted.org/packages/c9/f7/0df18a4f530ed3cc06f0060f548efe9e3316102101e311739d906f5650be/debugpy-1.8.13-cp312-cp312-win_amd64.whl", hash = "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea", size = 5268735 }, + { url = "https://files.pythonhosted.org/packages/b1/db/ae7cd645c1826aae557cebccbc448f0cc9a818d364efb88f8d80e7a03f41/debugpy-1.8.13-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503", size = 2485416 }, + { url = "https://files.pythonhosted.org/packages/ec/ed/db4b10ff3b5bb30fe41d9e86444a08bb6448e4d8265e7768450b8408dd36/debugpy-1.8.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb", size = 4218784 }, + { url = "https://files.pythonhosted.org/packages/82/82/ed81852a8d94086f51664d032d83c7f87cd2b087c6ea70dabec7c1ba813d/debugpy-1.8.13-cp313-cp313-win32.whl", hash = "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02", size = 5226270 }, + { url = "https://files.pythonhosted.org/packages/15/63/aa92fb341a78ec40f1c414ec7a7885c2ee17032eee00d12cee0cdc502af4/debugpy-1.8.13-cp313-cp313-win_amd64.whl", hash = "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8", size = 5268621 }, + { url = "https://files.pythonhosted.org/packages/37/4f/0b65410a08b6452bfd3f7ed6f3610f1a31fb127f46836e82d31797065dcb/debugpy-1.8.13-py2.py3-none-any.whl", hash = "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f", size = 5229306 }, ] [[package]] name = "decorator" -version = "5.1.1" +version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, ] [[package]] @@ -389,16 +391,16 @@ wheels = [ [[package]] name = "flake8" -version = "7.1.1" +version = "7.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mccabe" }, { name = "pycodestyle" }, { name = "pyflakes" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/72/e8d66150c4fcace3c0a450466aa3480506ba2cae7b61e100a2613afc3907/flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38", size = 48054 } +sdist = { url = "https://files.pythonhosted.org/packages/e7/c4/5842fc9fc94584c455543540af62fd9900faade32511fab650e9891ec225/flake8-7.2.0.tar.gz", hash = "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426", size = 48177 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/42/65004373ac4617464f35ed15931b30d764f53cdd30cc78d5aea349c8c050/flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213", size = 57731 }, + { url = "https://files.pythonhosted.org/packages/83/5c/0627be4c9976d56b1217cb5187b7504e7fd7d3503f8bfd312a04077bd4f7/flake8-7.2.0-py2.py3-none-any.whl", hash = "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343", size = 57786 }, ] [[package]] @@ -437,14 +439,14 @@ wheels = [ [[package]] name = "griffe" -version = "1.5.5" +version = "1.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/74/cd35a98cb11f79de0581e8e1e6fbd738aeeed1f2d90e9b5106728b63f5f7/griffe-1.5.5.tar.gz", hash = "sha256:35ee5b38b93d6a839098aad0f92207e6ad6b70c3e8866c08ca669275b8cba585", size = 391124 } +sdist = { url = "https://files.pythonhosted.org/packages/59/08/7df7e90e34d08ad890bd71d7ba19451052f88dc3d2c483d228d1331a4736/griffe-1.7.2.tar.gz", hash = "sha256:98d396d803fab3b680c2608f300872fd57019ed82f0672f5b5323a9ad18c540c", size = 394919 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/88/52c9422bc853cd7c2b6122090e887d17b5fad29b67f930e4277c9c557357/griffe-1.5.5-py3-none-any.whl", hash = "sha256:2761b1e8876c6f1f9ab1af274df93ea6bbadd65090de5f38f4cb5cc84897c7dd", size = 128221 }, + { url = "https://files.pythonhosted.org/packages/b1/5e/38b408f41064c9fcdbb0ea27c1bd13a1c8657c4846e04dab9f5ea770602c/griffe-1.7.2-py3-none-any.whl", hash = "sha256:1ed9c2e338a75741fc82083fe5a1bc89cb6142efe126194cc313e34ee6af5423", size = 129187 }, ] [[package]] @@ -495,11 +497,11 @@ wheels = [ [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, ] [[package]] @@ -528,11 +530,12 @@ wheels = [ [[package]] name = "ipython" -version = "8.31.0" +version = "9.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "decorator" }, + { name = "ipython-pygments-lexers" }, { name = "jedi" }, { name = "matplotlib-inline" }, { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, @@ -542,9 +545,21 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/35/6f90fdddff7a08b7b715fccbd2427b5212c9525cd043d26fdc45bee0708d/ipython-8.31.0.tar.gz", hash = "sha256:b6a2274606bec6166405ff05e54932ed6e5cfecaca1fc05f2cacde7bb074d70b", size = 5501011 } +sdist = { url = "https://files.pythonhosted.org/packages/70/9a/6b8984bedc990f3a4aa40ba8436dea27e23d26a64527de7c2e5e12e76841/ipython-9.1.0.tar.gz", hash = "sha256:a47e13a5e05e02f3b8e1e7a0f9db372199fe8c3763532fe7a1e0379e4e135f16", size = 4373688 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/9d/4ff2adf55d1b6e3777b0303fdbe5b723f76e46cba4a53a32fe82260d2077/ipython-9.1.0-py3-none-any.whl", hash = "sha256:2df07257ec2f84a6b346b8d83100bcf8fa501c6e01ab75cd3799b0bb253b3d2a", size = 604053 }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/60/d0feb6b6d9fe4ab89fe8fe5b47cbf6cd936bfd9f1e7ffa9d0015425aeed6/ipython-8.31.0-py3-none-any.whl", hash = "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6", size = 821583 }, + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074 }, ] [[package]] @@ -577,11 +592,11 @@ wheels = [ [[package]] name = "isort" -version = "5.13.2" +version = "6.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303 } +sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310 }, + { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186 }, ] [[package]] @@ -598,23 +613,23 @@ wheels = [ [[package]] name = "jinja2" -version = "3.1.5" +version = "3.1.6" 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/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } 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/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, ] [[package]] name = "json5" -version = "0.10.0" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/3d/bbe62f3d0c05a689c711cff57b2e3ac3d3e526380adb7c781989f075115c/json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559", size = 48202 } +sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907 } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/42/797895b952b682c3dafe23b1834507ee7f02f4d6299b65aaa61425763278/json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa", size = 34049 }, + { url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079 }, ] [[package]] @@ -697,10 +712,11 @@ wheels = [ [[package]] name = "jupyter-events" -version = "0.11.0" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "packaging" }, { name = "python-json-logger" }, { name = "pyyaml" }, { name = "referencing" }, @@ -708,9 +724,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/65/5791c8a979b5646ca29ea50e42b6708908b789f7ff389d1a03c1b93a1c54/jupyter_events-0.11.0.tar.gz", hash = "sha256:c0bc56a37aac29c1fbc3bcfbddb8c8c49533f9cf11f1c4e6adadba936574ab90", size = 62039 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/8c/9b65cb2cd4ea32d885993d5542244641590530836802a2e8c7449a4c61c9/jupyter_events-0.11.0-py3-none-any.whl", hash = "sha256:36399b41ce1ca45fe8b8271067d6a140ffa54cec4028e95491c93b78a855cacf", size = 19423 }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, ] [[package]] @@ -770,7 +786,7 @@ wheels = [ [[package]] name = "jupyterlab" -version = "4.3.4" +version = "4.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-lru" }, @@ -787,9 +803,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/45/1052f842e066902b1d78126df7e2269b1b9408991e1344e167b2e429f9e1/jupyterlab-4.3.4.tar.gz", hash = "sha256:f0bb9b09a04766e3423cccc2fc23169aa2ffedcdf8713e9e0fb33cac0b6859d0", size = 21797583 } +sdist = { url = "https://files.pythonhosted.org/packages/46/49/0beaab21155e5f7438032f3da920abbcf46159b28adafbdf596dd33c57a6/jupyterlab-4.4.0.tar.gz", hash = "sha256:f1767d5f0104e40f3b4a63bf6892bbef8e4704dcabf0c78408a3bdc411792f04", size = 22996521 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/48/af57263e53cfc220e522de047aa0993f53bab734fe812af1e03e33ac6d7c/jupyterlab-4.3.4-py3-none-any.whl", hash = "sha256:b754c2601c5be6adf87cb5a1d8495d653ffb945f021939f77776acaa94dae952", size = 11665373 }, + { url = "https://files.pythonhosted.org/packages/a2/64/1a559e1b945c3d424c1ac9f333bfd6f595d5819efde3a6d8b036e6b0585f/jupyterlab-4.4.0-py3-none-any.whl", hash = "sha256:61d33991fbb352cc7caac08bd0c34577fea86d8d5d9772600d9d5a6bcbc882c0", size = 12291918 }, ] [[package]] @@ -938,11 +954,11 @@ wheels = [ [[package]] name = "mistune" -version = "3.1.0" +version = "3.1.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/6e/96fc7cb3288666c5de2c396eb0e338dc95f7a8e4920e43e38783a22d0084/mistune-3.1.0.tar.gz", hash = "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667", size = 94401 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/79/bda47f7dd7c3c55770478d6d02c9960c430b0cf1773b72366ff89126ea31/mistune-3.1.3.tar.gz", hash = "sha256:a7035c21782b2becb6be62f8f25d3df81ccb4d6fa477a6525b15af06539f02a0", size = 94347 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/b3/743ffc3f59da380da504d84ccd1faf9a857a1445991ff19bf2ec754163c2/mistune-3.1.0-py3-none-any.whl", hash = "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1", size = 53694 }, + { url = "https://files.pythonhosted.org/packages/01/4d/23c4e4f09da849e127e9f123241946c23c1e30f45a88366879e064211815/mistune-3.1.3-py3-none-any.whl", hash = "sha256:1a32314113cff28aa6432e99e522677c8587fd83e3d51c29b82a52409c842bd9", size = 53410 }, ] [[package]] @@ -971,16 +987,16 @@ wheels = [ [[package]] name = "mkdocs-autorefs" -version = "1.3.0" +version = "1.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "markupsafe" }, { name = "mkdocs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/18/fb1e17fb705228b51bf7b2f791adaf83c0fa708e51bbc003411ba48ae21e/mkdocs_autorefs-1.3.0.tar.gz", hash = "sha256:6867764c099ace9025d6ac24fd07b85a98335fbd30107ef01053697c8f46db61", size = 42597 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/44/140469d87379c02f1e1870315f3143718036a983dd0416650827b8883192/mkdocs_autorefs-1.4.1.tar.gz", hash = "sha256:4b5b6235a4becb2b10425c2fa191737e415b37aa3418919db33e5d774c9db079", size = 4131355 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/4a/960c441950f98becfa5dd419adab20274939fd575ab848aee2c87e3599ac/mkdocs_autorefs-1.3.0-py3-none-any.whl", hash = "sha256:d180f9778a04e78b7134e31418f238bba56f56d6a8af97873946ff661befffb3", size = 17642 }, + { url = "https://files.pythonhosted.org/packages/f8/29/1125f7b11db63e8e32bcfa0752a4eea30abff3ebd0796f808e14571ddaa2/mkdocs_autorefs-1.4.1-py3-none-any.whl", hash = "sha256:9793c5ac06a6ebbe52ec0f8439256e66187badf4b5334b5fde0b128ec134df4f", size = 5782047 }, ] [[package]] @@ -999,34 +1015,32 @@ wheels = [ [[package]] name = "mkdocs-include-markdown-plugin" -version = "7.1.2" +version = "7.1.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mkdocs" }, { name = "wcmatch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/c6/863c7564872aaebc0d00f3f002adf5ef85f1f5549a44f94aec4c4624c630/mkdocs_include_markdown_plugin-7.1.2.tar.gz", hash = "sha256:1b393157b1aa231b0e6c59ba80f52b723f4b7827bb7a1264b505334f8542aaf1", size = 22213 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/34/ece85384e3ab29f05c2e12e50bde95449aa6dbb47b471923bba8fcf1596c/mkdocs_include_markdown_plugin-7.1.5.tar.gz", hash = "sha256:a986967594da6789226798e3c41c70bc17130fadb92b4313f42bd3defdac0adc", size = 23329 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/3c/41ffab81ef2f1c2186a0fa563680274ad03a651eddf02a1488f69a49524e/mkdocs_include_markdown_plugin-7.1.2-py3-none-any.whl", hash = "sha256:ff1175d1b4f83dea6a38e200d6f0c3db10308975bf60c197d31172671753dbc4", size = 25944 }, + { url = "https://files.pythonhosted.org/packages/ea/eb/472c1bbe93f26fe97647af0b613e9710916a2cf555b64fc969b91e24cf2c/mkdocs_include_markdown_plugin-7.1.5-py3-none-any.whl", hash = "sha256:d0b96edee45e7fda5eb189e63331cfaf1bf1fbdbebbd08371f1daa77045d3ae9", size = 27114 }, ] [[package]] name = "mkdocstrings" -version = "0.27.0" +version = "0.29.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, { name = "jinja2" }, { name = "markdown" }, { name = "markupsafe" }, { name = "mkdocs" }, { name = "mkdocs-autorefs" }, - { name = "platformdirs" }, { name = "pymdown-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e2/5a/5de70538c2cefae7ac3a15b5601e306ef3717290cb2aab11d51cbbc2d1c0/mkdocstrings-0.27.0.tar.gz", hash = "sha256:16adca6d6b0a1f9e0c07ff0b02ced8e16f228a9d65a37c063ec4c14d7b76a657", size = 94830 } +sdist = { url = "https://files.pythonhosted.org/packages/41/e8/d22922664a627a0d3d7ff4a6ca95800f5dde54f411982591b4621a76225d/mkdocstrings-0.29.1.tar.gz", hash = "sha256:8722f8f8c5cd75da56671e0a0c1bbed1df9946c0cef74794d6141b34011abd42", size = 1212686 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/10/4c27c3063c2b3681a4b7942f8dbdeb4fa34fecb2c19b594e7345ebf4f86f/mkdocstrings-0.27.0-py3-none-any.whl", hash = "sha256:6ceaa7ea830770959b55a16203ac63da24badd71325b96af950e59fd37366332", size = 30658 }, + { url = "https://files.pythonhosted.org/packages/98/14/22533a578bf8b187e05d67e2c1721ce10e3f526610eebaf7a149d557ea7a/mkdocstrings-0.29.1-py3-none-any.whl", hash = "sha256:37a9736134934eea89cbd055a513d40a020d87dfcae9e3052c2a6b8cd4af09b6", size = 1631075 }, ] [package.optional-dependencies] @@ -1036,16 +1050,16 @@ python = [ [[package]] name = "mkdocstrings-python" -version = "1.13.0" +version = "1.16.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "griffe" }, { name = "mkdocs-autorefs" }, { name = "mkdocstrings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/ae/32703e35d74040051c672400fd9f5f2b48a6ea094f5071dd8a0e3be35322/mkdocstrings_python-1.13.0.tar.gz", hash = "sha256:2dbd5757e8375b9720e81db16f52f1856bf59905428fd7ef88005d1370e2f64c", size = 185697 } +sdist = { url = "https://files.pythonhosted.org/packages/44/c8/600c4201b6b9e72bab16802316d0c90ce04089f8e6bb5e064cd2a5abba7e/mkdocstrings_python-1.16.10.tar.gz", hash = "sha256:f9eedfd98effb612ab4d0ed6dd2b73aff6eba5215e0a65cea6d877717f75502e", size = 205771 } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/23/d02d86553327296c3bf369d444194ea83410cce8f0e690565264f37f3261/mkdocstrings_python-1.13.0-py3-none-any.whl", hash = "sha256:b88bbb207bab4086434743849f8e796788b373bd32e7bfefbf8560ac45d88f97", size = 112254 }, + { url = "https://files.pythonhosted.org/packages/53/37/19549c5e0179785308cc988a68e16aa7550e4e270ec8a9878334e86070c6/mkdocstrings_python-1.16.10-py3-none-any.whl", hash = "sha256:63bb9f01f8848a644bdb6289e86dc38ceddeaa63ecc2e291e3b2ca52702a6643", size = 124112 }, ] [[package]] @@ -1074,7 +1088,7 @@ wheels = [ [[package]] name = "nbconvert" -version = "7.16.5" +version = "7.16.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -1092,9 +1106,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/2c/d026c0367f2be2463d4c2f5b538e28add2bc67bc13730abb7f364ae4eb8b/nbconvert-7.16.5.tar.gz", hash = "sha256:c83467bb5777fdfaac5ebbb8e864f300b277f68692ecc04d6dab72f2d8442344", size = 856367 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/9e/2dcc9fe00cf55d95a8deae69384e9cea61816126e345754f6c75494d32ec/nbconvert-7.16.5-py3-none-any.whl", hash = "sha256:e12eac052d6fd03040af4166c563d76e7aeead2e9aadf5356db552a1784bd547", size = 258061 }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525 }, ] [[package]] @@ -1192,11 +1206,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.3.6" +version = "4.3.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +sdist = { url = "https://files.pythonhosted.org/packages/b6/2d/7d512a3913d60623e7eb945c6d1b4f0bddf1d0b7ada5225274c87e5b53d1/platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351", size = 21291 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, + { url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", size = 18499 }, ] [[package]] @@ -1297,17 +1311,17 @@ wheels = [ [[package]] name = "psutil" -version = "6.1.1" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/5a/07871137bb752428aa4b659f910b399ba6f291156bdea939be3e96cae7cb/psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5", size = 508502 } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/99/ca79d302be46f7bdd8321089762dd4476ee725fce16fc2b2e1dbba8cac17/psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8", size = 247511 }, - { url = "https://files.pythonhosted.org/packages/0b/6b/73dbde0dd38f3782905d4587049b9be64d76671042fdcaf60e2430c6796d/psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377", size = 248985 }, - { url = "https://files.pythonhosted.org/packages/17/38/c319d31a1d3f88c5b79c68b3116c129e5133f1822157dd6da34043e32ed6/psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003", size = 284488 }, - { url = "https://files.pythonhosted.org/packages/9c/39/0f88a830a1c8a3aba27fededc642da37613c57cbff143412e3536f89784f/psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160", size = 287477 }, - { url = "https://files.pythonhosted.org/packages/47/da/99f4345d4ddf2845cb5b5bd0d93d554e84542d116934fde07a0c50bd4e9f/psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3", size = 289017 }, - { url = "https://files.pythonhosted.org/packages/38/53/bd755c2896f4461fd4f36fa6a6dcb66a88a9e4b9fd4e5b66a77cf9d4a584/psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53", size = 250602 }, - { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444 }, + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051 }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535 }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004 }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986 }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544 }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053 }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 }, ] [[package]] @@ -1330,11 +1344,11 @@ wheels = [ [[package]] name = "pycodestyle" -version = "2.12.1" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232 } +sdist = { url = "https://files.pythonhosted.org/packages/04/6e/1f4a62078e4d95d82367f24e685aef3a672abfd27d1a868068fed4ed2254/pycodestyle-2.13.0.tar.gz", hash = "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae", size = 39312 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284 }, + { url = "https://files.pythonhosted.org/packages/07/be/b00116df1bfb3e0bb5b45e29d604799f7b91dd861637e4d448b4e09e6a3e/pycodestyle-2.13.0-py2.py3-none-any.whl", hash = "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9", size = 31424 }, ] [[package]] @@ -1348,23 +1362,23 @@ wheels = [ [[package]] name = "pyee" -version = "12.1.1" +version = "13.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/37/8fb6e653597b2b67ef552ed49b438d5398ba3b85a9453f8ada0fd77d455c/pyee-12.1.1.tar.gz", hash = "sha256:bbc33c09e2ff827f74191e3e5bbc6be7da02f627b7ec30d86f5ce1a6fb2424a3", size = 30915 } +sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/68/7e150cba9eeffdeb3c5cecdb6896d70c8edd46ce41c0491e12fb2b2256ff/pyee-12.1.1-py3-none-any.whl", hash = "sha256:18a19c650556bb6b32b406d7f017c8f513aceed1ef7ca618fb65de7bd2d347ef", size = 15527 }, + { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730 }, ] [[package]] name = "pyflakes" -version = "3.2.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } +sdist = { url = "https://files.pythonhosted.org/packages/af/cc/1df338bd7ed1fa7c317081dcf29bf2f01266603b301e6858856d346a12b3/pyflakes-3.3.2.tar.gz", hash = "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b", size = 64175 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, + { url = "https://files.pythonhosted.org/packages/15/40/b293a4fa769f3b02ab9e387c707c4cbdc34f073f945de0386107d4e669e6/pyflakes-3.3.2-py2.py3-none-any.whl", hash = "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a", size = 63164 }, ] [[package]] @@ -1378,15 +1392,15 @@ wheels = [ [[package]] name = "pymdown-extensions" -version = "10.14.1" +version = "10.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/24/f7a412dc1630b1a6d7b288e7c736215ce878ee4aad24359f7f67b53bbaa9/pymdown_extensions-10.14.1.tar.gz", hash = "sha256:b65801996a0cd4f42a3110810c306c45b7313c09b0610a6f773730f2a9e3c96b", size = 845243 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/44/e6de2fdc880ad0ec7547ca2e087212be815efbc9a425a8d5ba9ede602cbb/pymdown_extensions-10.14.3.tar.gz", hash = "sha256:41e576ce3f5d650be59e900e4ceff231e0aed2a88cf30acaee41e02f063a061b", size = 846846 } wheels = [ - { url = "https://files.pythonhosted.org/packages/09/fb/79a8d27966e90feeeb686395c8b1bff8221727abcbd80d2485841393a955/pymdown_extensions-10.14.1-py3-none-any.whl", hash = "sha256:637951cbfbe9874ba28134fb3ce4b8bcadd6aca89ac4998ec29dcbafd554ae08", size = 264283 }, + { url = "https://files.pythonhosted.org/packages/eb/f5/b9e2a42aa8f9e34d52d66de87941ecd236570c7ed2e87775ed23bbe4e224/pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9", size = 264467 }, ] [[package]] @@ -1412,7 +1426,7 @@ wheels = [ [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1420,34 +1434,34 @@ 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/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } 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/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, ] [[package]] name = "pytest-asyncio" -version = "0.25.2" +version = "0.26.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/8e/c4/453c52c659521066969523e87d85d54139bbd17b78f09532fb8eb8cdb58e/pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f", size = 54156 } 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/20/7f/338843f449ace853647ace35870874f69a764d251872ed1b4de9f234822c/pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0", size = 19694 }, ] [[package]] name = "pytest-gak" -version = "1.0.0" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/af/c3/99ccd212a60f57a7da415ede9271c3d23dcd1d65c15d73f70c7a80c1e72d/pytest_gak-1.0.0.tar.gz", hash = "sha256:09f723bcf03ea0fe3c58aa4847ce18aa2b8ff7b678512d17756fc3ae5583c6ca", size = 43504 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/61/8c5b44e0aeae196160fc4e337367eb05fa16fef5cc6259ed595127aac527/pytest_gak-2.0.0.tar.gz", hash = "sha256:1e6aef3f1aa007ed50a5fb974d8745ffd99d5f6c0408414e2237d264080690a4", size = 31015 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c9/7e68e2525bbf288f0064647146ad98d20cec5cf653d51ef01463773a6062/pytest_gak-1.0.0-py3-none-any.whl", hash = "sha256:e3e5528b06e0b0f40a1a64a1a3994680bb15de988638cca4d1f6325cd579e9ad", size = 4581 }, + { url = "https://files.pythonhosted.org/packages/95/f8/fe70112fded135a43360f896192b850d12f4eb76e23c5152a6f579d2bc0e/pytest_gak-2.0.0-py3-none-any.whl", hash = "sha256:a59a19d2a5bd1b4d24438358a30c9f08b14a6fe07543980ae87d5fb10cbe0a96", size = 4751 }, ] [[package]] @@ -1464,38 +1478,39 @@ wheels = [ [[package]] name = "python-json-logger" -version = "3.2.1" +version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/c4/358cd13daa1d912ef795010897a483ab2f0b41c9ea1b35235a8b2f7d15a7/python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008", size = 16287 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090", size = 14924 }, + { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163 }, ] [[package]] name = "pywin32" -version = "308" +version = "310" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, - { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, - { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, - { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, - { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, - { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, - { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, - { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, - { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, + { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284 }, + { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748 }, + { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941 }, + { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239 }, + { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839 }, + { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470 }, + { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384 }, + { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039 }, + { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152 }, ] [[package]] name = "pywinpty" -version = "2.0.14" +version = "2.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/82/90f8750423cba4b9b6c842df227609fb60704482d7abf6dd47e2babc055a/pywinpty-2.0.14.tar.gz", hash = "sha256:18bd9529e4a5daf2d9719aa17788ba6013e594ae94c5a0c27e83df3278b0660e", size = 27769 } +sdist = { url = "https://files.pythonhosted.org/packages/2d/7c/917f9c4681bb8d34bfbe0b79d36bbcd902651aeab48790df3d30ba0202fb/pywinpty-2.0.15.tar.gz", hash = "sha256:312cf39153a8736c617d45ce8b6ad6cd2107de121df91c455b10ce6bba7a39b2", size = 29017 } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/e2/af1a99c0432e4e58c9ac8e334ee191790ec9793d33559189b9d2069bdc1d/pywinpty-2.0.14-cp311-none-win_amd64.whl", hash = "sha256:cf2a43ac7065b3e0dc8510f8c1f13a75fb8fde805efa3b8cff7599a1ef497bc7", size = 1397223 }, - { url = "https://files.pythonhosted.org/packages/ad/79/759ae767a3b78d340446efd54dd1fe4f7dafa4fc7be96ed757e44bcdba54/pywinpty-2.0.14-cp312-none-win_amd64.whl", hash = "sha256:55dad362ef3e9408ade68fd173e4f9032b3ce08f68cfe7eacb2c263ea1179737", size = 1397207 }, - { url = "https://files.pythonhosted.org/packages/7d/34/b77b3c209bf2eaa6455390c8d5449241637f5957f41636a2204065d52bfa/pywinpty-2.0.14-cp313-none-win_amd64.whl", hash = "sha256:074fb988a56ec79ca90ed03a896d40707131897cefb8f76f926e3834227f2819", size = 1396698 }, + { url = "https://files.pythonhosted.org/packages/5e/ac/6884dcb7108af66ad53f73ef4dad096e768c9203a6e6ce5e6b0c4a46e238/pywinpty-2.0.15-cp311-cp311-win_amd64.whl", hash = "sha256:9a6bcec2df2707aaa9d08b86071970ee32c5026e10bcc3cc5f6f391d85baf7ca", size = 1405249 }, + { url = "https://files.pythonhosted.org/packages/88/e5/9714def18c3a411809771a3fbcec70bffa764b9675afb00048a620fca604/pywinpty-2.0.15-cp312-cp312-win_amd64.whl", hash = "sha256:83a8f20b430bbc5d8957249f875341a60219a4e971580f2ba694fbfb54a45ebc", size = 1405243 }, + { url = "https://files.pythonhosted.org/packages/fb/16/2ab7b3b7f55f3c6929e5f629e1a68362981e4e5fed592a2ed1cb4b4914a5/pywinpty-2.0.15-cp313-cp313-win_amd64.whl", hash = "sha256:ab5920877dd632c124b4ed17bc6dd6ef3b9f86cd492b963ffdb1a67b85b0f408", size = 1405020 }, + { url = "https://files.pythonhosted.org/packages/7c/16/edef3515dd2030db2795dbfbe392232c7a0f3dc41b98e92b38b42ba497c7/pywinpty-2.0.15-cp313-cp313t-win_amd64.whl", hash = "sha256:a4560ad8c01e537708d2790dbe7da7d986791de805d89dd0d3697ca59e9e4901", size = 1404151 }, ] [[package]] @@ -1547,58 +1562,59 @@ wheels = [ [[package]] name = "pyzmq" -version = "26.2.0" +version = "26.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/05/bed626b9f7bb2322cdbbf7b4bd8f54b1b617b0d2ab2d3547d6e39428a48e/pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", size = 271975 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/20/de7442172f77f7c96299a0ac70e7d4fb78cd51eca67aa2cf552b66c14196/pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218", size = 1340639 }, - { url = "https://files.pythonhosted.org/packages/98/4d/5000468bd64c7910190ed0a6c76a1ca59a68189ec1f007c451dc181a22f4/pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4", size = 1008710 }, - { url = "https://files.pythonhosted.org/packages/e1/bf/c67fd638c2f9fbbab8090a3ee779370b97c82b84cc12d0c498b285d7b2c0/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef", size = 673129 }, - { url = "https://files.pythonhosted.org/packages/86/94/99085a3f492aa538161cbf27246e8886ff850e113e0c294a5b8245f13b52/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317", size = 910107 }, - { url = "https://files.pythonhosted.org/packages/31/1d/346809e8a9b999646d03f21096428453465b1bca5cd5c64ecd048d9ecb01/pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf", size = 867960 }, - { url = "https://files.pythonhosted.org/packages/ab/68/6fb6ae5551846ad5beca295b7bca32bf0a7ce19f135cb30e55fa2314e6b6/pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e", size = 869204 }, - { url = "https://files.pythonhosted.org/packages/0f/f9/18417771dee223ccf0f48e29adf8b4e25ba6d0e8285e33bcbce078070bc3/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37", size = 1203351 }, - { url = "https://files.pythonhosted.org/packages/e0/46/f13e67fe0d4f8a2315782cbad50493de6203ea0d744610faf4d5f5b16e90/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3", size = 1514204 }, - { url = "https://files.pythonhosted.org/packages/50/11/ddcf7343b7b7a226e0fc7b68cbf5a5bb56291fac07f5c3023bb4c319ebb4/pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6", size = 1414339 }, - { url = "https://files.pythonhosted.org/packages/01/14/1c18d7d5b7be2708f513f37c61bfadfa62161c10624f8733f1c8451b3509/pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4", size = 576928 }, - { url = "https://files.pythonhosted.org/packages/3b/1b/0a540edd75a41df14ec416a9a500b9fec66e554aac920d4c58fbd5756776/pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5", size = 642317 }, - { url = "https://files.pythonhosted.org/packages/98/77/1cbfec0358078a4c5add529d8a70892db1be900980cdb5dd0898b3d6ab9d/pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003", size = 543834 }, - { url = "https://files.pythonhosted.org/packages/28/2f/78a766c8913ad62b28581777ac4ede50c6d9f249d39c2963e279524a1bbe/pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", size = 1343105 }, - { url = "https://files.pythonhosted.org/packages/b7/9c/4b1e2d3d4065be715e007fe063ec7885978fad285f87eae1436e6c3201f4/pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", size = 1008365 }, - { url = "https://files.pythonhosted.org/packages/4f/ef/5a23ec689ff36d7625b38d121ef15abfc3631a9aecb417baf7a4245e4124/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", size = 665923 }, - { url = "https://files.pythonhosted.org/packages/ae/61/d436461a47437d63c6302c90724cf0981883ec57ceb6073873f32172d676/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", size = 903400 }, - { url = "https://files.pythonhosted.org/packages/47/42/fc6d35ecefe1739a819afaf6f8e686f7f02a4dd241c78972d316f403474c/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", size = 860034 }, - { url = "https://files.pythonhosted.org/packages/07/3b/44ea6266a6761e9eefaa37d98fabefa112328808ac41aa87b4bbb668af30/pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", size = 860579 }, - { url = "https://files.pythonhosted.org/packages/38/6f/4df2014ab553a6052b0e551b37da55166991510f9e1002c89cab7ce3b3f2/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", size = 1196246 }, - { url = "https://files.pythonhosted.org/packages/38/9d/ee240fc0c9fe9817f0c9127a43238a3e28048795483c403cc10720ddef22/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", size = 1507441 }, - { url = "https://files.pythonhosted.org/packages/85/4f/01711edaa58d535eac4a26c294c617c9a01f09857c0ce191fd574d06f359/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", size = 1406498 }, - { url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 }, - { url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 }, - { url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 }, - { url = "https://files.pythonhosted.org/packages/04/a7/0f7e2f6c126fe6e62dbae0bc93b1bd3f1099cf7fea47a5468defebe3f39d/pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", size = 1006564 }, - { url = "https://files.pythonhosted.org/packages/31/b6/a187165c852c5d49f826a690857684333a6a4a065af0a6015572d2284f6a/pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", size = 1340447 }, - { url = "https://files.pythonhosted.org/packages/68/ba/f4280c58ff71f321602a6e24fd19879b7e79793fb8ab14027027c0fb58ef/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", size = 665485 }, - { url = "https://files.pythonhosted.org/packages/77/b5/c987a5c53c7d8704216f29fc3d810b32f156bcea488a940e330e1bcbb88d/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", size = 903484 }, - { url = "https://files.pythonhosted.org/packages/29/c9/07da157d2db18c72a7eccef8e684cefc155b712a88e3d479d930aa9eceba/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", size = 859981 }, - { url = "https://files.pythonhosted.org/packages/43/09/e12501bd0b8394b7d02c41efd35c537a1988da67fc9c745cae9c6c776d31/pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", size = 860334 }, - { url = "https://files.pythonhosted.org/packages/eb/ff/f5ec1d455f8f7385cc0a8b2acd8c807d7fade875c14c44b85c1bddabae21/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", size = 1196179 }, - { url = "https://files.pythonhosted.org/packages/ec/8a/bb2ac43295b1950fe436a81fc5b298be0b96ac76fb029b514d3ed58f7b27/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", size = 1507668 }, - { url = "https://files.pythonhosted.org/packages/a9/49/dbc284ebcfd2dca23f6349227ff1616a7ee2c4a35fe0a5d6c3deff2b4fed/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", size = 1406539 }, - { url = "https://files.pythonhosted.org/packages/00/68/093cdce3fe31e30a341d8e52a1ad86392e13c57970d722c1f62a1d1a54b6/pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", size = 575567 }, - { url = "https://files.pythonhosted.org/packages/92/ae/6cc4657148143412b5819b05e362ae7dd09fb9fe76e2a539dcff3d0386bc/pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", size = 637551 }, - { url = "https://files.pythonhosted.org/packages/6c/67/fbff102e201688f97c8092e4c3445d1c1068c2f27bbd45a578df97ed5f94/pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", size = 540378 }, - { url = "https://files.pythonhosted.org/packages/3f/fe/2d998380b6e0122c6c4bdf9b6caf490831e5f5e2d08a203b5adff060c226/pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", size = 1007378 }, - { url = "https://files.pythonhosted.org/packages/4a/f4/30d6e7157f12b3a0390bde94d6a8567cdb88846ed068a6e17238a4ccf600/pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", size = 1329532 }, - { url = "https://files.pythonhosted.org/packages/82/86/3fe917870e15ee1c3ad48229a2a64458e36036e64b4afa9659045d82bfa8/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", size = 653242 }, - { url = "https://files.pythonhosted.org/packages/50/2d/242e7e6ef6c8c19e6cb52d095834508cd581ffb925699fd3c640cdc758f1/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", size = 888404 }, - { url = "https://files.pythonhosted.org/packages/ac/11/7270566e1f31e4ea73c81ec821a4b1688fd551009a3d2bab11ec66cb1e8f/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", size = 845858 }, - { url = "https://files.pythonhosted.org/packages/91/d5/72b38fbc69867795c8711bdd735312f9fef1e3d9204e2f63ab57085434b9/pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", size = 847375 }, - { url = "https://files.pythonhosted.org/packages/dd/9a/10ed3c7f72b4c24e719c59359fbadd1a27556a28b36cdf1cd9e4fb7845d5/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", size = 1183489 }, - { url = "https://files.pythonhosted.org/packages/72/2d/8660892543fabf1fe41861efa222455811adac9f3c0818d6c3170a1153e3/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", size = 1492932 }, - { url = "https://files.pythonhosted.org/packages/7b/d6/32fd69744afb53995619bc5effa2a405ae0d343cd3e747d0fbc43fe894ee/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", size = 1392485 }, +sdist = { url = "https://files.pythonhosted.org/packages/b1/11/b9213d25230ac18a71b39b3723494e57adebe36e066397b961657b3b41c1/pyzmq-26.4.0.tar.gz", hash = "sha256:4bd13f85f80962f91a651a7356fe0472791a5f7a92f227822b5acf44795c626d", size = 278293 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/6d/234e3b0aa82fd0290b1896e9992f56bdddf1f97266110be54d0177a9d2d9/pyzmq-26.4.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:bfcf82644c9b45ddd7cd2a041f3ff8dce4a0904429b74d73a439e8cab1bd9e54", size = 1339723 }, + { url = "https://files.pythonhosted.org/packages/4f/11/6d561efe29ad83f7149a7cd48e498e539ed09019c6cd7ecc73f4cc725028/pyzmq-26.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9bcae3979b2654d5289d3490742378b2f3ce804b0b5fd42036074e2bf35b030", size = 672645 }, + { url = "https://files.pythonhosted.org/packages/19/fd/81bfe3e23f418644660bad1a90f0d22f0b3eebe33dd65a79385530bceb3d/pyzmq-26.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccdff8ac4246b6fb60dcf3982dfaeeff5dd04f36051fe0632748fc0aa0679c01", size = 910133 }, + { url = "https://files.pythonhosted.org/packages/97/68/321b9c775595ea3df832a9516252b653fe32818db66fdc8fa31c9b9fce37/pyzmq-26.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4550af385b442dc2d55ab7717837812799d3674cb12f9a3aa897611839c18e9e", size = 867428 }, + { url = "https://files.pythonhosted.org/packages/4e/6e/159cbf2055ef36aa2aa297e01b24523176e5b48ead283c23a94179fb2ba2/pyzmq-26.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f7ffe9db1187a253fca95191854b3fda24696f086e8789d1d449308a34b88", size = 862409 }, + { url = "https://files.pythonhosted.org/packages/05/1c/45fb8db7be5a7d0cadea1070a9cbded5199a2d578de2208197e592f219bd/pyzmq-26.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3709c9ff7ba61589b7372923fd82b99a81932b592a5c7f1a24147c91da9a68d6", size = 1205007 }, + { url = "https://files.pythonhosted.org/packages/f8/fa/658c7f583af6498b463f2fa600f34e298e1b330886f82f1feba0dc2dd6c3/pyzmq-26.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f8f3c30fb2d26ae5ce36b59768ba60fb72507ea9efc72f8f69fa088450cff1df", size = 1514599 }, + { url = "https://files.pythonhosted.org/packages/4d/d7/44d641522353ce0a2bbd150379cb5ec32f7120944e6bfba4846586945658/pyzmq-26.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:382a4a48c8080e273427fc692037e3f7d2851959ffe40864f2db32646eeb3cef", size = 1414546 }, + { url = "https://files.pythonhosted.org/packages/72/76/c8ed7263218b3d1e9bce07b9058502024188bd52cc0b0a267a9513b431fc/pyzmq-26.4.0-cp311-cp311-win32.whl", hash = "sha256:d56aad0517d4c09e3b4f15adebba8f6372c5102c27742a5bdbfc74a7dceb8fca", size = 579247 }, + { url = "https://files.pythonhosted.org/packages/c3/d0/2d9abfa2571a0b1a67c0ada79a8aa1ba1cce57992d80f771abcdf99bb32c/pyzmq-26.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:963977ac8baed7058c1e126014f3fe58b3773f45c78cce7af5c26c09b6823896", size = 644727 }, + { url = "https://files.pythonhosted.org/packages/0d/d1/c8ad82393be6ccedfc3c9f3adb07f8f3976e3c4802640fe3f71441941e70/pyzmq-26.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0c8e8cadc81e44cc5088fcd53b9b3b4ce9344815f6c4a03aec653509296fae3", size = 559942 }, + { url = "https://files.pythonhosted.org/packages/10/44/a778555ebfdf6c7fc00816aad12d185d10a74d975800341b1bc36bad1187/pyzmq-26.4.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:5227cb8da4b6f68acfd48d20c588197fd67745c278827d5238c707daf579227b", size = 1341586 }, + { url = "https://files.pythonhosted.org/packages/9c/4f/f3a58dc69ac757e5103be3bd41fb78721a5e17da7cc617ddb56d973a365c/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1c07a7fa7f7ba86554a2b1bef198c9fed570c08ee062fd2fd6a4dcacd45f905", size = 665880 }, + { url = "https://files.pythonhosted.org/packages/fe/45/50230bcfb3ae5cb98bee683b6edeba1919f2565d7cc1851d3c38e2260795/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae775fa83f52f52de73183f7ef5395186f7105d5ed65b1ae65ba27cb1260de2b", size = 902216 }, + { url = "https://files.pythonhosted.org/packages/41/59/56bbdc5689be5e13727491ad2ba5efd7cd564365750514f9bc8f212eef82/pyzmq-26.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c760d0226ebd52f1e6b644a9e839b5db1e107a23f2fcd46ec0569a4fdd4e63", size = 859814 }, + { url = "https://files.pythonhosted.org/packages/81/b1/57db58cfc8af592ce94f40649bd1804369c05b2190e4cbc0a2dad572baeb/pyzmq-26.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ef8c6ecc1d520debc147173eaa3765d53f06cd8dbe7bd377064cdbc53ab456f5", size = 855889 }, + { url = "https://files.pythonhosted.org/packages/e8/92/47542e629cbac8f221c230a6d0f38dd3d9cff9f6f589ed45fdf572ffd726/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3150ef4084e163dec29ae667b10d96aad309b668fac6810c9e8c27cf543d6e0b", size = 1197153 }, + { url = "https://files.pythonhosted.org/packages/07/e5/b10a979d1d565d54410afc87499b16c96b4a181af46e7645ab4831b1088c/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4448c9e55bf8329fa1dcedd32f661bf611214fa70c8e02fee4347bc589d39a84", size = 1507352 }, + { url = "https://files.pythonhosted.org/packages/ab/58/5a23db84507ab9c01c04b1232a7a763be66e992aa2e66498521bbbc72a71/pyzmq-26.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e07dde3647afb084d985310d067a3efa6efad0621ee10826f2cb2f9a31b89d2f", size = 1406834 }, + { url = "https://files.pythonhosted.org/packages/22/74/aaa837b331580c13b79ac39396601fb361454ee184ca85e8861914769b99/pyzmq-26.4.0-cp312-cp312-win32.whl", hash = "sha256:ba034a32ecf9af72adfa5ee383ad0fd4f4e38cdb62b13624278ef768fe5b5b44", size = 577992 }, + { url = "https://files.pythonhosted.org/packages/30/0f/55f8c02c182856743b82dde46b2dc3e314edda7f1098c12a8227eeda0833/pyzmq-26.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:056a97aab4064f526ecb32f4343917a4022a5d9efb6b9df990ff72e1879e40be", size = 640466 }, + { url = "https://files.pythonhosted.org/packages/e4/29/073779afc3ef6f830b8de95026ef20b2d1ec22d0324d767748d806e57379/pyzmq-26.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f23c750e485ce1eb639dbd576d27d168595908aa2d60b149e2d9e34c9df40e0", size = 556342 }, + { url = "https://files.pythonhosted.org/packages/d7/20/fb2c92542488db70f833b92893769a569458311a76474bda89dc4264bd18/pyzmq-26.4.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:c43fac689880f5174d6fc864857d1247fe5cfa22b09ed058a344ca92bf5301e3", size = 1339484 }, + { url = "https://files.pythonhosted.org/packages/58/29/2f06b9cabda3a6ea2c10f43e67ded3e47fc25c54822e2506dfb8325155d4/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902aca7eba477657c5fb81c808318460328758e8367ecdd1964b6330c73cae43", size = 666106 }, + { url = "https://files.pythonhosted.org/packages/77/e4/dcf62bd29e5e190bd21bfccaa4f3386e01bf40d948c239239c2f1e726729/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e48a830bfd152fe17fbdeaf99ac5271aa4122521bf0d275b6b24e52ef35eb6", size = 902056 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/b36b3d7aea236087d20189bec1a87eeb2b66009731d7055e5c65f845cdba/pyzmq-26.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31be2b6de98c824c06f5574331f805707c667dc8f60cb18580b7de078479891e", size = 860148 }, + { url = "https://files.pythonhosted.org/packages/18/a6/f048826bc87528c208e90604c3bf573801e54bd91e390cbd2dfa860e82dc/pyzmq-26.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6332452034be001bbf3206ac59c0d2a7713de5f25bb38b06519fc6967b7cf771", size = 855983 }, + { url = "https://files.pythonhosted.org/packages/0a/27/454d34ab6a1d9772a36add22f17f6b85baf7c16e14325fa29e7202ca8ee8/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:da8c0f5dd352136853e6a09b1b986ee5278dfddfebd30515e16eae425c872b30", size = 1197274 }, + { url = "https://files.pythonhosted.org/packages/f4/3d/7abfeab6b83ad38aa34cbd57c6fc29752c391e3954fd12848bd8d2ec0df6/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f4ccc1a0a2c9806dda2a2dd118a3b7b681e448f3bb354056cad44a65169f6d86", size = 1507120 }, + { url = "https://files.pythonhosted.org/packages/13/ff/bc8d21dbb9bc8705126e875438a1969c4f77e03fc8565d6901c7933a3d01/pyzmq-26.4.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1c0b5fceadbab461578daf8d1dcc918ebe7ddd2952f748cf30c7cf2de5d51101", size = 1406738 }, + { url = "https://files.pythonhosted.org/packages/f5/5d/d4cd85b24de71d84d81229e3bbb13392b2698432cf8fdcea5afda253d587/pyzmq-26.4.0-cp313-cp313-win32.whl", hash = "sha256:28e2b0ff5ba4b3dd11062d905682bad33385cfa3cc03e81abd7f0822263e6637", size = 577826 }, + { url = "https://files.pythonhosted.org/packages/c6/6c/f289c1789d7bb6e5a3b3bef7b2a55089b8561d17132be7d960d3ff33b14e/pyzmq-26.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:23ecc9d241004c10e8b4f49d12ac064cd7000e1643343944a10df98e57bc544b", size = 640406 }, + { url = "https://files.pythonhosted.org/packages/b3/99/676b8851cb955eb5236a0c1e9ec679ea5ede092bf8bf2c8a68d7e965cac3/pyzmq-26.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:1edb0385c7f025045d6e0f759d4d3afe43c17a3d898914ec6582e6f464203c08", size = 556216 }, + { url = "https://files.pythonhosted.org/packages/65/c2/1fac340de9d7df71efc59d9c50fc7a635a77b103392d1842898dd023afcb/pyzmq-26.4.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:93a29e882b2ba1db86ba5dd5e88e18e0ac6b627026c5cfbec9983422011b82d4", size = 1333769 }, + { url = "https://files.pythonhosted.org/packages/5c/c7/6c03637e8d742c3b00bec4f5e4cd9d1c01b2f3694c6f140742e93ca637ed/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45684f276f57110bb89e4300c00f1233ca631f08f5f42528a5c408a79efc4a", size = 658826 }, + { url = "https://files.pythonhosted.org/packages/a5/97/a8dca65913c0f78e0545af2bb5078aebfc142ca7d91cdaffa1fbc73e5dbd/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f72073e75260cb301aad4258ad6150fa7f57c719b3f498cb91e31df16784d89b", size = 891650 }, + { url = "https://files.pythonhosted.org/packages/7d/7e/f63af1031eb060bf02d033732b910fe48548dcfdbe9c785e9f74a6cc6ae4/pyzmq-26.4.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be37e24b13026cfedd233bcbbccd8c0bcd2fdd186216094d095f60076201538d", size = 849776 }, + { url = "https://files.pythonhosted.org/packages/f6/fa/1a009ce582802a895c0d5fe9413f029c940a0a8ee828657a3bb0acffd88b/pyzmq-26.4.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:237b283044934d26f1eeff4075f751b05d2f3ed42a257fc44386d00df6a270cf", size = 842516 }, + { url = "https://files.pythonhosted.org/packages/6e/bc/f88b0bad0f7a7f500547d71e99f10336f2314e525d4ebf576a1ea4a1d903/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:b30f862f6768b17040929a68432c8a8be77780317f45a353cb17e423127d250c", size = 1189183 }, + { url = "https://files.pythonhosted.org/packages/d9/8c/db446a3dd9cf894406dec2e61eeffaa3c07c3abb783deaebb9812c4af6a5/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:c80fcd3504232f13617c6ab501124d373e4895424e65de8b72042333316f64a8", size = 1495501 }, + { url = "https://files.pythonhosted.org/packages/05/4c/bf3cad0d64c3214ac881299c4562b815f05d503bccc513e3fd4fdc6f67e4/pyzmq-26.4.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:26a2a7451606b87f67cdeca2c2789d86f605da08b4bd616b1a9981605ca3a364", size = 1395540 }, + { url = "https://files.pythonhosted.org/packages/04/52/a70fcd5592715702248306d8e1729c10742c2eac44529984413b05c68658/pyzmq-26.4.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4478b14cb54a805088299c25a79f27eaf530564a7a4f72bf432a040042b554eb", size = 834405 }, + { url = "https://files.pythonhosted.org/packages/25/f9/1a03f1accff16b3af1a6fa22cbf7ced074776abbf688b2e9cb4629700c62/pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a28ac29c60e4ba84b5f58605ace8ad495414a724fe7aceb7cf06cd0598d04e1", size = 569578 }, + { url = "https://files.pythonhosted.org/packages/76/0c/3a633acd762aa6655fcb71fa841907eae0ab1e8582ff494b137266de341d/pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43b03c1ceea27c6520124f4fb2ba9c647409b9abdf9a62388117148a90419494", size = 798248 }, + { url = "https://files.pythonhosted.org/packages/cd/cc/6c99c84aa60ac1cc56747bed6be8ce6305b9b861d7475772e7a25ce019d3/pyzmq-26.4.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7731abd23a782851426d4e37deb2057bf9410848a4459b5ede4fe89342e687a9", size = 756757 }, + { url = "https://files.pythonhosted.org/packages/13/9c/d8073bd898eb896e94c679abe82e47506e2b750eb261cf6010ced869797c/pyzmq-26.4.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a222ad02fbe80166b0526c038776e8042cd4e5f0dec1489a006a1df47e9040e0", size = 555371 }, ] [[package]] @@ -1653,85 +1669,97 @@ wheels = [ [[package]] name = "rich" -version = "13.9.4" +version = "14.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 }, ] [[package]] name = "rpds-py" -version = "0.22.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/ad/8d1ddf78f2805a71253fcd388017e7b4a0615c22c762b6d35301fef20106/rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f", size = 359773 }, - { url = "https://files.pythonhosted.org/packages/c8/75/68c15732293a8485d79fe4ebe9045525502a067865fa4278f178851b2d87/rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a", size = 349214 }, - { url = "https://files.pythonhosted.org/packages/3c/4c/7ce50f3070083c2e1b2bbd0fb7046f3da55f510d19e283222f8f33d7d5f4/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5", size = 380477 }, - { url = "https://files.pythonhosted.org/packages/9a/e9/835196a69cb229d5c31c13b8ae603bd2da9a6695f35fe4270d398e1db44c/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb", size = 386171 }, - { url = "https://files.pythonhosted.org/packages/f9/8e/33fc4eba6683db71e91e6d594a2cf3a8fbceb5316629f0477f7ece5e3f75/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2", size = 422676 }, - { url = "https://files.pythonhosted.org/packages/37/47/2e82d58f8046a98bb9497a8319604c92b827b94d558df30877c4b3c6ccb3/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0", size = 446152 }, - { url = "https://files.pythonhosted.org/packages/e1/78/79c128c3e71abbc8e9739ac27af11dc0f91840a86fce67ff83c65d1ba195/rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1", size = 381300 }, - { url = "https://files.pythonhosted.org/packages/c9/5b/2e193be0e8b228c1207f31fa3ea79de64dadb4f6a4833111af8145a6bc33/rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d", size = 409636 }, - { url = "https://files.pythonhosted.org/packages/c2/3f/687c7100b762d62186a1c1100ffdf99825f6fa5ea94556844bbbd2d0f3a9/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648", size = 556708 }, - { url = "https://files.pythonhosted.org/packages/8c/a2/c00cbc4b857e8b3d5e7f7fc4c81e23afd8c138b930f4f3ccf9a41a23e9e4/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74", size = 583554 }, - { url = "https://files.pythonhosted.org/packages/d0/08/696c9872cf56effdad9ed617ac072f6774a898d46b8b8964eab39ec562d2/rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a", size = 552105 }, - { url = "https://files.pythonhosted.org/packages/18/1f/4df560be1e994f5adf56cabd6c117e02de7c88ee238bb4ce03ed50da9d56/rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64", size = 220199 }, - { url = "https://files.pythonhosted.org/packages/b8/1b/c29b570bc5db8237553002788dc734d6bd71443a2ceac2a58202ec06ef12/rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c", size = 231775 }, - { url = "https://files.pythonhosted.org/packages/75/47/3383ee3bd787a2a5e65a9b9edc37ccf8505c0a00170e3a5e6ea5fbcd97f7/rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", size = 352334 }, - { url = "https://files.pythonhosted.org/packages/40/14/aa6400fa8158b90a5a250a77f2077c0d0cd8a76fce31d9f2b289f04c6dec/rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", size = 342111 }, - { url = "https://files.pythonhosted.org/packages/7d/06/395a13bfaa8a28b302fb433fb285a67ce0ea2004959a027aea8f9c52bad4/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", size = 384286 }, - { url = "https://files.pythonhosted.org/packages/43/52/d8eeaffab047e6b7b7ef7f00d5ead074a07973968ffa2d5820fa131d7852/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e", size = 391739 }, - { url = "https://files.pythonhosted.org/packages/83/31/52dc4bde85c60b63719610ed6f6d61877effdb5113a72007679b786377b8/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", size = 427306 }, - { url = "https://files.pythonhosted.org/packages/70/d5/1bab8e389c2261dba1764e9e793ed6830a63f830fdbec581a242c7c46bda/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", size = 442717 }, - { url = "https://files.pythonhosted.org/packages/82/a1/a45f3e30835b553379b3a56ea6c4eb622cf11e72008229af840e4596a8ea/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", size = 385721 }, - { url = "https://files.pythonhosted.org/packages/a6/27/780c942de3120bdd4d0e69583f9c96e179dfff082f6ecbb46b8d6488841f/rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", size = 415824 }, - { url = "https://files.pythonhosted.org/packages/94/0b/aa0542ca88ad20ea719b06520f925bae348ea5c1fdf201b7e7202d20871d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", size = 561227 }, - { url = "https://files.pythonhosted.org/packages/0d/92/3ed77d215f82c8f844d7f98929d56cc321bb0bcfaf8f166559b8ec56e5f1/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", size = 587424 }, - { url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 }, - { url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 }, - { url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 }, - { url = "https://files.pythonhosted.org/packages/d0/bf/36d5cc1f2c609ae6e8bf0fc35949355ca9d8790eceb66e6385680c951e60/rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", size = 351657 }, - { url = "https://files.pythonhosted.org/packages/24/2a/f1e0fa124e300c26ea9382e59b2d582cba71cedd340f32d1447f4f29fa4e/rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", size = 341829 }, - { url = "https://files.pythonhosted.org/packages/cf/c2/0da1231dd16953845bed60d1a586fcd6b15ceaeb965f4d35cdc71f70f606/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", size = 384220 }, - { url = "https://files.pythonhosted.org/packages/c7/73/a4407f4e3a00a9d4b68c532bf2d873d6b562854a8eaff8faa6133b3588ec/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", size = 391009 }, - { url = "https://files.pythonhosted.org/packages/a9/c3/04b7353477ab360fe2563f5f0b176d2105982f97cd9ae80a9c5a18f1ae0f/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", size = 426989 }, - { url = "https://files.pythonhosted.org/packages/8d/e6/e4b85b722bcf11398e17d59c0f6049d19cd606d35363221951e6d625fcb0/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", size = 441544 }, - { url = "https://files.pythonhosted.org/packages/27/fc/403e65e56f65fff25f2973216974976d3f0a5c3f30e53758589b6dc9b79b/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", size = 385179 }, - { url = "https://files.pythonhosted.org/packages/57/9b/2be9ff9700d664d51fd96b33d6595791c496d2778cb0b2a634f048437a55/rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", size = 415103 }, - { url = "https://files.pythonhosted.org/packages/bb/a5/03c2ad8ca10994fcf22dd2150dd1d653bc974fa82d9a590494c84c10c641/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", size = 560916 }, - { url = "https://files.pythonhosted.org/packages/ba/2e/be4fdfc8b5b576e588782b56978c5b702c5a2307024120d8aeec1ab818f0/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", size = 587062 }, - { url = "https://files.pythonhosted.org/packages/67/e0/2034c221937709bf9c542603d25ad43a68b4b0a9a0c0b06a742f2756eb66/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", size = 555734 }, - { url = "https://files.pythonhosted.org/packages/ea/ce/240bae07b5401a22482b58e18cfbabaa392409b2797da60223cca10d7367/rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", size = 220663 }, - { url = "https://files.pythonhosted.org/packages/cb/f0/d330d08f51126330467edae2fa4efa5cec8923c87551a79299380fdea30d/rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", size = 235503 }, - { url = "https://files.pythonhosted.org/packages/f7/c4/dbe1cc03df013bf2feb5ad00615038050e7859f381e96fb5b7b4572cd814/rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", size = 347698 }, - { url = "https://files.pythonhosted.org/packages/a4/3a/684f66dd6b0f37499cad24cd1c0e523541fd768576fa5ce2d0a8799c3cba/rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", size = 337330 }, - { url = "https://files.pythonhosted.org/packages/82/eb/e022c08c2ce2e8f7683baa313476492c0e2c1ca97227fe8a75d9f0181e95/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", size = 380022 }, - { url = "https://files.pythonhosted.org/packages/e4/21/5a80e653e4c86aeb28eb4fea4add1f72e1787a3299687a9187105c3ee966/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", size = 390754 }, - { url = "https://files.pythonhosted.org/packages/37/a4/d320a04ae90f72d080b3d74597074e62be0a8ecad7d7321312dfe2dc5a6a/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", size = 423840 }, - { url = "https://files.pythonhosted.org/packages/87/70/674dc47d93db30a6624279284e5631be4c3a12a0340e8e4f349153546728/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", size = 438970 }, - { url = "https://files.pythonhosted.org/packages/3f/64/9500f4d66601d55cadd21e90784cfd5d5f4560e129d72e4339823129171c/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", size = 383146 }, - { url = "https://files.pythonhosted.org/packages/4d/45/630327addb1d17173adcf4af01336fd0ee030c04798027dfcb50106001e0/rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", size = 408294 }, - { url = "https://files.pythonhosted.org/packages/5f/ef/8efb3373cee54ea9d9980b772e5690a0c9e9214045a4e7fa35046e399fee/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", size = 556345 }, - { url = "https://files.pythonhosted.org/packages/54/01/151d3b9ef4925fc8f15bfb131086c12ec3c3d6dd4a4f7589c335bf8e85ba/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", size = 582292 }, - { url = "https://files.pythonhosted.org/packages/30/89/35fc7a6cdf3477d441c7aca5e9bbf5a14e0f25152aed7f63f4e0b141045d/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", size = 553855 }, - { url = "https://files.pythonhosted.org/packages/8f/e0/830c02b2457c4bd20a8c5bb394d31d81f57fbefce2dbdd2e31feff4f7003/rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", size = 219100 }, - { url = "https://files.pythonhosted.org/packages/f8/30/7ac943f69855c2db77407ae363484b915d861702dbba1aa82d68d57f42be/rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", size = 233794 }, +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/b3/52b213298a0ba7097c7ea96bee95e1947aa84cc816d48cebb539770cdf41/rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", size = 26863 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/e6/c1458bbfb257448fdb2528071f1f4e19e26798ed5ef6d47d7aab0cb69661/rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", size = 377679 }, + { url = "https://files.pythonhosted.org/packages/dd/26/ea4181ef78f58b2c167548c6a833d7dc22408e5b3b181bda9dda440bb92d/rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", size = 362571 }, + { url = "https://files.pythonhosted.org/packages/56/fa/1ec54dd492c64c280a2249a047fc3369e2789dc474eac20445ebfc72934b/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", size = 388012 }, + { url = "https://files.pythonhosted.org/packages/3a/be/bad8b0e0f7e58ef4973bb75e91c472a7d51da1977ed43b09989264bf065c/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", size = 394730 }, + { url = "https://files.pythonhosted.org/packages/35/56/ab417fc90c21826df048fc16e55316ac40876e4b790104ececcbce813d8f/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", size = 448264 }, + { url = "https://files.pythonhosted.org/packages/b6/75/4c63862d5c05408589196c8440a35a14ea4ae337fa70ded1f03638373f06/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", size = 446813 }, + { url = "https://files.pythonhosted.org/packages/e7/0c/91cf17dffa9a38835869797a9f041056091ebba6a53963d3641207e3d467/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", size = 389438 }, + { url = "https://files.pythonhosted.org/packages/1b/b0/60e6c72727c978276e02851819f3986bc40668f115be72c1bc4d922c950f/rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", size = 420416 }, + { url = "https://files.pythonhosted.org/packages/a1/d7/f46f85b9f863fb59fd3c534b5c874c48bee86b19e93423b9da8784605415/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", size = 565236 }, + { url = "https://files.pythonhosted.org/packages/2a/d1/1467620ded6dd70afc45ec822cdf8dfe7139537780d1f3905de143deb6fd/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", size = 592016 }, + { url = "https://files.pythonhosted.org/packages/5d/13/fb1ded2e6adfaa0c0833106c42feb290973f665300f4facd5bf5d7891d9c/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", size = 560123 }, + { url = "https://files.pythonhosted.org/packages/1e/df/09fc1857ac7cc2eb16465a7199c314cbce7edde53c8ef21d615410d7335b/rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", size = 222256 }, + { url = "https://files.pythonhosted.org/packages/ff/25/939b40bc4d54bf910e5ee60fb5af99262c92458f4948239e8c06b0b750e7/rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", size = 234718 }, + { url = "https://files.pythonhosted.org/packages/1a/e0/1c55f4a3be5f1ca1a4fd1f3ff1504a1478c1ed48d84de24574c4fa87e921/rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", size = 366945 }, + { url = "https://files.pythonhosted.org/packages/39/1b/a3501574fbf29118164314dbc800d568b8c1c7b3258b505360e8abb3902c/rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", size = 351935 }, + { url = "https://files.pythonhosted.org/packages/dc/47/77d3d71c55f6a374edde29f1aca0b2e547325ed00a9da820cabbc9497d2b/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", size = 390817 }, + { url = "https://files.pythonhosted.org/packages/4e/ec/1e336ee27484379e19c7f9cc170f4217c608aee406d3ae3a2e45336bff36/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", size = 401983 }, + { url = "https://files.pythonhosted.org/packages/07/f8/39b65cbc272c635eaea6d393c2ad1ccc81c39eca2db6723a0ca4b2108fce/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", size = 451719 }, + { url = "https://files.pythonhosted.org/packages/32/05/05c2b27dd9c30432f31738afed0300659cb9415db0ff7429b05dfb09bbde/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", size = 442546 }, + { url = "https://files.pythonhosted.org/packages/7d/e0/19383c8b5d509bd741532a47821c3e96acf4543d0832beba41b4434bcc49/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", size = 393695 }, + { url = "https://files.pythonhosted.org/packages/9d/15/39f14e96d94981d0275715ae8ea564772237f3fa89bc3c21e24de934f2c7/rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", size = 427218 }, + { url = "https://files.pythonhosted.org/packages/22/b9/12da7124905a680f690da7a9de6f11de770b5e359f5649972f7181c8bf51/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", size = 568062 }, + { url = "https://files.pythonhosted.org/packages/88/17/75229017a2143d915f6f803721a6d721eca24f2659c5718a538afa276b4f/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", size = 596262 }, + { url = "https://files.pythonhosted.org/packages/aa/64/8e8a1d8bd1b6b638d6acb6d41ab2cec7f2067a5b8b4c9175703875159a7c/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", size = 564306 }, + { url = "https://files.pythonhosted.org/packages/68/1c/a7eac8d8ed8cb234a9b1064647824c387753343c3fab6ed7c83481ed0be7/rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", size = 224281 }, + { url = "https://files.pythonhosted.org/packages/bb/46/b8b5424d1d21f2f2f3f2d468660085318d4f74a8df8289e3dd6ad224d488/rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", size = 239719 }, + { url = "https://files.pythonhosted.org/packages/9d/c3/3607abc770395bc6d5a00cb66385a5479fb8cd7416ddef90393b17ef4340/rpds_py-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2d8e4508e15fc05b31285c4b00ddf2e0eb94259c2dc896771966a163122a0c", size = 367072 }, + { url = "https://files.pythonhosted.org/packages/d8/35/8c7ee0fe465793e3af3298dc5a9f3013bd63e7a69df04ccfded8293a4982/rpds_py-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f00c16e089282ad68a3820fd0c831c35d3194b7cdc31d6e469511d9bffc535c", size = 351919 }, + { url = "https://files.pythonhosted.org/packages/91/d3/7e1b972501eb5466b9aca46a9c31bcbbdc3ea5a076e9ab33f4438c1d069d/rpds_py-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951cc481c0c395c4a08639a469d53b7d4afa252529a085418b82a6b43c45c240", size = 390360 }, + { url = "https://files.pythonhosted.org/packages/a2/a8/ccabb50d3c91c26ad01f9b09a6a3b03e4502ce51a33867c38446df9f896b/rpds_py-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9ca89938dff18828a328af41ffdf3902405a19f4131c88e22e776a8e228c5a8", size = 400704 }, + { url = "https://files.pythonhosted.org/packages/53/ae/5fa5bf0f3bc6ce21b5ea88fc0ecd3a439e7cb09dd5f9ffb3dbe1b6894fc5/rpds_py-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed0ef550042a8dbcd657dfb284a8ee00f0ba269d3f2286b0493b15a5694f9fe8", size = 450839 }, + { url = "https://files.pythonhosted.org/packages/e3/ac/c4e18b36d9938247e2b54f6a03746f3183ca20e1edd7d3654796867f5100/rpds_py-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2356688e5d958c4d5cb964af865bea84db29971d3e563fb78e46e20fe1848b", size = 441494 }, + { url = "https://files.pythonhosted.org/packages/bf/08/b543969c12a8f44db6c0f08ced009abf8f519191ca6985509e7c44102e3c/rpds_py-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78884d155fd15d9f64f5d6124b486f3d3f7fd7cd71a78e9670a0f6f6ca06fb2d", size = 393185 }, + { url = "https://files.pythonhosted.org/packages/da/7e/f6eb6a7042ce708f9dfc781832a86063cea8a125bbe451d663697b51944f/rpds_py-0.24.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a4a535013aeeef13c5532f802708cecae8d66c282babb5cd916379b72110cf7", size = 426168 }, + { url = "https://files.pythonhosted.org/packages/38/b0/6cd2bb0509ac0b51af4bb138e145b7c4c902bb4b724d6fd143689d6e0383/rpds_py-0.24.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:84e0566f15cf4d769dade9b366b7b87c959be472c92dffb70462dd0844d7cbad", size = 567622 }, + { url = "https://files.pythonhosted.org/packages/64/b0/c401f4f077547d98e8b4c2ec6526a80e7cb04f519d416430ec1421ee9e0b/rpds_py-0.24.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:823e74ab6fbaa028ec89615ff6acb409e90ff45580c45920d4dfdddb069f2120", size = 595435 }, + { url = "https://files.pythonhosted.org/packages/9f/ec/7993b6e803294c87b61c85bd63e11142ccfb2373cf88a61ec602abcbf9d6/rpds_py-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c61a2cb0085c8783906b2f8b1f16a7e65777823c7f4d0a6aaffe26dc0d358dd9", size = 563762 }, + { url = "https://files.pythonhosted.org/packages/1f/29/4508003204cb2f461dc2b83dd85f8aa2b915bc98fe6046b9d50d4aa05401/rpds_py-0.24.0-cp313-cp313-win32.whl", hash = "sha256:60d9b630c8025b9458a9d114e3af579a2c54bd32df601c4581bd054e85258143", size = 223510 }, + { url = "https://files.pythonhosted.org/packages/f9/12/09e048d1814195e01f354155fb772fb0854bd3450b5f5a82224b3a319f0e/rpds_py-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:6eea559077d29486c68218178ea946263b87f1c41ae7f996b1f30a983c476a5a", size = 239075 }, + { url = "https://files.pythonhosted.org/packages/d2/03/5027cde39bb2408d61e4dd0cf81f815949bb629932a6c8df1701d0257fc4/rpds_py-0.24.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:d09dc82af2d3c17e7dd17120b202a79b578d79f2b5424bda209d9966efeed114", size = 362974 }, + { url = "https://files.pythonhosted.org/packages/bf/10/24d374a2131b1ffafb783e436e770e42dfdb74b69a2cd25eba8c8b29d861/rpds_py-0.24.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5fc13b44de6419d1e7a7e592a4885b323fbc2f46e1f22151e3a8ed3b8b920405", size = 348730 }, + { url = "https://files.pythonhosted.org/packages/7a/d1/1ef88d0516d46cd8df12e5916966dbf716d5ec79b265eda56ba1b173398c/rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c347a20d79cedc0a7bd51c4d4b7dbc613ca4e65a756b5c3e57ec84bd43505b47", size = 387627 }, + { url = "https://files.pythonhosted.org/packages/4e/35/07339051b8b901ecefd449ebf8e5522e92bcb95e1078818cbfd9db8e573c/rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20f2712bd1cc26a3cc16c5a1bfee9ed1abc33d4cdf1aabd297fe0eb724df4272", size = 394094 }, + { url = "https://files.pythonhosted.org/packages/dc/62/ee89ece19e0ba322b08734e95441952062391065c157bbd4f8802316b4f1/rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad911555286884be1e427ef0dc0ba3929e6821cbeca2194b13dc415a462c7fd", size = 449639 }, + { url = "https://files.pythonhosted.org/packages/15/24/b30e9f9e71baa0b9dada3a4ab43d567c6b04a36d1cb531045f7a8a0a7439/rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aeb3329c1721c43c58cae274d7d2ca85c1690d89485d9c63a006cb79a85771a", size = 438584 }, + { url = "https://files.pythonhosted.org/packages/28/d9/49f7b8f3b4147db13961e19d5e30077cd0854ccc08487026d2cb2142aa4a/rpds_py-0.24.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0f156e9509cee987283abd2296ec816225145a13ed0391df8f71bf1d789e2d", size = 391047 }, + { url = "https://files.pythonhosted.org/packages/49/b0/e66918d0972c33a259ba3cd7b7ff10ed8bd91dbcfcbec6367b21f026db75/rpds_py-0.24.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa6800adc8204ce898c8a424303969b7aa6a5e4ad2789c13f8648739830323b7", size = 418085 }, + { url = "https://files.pythonhosted.org/packages/e1/6b/99ed7ea0a94c7ae5520a21be77a82306aac9e4e715d4435076ead07d05c6/rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a18fc371e900a21d7392517c6f60fe859e802547309e94313cd8181ad9db004d", size = 564498 }, + { url = "https://files.pythonhosted.org/packages/28/26/1cacfee6b800e6fb5f91acecc2e52f17dbf8b0796a7c984b4568b6d70e38/rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9168764133fd919f8dcca2ead66de0105f4ef5659cbb4fa044f7014bed9a1797", size = 590202 }, + { url = "https://files.pythonhosted.org/packages/a9/9e/57bd2f9fba04a37cef673f9a66b11ca8c43ccdd50d386c455cd4380fe461/rpds_py-0.24.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f6e3cec44ba05ee5cbdebe92d052f69b63ae792e7d05f1020ac5e964394080c", size = 561771 }, + { url = "https://files.pythonhosted.org/packages/9f/cf/b719120f375ab970d1c297dbf8de1e3c9edd26fe92c0ed7178dd94b45992/rpds_py-0.24.0-cp313-cp313t-win32.whl", hash = "sha256:8ebc7e65ca4b111d928b669713865f021b7773350eeac4a31d3e70144297baba", size = 221195 }, + { url = "https://files.pythonhosted.org/packages/2d/e5/22865285789f3412ad0c3d7ec4dc0a3e86483b794be8a5d9ed5a19390900/rpds_py-0.24.0-cp313-cp313t-win_amd64.whl", hash = "sha256:675269d407a257b8c00a6b58205b72eec8231656506c56fd429d924ca00bb350", size = 237354 }, + { url = "https://files.pythonhosted.org/packages/65/53/40bcc246a8354530d51a26d2b5b9afd1deacfb0d79e67295cc74df362f52/rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", size = 378386 }, + { url = "https://files.pythonhosted.org/packages/80/b0/5ea97dd2f53e3618560aa1f9674e896e63dff95a9b796879a201bc4c1f00/rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", size = 363440 }, + { url = "https://files.pythonhosted.org/packages/57/9d/259b6eada6f747cdd60c9a5eb3efab15f6704c182547149926c38e5bd0d5/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", size = 388816 }, + { url = "https://files.pythonhosted.org/packages/94/c1/faafc7183712f89f4b7620c3c15979ada13df137d35ef3011ae83e93b005/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", size = 395058 }, + { url = "https://files.pythonhosted.org/packages/6c/96/d7fa9d2a7b7604a61da201cc0306a355006254942093779d7121c64700ce/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", size = 448692 }, + { url = "https://files.pythonhosted.org/packages/96/37/a3146c6eebc65d6d8c96cc5ffdcdb6af2987412c789004213227fbe52467/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", size = 446462 }, + { url = "https://files.pythonhosted.org/packages/1f/13/6481dfd9ac7de43acdaaa416e3a7da40bc4bb8f5c6ca85e794100aa54596/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", size = 390460 }, + { url = "https://files.pythonhosted.org/packages/61/e1/37e36bce65e109543cc4ff8d23206908649023549604fa2e7fbeba5342f7/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", size = 421609 }, + { url = "https://files.pythonhosted.org/packages/20/dd/1f1a923d6cd798b8582176aca8a0784676f1a0449fb6f07fce6ac1cdbfb6/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", size = 565818 }, + { url = "https://files.pythonhosted.org/packages/56/ec/d8da6df6a1eb3a418944a17b1cb38dd430b9e5a2e972eafd2b06f10c7c46/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", size = 592627 }, + { url = "https://files.pythonhosted.org/packages/b3/14/c492b9c7d5dd133e13f211ddea6bb9870f99e4f73932f11aa00bc09a9be9/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", size = 560885 }, ] [[package]] name = "sdbus" -version = "0.13.0" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/c7/8740ff78e9ffdbb9a28e7722e145795015c62ea7ce812242f5968073511c/sdbus-0.13.0.tar.gz", hash = "sha256:801bd46608ee82614d42960c8ba8ae9300edb1bf5bbeb534bc8fd21f13d2c20e", size = 85887 } +sdist = { url = "https://files.pythonhosted.org/packages/17/9a/1dc010428fa1f444809d9aa1adb3ce231dae891b5f33635d8f4d7a8e33fd/sdbus-0.14.0.tar.gz", hash = "sha256:41d61b76cc05a9ea41d10d70a11e9f9a86ed95f40f713630c5e18340e0e4c76f", size = 89146 } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/fb/060bc3ffdbfae6062800ee516b68c5a050e5c4cb9424759a7650462a9f5b/sdbus-0.13.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcc88e70e76723234fd0987edccbcc3fe5f4e99245eb30a6b362ef7f882fd8a3", size = 540599 }, - { url = "https://files.pythonhosted.org/packages/57/33/5d6d93d2897901cf503ed6db47b10208195fedaa0ed4e9f7c9f511fc649c/sdbus-0.13.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:199a4c321fc5b4cded57a110f82625f6541909c40e733f574d12afc5ace149a7", size = 539172 }, + { url = "https://files.pythonhosted.org/packages/e7/de/cc625bd2c61a1ba917b7ef9f7bec5357e1d4f68ba204b3d71cf038facade/sdbus-0.14.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9a5b9315090ffbe232c82edc3e6f1a449ed27c7ef7f3ebc81d73326057fba8f1", size = 767982 }, + { url = "https://files.pythonhosted.org/packages/9f/68/47baafb1cc32ef18e45d6e1f0f8ca99864d582d59da855e035c1ce3fed13/sdbus-0.14.0-cp39-abi3-manylinux_2_28_armv7l.whl", hash = "sha256:46f60ee66f18f0a3b9cb19639bc8a9ada62cd7f89343bba8a3140c0563885561", size = 696782 }, + { url = "https://files.pythonhosted.org/packages/b6/74/4a00d5dcf0037e132db404bcc770d0e49c9c088a373e8916ef8e9eb074cf/sdbus-0.14.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:d38597858490c2063dd3de508942688075089843ef851fb8c062cb393e8b99d5", size = 741140 }, ] [[package]] @@ -1745,11 +1773,11 @@ wheels = [ [[package]] name = "setuptools" -version = "75.8.0" +version = "78.1.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/a9/5a/0db4da3bc908df06e5efae42b44e75c81dd52716e10192ff36d0c1c8e379/setuptools-78.1.0.tar.gz", hash = "sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54", size = 1367827 } 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/54/21/f43f0a1fa8b06b32812e0975981f4677d28e0f3271601dc88ac5a5b83220/setuptools-78.1.0-py3-none-any.whl", hash = "sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8", size = 1256108 }, ] [[package]] @@ -1795,14 +1823,14 @@ wheels = [ [[package]] name = "syrupy" -version = "4.8.1" +version = "4.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/32/8b56491ed50ae103c2db14885c29fe765170bdf044fe5868548113da35ef/syrupy-4.8.1.tar.gz", hash = "sha256:8da8c0311e6d92de0b15767768c6ab98982b7b4a4c67083c08fbac3fbad4d44c", size = 50192 } +sdist = { url = "https://files.pythonhosted.org/packages/8c/f8/022d8704a3314f3e96dbd6bbd16ebe119ce30e35f41aabfa92345652fceb/syrupy-4.9.1.tar.gz", hash = "sha256:b7d0fcadad80a7d2f6c4c71917918e8ebe2483e8c703dfc8d49cdbb01081f9a4", size = 52492 } wheels = [ - { url = "https://files.pythonhosted.org/packages/80/47/5e8f44ec0f287b08e8c1f3fc63fe1fbe182f07bf606eec903d7827b95e51/syrupy-4.8.1-py3-none-any.whl", hash = "sha256:274f97cbaf44175f5e478a2f3a53559d31f41c66c6bf28131695f94ac893ea00", size = 50326 }, + { url = "https://files.pythonhosted.org/packages/ec/9d/aef9ec5fd5a4ee2f6a96032c4eda5888c5c7cec65cef6b28c4fc37671d88/syrupy-4.9.1-py3-none-any.whl", hash = "sha256:b94cc12ed0e5e75b448255430af642516842a2374a46936dd2650cfb6dd20eda", size = 52214 }, ] [[package]] @@ -1860,11 +1888,11 @@ wheels = [ [[package]] name = "trove-classifiers" -version = "2025.1.15.22" +version = "2025.3.19.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/cb/8f6a91c74049180e395590901834d68bef5d6a2ce4c9ca9792cfadc1b9b4/trove_classifiers-2025.1.15.22.tar.gz", hash = "sha256:90af74358d3a01b3532bc7b3c88d8c6a094c2fd50a563d13d9576179326d7ed9", size = 16236 } +sdist = { url = "https://files.pythonhosted.org/packages/23/c6/1bc495f33ab4cd16c1044bde55d5ac76646c6c759df751218c7c2aeb3bba/trove_classifiers-2025.3.19.19.tar.gz", hash = "sha256:98e9d396fe908d5f43b7454fa4c43d17cd0fdadf046f45fb38a5e3af8d959ecd", size = 16280 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/c5/6422dbc59954389b20b2aba85b737ab4a552e357e7ea14b52f40312e7c84/trove_classifiers-2025.1.15.22-py3-none-any.whl", hash = "sha256:5f19c789d4f17f501d36c94dbbf969fb3e8c2784d008e6f5164dd2c3d6a2b07c", size = 13610 }, + { url = "https://files.pythonhosted.org/packages/40/f8/9c6d334002e7b4ff34a875d2f6fe76c6c1544bd7fde3e39cb7cd2593488f/trove_classifiers-2025.3.19.19-py3-none-any.whl", hash = "sha256:5fc02770ecd81588a605ac98b9d85d50a5a3f9daa30af2a6b1361a1999d75d07", size = 13678 }, ] [[package]] @@ -1878,11 +1906,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +sdist = { url = "https://files.pythonhosted.org/packages/76/ad/cd3e3465232ec2416ae9b983f27b9e94dc8171d56ac99b345319a9475967/typing_extensions-4.13.1.tar.gz", hash = "sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff", size = 106633 } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, + { url = "https://files.pythonhosted.org/packages/df/c5/e7a0b0f5ed69f94c8ab7379c599e6036886bffcde609969a5325f47f1332/typing_extensions-4.13.1-py3-none-any.whl", hash = "sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69", size = 45739 }, ] [[package]] @@ -1905,14 +1933,14 @@ wheels = [ [[package]] name = "validate-pyproject" -version = "0.23" +version = "0.24.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastjsonschema" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/07/b24689b11ef23226bdd3eebd8d89e103236f4c91043b71d707612a4c3ad7/validate_pyproject-0.23.tar.gz", hash = "sha256:12b2714bf647265c60e4f24a20674428bd891a8aa168a1be535bb99f8c0af0e3", size = 113397 } +sdist = { url = "https://files.pythonhosted.org/packages/d2/e5/dd60cbfc9b0701d8621c73e56c261142c1a01d1f74d0da30133bd272ecc6/validate_pyproject-0.24.1.tar.gz", hash = "sha256:e182fc51354add988e5bee6fc06ceb327832a78d921730fc618275e5b29e6b71", size = 117054 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/36/45f4bb7275b5afd70b1e4bc8b6bcf0c488cde20e39d72a3c98998ba8a9f5/validate_pyproject-0.23-py3-none-any.whl", hash = "sha256:8c2e678d7d52cff56eb1670a627eaa808fe6334d7a7f15218d12b89642d8a077", size = 52726 }, + { url = "https://files.pythonhosted.org/packages/a4/39/6983dd79f01aaa4c75d9ffa550fa393f0c4c28f7ccd6956e4188c62cefbc/validate_pyproject-0.24.1-py3-none-any.whl", hash = "sha256:b7b05fa9117204c9c4606ab317acd095b18d1bfc78fb7dc8cc06f77d0582ca2d", size = 53732 }, ] [package.optional-dependencies] From c3786dba7a0373ae7d358c3ad029ad253612847e Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 16:41:45 -0800 Subject: [PATCH 09/24] Remove plusdeck.dbus exports --- plusdeck/dbus/__init__.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/plusdeck/dbus/__init__.py b/plusdeck/dbus/__init__.py index 28fa915..e69de29 100644 --- a/plusdeck/dbus/__init__.py +++ b/plusdeck/dbus/__init__.py @@ -1,8 +0,0 @@ -from plusdeck.dbus.client import DbusClient -from plusdeck.dbus.interface import DBUS_NAME, DbusInterface - -__all__ = [ - "DbusClient", - "DbusInterface", - "DBUS_NAME", -] From 4ee863e9df99f887df9da148699ce92261714ad1 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 16:47:11 -0800 Subject: [PATCH 10/24] plusdeck.dbus.select --- plusdeck/dbus/client.py | 34 +++++++++++++-------- plusdeck/dbus/select.py | 65 ++++++++++++++++++++++++++++++++++++++++ plusdeck/dbus/service.py | 22 +++++++++++++- 3 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 plusdeck/dbus/select.py diff --git a/plusdeck/dbus/client.py b/plusdeck/dbus/client.py index 9422624..aa6a1a2 100644 --- a/plusdeck/dbus/client.py +++ b/plusdeck/dbus/client.py @@ -12,11 +12,6 @@ from unittest.mock import Mock import click -from sdbus import ( # pyright: ignore [reportMissingModuleSource] - sd_bus_open_system, - sd_bus_open_user, - SdBus, -) from plusdeck.cli import async_command, AsyncCommand, echo, LogLevel, OutputMode, STATE from plusdeck.client import State @@ -24,6 +19,11 @@ from plusdeck.dbus.config import StagedConfig from plusdeck.dbus.error import handle_dbus_error from plusdeck.dbus.interface import DBUS_NAME, DbusInterface +from plusdeck.dbus.select import ( + select_default_bus, + select_session_bus, + select_system_bus, +) logger = logging.getLogger(__name__) @@ -33,12 +33,12 @@ class DbusClient(DbusInterface): A DBus client for the Plus Deck 2C PC Cassette Deck. """ - def __init__(self: Self, bus: Optional[SdBus] = None) -> None: + def __init__(self: Self) -> None: client = Mock(name="client", side_effect=NotImplementedError("client")) self.subscribe = Mock(name="client.subscribe") super().__init__(client) - cast(Any, self)._proxify(DBUS_NAME, "/", bus=bus) + cast(Any, self)._proxify(DBUS_NAME, "/") async def staged_config(self: Self) -> StagedConfig: """ @@ -60,7 +60,6 @@ class Obj: client: DbusClient log_level: LogLevel output: OutputMode - user: bool def pass_config(fn: AsyncCommand) -> AsyncCommand: @@ -144,11 +143,14 @@ def warn_dirty() -> None: help="Output either human-friendly text or JSON", ) @click.option( - "--user/--no-user", type=bool, default=False, help="Connect to the user bus" + "--user/--default", + type=click.BOOL, + default=None, + help="Connect to either the user or default bus", ) @click.pass_context def main( - ctx: click.Context, log_level: LogLevel, output: OutputMode, user: bool + ctx: click.Context, log_level: LogLevel, output: OutputMode, user: Optional[bool] ) -> None: """ Control your Plus Deck 2C Cassette Drive through dbus. @@ -160,9 +162,15 @@ def main( echo.mode = output async def load() -> None: - bus: SdBus = sd_bus_open_user() if user else sd_bus_open_system() - client = DbusClient(bus) - ctx.obj = Obj(client=client, log_level=log_level, output=output, user=user) + if user: + select_session_bus() + elif user is None: + select_system_bus() + else: + select_default_bus() + + client = DbusClient() + ctx.obj = Obj(client=client, log_level=log_level, output=output) asyncio.run(load()) diff --git a/plusdeck/dbus/select.py b/plusdeck/dbus/select.py new file mode 100644 index 0000000..7f08e89 --- /dev/null +++ b/plusdeck/dbus/select.py @@ -0,0 +1,65 @@ +""" +Convenience functions for configuring the default bus. + +DBus has two buses: the user-level "session bus", and the system-wide "system bus". + +The session bus starts for your user when you log in, and doesn't have any particular +access or permissions. This is used for user-scoped services. Examples include audio +servers such as PulseAudio and Pioewire, desktop notification daemons, and the Emacs +daemon. + +The system bus is used for services accessible for all users, which persist across +login sessions. These services are typically run with elevated permissions, and +implement access control through many various mechanisms. Examples include networking +daemons such as firewalld and NetworkManager, as well as logging services such as +journald and rsyslog. + +The `sdbus` library has the concept of a "default bus". This is the bus that a given +object uses when another value isn't supplied, and is similar to `asyncio`'s default +event loop. Unless otherwise configured, this default bus is the system bus when +started through `systemd`, and the user bus otherwise. + +This default isn't necessarily appropriate. In particular, if a service is expected +to be run as a system service (as is typical for the `crystalfontz` service), then +the default bus for the DBus client should be the system bus, unless otherwise +specified. + +The functions in this module are used by the client and service CLIs to configure +which bus is used by those programs. +""" + +import logging + +from sdbus import ( # pyright: ignore [reportMissingModuleSource] + sd_bus_open_system, + sd_bus_open_user, + set_default_bus, +) + +logger = logging.getLogger(__name__) + + +def select_session_bus() -> None: + """ + Select the user session bus as the default bus. + """ + + logger.debug("Selecting the user session bus") + set_default_bus(sd_bus_open_user()) + + +def select_system_bus() -> None: + """ + Select the global system bus as the default bus. + """ + + logger.debug("Selecting the system bus") + set_default_bus(sd_bus_open_system()) + + +def select_default_bus() -> None: + """ + Log that the standard default bus is being used. + """ + + logger.debug("Selecting the default bus") diff --git a/plusdeck/dbus/service.py b/plusdeck/dbus/service.py index fe119d1..512b5fd 100644 --- a/plusdeck/dbus/service.py +++ b/plusdeck/dbus/service.py @@ -12,6 +12,11 @@ from plusdeck.config import GLOBAL_FILE from plusdeck.dbus.error import handle_dbus_error from plusdeck.dbus.interface import DBUS_NAME, DbusInterface, load_client +from plusdeck.dbus.select import ( + select_default_bus, + select_session_bus, + select_system_bus, +) logger = logging.getLogger(__name__) @@ -70,7 +75,15 @@ async def serve(config_file: Optional[str] = None) -> None: default="INFO", help="Set the log level", ) -def main(global_: bool, config_file: str, log_level: LogLevel) -> None: +@click.option( + "--user/--system", + type=click.BOOL, + default=None, + help="Connect to either the user or system bus", +) +def main( + global_: bool, config_file: str, log_level: LogLevel, user: Optional[bool] +) -> None: """ Expose the Plus Deck 2C PC Cassette Deck as a DBus service. """ @@ -87,6 +100,13 @@ def main(global_: bool, config_file: str, log_level: LogLevel) -> None: elif global_: file = GLOBAL_FILE + if user: + select_session_bus() + elif user is False: + select_system_bus() + else: + select_default_bus() + asyncio.run(serve(file)) From ec8366c4598cd9b5f4d7b3c0cb1bc2f56f47f758 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 17:00:34 -0800 Subject: [PATCH 11/24] plusdeck.dbus.domain --- plusdeck/dbus/client.py | 11 ++- plusdeck/dbus/config.py | 6 +- plusdeck/dbus/domain.py | 163 +++++++++++++++++++++++++++++++++++++ plusdeck/dbus/interface.py | 4 +- 4 files changed, 171 insertions(+), 13 deletions(-) create mode 100644 plusdeck/dbus/domain.py diff --git a/plusdeck/dbus/client.py b/plusdeck/dbus/client.py index aa6a1a2..5b40c14 100644 --- a/plusdeck/dbus/client.py +++ b/plusdeck/dbus/client.py @@ -17,6 +17,7 @@ from plusdeck.client import State from plusdeck.config import Config from plusdeck.dbus.config import StagedConfig +from plusdeck.dbus.domain import ConfigM, StateM, TimeoutM from plusdeck.dbus.error import handle_dbus_error from plusdeck.dbus.interface import DBUS_NAME, DbusInterface from plusdeck.dbus.select import ( @@ -45,12 +46,10 @@ async def staged_config(self: Self) -> StagedConfig: Fetch the state of staged configuration changes. """ - file, port = await self.config - - active_config: Config = cast(Any, Config)(file=file, port=port) + active_config: Config = ConfigM.unpack(await self.config) return StagedConfig( - target_config=Config.from_file(file), + target_config=Config.from_file(active_config.file), active_config=active_config, ) @@ -404,7 +403,7 @@ async def expect(client: DbusClient, state: State, timeout: Optional[float]) -> Wait for an expected state """ - ok = await client.wait_for(state.name, timeout if timeout is not None else -1.0) + ok = await client.wait_for(StateM.pack(state), TimeoutM.pack(timeout)) if not ok: logger.info(f"Timed out after {timeout} seconds.") @@ -422,7 +421,7 @@ async def subscribe(client: DbusClient, for_: Optional[float]) -> None: try: async with asyncio.timeout(for_): async for st in client.state: - echo(State[st]) + echo(StateM.unpack(st)) except TimeoutError: pass diff --git a/plusdeck/dbus/config.py b/plusdeck/dbus/config.py index f4800c4..3ba61e8 100644 --- a/plusdeck/dbus/config.py +++ b/plusdeck/dbus/config.py @@ -1,6 +1,6 @@ from dataclasses import asdict, dataclass, fields import json -from typing import Any, Dict, Generic, Literal, Self, Tuple, TypeVar +from typing import Any, Dict, Generic, Literal, Self, TypeVar import yaml @@ -11,10 +11,6 @@ from plusdeck.config import Config -File = str -Port = str -ConfigStruct = Tuple[File, Port] - StageType = Literal["set"] | Literal["unset"] | None T = TypeVar("T") diff --git a/plusdeck/dbus/domain.py b/plusdeck/dbus/domain.py new file mode 100644 index 0000000..a966251 --- /dev/null +++ b/plusdeck/dbus/domain.py @@ -0,0 +1,163 @@ +from typing import Any, cast, ClassVar, Optional, Protocol, Self, Tuple, Type, Union + +from plusdeck.client import State +from plusdeck.config import Config + + +class TypeProtocol(Protocol): + t: ClassVar[str] + + +def t(*args: Union[str, Type[TypeProtocol]]) -> str: + type_ = "" + + for arg in args: + if isinstance(arg, str): + type_ += arg + else: + type_ += arg.t + + return type_ + + +def struct(*args: Union[str, Type[TypeProtocol]]) -> str: + return t("(", *args, ")") + + +OptFloatT = float + + +class OptFloatM: + """ + Map `Optional[float]` to and from `OptFloatT` (`float`), where float values + are expected to be positive. + + None values are represented by negative values, namely `-1.0`. + """ + + t: ClassVar[str] = "d" + none: ClassVar[OptFloatT] = -1.0 + + @classmethod + def pack(cls: Type[Self], t: Optional[float]) -> OptFloatT: + """ + Pack `Optional[float]` to `OptFloatT`. + """ + + return t if t is not None else cls.none + + @staticmethod + def unpack(t: OptFloatT) -> Optional[float]: + """ + Unpack `OptFloatT` to `Optional[float]`. + """ + + return t if t >= 0 else None + + +OptStrT = str + + +class OptStrM: + """ + Map `Optional[str]` to and from `StrT` (`str`). + + None values are represented by an empty string. + """ + + t: ClassVar[str] = "s" + none: ClassVar[str] = "" + + @classmethod + def pack(cls: Type[Self], string: Optional[str]) -> OptStrT: + """ + Pack `Optional[str]` to `OptStrT`. + """ + + return string or cls.none + + @classmethod + def unpack(cls: Type[Self], string: OptStrT) -> Optional[str]: + """ + Unpack `OptStrT` to `Optional[str]`. + """ + + return string if string != cls.none else None + + +TimeoutT = float + + +class TimeoutM(OptFloatM): + """ + Map `Optional[float]` to and from `TimeoutT` (`float`). + + `TimeoutM` is an alias for `OptFloatM`. + """ + + t: ClassVar[str] = OptFloatM.t + none: ClassVar[float] = OptFloatM.none + + +FileT = OptStrT + + +class FileM(OptStrM): + t: ClassVar[str] = OptStrM.t + none: ClassVar[str] = OptStrM.none + + +PortT = str + + +class PortM: + t: ClassVar[str] = "s" + + +ConfigT = Tuple[FileT, PortT] + + +class ConfigM: + """ + Map `Config` to and from `ConfigT` + (`Tuple[Optional[str], str]`). + """ + + t: ClassVar[str] = struct(FileM, PortM) + + @staticmethod + def pack(config: Config) -> ConfigT: + """ + Pack `Config` to `ConfigT`. + """ + + return (FileM.pack(config.file), config.port) + + @staticmethod + def unpack(config: ConfigT) -> Config: + """ + Unpack `ConfigT` to `Config`. + """ + + file, port = config + + return cast(Any, Config)(file=file, port=port) + + +StateT = str + + +class StateM: + """ + Map `State` to and from `StateT` (`str`). + """ + + t: ClassVar[str] = "s" + + @staticmethod + def pack(state: State) -> StateT: + return state.name + + @staticmethod + def unpack(state: StateT) -> State: + return State[state] diff --git a/plusdeck/dbus/interface.py b/plusdeck/dbus/interface.py index 9057b19..da1e104 100644 --- a/plusdeck/dbus/interface.py +++ b/plusdeck/dbus/interface.py @@ -12,7 +12,7 @@ from plusdeck.client import Client, create_connection, Receiver, State from plusdeck.config import Config -from plusdeck.dbus.config import ConfigStruct +from plusdeck.dbus.domain import ConfigT logger = logging.getLogger(__name__) @@ -44,7 +44,7 @@ def __init__(self: Self, client: Client, config_file: Optional[str] = None) -> N self.subscribe() @dbus_property_async("(ss)") - def config(self: Self) -> ConfigStruct: + def config(self: Self) -> ConfigT: """ The DBus service's currently loaded configuration. """ From accef41b10f9beb695ad25b2d97ebd2398cf0265 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Tue, 8 Apr 2025 17:06:37 -0800 Subject: [PATCH 12/24] Separate client/service into multiple files --- plusdeck/dbus/client/__init__.py | 32 +++++++++++++++ plusdeck/dbus/client/__main__.py | 3 ++ plusdeck/dbus/{client.py => client/cli.py} | 33 ++------------- plusdeck/dbus/service/__init__.py | 42 ++++++++++++++++++++ plusdeck/dbus/service/__main__.py | 3 ++ plusdeck/dbus/{service.py => service/cli.py} | 37 +---------------- 6 files changed, 84 insertions(+), 66 deletions(-) create mode 100644 plusdeck/dbus/client/__init__.py create mode 100644 plusdeck/dbus/client/__main__.py rename plusdeck/dbus/{client.py => client/cli.py} (89%) create mode 100644 plusdeck/dbus/service/__init__.py create mode 100644 plusdeck/dbus/service/__main__.py rename plusdeck/dbus/{service.py => service/cli.py} (62%) diff --git a/plusdeck/dbus/client/__init__.py b/plusdeck/dbus/client/__init__.py new file mode 100644 index 0000000..bf2a1f7 --- /dev/null +++ b/plusdeck/dbus/client/__init__.py @@ -0,0 +1,32 @@ +from typing import Any, cast, Self +from unittest.mock import Mock + +from plusdeck.config import Config +from plusdeck.dbus.config import StagedConfig +from plusdeck.dbus.domain import ConfigM +from plusdeck.dbus.interface import DBUS_NAME, DbusInterface + + +class DbusClient(DbusInterface): + """ + A DBus client for the Plus Deck 2C PC Cassette Deck. + """ + + def __init__(self: Self) -> None: + client = Mock(name="client", side_effect=NotImplementedError("client")) + self.subscribe = Mock(name="client.subscribe") + super().__init__(client) + + cast(Any, self)._proxify(DBUS_NAME, "/") + + async def staged_config(self: Self) -> StagedConfig: + """ + Fetch the state of staged configuration changes. + """ + + active_config: Config = ConfigM.unpack(await self.config) + + return StagedConfig( + target_config=Config.from_file(active_config.file), + active_config=active_config, + ) diff --git a/plusdeck/dbus/client/__main__.py b/plusdeck/dbus/client/__main__.py new file mode 100644 index 0000000..8bade1f --- /dev/null +++ b/plusdeck/dbus/client/__main__.py @@ -0,0 +1,3 @@ +from plusdeck.dbus.client.cli import main + +main() diff --git a/plusdeck/dbus/client.py b/plusdeck/dbus/client/cli.py similarity index 89% rename from plusdeck/dbus/client.py rename to plusdeck/dbus/client/cli.py index 5b40c14..5fe5be7 100644 --- a/plusdeck/dbus/client.py +++ b/plusdeck/dbus/client/cli.py @@ -8,18 +8,16 @@ import shutil import subprocess import sys -from typing import Any, cast, List, Optional, Self -from unittest.mock import Mock +from typing import List, Optional import click from plusdeck.cli import async_command, AsyncCommand, echo, LogLevel, OutputMode, STATE from plusdeck.client import State -from plusdeck.config import Config +from plusdeck.dbus.client import DbusClient from plusdeck.dbus.config import StagedConfig -from plusdeck.dbus.domain import ConfigM, StateM, TimeoutM +from plusdeck.dbus.domain import StateM, TimeoutM from plusdeck.dbus.error import handle_dbus_error -from plusdeck.dbus.interface import DBUS_NAME, DbusInterface from plusdeck.dbus.select import ( select_default_bus, select_session_bus, @@ -29,31 +27,6 @@ logger = logging.getLogger(__name__) -class DbusClient(DbusInterface): - """ - A DBus client for the Plus Deck 2C PC Cassette Deck. - """ - - def __init__(self: Self) -> None: - client = Mock(name="client", side_effect=NotImplementedError("client")) - self.subscribe = Mock(name="client.subscribe") - super().__init__(client) - - cast(Any, self)._proxify(DBUS_NAME, "/") - - async def staged_config(self: Self) -> StagedConfig: - """ - Fetch the state of staged configuration changes. - """ - - active_config: Config = ConfigM.unpack(await self.config) - - return StagedConfig( - target_config=Config.from_file(active_config.file), - active_config=active_config, - ) - - @dataclass class Obj: client: DbusClient diff --git a/plusdeck/dbus/service/__init__.py b/plusdeck/dbus/service/__init__.py new file mode 100644 index 0000000..bd4a3a6 --- /dev/null +++ b/plusdeck/dbus/service/__init__.py @@ -0,0 +1,42 @@ +import logging +from typing import Optional + +from sdbus import ( # pyright: ignore [reportMissingModuleSource] + request_default_bus_name_async, +) + +from plusdeck.dbus.error import handle_dbus_error +from plusdeck.dbus.interface import DBUS_NAME, DbusInterface, load_client + +logger = logging.getLogger(__name__) + + +async def service(config_file: Optional[str] = None) -> DbusInterface: + """ + Create a configure DBus service with a supplied config file. + """ + + client = await load_client(config_file) + iface = DbusInterface(client, config_file=config_file) + + logger.debug(f"Requesting bus name {DBUS_NAME}...") + await request_default_bus_name_async(DBUS_NAME) + + logger.debug("Exporting interface to path /...") + + iface.export_to_dbus("/") + + logger.info(f"Listening on {DBUS_NAME} /") + + return iface + + +async def serve(config_file: Optional[str] = None) -> None: + """ + Create and serve configure DBus service with a supplied config file. + """ + + async with handle_dbus_error(logger): + srv = await service(config_file) + + await srv.closed diff --git a/plusdeck/dbus/service/__main__.py b/plusdeck/dbus/service/__main__.py new file mode 100644 index 0000000..7c87000 --- /dev/null +++ b/plusdeck/dbus/service/__main__.py @@ -0,0 +1,3 @@ +from plusdeck.dbus.service.cli import main + +main() diff --git a/plusdeck/dbus/service.py b/plusdeck/dbus/service/cli.py similarity index 62% rename from plusdeck/dbus/service.py rename to plusdeck/dbus/service/cli.py index 512b5fd..4819ad6 100644 --- a/plusdeck/dbus/service.py +++ b/plusdeck/dbus/service/cli.py @@ -4,54 +4,19 @@ from typing import Optional import click -from sdbus import ( # pyright: ignore [reportMissingModuleSource] - request_default_bus_name_async, -) from plusdeck.cli import LogLevel from plusdeck.config import GLOBAL_FILE -from plusdeck.dbus.error import handle_dbus_error -from plusdeck.dbus.interface import DBUS_NAME, DbusInterface, load_client from plusdeck.dbus.select import ( select_default_bus, select_session_bus, select_system_bus, ) +from plusdeck.dbus.service import serve logger = logging.getLogger(__name__) -async def service(config_file: Optional[str] = None) -> DbusInterface: - """ - Create a configure DBus service with a supplied config file. - """ - - client = await load_client(config_file) - iface = DbusInterface(client, config_file=config_file) - - logger.debug(f"Requesting bus name {DBUS_NAME}...") - await request_default_bus_name_async(DBUS_NAME) - - logger.debug("Exporting interface to path /...") - - iface.export_to_dbus("/") - - logger.info(f"Listening on {DBUS_NAME} /") - - return iface - - -async def serve(config_file: Optional[str] = None) -> None: - """ - Create and serve configure DBus service with a supplied config file. - """ - - async with handle_dbus_error(logger): - srv = await service(config_file) - - await srv.closed - - @click.command @click.option( "--global/--no-global", From b6e7f78a11cebde456be40cec098bbe2ca3cf076 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 16:39:32 -0800 Subject: [PATCH 13/24] Overhaul dbus API docs --- docs/api/plusdeck.dbus.md | 7 --- docs/api/plusdeck.dbus/index.md | 46 ++++++++++++++++ .../api/plusdeck.dbus/plusdeck.dbus.client.md | 7 +++ .../api/plusdeck.dbus/plusdeck.dbus.config.md | 3 + .../api/plusdeck.dbus/plusdeck.dbus.domain.md | 7 +++ .../plusdeck.dbus/plusdeck.dbus.interface.md | 7 +++ .../api/plusdeck.dbus/plusdeck.dbus.select.md | 3 + .../plusdeck.dbus/plusdeck.dbus.service.md | 3 + plusdeck/dbus/domain.py | 55 +++++++++++++++++++ 9 files changed, 131 insertions(+), 7 deletions(-) delete mode 100644 docs/api/plusdeck.dbus.md create mode 100644 docs/api/plusdeck.dbus/index.md create mode 100644 docs/api/plusdeck.dbus/plusdeck.dbus.client.md create mode 100644 docs/api/plusdeck.dbus/plusdeck.dbus.config.md create mode 100644 docs/api/plusdeck.dbus/plusdeck.dbus.domain.md create mode 100644 docs/api/plusdeck.dbus/plusdeck.dbus.interface.md create mode 100644 docs/api/plusdeck.dbus/plusdeck.dbus.select.md create mode 100644 docs/api/plusdeck.dbus/plusdeck.dbus.service.md diff --git a/docs/api/plusdeck.dbus.md b/docs/api/plusdeck.dbus.md deleted file mode 100644 index deb8b84..0000000 --- a/docs/api/plusdeck.dbus.md +++ /dev/null @@ -1,7 +0,0 @@ -# plusdeck.dbus - -The `plusdeck` library includes a DBus service and client. This service allows for multitenancy on Linux - the centralized service controls the serial bus, and clients - including `plusdeckctl` - can connect to the service. - -For information on the service daemon and CLI client, visit [the main DBus documentation](../dbus/index.md). - -::: plusdeck.dbus diff --git a/docs/api/plusdeck.dbus/index.md b/docs/api/plusdeck.dbus/index.md new file mode 100644 index 0000000..d8062d6 --- /dev/null +++ b/docs/api/plusdeck.dbus/index.md @@ -0,0 +1,46 @@ +# DBus API Overview + +The `plusdeck` library includes a DBus service and client. This service allows for multitenancy on Linux - the centralized service controls the serial bus, and clients - including `plusdeckctl` - can connect to the service. + +The DBus APIs largely depend on the [sdbus](https://pypi.org/project/sdbus/) Python library, which in turn depends on the [sd-bus](https://www.freedesktop.org/software/systemd/man/latest/sd-bus.html) library. This means that, effectively, the DBus API is only available on Linux. `sdbus` is therefore an optional dependency, under the `dbus` extra. + +As a consequence, the DBus API is (unlike the primary `plusdeck` API) not re-exported at the top level. This is to make it viable to run unit tests for parts of the DBus API which don't strictly depend on `sdbus`, namely tests for `plusdeck.dbus.domain`. + +For information on the DBus service and client CLI, check out [the core DBus documentation](../../dbus/index.md). + +## plusdeck.dbus.client + +This module contains the core `DbusClient` class. This class is used for interacting with a live DBus service. This is where most users will want to start. + +For more information, view the API docs for [`plusdeck.dbus.client`](./plusdeck.dbus.client.md). + +## plusdeck.dbus.domain + +The DBus interface uses DBus compatible types, rather than the standard `plusdeck` domain objects. The domain module contains type aliases and mapper classes for converting to and from `plusdeck` domain objects and DBus types. While not strictly necessary for using the client, it's highly recommended. + +For more information, view the API docs for [`plusdeck.dbus.domain`](./plusdeck.dbus.domain.md). + +## plusdeck.dbus.config + +Configuration for the DBus service is a little different than for the serial client. This is because the DBus service doesn't live reload a config after it changes. In other words, if you edit the config file, the DBus service's loaded config will show drift. This module helps track the drift between these sources. + +For more information, view the API docs for [`plusdeck.dbus.config`](./plusdeck.dbus.config.md). + +## plusdeck.dbus.service + +This module contains abstractions for running the DBus service. It will typically be used through [the service CLI](../../dbus/service.md). But this module may be useful for users wishing to embed it in another program. + +For more information, view the API docs for [`plusdeck.dbus.service`](./plusdeck.dbus.service.md). + +## plusdeck.dbus.select + +This module contains convenience functions for configuring which bus the program uses. + +For more information, view the API docs for [`plusdeck.dbus.select`](./plusdeck.dbus.select.md). + +## plusdeck.dbus.interface + +This module contains the core `DbusInterface` class. This is used directly when serving the interface, and subclassed by the client. + +For more information, view the API docs for [`plusdeck.dbus.interface`](./plusdeck.dbus.interface.md). + diff --git a/docs/api/plusdeck.dbus/plusdeck.dbus.client.md b/docs/api/plusdeck.dbus/plusdeck.dbus.client.md new file mode 100644 index 0000000..5c39e8f --- /dev/null +++ b/docs/api/plusdeck.dbus/plusdeck.dbus.client.md @@ -0,0 +1,7 @@ +# plusdeck.dbus.client + +This module contains the core `DbusClient` abstraction, which is used to interact with a DBus service. + +For information on how to use `plusdeck` domain objects with the DBus client, see [the API docs for `plusdeck.dbus.domain`](./plusdeck.dbus.domain.md). For examples of how to use the DBus client, look at [the source code for `plusdeckctl`](https://github.com/jfhbrook/plusdeck/blob/main/plusdeck/dbus/client/cli.py). + +::: plusdeck.dbus.client diff --git a/docs/api/plusdeck.dbus/plusdeck.dbus.config.md b/docs/api/plusdeck.dbus/plusdeck.dbus.config.md new file mode 100644 index 0000000..e464973 --- /dev/null +++ b/docs/api/plusdeck.dbus/plusdeck.dbus.config.md @@ -0,0 +1,3 @@ +# plusdeck.dbus.config + +::: plusdeck.dbus.config diff --git a/docs/api/plusdeck.dbus/plusdeck.dbus.domain.md b/docs/api/plusdeck.dbus/plusdeck.dbus.domain.md new file mode 100644 index 0000000..b170543 --- /dev/null +++ b/docs/api/plusdeck.dbus/plusdeck.dbus.domain.md @@ -0,0 +1,7 @@ +# plusdeck.dbus.domain + +DBus uses a collection of types that are documented [in the specification](https://dbus.freedesktop.org/doc/dbus-specification.html#basic-types). The base types are more fine-grained than Python's base types, but are non-nullable - ie, there's no `None` type in DBus. Moreover, its collection types don't map cleanly to arbitrary Python class instances - rather, you get basic structs (which correspond to Python tuples) and arrays (which correspond to Python lists). This means that, when interacting with the DBus client, you will need to work with types *other* than the domain objects used in the standard `plusdeck` client. + +To facilitate this, `plusdeck` includes a submodule for mapping between domain objects and DBus types, at `plusdeck.dbus.domain`. This module exports both aliases for the types used by the DBus interface, and mapper classes for packing and unpacking domain objects to and from DBus types. + +::: plusdeck.dbus.domain diff --git a/docs/api/plusdeck.dbus/plusdeck.dbus.interface.md b/docs/api/plusdeck.dbus/plusdeck.dbus.interface.md new file mode 100644 index 0000000..d0a8cbd --- /dev/null +++ b/docs/api/plusdeck.dbus/plusdeck.dbus.interface.md @@ -0,0 +1,7 @@ +# plusdeck.dbus.interface + +This module contains the core `DbusInterface` class. This class is used directly to serve the interface, and is subclassed by the `DbusClient` class in `plusdeck.dbus.client`. + +You will likely not use this module directly. For information on the client, see [`plusdeck.dbus.client`](./plusdeck.dbus.client.md). For information on the service, see [`plusdeck.dbus.service`](./plusdeck.dbus.service.md). + +::: plusdeck.dbus.interface diff --git a/docs/api/plusdeck.dbus/plusdeck.dbus.select.md b/docs/api/plusdeck.dbus/plusdeck.dbus.select.md new file mode 100644 index 0000000..3b7a30c --- /dev/null +++ b/docs/api/plusdeck.dbus/plusdeck.dbus.select.md @@ -0,0 +1,3 @@ +# plusdeck.dbus.select + +::: plusdeck.dbus.select diff --git a/docs/api/plusdeck.dbus/plusdeck.dbus.service.md b/docs/api/plusdeck.dbus/plusdeck.dbus.service.md new file mode 100644 index 0000000..cdb01a2 --- /dev/null +++ b/docs/api/plusdeck.dbus/plusdeck.dbus.service.md @@ -0,0 +1,3 @@ +# plusdeck.dbus.service + +::: plusdeck.dbus.service diff --git a/plusdeck/dbus/domain.py b/plusdeck/dbus/domain.py index a966251..8243e55 100644 --- a/plusdeck/dbus/domain.py +++ b/plusdeck/dbus/domain.py @@ -1,3 +1,58 @@ +""" +Represent entities in the plusdeck domain model with dbus-compatible types, and +map between the plusdeck and dbus domains. + +While these classes don't all implement the same protocols, they do follow +a number of important conventions. + +## Naming Conventions + +In general classes corresponding to entities share their names, but with a postfix +naming convention. + +Dbus types corresponding to entities in the plusdeck domain have `T` appended +to them. For instance, the dbus type corresponding to `Optional[float]` is `OptFloatT`, +which corresponds to the "d" dbus type signature. This applies to more complex +entities as well - for instance, the dbus type corresponding to the `Config` object +is `ConfigT`. + +Mappers - classes that map between entities and dbus types - have `M` appended to +their names. For intance, the mapper for `Optional[float]` and `OptFloatT` is called +`OptFloatM`. + +## `pack` methods and `none` properties + +Mappers which support it have a `pack` class method, which takes objects from the +plusdeck domain and converts them into dbus data types. For instance, `OptFloatM` +packs an `Optional[float]` value into a `OptFloatT`. + +Additionally, mappers representing optional data have a property called `none`, +which contains the value that the dbus client canonically interprets as `None`. +For instance, `TimeoutM.none` is equal to `-1.0`. Note that, in this case, +the dbus client treats any value less than 0 as `None`. + +As a user, you would typically use these APIs when constructing arguments for the +dbus client. For example, if you were to call `dbus_client.wait_for`, it would look like +this: + +```py +ok: bool = await client.wait_for(StateM.pack(state), TimeoutM.pack(timeout)) +``` + +## `unpack` methods + +Dbus client methods will not only *be called* with dbus-compatible types, but +will return dbus-compatible types as well. Sometimes these are sensible - in fact, +most methods return `None`. However, for dbus-based subscriptions, you may want to +unpack the emitted `state`. For example: + +```py + +async for st in client.state: + print(StateM.unpack(st)) +``` +""" + from typing import Any, cast, ClassVar, Optional, Protocol, Self, Tuple, Type, Union from plusdeck.client import State From f8f3cbd44e2347f9034c4b8fe20eac359558449b Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 16:43:48 -0800 Subject: [PATCH 14/24] Overhaul dbus docs --- docs/dbus/access.md | 8 ++++---- docs/dbus/client.md | 20 ++++++++++++-------- docs/dbus/index.md | 4 ++-- docs/dbus/service.md | 18 +++++++++++------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/dbus/access.md b/docs/dbus/access.md index ad29bac..4f060a1 100644 --- a/docs/dbus/access.md +++ b/docs/dbus/access.md @@ -1,13 +1,13 @@ -# Dbus Access Policies +# DBus Access and Permissions When running services under the `system` bus, care must be taken to manage access policies. Dbus does this primarily with [an XML-based policy language](https://dbus.freedesktop.org/doc/dbus-daemon.1.html). Systemd additionally manages access to privileged methods, seemingly with the intent of delegating to polkit. By default, Dbus is configured with the following policies: -* The root user may own the bus, and send and receive messages from `org.jfhbrook.plusdeck` -* Users in the `plusdeck` Unix group may additionally send and receive messages from `org.jfhbrook.plusdeck` +- The root user may own the bus, and send and receive messages from `org.jfhbrook.plusdeck` +- Users in the `plusdeck` Unix group may additionally send and receive messages from `org.jfhbrook.plusdeck` -This means that, if the service is running, `sudo plusdeckctl` commands should always work; and that if your user is in the `plusdeck` Unix group, Dbus will allow for unprivileged `plusdeckctl` commands as well. You can create this group and add yourself to it by running: +This means that, if the service is running, `sudo plusdeckctl` commands should always work; and that if your user is in the `plusdeck` Unix group, Dbus will allow for `plusdeckctl` commands as well. You can create this group and add yourself to it by running: ```bash sudo groupadd plusdeck diff --git a/docs/dbus/client.md b/docs/dbus/client.md index 36ca222..da2328e 100644 --- a/docs/dbus/client.md +++ b/docs/dbus/client.md @@ -1,10 +1,10 @@ # DBus Client CLI -Assuming `plusdeckd` is running, you may interact with the service using `plusdeckctl`: +Assuming the DBus service is running, you may interact with the service using the client CLI: ```sh -$ plusdeckctl --help -Usage: plusdeckctl [OPTIONS] COMMAND [ARGS]... +$ python3 -m plusdeck.dbus.client --help +Usage: python3 -m plusdeck.dbus.client [OPTIONS] COMMAND [ARGS]... Control your Plus Deck 2C Cassette Drive through dbus. @@ -12,7 +12,7 @@ Options: --log-level [DEBUG|INFO|WARNING|ERROR|CRITICAL] Set the log level --output [text|json] Output either human-friendly text or JSON - --user / --no-user Connect to the user bus + --user / --default Connect to either the user or default bus --help Show this message and exit. Commands: @@ -28,8 +28,12 @@ Commands: subscribe Subscribe to state changes ``` -The interface is similar to the vanilla `plusdeck` CLI. However, there are a few differences: +The interface is similar to the vanilla CLI. However, there are a few differences: -1. By default, `plusdeckctl` will connect to the `system` bus. To connect to the local bus, set the `--user` flag. -2. Configuration commands do not reload `plusdeckctl`'s configuration. Instead, they will update the relevant config file, and show the differences between the file config and the service's loaded config. -3. If the config file isn't owned by the user, `plusdeckctl` will attempt to run editing commands with `sudo`. +1. By default, the DBus client CLI will connect to the default bus. To connect to the user session bus, set the `--user` flag. To connect to the system bus, set the `--system` flag. +2. Configuration commands do not reload the service's configuration. Instead, they will update the relevant config file, and show the differences between the file config and the service's loaded config. +3. If the config file isn't owned by the user, the client CLI will attempt to run editing commands with `sudo`. + +## Installing the `plusdeck-dbus` Shim + +Included in this project is `./bin/plusdeck-dbus`, a script that you can add to your PATH for convenience. If you primarily interact with the device through DBus, you may want to name this `plusdeck` on your system. diff --git a/docs/dbus/index.md b/docs/dbus/index.md index fd3161e..e30f1b6 100644 --- a/docs/dbus/index.md +++ b/docs/dbus/index.md @@ -1,5 +1,5 @@ # DBus Support -The `plusdeck` library includes a DBus interface, service and client. This service allows for multitenancy on Linux - the centralized service controls the serial bus, and clients (including `plusdeckctl`) can connect to the service. +The `plusdeck` library includes a DBus interface, service and client. This service allows for multitenancy on Linux - the centralized service controls the serial bus, and clients (including `python3 -m plusdeck.dbus.client`) can connect to the service. -For information on the API, visit [the API docs for `plusdeck.dbus`](../api/plusdeck.dbus.md). +For information on the API, visit [the API docs for dbus](../api/plusdeck.dbus/index.md): diff --git a/docs/dbus/service.md b/docs/dbus/service.md index 5b6f52b..a7f27c3 100644 --- a/docs/dbus/service.md +++ b/docs/dbus/service.md @@ -1,8 +1,8 @@ # DBus Service -`plusdeck` includes a dbus service, which can be started with the `plusdeckctl` CLI tool. +`plusdeck` includes a dbus service, which can be started either through SystemD or directly through the command line. -## Starting the Service +## Starting the Service with SystemD `plusdeck` ships with a systemd unit that configures the service as a Dbus service. To set up the service, run: @@ -13,21 +13,25 @@ sudo systemctl start plusdeck # optional This unit will start on the `system` bus, under the root user. -## Running `plusdeckd` Directly +## Running the Service Directly -The DBus service can be launched directly using `plusdeckd`: +The DBus service can be launched directly using `python3 -m plusdeck.dbus.service`: ```sh -$ plusdeckd --help -Usage: plusdeckd [OPTIONS] +$ python3 -m plusdeck.dbus.service --help +Usage: python3 -m plusdeck.dbus.service [OPTIONS] Expose the Plus Deck 2C PC Cassette Deck as a DBus service. Options: + --global / --no-global Load the global config file at + /etc/plusdeck.yaml (default true when + called with sudo) -C, --config-file PATH A path to a config file --log-level [DEBUG|INFO|WARNING|ERROR|CRITICAL] Set the log level + --user / --system Connect to either the user or system bus --help Show this message and exit. ``` -In most cases, this can be called without arguments. By default, `plusdeckd` will listen on the `system` bus and load the global config file (`/etc/plusdeck.yml`) if launched as root; and otherwise listen on the `user` bus and load the user's config file (`~/.config/plusdeck.yml`). +In most cases, this can be called without arguments. By default, the service will listen on the `system` bus and load the global config file (`/etc/plusdeck.yml`) if launched as root; and otherwise listen on the `user` bus and load the user's config file (`~/.config/plusdeck.yml`). From 97f6709fba0ce8eeb38d8b9237dafef60925edb9 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 16:56:33 -0800 Subject: [PATCH 15/24] Update access docs --- docs/{dialout.md => access.md} | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) rename docs/{dialout.md => access.md} (58%) diff --git a/docs/dialout.md b/docs/access.md similarity index 58% rename from docs/dialout.md rename to docs/access.md index 040a076..fd8bcb5 100644 --- a/docs/dialout.md +++ b/docs/access.md @@ -1,6 +1,14 @@ -# Dialout +# Access and Permissions -In Linux, by default, accessing serial ports requires `sudo`. This is inconvenient - you probably want your current user to have acccess without using `sudo`. +In Linux, by default, accessing serial ports requires `sudo`. This is inconvenient - you probably want your current user to have access without using `sudo`. There are two ways to manage this access: either through the DBus service, or with the `dialout` group. + +## DBus + +The DBus service has the advantage of more fine-grained access control. However, it is only supported in Linux. + +For more information, see [DBus Access and Permissions](./dbus/access.md) + +## Dialout Typically, Linux serial ports are generally owned by `root` and are attached to the `dialout` group, with permissions such that members of the `dialout` group may read and write to the port. From d3f60ec45f13fbed3f6bdf09cbceac4c852c2226 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 16:56:48 -0800 Subject: [PATCH 16/24] Update development docs, justfile --- docs/development.md | 35 +++++++++++++++++++++++++++++++++-- justfile | 14 +++++++++++--- scripts/integration.sh | 2 +- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/docs/development.md b/docs/development.md index 705cc4e..b50c4ec 100644 --- a/docs/development.md +++ b/docs/development.md @@ -46,8 +46,10 @@ ### Interactive - `run` - Thin wrapper around `uv run` -- `start` - Run `plusdeck` CLI -- `jupyterlab` - Run jupyterlab +- `client` - Run `plusdeck` serial client CLI +- `service` - Run `plusdeck.dbus.service` DBus service on user session bus +- `dbus-client` - Run `plusdeck.dbus.client` DBus client CLI on user session bus +- `console` - Run a Python repl - `shell` - Start a bash shell with a sourced virtualenv ### Other @@ -56,6 +58,35 @@ - `docs` - Serve the mkdocs documentation - `publish` - Run all publish tasks +## Integration Tests + +You can run integration tests with `just integration`. It optionally takes arguments. You can show them with `just integration --help`: + +``` +./scripts/integration.sh --help +USAGE: ./scripts/integration.sh [OPTIONS] [COMPONENTS] + +Run integration tests for the supplied components. By default, runs client tests. + +Components: + client Run plusdeck client integration tests + dbus Start plusdeck dbus integration tests + +Options: + --help Show this help text + --snapshot-update Update snapshots + --system Run any dbus tests against the system bus + + Other options are passed to pytest. + +Environment: + PLUSDECK_CONFIG_FILE Use an alternative config file. The default is + ./tests/fixtures/plusdeck.yaml. + PLUSDECK_LOG_LEVEL +``` + +To run standard client tests, you can do `just integration`. For DBus tests, do `just integration dbus`. + ## CHANGELOG.md When submitting features, be sure to update the changelog! diff --git a/justfile b/justfile index b02a717..a21e4ca 100644 --- a/justfile +++ b/justfile @@ -55,9 +55,17 @@ clean-compile: run *argv: uv run {{ argv }} -# Run the plusdeck cli -start *argv: - uv run -- plusdeck {{ argv }} +# Run plusdeck client cli +client *argv: + uv run -- python -m plusdeck {{ argv }} + +# Run plusdeck.dbus.service cli +service *argv: + uv run -- python -m plusdeck.dbus.service --user {{ argv }} + +# Run plusdeck.dbus.client cli +dbus-client *argv: + uv run -- python -m plusdeck.dbus.client --user {{ argv }} # # Development tooling - linting, formatting, etc diff --git a/scripts/integration.sh b/scripts/integration.sh index 6d8c12e..45c133c 100755 --- a/scripts/integration.sh +++ b/scripts/integration.sh @@ -7,7 +7,7 @@ ARGV=() HELP='USAGE: ./scripts/integration.sh [OPTIONS] [COMPONENTS] -Run integration tests for the supplied components. By default, runs cli tests. +Run integration tests for the supplied components. By default, runs client tests. Components: client Run plusdeck client integration tests From 773d946e55731d32f87f939ceabcc95278ce9448 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 16:56:57 -0800 Subject: [PATCH 17/24] Update CLI docs --- docs/cli.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/cli.md b/docs/cli.md index fa7b880..9dcafa6 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,10 +1,10 @@ # Command Line Interface -The `plusdeck` CLI allows for direct control of the Plus Deck 2C over its serial port: +This library has a CLI, which you can run like so: ```sh -$ plusdeck --help -Usage: plusdeck [OPTIONS] COMMAND [ARGS]... +$ python3 -m plusdeck --help +Usage: python3 -m plusdeck [OPTIONS] COMMAND [ARGS]... Control your Plus Deck 2C tape deck. @@ -32,3 +32,11 @@ Commands: ``` For more information, use the `--help` flag for any command. + +## Output Format + +This CLI supports two output formats: `text` and `json`. The former will output a human-readable format, and the latter will output JSON. This is mostly relevant for the `subscribe` command. + +## Installing the `plusdeck` Shim + +Included in this project is `./bin/plusdeck`, a script that you can add to your PATH for convenience. From feaba683a5a09209d8b903187d0c3eb31d0ae53e Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 16:57:12 -0800 Subject: [PATCH 18/24] Update install docs --- docs/install.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/install.md b/docs/install.md index 9a00d6c..1624495 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,20 +1,32 @@ # Install +`plusdeck` is released as a PyPI package, a series of COPR packages, and a GitHub release. + +## Python Package + `plusdeck` is a Python package, and therefore can be installed [from PyPi](https://pypi.org/project/plusdeck/), for instance with `pip`: ```sh pip install plusdeck ``` -To install support for DBus, run: +This package contains the Python library, with the CLIs exposed with Python's `-m` flag (ie. `python3 -m plusdeck`). -```sh -pip install plusdeck[dbus] -``` +## COPR Packages -In addition, I have a Fedora package on COPR, which can be installed like so: +I package `plusdeck` for Fedora on COPR. It can be installed like so: ```sh sudo dnf copr enable jfhbrook/joshiverse sudo dnf install plusdeck ``` + +This package installs the Python package via `python-plusdeck`, configures the systemd service, and includes a bin called `plusdeck` that wraps `python3 -m plusdeck.dbus.client`. + +## GitHub Release + +`plusdeck` is also published as a GitHub release: + + + +These releases simply contain packaged source code, and will mostly be useful for package authors. From 4e10e41c7b7954da1f943c30461f8543f6ed8631 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 17:01:32 -0800 Subject: [PATCH 19/24] Docs fixes --- docs/api/plusdeck.dbus/index.md | 2 +- plusdeck/dbus/domain.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/api/plusdeck.dbus/index.md b/docs/api/plusdeck.dbus/index.md index d8062d6..4b0c656 100644 --- a/docs/api/plusdeck.dbus/index.md +++ b/docs/api/plusdeck.dbus/index.md @@ -1,6 +1,6 @@ # DBus API Overview -The `plusdeck` library includes a DBus service and client. This service allows for multitenancy on Linux - the centralized service controls the serial bus, and clients - including `plusdeckctl` - can connect to the service. +The `plusdeck` library includes a DBus service and client. This service allows for multitenancy on Linux - the centralized service controls the serial bus, and clients - including `python3 -m plusdeck.dbus.client` - can connect to the service. The DBus APIs largely depend on the [sdbus](https://pypi.org/project/sdbus/) Python library, which in turn depends on the [sd-bus](https://www.freedesktop.org/software/systemd/man/latest/sd-bus.html) library. This means that, effectively, the DBus API is only available on Linux. `sdbus` is therefore an optional dependency, under the `dbus` extra. diff --git a/plusdeck/dbus/domain.py b/plusdeck/dbus/domain.py index 8243e55..6d29a23 100644 --- a/plusdeck/dbus/domain.py +++ b/plusdeck/dbus/domain.py @@ -211,8 +211,16 @@ class StateM: @staticmethod def pack(state: State) -> StateT: + """ + Pack `State` to `StateT`. + """ + return state.name @staticmethod def unpack(state: StateT) -> State: + """ + Unpack `StateT` to `State`. + """ + return State[state] From 7953672c97e188842d255e87e52c2f1f278c2969 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Wed, 9 Apr 2025 17:09:32 -0800 Subject: [PATCH 20/24] Update CHANGELOG --- CHANGELOG.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47c9567..a17b1e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,25 @@ -yyyy/mm/dd Version x.y.z-1 +yyyy/mm/dd Version 5.0.0-1 ------------------------ -- Include generated DBus interface docs -- Fix links in documentation -- CLI respects `CRYSTALFONTZ_CONFIG_FILE` environment variable -- Remove `tox` from development tools -- Consistently licensed as MPL-2.0 -- Improved PyPI classifiers +- CLI changes: + - Main CLI respects `PLUSDECK_CONFIG_FILE` environment variable + - **BREAKING:** `plusdeck`, `plusdeckd` and `plusdeckctl` have been removed from the Python package in favor of `python3 -m plusdeck`, `python3 -m plusdeck.dbus.service` and `python3 -m plusdeck.dbus.client`, respectively + - Optional alias scripts for `plusdeck`, `plusdeck-service` and `plusdeck-dbus` included in the `./bin` folder + - DBus service CLI includes a `--system/--user` flag for explicitly selecting the bus + - **BREAKING:** DBus client CLI now uses `--user/--default` flag for selecting the bus +- DBus API Changes: + - **BREAKING:** Root `plusdeck.dbus` no longer includes convenience exports + - Addition of `plusdeck.dbus.domain` module for domain mapping + - Addition of `plusdeck.dbus.select` module for selecting the DBus bus +- Testing changes: + - Additional integration test for DBus + - Remove `tox` from development tools +- Documentation improvements: + - Include generated DBus interface docs + - Fix links in documentation + - General overhaul based on lessons from `crystalfontz` +- Packaging & Licensing + - **BREAKING:** Consistently licensed as MPL-2.0 + - Improved PyPI classifiers 2025/02/09 Version 4.0.1-1 -------------------------- From 289e61fecd06d13207162ceff6b1c7dcdbdd8cbf Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Thu, 10 Apr 2025 06:56:35 -0800 Subject: [PATCH 21/24] Update systemd unit --- systemd/plusdeck.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemd/plusdeck.service b/systemd/plusdeck.service index b67268c..ebc98e0 100644 --- a/systemd/plusdeck.service +++ b/systemd/plusdeck.service @@ -6,7 +6,7 @@ After=dbus.socket [Service] Type=dbus BusName=org.jfhbrook.plusdeck -ExecStart=/usr/bin/plusdeckd +ExecStart=/usr/bin/python3 -m plusdeck.dbus.service --system Restart=on-failure [Install] From 735483d52ec50424da09d80d5561f788eaba8dab Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Thu, 10 Apr 2025 07:08:47 -0800 Subject: [PATCH 22/24] Tests/integration pass --- tests/conftest.py | 6 +----- tests/integration/test_dbus.py | 8 ++++---- uv.lock | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index cb18ea2..8083bb6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -41,12 +41,8 @@ def environment(monkeypatch, config_file: str, port: str) -> Dict[str, str]: def config_file(monkeypatch) -> str: if "PLUSDECK_CONFIG_FILE" in os.environ: return os.environ["PLUSDECK_CONFIG_FILE"] - path = Path(__file__).parent / "fixtures/crystalfontz.yaml" - - def default_file() -> str: - return str(path) - monkeypatch.setattr(plusdeck.config, "default_file", default_file) + path = Path(__file__).parent / "fixtures/crystalfontz.yaml" return str(path) diff --git a/tests/integration/test_dbus.py b/tests/integration/test_dbus.py index fcd99a1..62272c2 100644 --- a/tests/integration/test_dbus.py +++ b/tests/integration/test_dbus.py @@ -3,10 +3,10 @@ from tests.helpers import Cli -def test_listen(dbus_cli, confirm) -> None: - with dbus_cli.bg("listen", quiet=False): +def test_subscribe(dbus_cli, confirm) -> None: + with dbus_cli.bg("subscribe", quiet=False): confirm("Mess with the Plusdeck. Are events showing up?") -def test_listen_for(dbus_cli: Cli) -> None: - dbus_cli("listen", "--for", "1.0") +def test_subscribe_for(dbus_cli: Cli) -> None: + dbus_cli("subscribe", "--for", "1.0") diff --git a/uv.lock b/uv.lock index 2794c5a..c4500d2 100644 --- a/uv.lock +++ b/uv.lock @@ -564,7 +564,7 @@ wheels = [ [[package]] name = "ipywidgets" -version = "8.1.5" +version = "8.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "comm" }, @@ -573,9 +573,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/4c/dab2a281b07596a5fc220d49827fe6c794c66f1493d7a74f1df0640f2cc5/ipywidgets-8.1.5.tar.gz", hash = "sha256:870e43b1a35656a80c18c9503bbf2d16802db1cb487eec6fab27d683381dde17", size = 116723 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/98/4074d9cb7e89f7ee387b41e9a4b74c8e0d6196e90b910af1cc674e1cdd3d/ipywidgets-8.1.6.tar.gz", hash = "sha256:d8ace49c66f14419fc66071371b99d01bed230bbc15d8a60233b18bfbd782851", size = 116764 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl", hash = "sha256:3290f526f87ae6e77655555baba4f36681c555b8bdbbff430b70e52c34c86245", size = 139767 }, + { url = "https://files.pythonhosted.org/packages/53/b8/62952729573d983d9433faacf62a52ee2e8cf46504418061ad1739967abe/ipywidgets-8.1.6-py3-none-any.whl", hash = "sha256:446e7630a1d025bdc7635e1169fcc06f2ce33b5bd41c2003edeb4a47c8d4bbb1", size = 139808 }, ] [[package]] @@ -837,11 +837,11 @@ wheels = [ [[package]] name = "jupyterlab-widgets" -version = "3.0.13" +version = "3.0.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/73/fa26bbb747a9ea4fca6b01453aa22990d52ab62dd61384f1ac0dc9d4e7ba/jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed", size = 203556 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/94/766b8199e8a902a4c5ee12a9407a348bbabe9fa22400758576b153d17d8e/jupyterlab_widgets-3.0.14.tar.gz", hash = "sha256:bad03e59546869f026e537e0d170e454259e6dc7048e14041707ca31e523c8a1", size = 203815 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/93/858e87edc634d628e5d752ba944c2833133a28fa87bb093e6832ced36a3e/jupyterlab_widgets-3.0.13-py3-none-any.whl", hash = "sha256:e3cda2c233ce144192f1e29914ad522b2f4c40e77214b0cc97377ca3d323db54", size = 214392 }, + { url = "https://files.pythonhosted.org/packages/64/7a/f2479ba401e02f7fcbd3fc6af201eac888eaa188574b8e9df19452ab4972/jupyterlab_widgets-3.0.14-py3-none-any.whl", hash = "sha256:54c33e3306b7fca139d165d6190dc6c0627aafa5d14adfc974a4e9a3d26cb703", size = 213999 }, ] [[package]] @@ -1906,11 +1906,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.13.1" +version = "4.13.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/ad/cd3e3465232ec2416ae9b983f27b9e94dc8171d56ac99b345319a9475967/typing_extensions-4.13.1.tar.gz", hash = "sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff", size = 106633 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/c5/e7a0b0f5ed69f94c8ab7379c599e6036886bffcde609969a5325f47f1332/typing_extensions-4.13.1-py3-none-any.whl", hash = "sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69", size = 45739 }, + { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, ] [[package]] @@ -2026,9 +2026,9 @@ wheels = [ [[package]] name = "widgetsnbextension" -version = "4.0.13" +version = "4.0.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/fc/238c424fd7f4ebb25f8b1da9a934a3ad7c848286732ae04263661eb0fc03/widgetsnbextension-4.0.13.tar.gz", hash = "sha256:ffcb67bc9febd10234a362795f643927f4e0c05d9342c727b65d2384f8feacb6", size = 1164730 } +sdist = { url = "https://files.pythonhosted.org/packages/41/53/2e0253c5efd69c9656b1843892052a31c36d37ad42812b5da45c62191f7e/widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af", size = 1097428 } wheels = [ - { url = "https://files.pythonhosted.org/packages/21/02/88b65cc394961a60c43c70517066b6b679738caf78506a5da7b88ffcb643/widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71", size = 2335872 }, + { url = "https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575", size = 2196503 }, ] From 7f5fbb988305d0b16b8b89f57792695971370668 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Thu, 10 Apr 2025 07:11:19 -0800 Subject: [PATCH 23/24] Include installing dbus extra --- docs/install.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/install.md b/docs/install.md index 1624495..1128b25 100644 --- a/docs/install.md +++ b/docs/install.md @@ -10,6 +10,12 @@ pip install plusdeck ``` +To install support for DBus, run: + +```sh +pip install plusdeck[dbus] +``` + This package contains the Python library, with the CLIs exposed with Python's `-m` flag (ie. `python3 -m plusdeck`). ## COPR Packages From 2ff7db982aa4c4c53f3c6b397cd5ec1d5fc1e2c1 Mon Sep 17 00:00:00 2001 From: Josh Holbrook Date: Thu, 10 Apr 2025 07:20:59 -0800 Subject: [PATCH 24/24] Domain tests --- .../__snapshots__/test_config.ambr} | 0 tests/dbus/__snapshots__/test_domain.ambr | 22 ++++++++ tests/{test_dbus.py => dbus/test_config.py} | 8 +-- tests/dbus/test_domain.py | 56 +++++++++++++++++++ 4 files changed, 79 insertions(+), 7 deletions(-) rename tests/{__snapshots__/test_dbus.ambr => dbus/__snapshots__/test_config.ambr} (100%) create mode 100644 tests/dbus/__snapshots__/test_domain.ambr rename tests/{test_dbus.py => dbus/test_config.py} (83%) create mode 100644 tests/dbus/test_domain.py diff --git a/tests/__snapshots__/test_dbus.ambr b/tests/dbus/__snapshots__/test_config.ambr similarity index 100% rename from tests/__snapshots__/test_dbus.ambr rename to tests/dbus/__snapshots__/test_config.ambr diff --git a/tests/dbus/__snapshots__/test_domain.ambr b/tests/dbus/__snapshots__/test_domain.ambr new file mode 100644 index 0000000..d0ef75c --- /dev/null +++ b/tests/dbus/__snapshots__/test_domain.ambr @@ -0,0 +1,22 @@ +# serializer version: 1 +# name: test_domain_pack_unpack[1.0-OptFloatM] + 1.0 +# --- +# name: test_domain_pack_unpack[1.0-TimeoutM] + 1.0 +# --- +# name: test_domain_pack_unpack[None-OptFloatM] + -1.0 +# --- +# name: test_domain_pack_unpack[None-TimeoutM] + -1.0 +# --- +# name: test_domain_pack_unpack[State.PLAYING_A-StateM] + 'PLAYING_A' +# --- +# name: test_domain_pack_unpack[entity5-ConfigM] + tuple( + '/etc/crystalfontz.yaml', + '/dev/ttyUSB1', + ) +# --- diff --git a/tests/test_dbus.py b/tests/dbus/test_config.py similarity index 83% rename from tests/test_dbus.py rename to tests/dbus/test_config.py index 55ad98f..f41ecfd 100644 --- a/tests/test_dbus.py +++ b/tests/dbus/test_config.py @@ -3,16 +3,11 @@ import pytest from plusdeck.config import Config, GLOBAL_FILE - -try: - from plusdeck.dbus.config import StagedConfig -except ImportError: - StagedConfig = None +from plusdeck.dbus.config import StagedConfig cfg_cls = cast(Any, Config) -@pytest.mark.skipif(StagedConfig is None, reason="dbus is not installed") @pytest.mark.parametrize( "active_config,target_config", [ @@ -32,7 +27,6 @@ def test_staged_config_as_dict(active_config, target_config, snapshot) -> None: assert staged.as_dict() == snapshot -@pytest.mark.skipif(StagedConfig is None, reason="dbus is not installed") @pytest.mark.parametrize( "active_config,target_config", [ diff --git a/tests/dbus/test_domain.py b/tests/dbus/test_domain.py new file mode 100644 index 0000000..f794e96 --- /dev/null +++ b/tests/dbus/test_domain.py @@ -0,0 +1,56 @@ +from typing import Any, Callable, cast, List, Union + +import pytest + +from plusdeck.client import State +from plusdeck.config import Config +from plusdeck.dbus.domain import ( + ConfigM, + OptFloatM, + OptStrM, + StateM, + struct, + t, + TimeoutM, + TypeProtocol, +) + + +@pytest.mark.parametrize( + "fn,args,signature", + [ + (t, ["s", "b", OptStrM, OptFloatM], "sbsd"), + (struct, ["sss"], "(sss)"), + ], +) +def test_signature_fn( + fn: Callable[[Any], str], args: List[Union[str, TypeProtocol]], signature: str +) -> None: + assert fn(*args) == signature + + +@pytest.mark.parametrize( + "entity,map_cls", + [ + (1.0, OptFloatM), + (None, OptFloatM), + (1.0, TimeoutM), + (None, TimeoutM), + (State.PLAYING_A, StateM), + ( + cast(Any, Config)( + file="/etc/crystalfontz.yaml", + port="/dev/ttyUSB1", + ), + ConfigM, + ), + ], +) +def test_domain_pack_unpack(entity: Any, map_cls: Any, snapshot) -> None: + packed = map_cls.pack(entity) + + assert packed == snapshot + + if hasattr(map_cls, "unpack"): + unpacked = map_cls.unpack(packed) + assert unpacked == entity