From b0dc60e6ff105cbd734ac3e71303dce5cce0a36d Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 8 Jan 2026 16:23:04 +0100 Subject: [PATCH 01/78] use cli to start service only --- .pre-commit-config.yaml | 14 ++++---- src/service/cli.py | 57 ++++++++++++------------------ tests/config/service_settings.yaml | 3 +- 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b3a53b..2dd2d24 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,11 @@ repos: - id: check-symlinks - id: check-toml +- repo: https://github.com/myint/autoflake + rev: v2.3.1 + hooks: + - id: autoflake + args: [--in-place, --remove-all-unused-imports, --remove-unused-variables] # Type checking - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.18.2 @@ -37,9 +42,8 @@ repos: rev: v2.3.2 hooks: - id: autopep8 - args: [--max-line-length=110, --diff] + args: [--max-line-length=110, --in-place] -# Linting - repo: https://github.com/PyCQA/flake8 rev: 7.3.0 hooks: @@ -59,12 +63,6 @@ repos: - id: bandit exclude: ^tests/ -# Unused code detection -- repo: https://github.com/jendrikseipp/vulture - rev: v2.14 - hooks: - - id: vulture - args: [--min-confidence=70, src/] # Log and syntax pattern checks - repo: https://github.com/pre-commit/pygrep-hooks diff --git a/src/service/cli.py b/src/service/cli.py index 0e7e356..36b038a 100644 --- a/src/service/cli.py +++ b/src/service/cli.py @@ -185,44 +185,33 @@ def get_status(settings_path: Path) -> None: def main() -> None: setup_logging() - parser = argparse.ArgumentParser(description="DetectMate Service CLI") - subparsers = parser.add_subparsers(dest="command", required=True) - - # Start command - start_parser = subparsers.add_parser("start", help="Start the service") - start_parser.add_argument("--settings", required=False, type=Path, help="Service settings YAML file") - start_parser.add_argument("--config", type=Path, help="Component configuration YAML file") - - # Stop command - stop_parser = subparsers.add_parser("stop", help="Stop the service") - stop_parser.add_argument("--settings", required=True, type=Path, help="Service settings YAML file") - - # Status command - status_parser = subparsers.add_parser("status", help="Get service status") - status_parser.add_argument("--settings", required=True, type=Path, help="Service settings YAML file") - - # Reconfigure command - reconfigure_parser = subparsers.add_parser("reconfigure", help="Reconfigure service configs") - reconfigure_parser.add_argument("--settings", required=True, type=Path, - help="Service settings YAML file (to get manager address)") - reconfigure_parser.add_argument("--config", required=True, type=Path, help="New configuration YAML file") - reconfigure_parser.add_argument("--persist", action="store_true", - help="Persist changes to parameter file") + parser = argparse.ArgumentParser(description="DetectMate Service Launcher") + parser.add_argument("--settings", type=Path, help="Path to service settings YAML") + parser.add_argument("--config", type=Path, help="Path to component config YAML") args = parser.parse_args() + # Load settings + if args.settings and args.settings.exists(): + settings = ServiceSettings.from_yaml(args.settings) + else: + settings = ServiceSettings() + + if args.config: + settings.config_file = args.config + + # Initialize and run + # Note: Service now inherits from Service, not CLIService + service = Service(settings=settings) + try: - if args.command == "start": - start_service(args.settings, args.config) - elif args.command == "stop": - stop_service(args.settings) - elif args.command == "status": - get_status(args.settings) - elif args.command == "reconfigure": - reconfigure_service(args.settings, args.config, args.persist) - except Exception as e: - logger.error(f"Command failed: {e}") - sys.exit(1) + with service: + # This blocks until _stop_event.set() or KeyboardInterrupt + service.run() + except KeyboardInterrupt: + logger.info("Shutdown signal received (Ctrl+C)...") + finally: + logger.info("Clean exit.") if __name__ == "__main__": diff --git a/tests/config/service_settings.yaml b/tests/config/service_settings.yaml index 93bdee6..4681075 100644 --- a/tests/config/service_settings.yaml +++ b/tests/config/service_settings.yaml @@ -1,4 +1,5 @@ -component_type: "my_detector" +component_type: "detectors.dummy_detector.DummyDetector" +component_config_class: "detectors.dummy_detector.DummyDetectorConfig" component_name: "detector-1" manager_addr: "ipc:///tmp/detector_cmd.ipc" engine_addr: "ipc:///tmp/detector_engine.ipc" From 6806200a065832d3ce3cdeadb6744d0be653a97a Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 8 Jan 2026 16:37:33 +0100 Subject: [PATCH 02/78] add webserver --- src/service/features/web/__init__.py | 0 src/service/features/web/router.py | 44 ++++++++++++++++++++++++++++ src/service/features/web/server.py | 39 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 src/service/features/web/__init__.py create mode 100644 src/service/features/web/router.py create mode 100644 src/service/features/web/server.py diff --git a/src/service/features/web/__init__.py b/src/service/features/web/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/service/features/web/router.py b/src/service/features/web/router.py new file mode 100644 index 0000000..ee94605 --- /dev/null +++ b/src/service/features/web/router.py @@ -0,0 +1,44 @@ +from fastapi import APIRouter, Depends +from typing import Any, Dict +from pydantic import BaseModel + +router = APIRouter(prefix="/admin") + + +class ReconfigPayload(BaseModel): + config: Dict[str, Any] + persist: bool = False + + +def get_service() -> Any: + # This gets overridden by the server setup in server.py + raise NotImplementedError + + +@router.post("/start") # type: ignore[misc] +async def admin_start(service: Any = Depends(get_service)) -> Dict[str, Any]: + return {"message": service.start()} + + +@router.post("/stop") # type: ignore[misc] +async def admin_stop(service: Any = Depends(get_service)) -> Dict[str, Any]: + return {"message": service.stop()} + + +@router.get("/status") # type: ignore[misc] +async def admin_status(service: Any = Depends(get_service)) -> Any: + return service._create_status_report(getattr(service, "_running", False)) + + +@router.post("/reconfigure") # type: ignore[misc] +async def admin_reconfigure(payload: ReconfigPayload, service: Any = Depends(get_service)) -> Dict[str, Any]: + # format the string to match what internal reconfigure() expects + import json + cmd_str = f"{'persist ' if payload.persist else ''}{json.dumps(payload.config)}" + return {"message": service.reconfigure(cmd_str)} + + +@router.post("/shutdown") # type: ignore[misc] +async def admin_shutdown(service: Any = Depends(get_service)) -> Dict[str, Any]: + # Kills the entire process + return {"message": service.shutdown()} diff --git a/src/service/features/web/server.py b/src/service/features/web/server.py new file mode 100644 index 0000000..ebbdd24 --- /dev/null +++ b/src/service/features/web/server.py @@ -0,0 +1,39 @@ +from __future__ import annotations +import threading +from typing import TYPE_CHECKING +import uvicorn +from fastapi import FastAPI +from service.features.web.router import router, get_service + + +if TYPE_CHECKING: + from service.core.service import Service + + +class WebServer(threading.Thread): + # Wraps a FastAPI web server in a thread + def __init__(self, service: Service) -> None: + super().__init__(name="WebServerThread", daemon=True) + self.service = service + self.app = FastAPI(title=f"DetectMate Admin - {service.component_id}") + + # Inject service instance into the router + self.app.include_router(router) + self.app.dependency_overrides[get_service] = lambda: self.service + + self.config = uvicorn.Config( + app=self.app, + host=service.settings.http_host, + port=service.settings.http_port, + log_level="info", + ) + self.server = uvicorn.Server(self.config) + self.server.install_signal_handlers = False # Importnt for running in thread, + # pythons signal module only allows the Main Thread to resgister signal handlers + # uvicrons default behaviour to listen for shutdown signals will raise ValueError + + def run(self) -> None: + self.server.run() + + def stop(self) -> None: + self.server.should_exit = True From 874c2215733395cbb3f52f1721bfd6b621b71cb5 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 8 Jan 2026 16:38:33 +0100 Subject: [PATCH 03/78] add webserver settings --- src/service/settings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/service/settings.py b/src/service/settings.py index bd75609..0b1e87b 100644 --- a/src/service/settings.py +++ b/src/service/settings.py @@ -53,6 +53,10 @@ class ServiceSettings(BaseSettings): # timeout for output dials. Used with blocking dial in Engine out_dial_timeout: int = 1000 # milliseconds + http_enabled: bool = True + http_host: str = "0.0.0.0" + http_port: int = 8000 + model_config = SettingsConfigDict( env_prefix="DETECTMATE_", # DETECTMATE_LOG_LEVEL etc. env_nested_delimiter="__", # DETECTMATE_DETECTOR__THRESHOLD From 8de5ffdb8905c1b5e994fef92c56500f9c54c01f Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 8 Jan 2026 16:39:04 +0100 Subject: [PATCH 04/78] change start stop run and shutdown logic of service and engine --- src/service/core.py | 57 ++++++++++++++++++++++++++-------- src/service/features/engine.py | 9 +++++- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index bd854f9..fc7c916 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -14,6 +14,7 @@ from service.features.engine import Engine, EngineException from service.features.component_loader import ComponentLoader from service.features.config_loader import ConfigClassLoader +from service.features.web.server import WebServer from library.processor import BaseProcessor from detectmatelibrary.common.core import CoreComponent, CoreConfig @@ -21,6 +22,7 @@ class ServiceProcessorAdapter(BaseProcessor): """Adapter class to use a Service's process method as a BaseProcessor.""" + def __init__(self, service: Service) -> None: self.service = service @@ -55,7 +57,10 @@ def __init__( # Prepare attributes & logger first self.settings: ServiceSettings = settings self.component_id: str = settings.component_id # type: ignore[assignment] - self._stop_event: threading.Event = threading.Event() + self._service_exit_event: threading.Event = threading.Event() + self.web_server = None + if self.settings.http_enabled: + self.web_server = WebServer(self) # set component_type if hasattr(self, 'component_type'): # prioritize class attribute over settings @@ -163,20 +168,38 @@ def setup_io(self) -> None: self.log.info("setup_io: ready to process messages") def run(self) -> None: - """Kick off the engine, then await stop.""" - if not getattr(self, '_running', False): - self.log.info(self.start()) # start engine loop + """Starts the WebServer and waits for the shutdown signal.""" + # 1. Start Web Server + if self.web_server: + self.log.info(f"HTTP Admin active at {self.settings.http_host}:{self.settings.http_port}") + self.web_server.start() + + # 2. Engine Start logic + if self.settings.engine_autostart: + self.log.info("Auto-starting engine...") + self.start() else: - self.log.debug("Engine already running") - self._stop_event.wait() - if getattr(self, '_running', False): # don't call stop() again if it was already called by a command - self.log.info(self.stop()) # ensure engine thread is joined + self.log.info("Engine idle. Awaiting /admin/start") + + # 3. Wait for the global shutdown event + self._service_exit_event.wait() + + # 4. Final teardown + if self.web_server: + self.web_server.stop() + if getattr(self, "_running", False): + Engine.stop(self) else: self.log.debug("Engine already stopped") @manager_command() def start(self) -> str: """Expose engine start as a command.""" + # Check if already running to avoid redundant starts + if getattr(self, '_running', False): + msg = "Ignored: Engine is already running" + self.log.debug(msg) + return msg msg = Engine.start(self) self.log.info(msg) return msg @@ -184,10 +207,10 @@ def start(self) -> str: @manager_command() def stop(self) -> str: """Stop both the engine loop and mark the component to exit.""" - if self._stop_event.is_set(): - return "already stopping or stopped" + if not getattr(self, "_running", False): + return "engine already stopped" + self.log.info("Stop command received") - self._stop_event.set() try: Engine.stop(self) self.log.info("Engine stopped successfully") @@ -255,7 +278,15 @@ def reconfigure(self, cmd: str | None = None) -> str: except Exception as e: return f"reconfigure: error - {e}" + @manager_command() + def shutdown(self) -> str: + """Stops everything and exits the process.""" + self.log.info("Process shutdown initiated.") + self._service_exit_event.set() + return "Service is shutting down..." + # helpers + def _build_logger(self) -> logging.Logger: Path(self.settings.log_dir).mkdir(parents=True, exist_ok=True) name = f"{self.component_type}.{self.component_id}" @@ -333,7 +364,7 @@ def __exit__( _exc_val: BaseException | None, _exc_tb: TracebackType | None ) -> Literal[False]: - if not self._stop_event.is_set(): # only stop if not already stopped - self.stop() # shut down gracefully + if not self._service_exit_event.is_set(): # only stop if not already stopped + self.shutdown() # shut down gracefully self._close_manager() # close REP socket & thread return False # propagate exceptions diff --git a/src/service/features/engine.py b/src/service/features/engine.py index 5f29485..8fa90ec 100644 --- a/src/service/features/engine.py +++ b/src/service/features/engine.py @@ -15,7 +15,6 @@ class EngineException(Exception): """Custom exception for engine-related errors.""" - pass class DefaultProcessor(BaseProcessor): @@ -23,6 +22,7 @@ class DefaultProcessor(BaseProcessor): This is necessary to satisfy the abstract BaseProcessor requirement. """ + def __call__(self, raw: bytes) -> bytes | None: return raw @@ -124,6 +124,13 @@ def _setup_output_sockets(self) -> None: def start(self) -> str: if not self._running: self._running = True + # RECREATE THE THREAD if it's dead or doesn't exist + if not self._thread.is_alive(): + self._thread = threading.Thread( + target=self._run_loop, + name="EngineLoop", + daemon=True + ) self._thread.start() return "engine started" return "engine already running" From 6bd1b49eb3d232e8b9f0c327abdbb946e9762ac7 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 12 Jan 2026 12:14:21 +0100 Subject: [PATCH 05/78] always enable webserver --- src/service/core.py | 17 +++-------------- src/service/settings.py | 11 +++-------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index fc7c916..3a8d1df 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -10,7 +10,6 @@ from service.features.config_manager import ConfigManager from service.settings import ServiceSettings -from service.features.manager import Manager, manager_command from service.features.engine import Engine, EngineException from service.features.component_loader import ComponentLoader from service.features.config_loader import ConfigClassLoader @@ -46,7 +45,7 @@ def __call__(self, raw_message: bytes) -> bytes | None | Any: return None -class Service(Manager, Engine, ABC): +class Service(Engine, ABC): """Abstract base for every DetectMate service/component.""" def __init__( @@ -59,8 +58,7 @@ def __init__( self.component_id: str = settings.component_id # type: ignore[assignment] self._service_exit_event: threading.Event = threading.Event() self.web_server = None - if self.settings.http_enabled: - self.web_server = WebServer(self) + self.web_server = WebServer(self) # set component_type if hasattr(self, 'component_type'): # prioritize class attribute over settings @@ -118,9 +116,6 @@ def __init__( # Create processor instance self.processor = self.create_processor() - # now init Manager (opens REP socket & discovers commands) - Manager.__init__(self, settings=settings, logger=self.log) - # then init Engine with the processor (opens PAIR socket, may autostart) Engine.__init__(self, settings=settings, processor=self.processor, logger=self.log) @@ -192,7 +187,6 @@ def run(self) -> None: else: self.log.debug("Engine already stopped") - @manager_command() def start(self) -> str: """Expose engine start as a command.""" # Check if already running to avoid redundant starts @@ -204,7 +198,6 @@ def start(self) -> str: self.log.info(msg) return msg - @manager_command() def stop(self) -> str: """Stop both the engine loop and mark the component to exit.""" if not getattr(self, "_running", False): @@ -219,7 +212,6 @@ def stop(self) -> str: self.log.error("Failed to stop engine: %s", e) return f"error: failed to stop engine - {e}" - @manager_command() def status(self, cmd: str | None = None) -> str: """Comprehensive status report including settings and configs.""" if self.config_manager: @@ -239,7 +231,6 @@ def status(self, cmd: str | None = None) -> str: status_info = self._create_status_report(running) return json.dumps(status_info, indent=2) - @manager_command() def reconfigure(self, cmd: str | None = None) -> str: """Reconfigure service configurations dynamically.""" if not self.config_manager: @@ -278,7 +269,6 @@ def reconfigure(self, cmd: str | None = None) -> str: except Exception as e: return f"reconfigure: error - {e}" - @manager_command() def shutdown(self) -> str: """Stops everything and exits the process.""" self.log.info("Process shutdown initiated.") @@ -365,6 +355,5 @@ def __exit__( _exc_tb: TracebackType | None ) -> Literal[False]: if not self._service_exit_event.is_set(): # only stop if not already stopped - self.shutdown() # shut down gracefully - self._close_manager() # close REP socket & thread + self.shutdown() # shut down gracefully # close REP socket & thread return False # propagate exceptions diff --git a/src/service/settings.py b/src/service/settings.py index 0b1e87b..183cd87 100644 --- a/src/service/settings.py +++ b/src/service/settings.py @@ -38,11 +38,6 @@ class ServiceSettings(BaseSettings): log_to_file: bool = True log_level: str = "INFO" - # Manager (command) channel (REQ/REP) - manager_addr: str | None = "ipc:///tmp/detectmate.cmd.ipc" - manager_recv_timeout: int = 100 # milliseconds - manager_thread_join_timeout: float = 1.0 # seconds - # Engine channel (PAIR0) engine_addr: str | None = "ipc:///tmp/detectmate.engine.ipc" engine_autostart: bool = True @@ -53,8 +48,8 @@ class ServiceSettings(BaseSettings): # timeout for output dials. Used with blocking dial in Engine out_dial_timeout: int = 1000 # milliseconds - http_enabled: bool = True - http_host: str = "0.0.0.0" + # HTTP server (FastAPI) settings + http_host: str = "127.0.0.1" http_port: int = 8000 model_config = SettingsConfigDict( @@ -89,7 +84,7 @@ def _ensure_component_id(self) -> "ServiceSettings": # 2) No name: derive deterministically from addresses (also stable) # This stays the same as long as the addresses don't change. - base = f"{self.component_type}|{self.manager_addr or ''}|{self.engine_addr or ''}" + base = f"{self.component_type}|{self.engine_addr or ''}" self.component_id = self._generate_uuid_from_string(f"detectmate/{base}") return self From f8a6371ea8515d4daa054747acea80360b959190 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 12 Jan 2026 12:21:53 +0100 Subject: [PATCH 06/78] remove manager --- demo/config/detector_settings.yaml | 3 +- demo/config/ipc/detector_settings.yaml | 4 +- demo/config/ipc/parser_settings.yaml | 3 +- demo/config/ipc/reader_settings.yaml | 3 +- demo/config/parser_settings.yaml | 3 +- demo/config/reader_settings.yaml | 3 +- src/service/__init__.py | 5 - src/service/cli.py | 290 ++++++++++++------------- src/service/features/manager.py | 175 --------------- src/service/features/manager_socket.py | 57 ----- tests/config/service_settings.yaml | 3 +- tests/test_component_id.py | 6 +- tests/test_config_reading.py | 9 - 13 files changed, 156 insertions(+), 408 deletions(-) delete mode 100644 src/service/features/manager.py delete mode 100644 src/service/features/manager_socket.py diff --git a/demo/config/detector_settings.yaml b/demo/config/detector_settings.yaml index 7ab7a3e..687710f 100644 --- a/demo/config/detector_settings.yaml +++ b/demo/config/detector_settings.yaml @@ -1,7 +1,8 @@ component_type: "detectors.new_value_detector.NewValueDetector" component_config_class: "detectors.new_value_detector.NewValueDetectorConfig" component_name: "test-nvd" -manager_addr: "tcp://detector:8020" +http_host: "127.0.0.1" +http_port: 8020 engine_addr: "tcp://detector:8021" log_level: "DEBUG" log_dir: "./logs" diff --git a/demo/config/ipc/detector_settings.yaml b/demo/config/ipc/detector_settings.yaml index 4229cd6..09b5d5b 100644 --- a/demo/config/ipc/detector_settings.yaml +++ b/demo/config/ipc/detector_settings.yaml @@ -1,9 +1,9 @@ component_type: "detectors.new_value_detector.NewValueDetector" component_config_class: "detectors.new_value_detector.NewValueDetectorConfig" component_name: "test-nvd" -manager_addr: "ipc:///tmp/test_nvd_cmd.ipc" +http_host: "127.0.0.1" +http_port: 8020 engine_addr: "ipc:///tmp/test_nvd_engine.ipc" - log_level: "DEBUG" log_dir: "./logs" log_to_console: true diff --git a/demo/config/ipc/parser_settings.yaml b/demo/config/ipc/parser_settings.yaml index 25ccc61..216363e 100644 --- a/demo/config/ipc/parser_settings.yaml +++ b/demo/config/ipc/parser_settings.yaml @@ -1,7 +1,8 @@ component_type: "parsers.template_matcher.MatcherParser" component_config_class: "parsers.template_matcher.MatcherParserConfig" component_name: "test-parser" -manager_addr: "ipc:///tmp/test_parser_cmd.ipc" +http_host: +http_port: engine_addr: "ipc:///tmp/test_parser_engine.ipc" output_engine_addr: "ipc:///tmp/test_nvd_engine.ipc" log_level: "DEBUG" diff --git a/demo/config/ipc/reader_settings.yaml b/demo/config/ipc/reader_settings.yaml index bf4fe4f..7f33e26 100644 --- a/demo/config/ipc/reader_settings.yaml +++ b/demo/config/ipc/reader_settings.yaml @@ -1,7 +1,8 @@ component_type: "readers.log_file.LogFileReader" component_config_class: "readers.log_file.LogFileConfig" component_name: "test-reader" -manager_addr: "ipc:///tmp/test_reader_cmd.ipc" +http_host: +http_port: engine_addr: "ipc:///tmp/test_reader_engine.ipc" log_level: "DEBUG" log_dir: "./logs" diff --git a/demo/config/parser_settings.yaml b/demo/config/parser_settings.yaml index d47b633..6a4f95a 100644 --- a/demo/config/parser_settings.yaml +++ b/demo/config/parser_settings.yaml @@ -1,7 +1,8 @@ component_type: "parsers.template_matcher.MatcherParser" component_config_class: "parsers.template_matcher.MatcherParserConfig" component_name: "test-parser" -manager_addr: "tcp://parser:8010" +http_host: "127.0.0.1" +http_port: 8010 engine_addr: "tcp://parser:8011" log_level: "DEBUG" log_dir: "./logs" diff --git a/demo/config/reader_settings.yaml b/demo/config/reader_settings.yaml index 98f2437..42d962f 100644 --- a/demo/config/reader_settings.yaml +++ b/demo/config/reader_settings.yaml @@ -1,7 +1,8 @@ component_type: "readers.log_file.LogFileReader" component_config_class: "readers.log_file.LogFileConfig" component_name: "test-reader" -manager_addr: "tcp://reader:8000" +http_host: "127.0.0.1" +http_port: 8000 engine_addr: "tcp://reader:8001" log_level: "DEBUG" log_dir: "./logs" diff --git a/src/service/__init__.py b/src/service/__init__.py index d5a816a..4e40451 100644 --- a/src/service/__init__.py +++ b/src/service/__init__.py @@ -1,17 +1,12 @@ from .core import Service from .settings import ServiceSettings -from .features.manager import Manager from .features.engine import Engine from .features.engine_socket import EngineSocketFactory, NngPairSocketFactory -from .features.manager_socket import ManagerSocketFactory, NngRepSocketFactory __all__ = [ "Service", "ServiceSettings", - "Manager", "Engine", "EngineSocketFactory", "NngPairSocketFactory", - "ManagerSocketFactory", - "NngRepSocketFactory", ] diff --git a/src/service/cli.py b/src/service/cli.py index 36b038a..c8fbe36 100644 --- a/src/service/cli.py +++ b/src/service/cli.py @@ -1,11 +1,7 @@ import argparse -import json import logging import sys -from typing import Optional from pathlib import Path -import pynng -import yaml from .settings import ServiceSettings from .core import Service @@ -13,10 +9,6 @@ logger = logging.getLogger(__name__) -class CLIService(Service): - pass - - def setup_logging(level: int = logging.INFO) -> None: """Set up logging with errors to stderr and others to stdout.""" # create separate handlers for stdout and stderr @@ -40,147 +32,147 @@ def setup_logging(level: int = logging.INFO) -> None: root_logger.addHandler(stderr_handler) -def start_service(settings_path: Optional[Path] = None, config_path: Optional[Path] = None) -> None: - """Start the service with given settings and component configuration.""" - - # Load service settings - try: - # if no settings path provided, use default settings - if settings_path is None: - settings = ServiceSettings() - # if settings path provided but doesn't exist, raise error - elif not settings_path.exists(): - logger.error(f"Settings file not found: {settings_path}") - sys.exit(1) - # otherwise, load settings from file - else: - settings = ServiceSettings.from_yaml(settings_path) - except Exception as e: - logger.error(f"Error loading settings: {e}") - sys.exit(1) - - # Load parameters (if provided) - try: - if config_path is not None: - # if parameters file provided but doesn't exist, raise error - if not config_path.exists(): - logger.error(f"Config file not found: {config_path}") - sys.exit(1) - # if parameters file exists, set it - settings.config_file = config_path - except Exception as e: - logger.error(f"Error loading config file: {e}") - sys.exit(1) - - service = CLIService(settings=settings) - try: - with service: - service.run() - except KeyboardInterrupt: - logger.info("Shutting down service...") - service.stop() - except Exception as e: - logger.error(f"Service failed: {e}") - raise - - -def stop_service(settings_path: Path) -> None: - """Stop a running service.""" - try: - settings = ServiceSettings.from_yaml(settings_path) - except Exception as e: - logger.error(f"Error loading settings from yaml file: {e}") - sys.exit(1) - - try: - with pynng.Req0(dial=settings.manager_addr) as req: - req.send(b"stop") - response = req.recv().decode() - logger.info(f"Service response: {response}") - except pynng.exceptions.NNGException as e: - logger.error(f"Communication error stopping service: {e}") - sys.exit(1) - except Exception as e: - logger.error(f"Unexpected error stopping service: {e}") - sys.exit(1) - - -def reconfigure_service(settings_path: Path, config_path: Path, persist: bool) -> None: - """Reconfigure a running service with new parameters.""" - try: - settings = ServiceSettings.from_yaml(settings_path) - except Exception as e: - logger.error(f"Error loading settings: {e}") - sys.exit(1) - - # Load new parameters from YAML file - try: - with open(config_path, 'r') as f: - config_data = yaml.safe_load(f) - except FileNotFoundError: - logger.error(f"Parameters file not found: {config_path}") - sys.exit(1) - except PermissionError: - logger.error(f"Permission denied reading configuration file: {config_path}") - sys.exit(1) - except yaml.YAMLError as e: - logger.error(f"Invalid YAML in parameters file: {e}") - sys.exit(1) - except Exception as e: - logger.error(f"Unexpected error reading parameters file: {e}") - sys.exit(1) - - # Convert to JSON string for the reconfigure command - try: - config_json = json.dumps(config_data) - if persist: - config_json = f"persist {config_json}" - except TypeError as e: - logger.error(f"Invalid parameters format: {e}") - sys.exit(1) - except Exception as e: - logger.error(f"Unexpected error serializing parameters: {e}") - sys.exit(1) - - try: - with pynng.Req0(dial=settings.manager_addr) as req: - req.send(f"reconfigure {config_json}".encode()) - response = req.recv().decode() - logger.info(f"Reconfiguration response: {response}") - except pynng.exceptions.NNGException as e: - logger.error(f"Communication error during reconfiguration: {e}") - sys.exit(1) - except Exception as e: - logger.error(f"Unexpected error during reconfiguration: {e}") - sys.exit(1) - - -def get_status(settings_path: Path) -> None: - """Get the current status of the service.""" - try: - settings = ServiceSettings.from_yaml(settings_path) - except Exception as e: - logger.error(f"Error loading settings: {e}") - sys.exit(1) - - try: - with pynng.Req0(dial=settings.manager_addr) as req: - req.send(b"status") - response = req.recv().decode() - - try: - # Try to parse as JSON for pretty printing - data = json.loads(response) - logger.info(f"Service Status:\n {json.dumps(data, indent=2)}") - except json.JSONDecodeError: - # Fallback to raw response if not json - logger.info(f"Service status: {response}") - except pynng.exceptions.NNGException as e: - logger.error(f"Communication error getting status: {e}") - sys.exit(1) - except Exception as e: - logger.error(f"Unexpected error getting service status: {e}") - sys.exit(1) +# def start_service(settings_path: Optional[Path] = None, config_path: Optional[Path] = None) -> None: +# """Start the service with given settings and component configuration.""" + +# # Load service settings +# try: +# # if no settings path provided, use default settings +# if settings_path is None: +# settings = ServiceSettings() +# # if settings path provided but doesn't exist, raise error +# elif not settings_path.exists(): +# logger.error(f"Settings file not found: {settings_path}") +# sys.exit(1) +# # otherwise, load settings from file +# else: +# settings = ServiceSettings.from_yaml(settings_path) +# except Exception as e: +# logger.error(f"Error loading settings: {e}") +# sys.exit(1) + +# # Load parameters (if provided) +# try: +# if config_path is not None: +# # if parameters file provided but doesn't exist, raise error +# if not config_path.exists(): +# logger.error(f"Config file not found: {config_path}") +# sys.exit(1) +# # if parameters file exists, set it +# settings.config_file = config_path +# except Exception as e: +# logger.error(f"Error loading config file: {e}") +# sys.exit(1) + +# service = CLIService(settings=settings) +# try: +# with service: +# service.run() +# except KeyboardInterrupt: +# logger.info("Shutting down service...") +# service.stop() +# except Exception as e: +# logger.error(f"Service failed: {e}") +# raise + + +# def stop_service(settings_path: Path) -> None: +# """Stop a running service.""" +# try: +# settings = ServiceSettings.from_yaml(settings_path) +# except Exception as e: +# logger.error(f"Error loading settings from yaml file: {e}") +# sys.exit(1) + +# try: +# with pynng.Req0(dial=settings.manager_addr) as req: +# req.send(b"stop") +# response = req.recv().decode() +# logger.info(f"Service response: {response}") +# except pynng.exceptions.NNGException as e: +# logger.error(f"Communication error stopping service: {e}") +# sys.exit(1) +# except Exception as e: +# logger.error(f"Unexpected error stopping service: {e}") +# sys.exit(1) + + +# def reconfigure_service(settings_path: Path, config_path: Path, persist: bool) -> None: +# """Reconfigure a running service with new parameters.""" +# try: +# settings = ServiceSettings.from_yaml(settings_path) +# except Exception as e: +# logger.error(f"Error loading settings: {e}") +# sys.exit(1) + +# # Load new parameters from YAML file +# try: +# with open(config_path, 'r') as f: +# config_data = yaml.safe_load(f) +# except FileNotFoundError: +# logger.error(f"Parameters file not found: {config_path}") +# sys.exit(1) +# except PermissionError: +# logger.error(f"Permission denied reading configuration file: {config_path}") +# sys.exit(1) +# except yaml.YAMLError as e: +# logger.error(f"Invalid YAML in parameters file: {e}") +# sys.exit(1) +# except Exception as e: +# logger.error(f"Unexpected error reading parameters file: {e}") +# sys.exit(1) + +# # Convert to JSON string for the reconfigure command +# try: +# config_json = json.dumps(config_data) +# if persist: +# config_json = f"persist {config_json}" +# except TypeError as e: +# logger.error(f"Invalid parameters format: {e}") +# sys.exit(1) +# except Exception as e: +# logger.error(f"Unexpected error serializing parameters: {e}") +# sys.exit(1) + +# try: +# with pynng.Req0(dial=settings.manager_addr) as req: +# req.send(f"reconfigure {config_json}".encode()) +# response = req.recv().decode() +# logger.info(f"Reconfiguration response: {response}") +# except pynng.exceptions.NNGException as e: +# logger.error(f"Communication error during reconfiguration: {e}") +# sys.exit(1) +# except Exception as e: +# logger.error(f"Unexpected error during reconfiguration: {e}") +# sys.exit(1) + + +# def get_status(settings_path: Path) -> None: +# """Get the current status of the service.""" +# try: +# settings = ServiceSettings.from_yaml(settings_path) +# except Exception as e: +# logger.error(f"Error loading settings: {e}") +# sys.exit(1) + +# try: +# with pynng.Req0(dial=settings.manager_addr) as req: +# req.send(b"status") +# response = req.recv().decode() + +# try: +# # Try to parse as JSON for pretty printing +# data = json.loads(response) +# logger.info(f"Service Status:\n {json.dumps(data, indent=2)}") +# except json.JSONDecodeError: +# # Fallback to raw response if not json +# logger.info(f"Service status: {response}") +# except pynng.exceptions.NNGException as e: +# logger.error(f"Communication error getting status: {e}") +# sys.exit(1) +# except Exception as e: +# logger.error(f"Unexpected error getting service status: {e}") +# sys.exit(1) def main() -> None: diff --git a/src/service/features/manager.py b/src/service/features/manager.py deleted file mode 100644 index b6a18b5..0000000 --- a/src/service/features/manager.py +++ /dev/null @@ -1,175 +0,0 @@ -"""Request/Reply command-manager for DetectMate services. - -The Manager class starts a background thread with a REP socket that -waits for simple string commands. It is meant to be inherited -by Service, so every concrete component automatically exposes -the same management interface. - -Default commands ----------------- -ping -> pong - -> dynamically dispatched on self - -> "unknown command" -""" -from __future__ import annotations -from typing import Optional, Callable, TypeVar, Any -import threading -import pynng -import time -import logging -from service.settings import ServiceSettings -from service.features.manager_socket import ManagerSocketFactory, NngRepSocketFactory - - -F = TypeVar('F', bound=Callable[..., str]) - - -# Decorator to mark callable commands on a component -def manager_command(name: str | None = None) -> Callable[[F], F]: - """Decorator to tag methods as manager-exposed commands. - - Usage: - @manager_command() -> command name is the method name (lowercase) - @manager_command("status") -> explicit command name - """ - def _wrap(fn: F) -> F: - setattr(fn, "_manager_command", True) - setattr(fn, "_manager_command_name", (name or fn.__name__).lower()) - return fn - return _wrap - - -class Manager: - """Mixin that starts a REP socket in the background and serves commands.""" - - def __init__( - self, - *_args: Any, - settings: Optional[ServiceSettings] = None, - socket_factory: Optional[ManagerSocketFactory] = None, - logger: Optional[logging.Logger] = None, - **_kwargs: Any - ): - self._stop_event = threading.Event() - self.settings: ServiceSettings = settings if settings is not None else ServiceSettings() - self.log = logger or logging.getLogger(__name__) - - # Use socket factory abstraction - self._manager_socket_factory: ManagerSocketFactory = ( - socket_factory if socket_factory is not None else NngRepSocketFactory() - ) - - listen_addr = str(self.settings.manager_addr) - - # Create socket using factory - self._rep_sock = self._manager_socket_factory.create(listen_addr, self.log) - self._rep_sock.recv_timeout = self.settings.manager_recv_timeout - - # background thread - self._thread = threading.Thread( - target=self._command_loop, name="ManagerCmdLoop", daemon=True - ) - self._thread.start() - - # discover @manager_command-decorated methods once - self._decorated_handlers: dict[str, Callable[..., str]] = {} - self._discover_decorated_commands() - - # discover decorated command methods on the instance/class - def _discover_decorated_commands(self) -> None: - for attr_name in dir(self): - if attr_name.startswith("_"): - continue - attr = getattr(self, attr_name) - # If it's a bound method, the function is on __func__ - func = getattr(attr, "__func__", None) - if func is None: - continue - if getattr(func, "_manager_command", False): - cmd_name = getattr(func, "_manager_command_name", attr_name).lower() - # store the bound method; call directly later - self._decorated_handlers[cmd_name] = attr - - # internal machinery - def _command_loop(self) -> None: - while not self._stop_event.is_set(): - try: - raw: bytes = self._rep_sock.recv() # blocks with timeout - cmd = raw.decode("utf-8", errors="ignore").strip() - if hasattr(self, 'log'): - self.log.debug(f"Received command: {cmd}") - except pynng.Timeout: - continue # Timeout occurred, check stop event and continue - except pynng.NNGException: - break # socket closed elsewhere - - # check if it's already stopping to prevent duplicate processing - if hasattr(self, '_stop_event') and self._stop_event.is_set() and cmd.lower() == "stop": - if hasattr(self, 'log'): - self.log.debug("Ignoring stop command - already stopping") - continue - - try: - reply: str = self._handle_cmd(cmd) - except Exception as e: - self.log.error(f"Unexpected error handling command '{cmd}': {e}") - reply = "error: internal error processing command" - - try: - self._rep_sock.send(reply.encode()) - if hasattr(self, 'log'): - self.log.debug(f"Sent response: {reply}") - except pynng.NNGException: - break - - def _handle_cmd(self, cmd: str) -> str: - """Route a command string to the right handler. - - Priority: - 1. @manager_command-decorated methods on self - 2. Built-in 'ping' - 3. Unknown - """ - if hasattr(self, 'log'): - self.log.info(f"Processing command: {cmd}") - - verb = cmd.split(" ", 1)[0].lower() # split: verb [args...] - - # 1. decorator-based dynamic dispatch - fn = self._decorated_handlers.get(verb) - if fn is not None: - try: - # Try to pass cmd; if the signature is zero-arg, call without - try: - reply = fn(cmd) - except TypeError: - reply = fn() - if hasattr(self, 'log'): - self.log.debug(f"Executed command '{verb}': {reply}") - return reply - except Exception as e: - if hasattr(self, 'log'): - self.log.error(f"Error executing command '{verb}': {e}") - return f"error: {e}" - - # 2. built-in ping - if verb == "ping": - return "pong" - - # 3. unknown - return f"unknown command: {cmd}" - - # tear-down helper - def _close_manager(self) -> None: - """Called by Service.__exit__.""" - self._stop_event.set() - time.sleep(0.05) # give the manager thread a moment to finish any current command processing - try: - # Just close; closing from another thread unblocks .recv() in pynng. - self._rep_sock.close() - except pynng.NNGException: - pass - - if self._thread.is_alive(): - join_timeout = getattr(self.settings, 'manager_thread_join_timeout', 1.0) - self._thread.join(timeout=join_timeout) diff --git a/src/service/features/manager_socket.py b/src/service/features/manager_socket.py deleted file mode 100644 index cee5fad..0000000 --- a/src/service/features/manager_socket.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations -from pathlib import Path -import errno -from typing import Protocol, runtime_checkable, cast -from urllib.parse import urlparse - -import pynng -import logging - - -@runtime_checkable -class ManagerSocket(Protocol): - """Minimal socket interface the Manager depends on.""" - def recv(self) -> bytes: ... - def send(self, data: bytes) -> None: ... - def close(self) -> None: ... - def listen(self, addr: str) -> None: ... - recv_timeout: int - - -class ManagerSocketFactory(Protocol): - """Factory that creates bound ManagerSocket instances.""" - def create(self, addr: str, logger: logging.Logger) -> ManagerSocket: ... - - -class NngRepSocketFactory: - """Default factory using pynng.Rep0 with proper error handling.""" - def create(self, addr: str, logger: logging.Logger) -> ManagerSocket: - sock = pynng.Rep0() - parsed = urlparse(addr) - if parsed.scheme == "ipc": - ipc_path = Path(parsed.path) - try: - if ipc_path.exists(): - ipc_path.unlink() - except OSError as exc: - if exc.errno != errno.ENOENT: # ignore file doesn't exist errors - logger.error("Failed to remove IPC file: %s", exc) - raise - - # Handle TCP port binding conflicts - elif parsed.scheme == "tcp": - try: - if not parsed.port: - raise ValueError(f"Missing port in TCP address: {addr}") - except (ValueError, IndexError, OSError) as exc: - logger.error("Invalid TCP address or port in use: %s", exc) - raise - - try: - sock.listen(addr) - logger.info("Manager listening on %s", addr) - return cast(ManagerSocket, sock) # use cast to tell mypy this implements ManagerSocket - except pynng.NNGException as exc: - logger.error("Failed to bind to address %s: %s", addr, exc) - sock.close() - raise diff --git a/tests/config/service_settings.yaml b/tests/config/service_settings.yaml index 4681075..d3da64d 100644 --- a/tests/config/service_settings.yaml +++ b/tests/config/service_settings.yaml @@ -1,7 +1,8 @@ component_type: "detectors.dummy_detector.DummyDetector" component_config_class: "detectors.dummy_detector.DummyDetectorConfig" component_name: "detector-1" -manager_addr: "ipc:///tmp/detector_cmd.ipc" +http_host: "127.0.0.1" +http_port: 8030 engine_addr: "ipc:///tmp/detector_engine.ipc" log_level: "DEBUG" log_dir: "./logs" diff --git a/tests/test_component_id.py b/tests/test_component_id.py index 0c493f1..dee894a 100644 --- a/tests/test_component_id.py +++ b/tests/test_component_id.py @@ -27,7 +27,6 @@ def test_uuid5_from_addresses_expected_and_stable(): # No component_name -> derive from addresses + type s1 = ServiceSettings( component_type="detector", - manager_addr="ipc:///tmp/a.ipc", engine_addr="ipc:///tmp/b.ipc", component_name=None, component_id=None, @@ -41,7 +40,6 @@ def test_uuid5_from_addresses_expected_and_stable(): # Recreate with same addresses -> same ID s2 = ServiceSettings( component_type="detector", - manager_addr="ipc:///tmp/a.ipc", engine_addr="ipc:///tmp/b.ipc", ) assert s2.component_id == expected @@ -50,13 +48,11 @@ def test_uuid5_from_addresses_expected_and_stable(): def test_changing_addresses_changes_id(): s1 = ServiceSettings( component_type="detector", - manager_addr="ipc:///tmp/a.ipc", engine_addr="ipc:///tmp/b.ipc", ) s2 = ServiceSettings( component_type="detector", - manager_addr="ipc:///tmp/c.ipc", # changed - engine_addr="ipc:///tmp/b.ipc", + engine_addr="ipc:///tmp/c.ipc", # changed ) assert s1.component_id != s2.component_id diff --git a/tests/test_config_reading.py b/tests/test_config_reading.py index 65beaba..5b6e44c 100644 --- a/tests/test_config_reading.py +++ b/tests/test_config_reading.py @@ -10,7 +10,6 @@ def test_read_config_from_yaml(): config_data = { 'component_name': 'test_detector', 'component_type': 'detector', - 'manager_addr': 'ipc:///tmp/test_cmd.ipc', 'engine_addr': 'ipc:///tmp/test_engine.ipc', 'log_level': 'DEBUG', 'log_dir': './test_logs', @@ -31,7 +30,6 @@ def test_read_config_from_yaml(): # Verify that the settings were loaded correctly assert settings.component_name == 'test_detector' assert settings.component_type == 'detector' - assert settings.manager_addr == 'ipc:///tmp/test_cmd.ipc' assert settings.engine_addr == 'ipc:///tmp/test_engine.ipc' assert settings.log_level == 'DEBUG' assert settings.log_dir == Path('./test_logs') @@ -70,7 +68,6 @@ def test_read_partial_config_from_yaml(): # Verify that defaults are used for missing values assert settings.component_type == 'core' # default value - assert settings.manager_addr == 'ipc:///tmp/detectmate.cmd.ipc' # default value assert settings.engine_addr == 'ipc:///tmp/detectmate.engine.ipc' # default value # Verify that component_id was generated @@ -95,7 +92,6 @@ def test_read_empty_config_from_yaml(): # Verify that all defaults are used assert settings.component_name is None assert settings.component_type == 'core' - assert settings.manager_addr == 'ipc:///tmp/detectmate.cmd.ipc' assert settings.engine_addr == 'ipc:///tmp/detectmate.engine.ipc' assert settings.log_level == 'INFO' @@ -116,7 +112,6 @@ def test_read_nonexistent_config_file(): # Should use all defaults assert settings.component_name is None assert settings.component_type == 'core' - assert settings.manager_addr == 'ipc:///tmp/detectmate.cmd.ipc' assert settings.engine_addr == 'ipc:///tmp/detectmate.engine.ipc' assert settings.log_level == 'INFO' @@ -130,7 +125,6 @@ def test_env_vars_override_yaml(tmpdir, monkeypatch): config_data = { 'component_name': 'yaml_detector', 'log_level': 'DEBUG', - 'manager_addr': 'ipc:///tmp/yaml_cmd.ipc' } config_file = tmpdir.join('config.yaml') with open(config_file, 'w') as f: @@ -147,8 +141,5 @@ def test_env_vars_override_yaml(tmpdir, monkeypatch): assert settings.component_name == 'env_detector' assert settings.log_level == 'ERROR' - # YAML values without environment overrides should remain - assert settings.manager_addr == 'ipc:///tmp/yaml_cmd.ipc' - # Verify that component_id was generated assert settings.component_id is not None From e797ab97c9cfbf1e3c1a78161cf89c0e92e563dc Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 12 Jan 2026 13:00:23 +0100 Subject: [PATCH 07/78] remove manager tests --- tests/test_manager_commands.py | 115 ---------------- tests/test_manager_socket_error_handling.py | 138 -------------------- 2 files changed, 253 deletions(-) delete mode 100644 tests/test_manager_commands.py delete mode 100644 tests/test_manager_socket_error_handling.py diff --git a/tests/test_manager_commands.py b/tests/test_manager_commands.py deleted file mode 100644 index 3199de6..0000000 --- a/tests/test_manager_commands.py +++ /dev/null @@ -1,115 +0,0 @@ -import threading -import pynng -import pytest -import json - -from service.core import Service -from service.settings import ServiceSettings -from service.features.manager import manager_command - - -class MockService(Service): - """Mock service with additional commands for testing.""" - component_type = "test" - - def process(self, raw_message: bytes) -> bytes | None: - return raw_message # echo for testing - - @manager_command() - def echo(self, cmd: str) -> str: - """Echo the received command.""" - return cmd - - @manager_command("custom") - def custom_command(self) -> str: - """Custom test command.""" - return "custom response" - - -@pytest.fixture -def mock_service(tmp_path): - settings = ServiceSettings( - manager_addr=f"ipc://{tmp_path}/test_cmd.ipc", - engine_addr=f"ipc://{tmp_path}/test_engine.ipc", - engine_autostart=False, - log_level="ERROR", - ) - service = MockService(settings=settings) - yield service - service._close_manager() - assert service._stop_event.is_set() - - -def test_manager_commands(mock_service): - """Test basic manager commands.""" - with pynng.Req0(dial=mock_service.settings.manager_addr) as req: - # Test ping - req.send(b"ping") - assert req.recv() == b"pong" - - # Test status - parse JSON response - req.send(b"status") - response = json.loads(req.recv().decode()) - assert response['status']['running'] is False # Check running field - - # Test echo command - test_message = b"echo test message" - req.send(test_message) - assert req.recv() == test_message - - # Test custom command - req.send(b"custom") - assert req.recv() == b"custom response" - - # Test unknown command - req.send(b"unknown") - assert b"unknown command" in req.recv() - - -def test_concurrent_commands(mock_service): - """Test that manager handles concurrent commands correctly.""" - def send_command(addr, command, results, index): - try: - with pynng.Req0(dial=addr) as req: - req.send(command) - results[index] = req.recv() - except Exception as e: - results[index] = str(e) - - # Send multiple concurrent commands - commands = [b"ping", b"status", b"echo test"] - results = [None] * len(commands) - threads = [] - - for i, cmd in enumerate(commands): - t = threading.Thread( - target=send_command, - args=(mock_service.settings.manager_addr, cmd, results, i) - ) - threads.append(t) - t.start() - - for t in threads: - t.join(timeout=2.0) - - # Verify all commands got responses - assert all(results) - assert results[0] == b"pong" - # Parse status response - status_response = json.loads(results[1].decode()) - assert status_response['status']['running'] is False - assert results[2] == b"echo test" - - -def test_manager_reconnect(mock_service): - """Test that manager handles client disconnects/reconnects properly.""" - # First connection - with pynng.Req0(dial=mock_service.settings.manager_addr) as req: - req.send(b"ping") - assert req.recv() == b"pong" - - # Second connection (should work fine) - with pynng.Req0(dial=mock_service.settings.manager_addr) as req: - req.send(b"status") - response = json.loads(req.recv().decode()) - assert response['status']['running'] is False diff --git a/tests/test_manager_socket_error_handling.py b/tests/test_manager_socket_error_handling.py deleted file mode 100644 index 5a61b15..0000000 --- a/tests/test_manager_socket_error_handling.py +++ /dev/null @@ -1,138 +0,0 @@ -import errno -import socket -from pathlib import Path -from unittest.mock import patch, MagicMock -from pynng.exceptions import NNGException, AddressInUse -import pytest - -from service.core import Service -from service.settings import ServiceSettings - - -class MockTestService(Service): - """Class for testing.""" - component_type = "test" - - def process(self, raw_message: bytes) -> bytes | None: - return raw_message # echo for testing - - -class TestManagerSocketErrorHandling: - def test_ipc_file_remove_error(self, tmp_path): - """Test error handling when removing an IPC file fails for unexpected - reasons.""" - ipc_file = tmp_path / "bad.ipc" - ipc_file.touch() # ensure exists -> hit unlink branch - - settings = ServiceSettings( - manager_addr=f"ipc://{ipc_file}", - engine_autostart=False, - log_level="ERROR", - ) - - # Stub the service logger so we can assert the error log call - mock_logger = MagicMock() - with patch.object(Service, "_build_logger", return_value=mock_logger): - # Simulate a non-ENOENT unlink error (eg. EPERM) - with patch.object(Path, "unlink", side_effect=OSError(errno.EPERM, "Permission denied")): - with pytest.raises(OSError): - MockTestService(settings=settings) - - # Ensure the error was logged by the service logger - assert mock_logger.error.called - assert any( - "Failed to remove IPC file" in (call.args[0] if call.args else "") - for call in mock_logger.error.call_args_list - ) - - def test_tcp_port_already_in_use(self, caplog): - """Test error handling when TCP port is already in use.""" - settings = ServiceSettings( - manager_addr="tcp://127.0.0.1:9999", - engine_autostart=False, - log_level="ERROR", - ) - - # Mock pynng to raise AddressInUse when creating sockets - with patch('pynng.Rep0') as mock_rep: - mock_rep.return_value.listen.side_effect = AddressInUse("Address in use", errno.EADDRINUSE) - - # Should raise an pynng.exceptions.AddressInUse when port is already in use - with pytest.raises(AddressInUse, match="Address in use"): - MockTestService(settings=settings) - - def test_invalid_tcp_address(self, caplog): - """Test error handling for invalid TCP addresses.""" - settings = ServiceSettings( - manager_addr="tcp://invalid-address:not-a-port", - engine_autostart=False, - log_level="ERROR", - ) - - # Should raise a ValueError for invalid port - with pytest.raises(ValueError): - MockTestService(settings=settings) - - def test_socket_bind_error(self, caplog): - """Test error handling when socket binding fails.""" - settings = ServiceSettings( - manager_addr="tcp://127.0.0.1:9999", - engine_autostart=False, - log_level="ERROR", - ) - - # Mock pynng to raise an exception on listen - with patch('pynng.Rep0') as mock_rep: - mock_sock = MagicMock() - mock_rep.return_value = mock_sock - # Create a proper NNGException with errno - mock_sock.listen.side_effect = NNGException("Bind failed", 1) - - # Should raise NNGException when binding fails - with pytest.raises(NNGException): - MockTestService(settings=settings) - - def test_successful_ipc_binding(self, tmp_path): - """Test successful IPC socket binding.""" - ipc_file = tmp_path / "test.ipc" - - settings = ServiceSettings( - manager_addr=f"ipc://{ipc_file}", - engine_autostart=False, - log_level="ERROR", - ) - - # Should not raise any exceptions - service = MockTestService(settings=settings) - service._close_manager() - - def test_successful_tcp_binding(self): - """Test successful TCP socket binding.""" - # Find an available port - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind(("127.0.0.1", 0)) - port = s.getsockname()[1] - - settings = ServiceSettings( - manager_addr=f"tcp://127.0.0.1:{port}", - engine_autostart=False, - log_level="ERROR", - ) - - # Should not raise any exceptions - service = MockTestService(settings=settings) - service._close_manager() - - def test_missing_ipc_file_handling(self, tmp_path): - """Test that missing IPC files don't cause errors.""" - ipc_file = tmp_path / "nonexistent.ipc" - - settings = ServiceSettings( - manager_addr=f"ipc://{ipc_file}", - engine_autostart=False, - log_level="ERROR", - ) - - # Should not raise any exceptions even though file doesn't exist - service = MockTestService(settings=settings) - service._close_manager() From c6a5b66d343253738b0cd7d162a003d945c9874c Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 19 Jan 2026 11:12:38 +0100 Subject: [PATCH 08/78] use json instead of string for reconfigure --- src/service/core.py | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index 3a8d1df..bbaf448 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -231,42 +231,34 @@ def status(self, cmd: str | None = None) -> str: status_info = self._create_status_report(running) return json.dumps(status_info, indent=2) - def reconfigure(self, cmd: str | None = None) -> str: + def reconfigure(self, config_data: Dict[str, Any], persist: bool = False) -> str: """Reconfigure service configurations dynamically.""" if not self.config_manager: return "reconfigure: no config manager configured" - payload = "" - persist = False - - if cmd: - # Parse the command: "reconfigure [persist] " - parts = cmd.split(maxsplit=2) # Split into at most 3 parts - if len(parts) >= 2: - # Check if the second part is "persist" - if parts[1].lower() == "persist": - persist = True - # Use the third part as payload if it exists - payload = parts[2] if len(parts) > 2 else "" - else: - # Use the rest of the command as payload - payload = cmd.split(maxsplit=1)[1] if len(parts) > 1 else "" - - if not payload: - return "reconfigure: no-op (no payload)" - + if not config_data: + return "reconfigure: no-op (empty config data)" try: - data = json.loads(payload) - except json.JSONDecodeError: - return "reconfigure: invalid JSON" + self.config_manager.update(config_data) + # problem: update() validates against the Schema, + # model_validate()constructs a pydantic model instance of for example + # (NewValueDetectorConfig), but save() expects a dict to serialize to YAML + # pydantic automatically fills in default values, including + # inherited from CoreDetectorConfig like parser, start_id) + # class CoreDetectorConfig(CoreConfig): + # comp_type: str = "detectors" + # method_type: str = "core_detector" + # parser: str = "" + # on save these get written in the config.yaml file + # -> then this file is missing "detectors" and other important fields and cannot be used - try: - self.config_manager.update(data) if persist: self.config_manager.save() - self.log.info("Reconfigured with: %s", data) + self.log.info("Reconfigured with: %s", config_data) return "reconfigure: ok" + except Exception as e: + self.log.error("Reconfiguration error: %s", e) return f"reconfigure: error - {e}" def shutdown(self) -> str: From 0b581ceb8beacae626e1f4df66a5017bc0af5661 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 19 Jan 2026 11:12:53 +0100 Subject: [PATCH 09/78] typo --- src/service/features/web/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/features/web/server.py b/src/service/features/web/server.py index ebbdd24..ca00bf6 100644 --- a/src/service/features/web/server.py +++ b/src/service/features/web/server.py @@ -29,8 +29,8 @@ def __init__(self, service: Service) -> None: ) self.server = uvicorn.Server(self.config) self.server.install_signal_handlers = False # Importnt for running in thread, - # pythons signal module only allows the Main Thread to resgister signal handlers - # uvicrons default behaviour to listen for shutdown signals will raise ValueError + # pythons signal module only allows the Main Thread to register signal handlers + # uvicorns default behaviour to listen for shutdown signals will raise ValueError def run(self) -> None: self.server.run() From 48a3bc85db80fcc33d18529b35fe74e3b4d807b1 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 19 Jan 2026 11:14:00 +0100 Subject: [PATCH 10/78] use json instead of string for reconfigure in router --- src/service/features/web/router.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/service/features/web/router.py b/src/service/features/web/router.py index ee94605..1307b0f 100644 --- a/src/service/features/web/router.py +++ b/src/service/features/web/router.py @@ -33,9 +33,11 @@ async def admin_status(service: Any = Depends(get_service)) -> Any: @router.post("/reconfigure") # type: ignore[misc] async def admin_reconfigure(payload: ReconfigPayload, service: Any = Depends(get_service)) -> Dict[str, Any]: # format the string to match what internal reconfigure() expects - import json - cmd_str = f"{'persist ' if payload.persist else ''}{json.dumps(payload.config)}" - return {"message": service.reconfigure(cmd_str)} + result = service.reconfigure( + config_data=payload.config, + persist=payload.persist + ) + return {"message": result} @router.post("/shutdown") # type: ignore[misc] From ef4de89cb82d06907f7392dfdd4f570a12a1a68f Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 19 Jan 2026 11:15:28 +0100 Subject: [PATCH 11/78] remove nano message admin cli --- src/service/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/cli.py b/src/service/cli.py index c8fbe36..e5d4116 100644 --- a/src/service/cli.py +++ b/src/service/cli.py @@ -191,7 +191,7 @@ def main() -> None: if args.config: settings.config_file = args.config - + logger.info("config file: %s", settings.config_file) # Initialize and run # Note: Service now inherits from Service, not CLIService service = Service(settings=settings) From f0db7708c0ed43add3df888e8e25d691c56843bd Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 13:24:34 +0100 Subject: [PATCH 12/78] validation against ServiceConfig --- src/service/features/config_manager.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/service/features/config_manager.py b/src/service/features/config_manager.py index fa99403..ac90714 100644 --- a/src/service/features/config_manager.py +++ b/src/service/features/config_manager.py @@ -9,6 +9,11 @@ from detectmatelibrary.common.core import CoreConfig +class ServiceConfig(BaseModel): + detectors: Optional[Dict[str, Dict[str, Any]]] = None + parsers: Optional[Dict[str, Dict[str, Any]]] = None + + class ConfigManager: def __init__( self, @@ -45,7 +50,13 @@ def load(self) -> None: self.logger.debug(f"Loaded data from file: {data}") if self.schema and data: - self._configs = data # self.schema.model_validate(data) + # Problem: mismatch between component config schema and structure the library expects + # cannot validate against self.schema + # self.schema does not accept "detectors" or "parsers" key which the library expects + # cannot nest, because self.schema does not accept a params field, which the library expects + # --> validate against ServiceConfig here, let library handle the rest + + self._configs = ServiceConfig.model_validate(data) self.logger.debug(f"Validated params: {self._configs}") elif data: # If no schema, store as raw dict @@ -94,7 +105,7 @@ def update(self, new_configs: Dict[str, Any]) -> None: """Update parameters with validation.""" with self._lock: if self.schema: - self._configs = self.schema.model_validate(new_configs) + self._configs = ServiceConfig.model_validate(new_configs) else: self._configs = new_configs self.logger.info(f"Parameters updated: {self._configs}") From 7b462e768b4abb3b01721a4001bd066cf9eb5d39 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 14:53:49 +0100 Subject: [PATCH 13/78] add detectmate-client cli --- .pre-commit-config.yaml | 1 + pyproject.toml | 3 + src/service/cli.py | 143 ---------------------------------------- src/service/client.py | 110 +++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 143 deletions(-) create mode 100755 src/service/client.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2dd2d24..05f266f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,6 +36,7 @@ repos: - pydantic - types-PyYAML - pydantic-settings + - types-requests # Code formatting - repo: https://github.com/hhatto/autopep8 diff --git a/pyproject.toml b/pyproject.toml index 06a5892..54a1aeb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ dependencies = [ "pynng>=0.8.1", "pyyaml>=6.0.2", "types-pyyaml>=6.0.12.20250915", + "requests>=2.31.0", ] [project.optional-dependencies] @@ -22,7 +23,9 @@ dev = [ "prek>=0.2.8", "pytest>=8.4.1", "pytest-cov>=6.2.1", + "types-requests", ] [project.scripts] detectmate = "service.cli:main" +detectmate-client = "service.client:main" diff --git a/src/service/cli.py b/src/service/cli.py index e5d4116..1ae33fc 100644 --- a/src/service/cli.py +++ b/src/service/cli.py @@ -32,149 +32,6 @@ def setup_logging(level: int = logging.INFO) -> None: root_logger.addHandler(stderr_handler) -# def start_service(settings_path: Optional[Path] = None, config_path: Optional[Path] = None) -> None: -# """Start the service with given settings and component configuration.""" - -# # Load service settings -# try: -# # if no settings path provided, use default settings -# if settings_path is None: -# settings = ServiceSettings() -# # if settings path provided but doesn't exist, raise error -# elif not settings_path.exists(): -# logger.error(f"Settings file not found: {settings_path}") -# sys.exit(1) -# # otherwise, load settings from file -# else: -# settings = ServiceSettings.from_yaml(settings_path) -# except Exception as e: -# logger.error(f"Error loading settings: {e}") -# sys.exit(1) - -# # Load parameters (if provided) -# try: -# if config_path is not None: -# # if parameters file provided but doesn't exist, raise error -# if not config_path.exists(): -# logger.error(f"Config file not found: {config_path}") -# sys.exit(1) -# # if parameters file exists, set it -# settings.config_file = config_path -# except Exception as e: -# logger.error(f"Error loading config file: {e}") -# sys.exit(1) - -# service = CLIService(settings=settings) -# try: -# with service: -# service.run() -# except KeyboardInterrupt: -# logger.info("Shutting down service...") -# service.stop() -# except Exception as e: -# logger.error(f"Service failed: {e}") -# raise - - -# def stop_service(settings_path: Path) -> None: -# """Stop a running service.""" -# try: -# settings = ServiceSettings.from_yaml(settings_path) -# except Exception as e: -# logger.error(f"Error loading settings from yaml file: {e}") -# sys.exit(1) - -# try: -# with pynng.Req0(dial=settings.manager_addr) as req: -# req.send(b"stop") -# response = req.recv().decode() -# logger.info(f"Service response: {response}") -# except pynng.exceptions.NNGException as e: -# logger.error(f"Communication error stopping service: {e}") -# sys.exit(1) -# except Exception as e: -# logger.error(f"Unexpected error stopping service: {e}") -# sys.exit(1) - - -# def reconfigure_service(settings_path: Path, config_path: Path, persist: bool) -> None: -# """Reconfigure a running service with new parameters.""" -# try: -# settings = ServiceSettings.from_yaml(settings_path) -# except Exception as e: -# logger.error(f"Error loading settings: {e}") -# sys.exit(1) - -# # Load new parameters from YAML file -# try: -# with open(config_path, 'r') as f: -# config_data = yaml.safe_load(f) -# except FileNotFoundError: -# logger.error(f"Parameters file not found: {config_path}") -# sys.exit(1) -# except PermissionError: -# logger.error(f"Permission denied reading configuration file: {config_path}") -# sys.exit(1) -# except yaml.YAMLError as e: -# logger.error(f"Invalid YAML in parameters file: {e}") -# sys.exit(1) -# except Exception as e: -# logger.error(f"Unexpected error reading parameters file: {e}") -# sys.exit(1) - -# # Convert to JSON string for the reconfigure command -# try: -# config_json = json.dumps(config_data) -# if persist: -# config_json = f"persist {config_json}" -# except TypeError as e: -# logger.error(f"Invalid parameters format: {e}") -# sys.exit(1) -# except Exception as e: -# logger.error(f"Unexpected error serializing parameters: {e}") -# sys.exit(1) - -# try: -# with pynng.Req0(dial=settings.manager_addr) as req: -# req.send(f"reconfigure {config_json}".encode()) -# response = req.recv().decode() -# logger.info(f"Reconfiguration response: {response}") -# except pynng.exceptions.NNGException as e: -# logger.error(f"Communication error during reconfiguration: {e}") -# sys.exit(1) -# except Exception as e: -# logger.error(f"Unexpected error during reconfiguration: {e}") -# sys.exit(1) - - -# def get_status(settings_path: Path) -> None: -# """Get the current status of the service.""" -# try: -# settings = ServiceSettings.from_yaml(settings_path) -# except Exception as e: -# logger.error(f"Error loading settings: {e}") -# sys.exit(1) - -# try: -# with pynng.Req0(dial=settings.manager_addr) as req: -# req.send(b"status") -# response = req.recv().decode() - -# try: -# # Try to parse as JSON for pretty printing -# data = json.loads(response) -# logger.info(f"Service Status:\n {json.dumps(data, indent=2)}") -# except json.JSONDecodeError: -# # Fallback to raw response if not json -# logger.info(f"Service status: {response}") -# except pynng.exceptions.NNGException as e: -# logger.error(f"Communication error getting status: {e}") -# sys.exit(1) -# except Exception as e: -# logger.error(f"Unexpected error getting service status: {e}") -# sys.exit(1) - - def main() -> None: setup_logging() parser = argparse.ArgumentParser(description="DetectMate Service Launcher") diff --git a/src/service/client.py b/src/service/client.py new file mode 100755 index 0000000..bfa8ed9 --- /dev/null +++ b/src/service/client.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +import argparse +import sys +import json +import yaml +import requests + + +class DetectMateClient: + def __init__(self, base_url: str): + self.base_url = base_url.rstrip('/') + self.timeout: int = 10 + + def _handle_response(self, response: requests.Response) -> None: + try: + response.raise_for_status() + print(json.dumps(response.json(), indent=2)) + except requests.exceptions.HTTPError as e: + print(f"Error: {e}") + if response.text: + print(f"Details: {response.text}") + sys.exit(1) + except Exception as e: + print(f"Unexpected error: {e}") + sys.exit(1) + + def start(self) -> None: + print(f"Sending START to {self.base_url}...") + response = requests.post(f"{self.base_url}/admin/start", timeout=self.timeout) + self._handle_response(response) + + def stop(self) -> None: + print(f"Sending STOP to {self.base_url}...") + response = requests.post(f"{self.base_url}/admin/stop", timeout=self.timeout) + self._handle_response(response) + + def status(self) -> None: + response = requests.get(f"{self.base_url}/admin/status", timeout=self.timeout) + self._handle_response(response) + + def reconfigure(self, yaml_file: str, persist: bool) -> None: + try: + with open(yaml_file, 'r') as f: + config_data = yaml.safe_load(f) + + payload = { + "config": config_data, + "persist": persist + } + + print(f"Sending RECONFIGURE (persist={persist}) to {self.base_url}...") + response = requests.post( + f"{self.base_url}/admin/reconfigure", timeout=self.timeout, + json=payload + ) + self._handle_response(response) + except FileNotFoundError: + print(f"Error: File '{yaml_file}' not found.") + except yaml.YAMLError as e: + print(f"Error parsing YAML: {e}") + + +def main() -> None: + parser = argparse.ArgumentParser( + prog="detectmate-client", + description="CLI Client for DetectMateService HTTP Admin API" + ) + parser.add_argument( + "--url", + default="http://localhost:8000", + help="Base URL of the service (default: http://localhost:8000)" + ) + + subparsers = parser.add_subparsers(dest="command", help="Commands") + + # Start + subparsers.add_parser("start", help="Start the detection engine") + + # Stop + subparsers.add_parser("stop", help="Stop the detection engine") + + # Status + subparsers.add_parser("status", help="Get service status and configuration") + + # Reconfigure + reconf = subparsers.add_parser("reconfigure", help="Update configuration from a YAML file") + reconf.add_argument("file", help="Path to the YAML configuration file") + reconf.add_argument( + "--persist", + action="store_true", + help="Persist changes to the service's config file" + ) + + args = parser.parse_args() + client = DetectMateClient(args.url) + + if args.command == "start": + client.start() + elif args.command == "stop": + client.stop() + elif args.command == "status": + client.status() + elif args.command == "reconfigure": + client.reconfigure(args.file, args.persist) + else: + parser.print_help() + + +if __name__ == "__main__": + main() From d0a9afcda3381e332791993c552e612bf88f376d Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 14:56:24 +0100 Subject: [PATCH 14/78] update demo settings --- demo/config/ipc/parser_settings.yaml | 4 ++-- demo/config/ipc/reader_settings.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/demo/config/ipc/parser_settings.yaml b/demo/config/ipc/parser_settings.yaml index 216363e..66bce7f 100644 --- a/demo/config/ipc/parser_settings.yaml +++ b/demo/config/ipc/parser_settings.yaml @@ -1,8 +1,8 @@ component_type: "parsers.template_matcher.MatcherParser" component_config_class: "parsers.template_matcher.MatcherParserConfig" component_name: "test-parser" -http_host: -http_port: +http_host: "127.0.0.1" +http_port: 8010 engine_addr: "ipc:///tmp/test_parser_engine.ipc" output_engine_addr: "ipc:///tmp/test_nvd_engine.ipc" log_level: "DEBUG" diff --git a/demo/config/ipc/reader_settings.yaml b/demo/config/ipc/reader_settings.yaml index 7f33e26..2c8044c 100644 --- a/demo/config/ipc/reader_settings.yaml +++ b/demo/config/ipc/reader_settings.yaml @@ -1,8 +1,8 @@ component_type: "readers.log_file.LogFileReader" component_config_class: "readers.log_file.LogFileConfig" component_name: "test-reader" -http_host: -http_port: +http_host: "127.0.0.1" +http_port: 8000 engine_addr: "ipc:///tmp/test_reader_engine.ipc" log_level: "DEBUG" log_dir: "./logs" From b80f6595387a8340b2928aa2664fee7fb1322e54 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 15:21:45 +0100 Subject: [PATCH 15/78] update docs --- docs/configuration.md | 43 +++++++++++++++++++++++++++++++++------- docs/library.md | 46 +++++++++++++++++++++++++++++++------------ docs/usage.md | 34 ++++++++++++++++++++------------ 3 files changed, 90 insertions(+), 33 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 563814c..9cdb942 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -16,7 +16,8 @@ These settings control the service infrastructure. | `log_dir` | `DETECTMATE_LOG_DIR` | `./logs` | Directory for log files. | | `log_to_console` | `DETECTMATE_LOG_TO_CONSOLE` | `true` | Whether logs are written to stdout/stderr. | | `log_to_file` | `DETECTMATE_LOG_TO_FILE` | `true` | Whether logs are written to files in `log_dir`. | -| `manager_addr` | `DETECTMATE_MANAGER_ADDR` | `ipc:///tmp/detectmate.cmd.ipc` | Address for management commands (REQ/REP). | +| `http_host` | `DETECTMATE_HTTP_HOST` | `127.0.0.1` | Host address for the HTTP server. +| `http_port` | `DETECTMATE_HTTP_PORT` | `8000` | Port for the HTTP server. | | `manager_recv_timeout` | `DETECTMATE_MANAGER_RECV_TIMEOUT` | `100` | Receive timeout (ms) for the manager command channel. | | `manager_thread_join_timeout` | `DETECTMATE_MANAGER_THREAD_JOIN_TIMEOUT` | `1.0` | Timeout (s) when waiting for the manager thread to stop. | | `engine_addr` | `DETECTMATE_ENGINE_ADDR` | `ipc:///tmp/detectmate.engine.ipc` | Address for data processing (PAIR0/1). | @@ -35,8 +36,9 @@ component_name: "my-detector" log_level: "DEBUG" log_dir: "./logs" -# Manager Interface (Command Channel) -manager_addr: "ipc:///tmp/detectmate.cmd.ipc" +# Manager Interface +http_host: 127.0.0.1 +http_port: 8000 # Engine Interface (Data Channel) engine_addr: "ipc:///tmp/detectmate.engine.ipc" @@ -66,13 +68,40 @@ detectmate start In addition to the service settings (which configure the *runner*), you can also pass a separate configuration file for the specific component logic (e.g., detector parameters) using the `--config` flag in the CLI. This file is specific to the implementation of the component you are running. +Component configuration controls the specific logic of the detector or parser. To support dynamic library loading, this file uses a nested structure. +The configuration must be namespaced by the component category (detectors or parsers) and the specific class name to allow the library to correctly route parameters. +Example detector_config.yaml ```yaml -# detector-config.yaml -threshold: 0.85 -sensitivity: high -enabled: true +detectors: # Category Level + NewValueDetector: # Class Name Level + auto_config: false + method_type: new_value_detector + params: # Implementation Specific Level + log_variables: + - id: test + template: dummy_template + variables: + - name: var1 + pos: 0 + params: + threshold: 0.0 ``` You can read more about Components in the [Using a Library Component](library.md) section. + + +## HTTP Admin Interface + +The service provides a REST API for runtime management and monitoring. + +### Core Endpoints + +| Method | Endpoint | Description | +| :--- | :--- | :--- | +| `GET` | `/admin/status` | Returns the health, running state, and current effective configurations. | +| `POST` | `/admin/start` | Starts the data processing engine thread. | +| `POST` | `/admin/stop` | Stops the data processing engine thread. | +| `POST` | `/admin/reconfigure` | Updates component parameters dynamically. | +| `POST` | `/admin/shutdown` | Gracefully terminates the entire service process. | diff --git a/docs/library.md b/docs/library.md index 5444b67..a8d88b3 100644 --- a/docs/library.md +++ b/docs/library.md @@ -8,9 +8,9 @@ For this, ensure that the library is installed in the same activated virtual env Modify `settings.yaml` to use a library component: ```yaml -component_name: random-detector -component_type: detectors.RandomDetector -component_config_class: detectors.RandomDetectorConfig +component_name: new_value_detector +component_type: detectors.NewValueDetector +component_config_class: detectors.NewValueDetectorConfig config_file: detector-config.yaml log_level: INFO manager_addr: ipc:///tmp/detectmate.cmd.ipc @@ -22,15 +22,25 @@ engine_addr: ipc:///tmp/detectmate.engine.ipc Create `detector-config.yaml`: ```yaml -threshold: 0.75 -window_size: 10 -enabled: true +detectors: # Category Level + NewValueDetector: # Class Name Level + auto_config: false + method_type: new_value_detector + params: # Implementation Specific Level + log_variables: + - id: test + template: dummy_template + variables: + - name: var1 + pos: 0 + params: + threshold: 0.0 ``` ### 3. Start with configuration ```bash -detectmate start --settings settings.yaml --config detector-config.yaml +detectmate --settings settings.yaml --config detector-config.yaml ``` ### 4. Reconfigure at runtime @@ -38,9 +48,19 @@ detectmate start --settings settings.yaml --config detector-config.yaml Create `new-config.yaml`: ```yaml -threshold: 0.85 -window_size: 15 -enabled: true +detectors: + NewValueDetector: + auto_config: false + method_type: new_value_detector + params: + log_variables: + - id: test + template: dummy_template + variables: + - name: var1 + pos: 0 + params: + threshold: 0.8 ``` The service supports dynamic reconfiguration with two modes: @@ -49,14 +69,14 @@ The service supports dynamic reconfiguration with two modes: Changes are applied to the running service but not saved to disk. The changes will be lost when the service restarts. ```bash -detectmate reconfigure --settings settings.yaml --config new-config.yaml +detectmate-client --url 127.0.0.1: 8000 reconfigure path/to/new-config.yaml ``` #### 2. Persistent update (with --persist flag) Changes are applied to the running service AND saved to the original parameter file. The changes persist across service restarts. ```bash -detectmate reconfigure --settings settings.yaml --config new-config.yaml --persist +detectmate-client --url 127.0.0.1: 8000 reconfigure path/to/new-config.yaml --persist ``` -**Note:** The `--persist` flag will overwrite the original parameter file specified in your service configuration with the new values from the `--params` file. +**Note:** The `--persist` flag will overwrite the original parameter file specified in your service configuration with the new values. diff --git a/docs/usage.md b/docs/usage.md index e8b2571..aa2c799 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -6,15 +6,24 @@ DetectMateService provides a command-line interface (CLI) `detectmate` to manage To run a component with default settings only, you can use this command: ```bash -detectmate start +detectmate ``` You should see output like: ``` -[2025-10-21 10:30:00] INFO core.abc123: Manager listening on ipc:///tmp/detectmate.cmd.ipc -[2025-10-21 10:30:00] INFO core.abc123: engine started -[2025-10-21 10:30:00] INFO core.abc123: setup_io: ready to process messages +[2026-01-20 15:16:21,140] INFO service.cli: config file: None +[2026-01-20 15:16:21,140] INFO service.cli: config file: None +[2026-01-20 15:16:21,143] INFO core.5958cc49c05e572baa4f0acbc4b33f87: No output addresses configured, processed messages will not be forwarded +[2026-01-20 15:16:21,143] INFO core.5958cc49c05e572baa4f0acbc4b33f87: engine started +[2026-01-20 15:16:21,143] INFO core.5958cc49c05e572baa4f0acbc4b33f87: setup_io: ready to process messages +[2026-01-20 15:16:21,143] INFO core.5958cc49c05e572baa4f0acbc4b33f87: HTTP Admin active at 127.0.0.1:8000 +[2026-01-20 15:16:21,143] INFO core.5958cc49c05e572baa4f0acbc4b33f87: Auto-starting engine... +INFO: Started server process [3933168] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) + ``` ## Create service settings @@ -26,16 +35,17 @@ component_name: my-first-service component_type: core # or use a library component like "detectors.RandomDetector" log_level: INFO log_dir: ./logs -manager_addr: ipc:///tmp/detectmate.cmd.ipc +http_host: 127.0.0.1 +http_port: 8000 engine_addr: ipc:///tmp/detectmate.engine.ipc ``` ## Start the service with settings -To start the service, use the `start` command. You can optionally specify a settings file and a component configuration file. +To start the service, use the `detectmate` command. You can optionally specify a settings file and a component configuration file. ```bash -detectmate start --settings settings.yaml --config config.yaml +detectmate --settings settings.yaml --config config.yaml ``` - `--settings`: Path to the service settings YAML file. @@ -46,11 +56,9 @@ detectmate start --settings settings.yaml --config config.yaml To check the status of a running service run: ```bash -detectmate status --settings settings.yaml +detectmate-client status --url ``` -The `--settings` argument is required to know where to contact the service manager (via `manager_addr`). - Output: ```json @@ -74,13 +82,13 @@ Output: You can update the component configuration of a running service without restarting it: ```bash -detectmate reconfigure --settings settings.yaml --config new_config.yaml +detectmate-client --url reconfigure new_config.yaml ``` Add `--persist` to save the new configuration to the original config file (if supported). ```bash -detectmate reconfigure --settings settings.yaml --config new_config.yaml --persist +detectmate --url reconfigure new_config.yaml --persist ``` ## Stopping the service @@ -88,5 +96,5 @@ detectmate reconfigure --settings settings.yaml --config new_config.yaml --persi To stop the service: ```bash -detectmate stop --settings settings.yaml +detectmate stop --url ``` From 6d7ec7e8ba31bdd5f1e87de2ce61a63abbaa2d0f Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 15:26:17 +0100 Subject: [PATCH 16/78] update readme --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c01c087..4a3cab4 100644 --- a/README.md +++ b/README.md @@ -73,19 +73,31 @@ Example configuration files can be found in the `tests/config` directory. Start the service: ```bash -uv run detectmate start --settings examples/service_settings.yaml +uv run detectmate --settings examples/service_settings.yaml ``` +To survey the state of your component and interact with the running service, use the detectmate-client tool. Get the service status: ```bash -uv run detectmate status --settings examples/service_settings.yaml +uv run detectmate-client status --url ``` -Stop the service: +Stop the engine: ```bash -uv run detectmate stop --settings examples/service_settings.yaml +uv run detectmate-client stop --url +``` + +Start the engine: +```bash +uv run detectmate-client start --url +``` + +Shutdown entire service: + +```bash +uv run detectmate-client shutdown --url ``` From 62b86732f0aa77fb718338e913f94e9d2bc253c3 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 15:29:21 +0100 Subject: [PATCH 17/78] typo --- docs/library.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/library.md b/docs/library.md index a8d88b3..9d471b0 100644 --- a/docs/library.md +++ b/docs/library.md @@ -69,14 +69,14 @@ The service supports dynamic reconfiguration with two modes: Changes are applied to the running service but not saved to disk. The changes will be lost when the service restarts. ```bash -detectmate-client --url 127.0.0.1: 8000 reconfigure path/to/new-config.yaml +detectmate-client --url 127.0.0.1:8000 reconfigure path/to/new-config.yaml ``` #### 2. Persistent update (with --persist flag) Changes are applied to the running service AND saved to the original parameter file. The changes persist across service restarts. ```bash -detectmate-client --url 127.0.0.1: 8000 reconfigure path/to/new-config.yaml --persist +detectmate-client --url 127.0.0.1:8000 reconfigure path/to/new-config.yaml --persist ``` **Note:** The `--persist` flag will overwrite the original parameter file specified in your service configuration with the new values. From b0c07e5270835f43846e67895c8130e889af50f7 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 17:27:24 +0100 Subject: [PATCH 18/78] empty lines --- src/service/features/engine_socket.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/service/features/engine_socket.py b/src/service/features/engine_socket.py index 678d73b..7b97b6f 100644 --- a/src/service/features/engine_socket.py +++ b/src/service/features/engine_socket.py @@ -11,6 +11,7 @@ @runtime_checkable class EngineSocket(Protocol): """Minimal socket interface the Engine depends on.""" + def recv(self) -> bytes: ... def send(self, data: bytes) -> None: ... def close(self) -> None: ... @@ -21,11 +22,13 @@ def listen(self, addr: str) -> None: ... class EngineSocketFactory(Protocol): """Factory that creates bound EngineSocket instances for a given address.""" + def create(self, addr: str, logger: logging.Logger) -> EngineSocket: ... class NngPairSocketFactory: """Default factory using pynng.Pair0 and binding to the given address.""" + def create(self, addr: str, logger: logging.Logger) -> EngineSocket: sock = pynng.Pair0() parsed = urlparse(addr) From 68beac5aa922f2ad634f9b4ef903bc292d47494f Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 20 Jan 2026 17:29:32 +0100 Subject: [PATCH 19/78] remove pass from abtract method --- src/library/processor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library/processor.py b/src/library/processor.py index 8c6e513..2344bb0 100644 --- a/src/library/processor.py +++ b/src/library/processor.py @@ -6,9 +6,8 @@ class BaseProcessor: def __call__(self, _raw_message: bytes) -> bytes | None: """Decode raw_message, run parser(s)/detector(s), and return something to publish (or None to skip).""" - pass class ProcessorException(Exception): """Custom exception for processor-related errors.""" - pass + ... From 26cc11d102c407300714c7491b2b4c4c8016fc45 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 26 Jan 2026 16:15:36 +0100 Subject: [PATCH 20/78] add metrics endpoint --- src/service/core.py | 32 ++++++++++++++++++++++++++++-- src/service/features/web/server.py | 13 ++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index bbaf448..be2b2d5 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -13,10 +13,21 @@ from service.features.engine import Engine, EngineException from service.features.component_loader import ComponentLoader from service.features.config_loader import ConfigClassLoader -from service.features.web.server import WebServer - from library.processor import BaseProcessor from detectmatelibrary.common.core import CoreComponent, CoreConfig +from prometheus_client import Counter, Gauge + +service_running = Gauge( + "service_running", + "Whether the service engine is running (1 = running, 0 = stopped)", + ["component_type", "component_id"] +) + +engine_starts_total = Counter( + "engine_starts_total", + "Number of times the engine was started", + ["component_type", "component_id"] +) class ServiceProcessorAdapter(BaseProcessor): @@ -57,6 +68,7 @@ def __init__( self.settings: ServiceSettings = settings self.component_id: str = settings.component_id # type: ignore[assignment] self._service_exit_event: threading.Event = threading.Event() + from service.features.web.server import WebServer self.web_server = None self.web_server = WebServer(self) @@ -194,7 +206,19 @@ def start(self) -> str: msg = "Ignored: Engine is already running" self.log.debug(msg) return msg + + engine_starts_total.labels( + component_type=self.component_type, + component_id=self.component_id + ).inc() + msg = Engine.start(self) + + service_running.labels( + component_type=self.component_type, + component_id=self.component_id + ).set(1) + self.log.info(msg) return msg @@ -206,6 +230,10 @@ def stop(self) -> str: self.log.info("Stop command received") try: Engine.stop(self) + service_running.labels( + component_type=self.component_type, + component_id=self.component_id + ).set(0) self.log.info("Engine stopped successfully") return "engine stopped" except EngineException as e: diff --git a/src/service/features/web/server.py b/src/service/features/web/server.py index ca00bf6..e18b8e1 100644 --- a/src/service/features/web/server.py +++ b/src/service/features/web/server.py @@ -2,7 +2,8 @@ import threading from typing import TYPE_CHECKING import uvicorn -from fastapi import FastAPI +from fastapi import FastAPI, Response +from prometheus_client import generate_latest, CONTENT_TYPE_LATEST from service.features.web.router import router, get_service @@ -17,6 +18,14 @@ def __init__(self, service: Service) -> None: self.service = service self.app = FastAPI(title=f"DetectMate Admin - {service.component_id}") + # Prometheus metrics endpoint + @self.app.get("/metrics") # type: ignore[misc] + def metrics() -> Response: + return Response( + content=generate_latest(), + media_type=CONTENT_TYPE_LATEST + ) + # Inject service instance into the router self.app.include_router(router) self.app.dependency_overrides[get_service] = lambda: self.service @@ -28,7 +37,7 @@ def __init__(self, service: Service) -> None: log_level="info", ) self.server = uvicorn.Server(self.config) - self.server.install_signal_handlers = False # Importnt for running in thread, + self.server.install_signal_handlers = False # Important for running in thread, # pythons signal module only allows the Main Thread to register signal handlers # uvicorns default behaviour to listen for shutdown signals will raise ValueError From b6e3ab2c4d4df89488fc48f5232883f625ca2509 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 26 Jan 2026 16:16:05 +0100 Subject: [PATCH 21/78] add dependencies --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 0acaf42..3e81b33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,9 @@ dependencies = [ "pyyaml>=6.0.2", "types-pyyaml>=6.0.12.20250915", "requests>=2.31.0", + "prometheus-client>=0.20.0", + "uvicorn[standard]>=0.34.0", + "fastapi>=0.115.0" ] [dependency-groups] From d8441e139ca2a472b2ce1e25f69ea59338e1489f Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 26 Jan 2026 16:16:26 +0100 Subject: [PATCH 22/78] add metrics to detectmate client --- src/service/client.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/service/client.py b/src/service/client.py index bfa8ed9..c29c6d7 100755 --- a/src/service/client.py +++ b/src/service/client.py @@ -38,6 +38,16 @@ def status(self) -> None: response = requests.get(f"{self.base_url}/admin/status", timeout=self.timeout) self._handle_response(response) + def metrics(self) -> None: + response = requests.get(f"{self.base_url}/metrics", timeout=self.timeout) + try: + response.raise_for_status() + # Prometheus returns plain text + print(response.text) + except requests.exceptions.HTTPError as e: + print(f"Error: {e}") + sys.exit(1) + def reconfigure(self, yaml_file: str, persist: bool) -> None: try: with open(yaml_file, 'r') as f: @@ -82,6 +92,8 @@ def main() -> None: # Status subparsers.add_parser("status", help="Get service status and configuration") + subparsers.add_parser("metrics", help="Get service metrics") + # Reconfigure reconf = subparsers.add_parser("reconfigure", help="Update configuration from a YAML file") reconf.add_argument("file", help="Path to the YAML configuration file") @@ -100,6 +112,8 @@ def main() -> None: client.stop() elif args.command == "status": client.status() + elif args.command == "metrics": + client.metrics() elif args.command == "reconfigure": client.reconfigure(args.file, args.persist) else: From abd541c3361ca9d6626f32b70c55c7fd9ad54e86 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 26 Jan 2026 16:18:55 +0100 Subject: [PATCH 23/78] rename metric --- src/service/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index be2b2d5..fef87d6 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -17,8 +17,8 @@ from detectmatelibrary.common.core import CoreComponent, CoreConfig from prometheus_client import Counter, Gauge -service_running = Gauge( - "service_running", +engine_running = Gauge( + "engine_running", "Whether the service engine is running (1 = running, 0 = stopped)", ["component_type", "component_id"] ) @@ -214,7 +214,7 @@ def start(self) -> str: msg = Engine.start(self) - service_running.labels( + engine_running.labels( component_type=self.component_type, component_id=self.component_id ).set(1) @@ -230,7 +230,7 @@ def stop(self) -> str: self.log.info("Stop command received") try: Engine.stop(self) - service_running.labels( + engine_running.labels( component_type=self.component_type, component_id=self.component_id ).set(0) From eba58c11b65197e4a951efca7fd1bb30235a6a7c Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Mon, 26 Jan 2026 16:25:51 +0100 Subject: [PATCH 24/78] fix imports --- src/service/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/core.py b/src/service/core.py index fef87d6..3991d2b 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -8,6 +8,7 @@ from typing import Optional, Type, Literal, Dict, Any, cast from types import TracebackType +from service.features.web.server import WebServer from service.features.config_manager import ConfigManager from service.settings import ServiceSettings from service.features.engine import Engine, EngineException @@ -68,7 +69,6 @@ def __init__( self.settings: ServiceSettings = settings self.component_id: str = settings.component_id # type: ignore[assignment] self._service_exit_event: threading.Event = threading.Event() - from service.features.web.server import WebServer self.web_server = None self.web_server = WebServer(self) From f7f7de85b64f2b67541e59070a36994fe13041e0 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 27 Jan 2026 13:21:26 +0100 Subject: [PATCH 25/78] add metrics for processed bytes --- src/service/core.py | 18 +++++++++++++++ src/service/features/engine.py | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/service/core.py b/src/service/core.py index 3991d2b..7df035d 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -30,6 +30,24 @@ ["component_type", "component_id"] ) +data_read_bytes_total = Counter( + "data_read_bytes_total", + "Total bytes read from input interfaces", + ["component_type", "component_id"] +) + +data_processed_bytes_total = Counter( + "data_processed_bytes_total", + "Total bytes processed by the engine", + ["component_type", "component_id"] +) + +data_written_bytes_total = Counter( + "data_written_bytes_total", + "Total bytes written to output interfaces", + ["component_type", "component_id"] +) + class ServiceProcessorAdapter(BaseProcessor): """Adapter class to use a Service's process method as a BaseProcessor.""" diff --git a/src/service/features/engine.py b/src/service/features/engine.py index 3265c59..31fc35d 100644 --- a/src/service/features/engine.py +++ b/src/service/features/engine.py @@ -3,6 +3,7 @@ import logging from abc import ABC from typing import Optional, List +from prometheus_client import Counter from service.settings import ServiceSettings from service.features.engine_socket import ( EngineSocketFactory, @@ -12,6 +13,24 @@ # TODO: replace these imports with the actual library implementations from library.processor import BaseProcessor, ProcessorException +data_read_bytes_total = Counter( + "data_read_bytes_total", + "Total bytes read from input interfaces", + ["component_type", "component_id"] +) + +data_written_bytes_total = Counter( + "data_written_bytes_total", + "Total bytes written to output interfaces", + ["component_type", "component_id"] +) + +data_dropped_bytes_total = Counter( + "data_dropped_bytes_total", + "Total bytes dropped due to disconnected or slow downstream peers", + ["component_type", "component_id"] +) + class EngineException(Exception): """Custom exception for engine-related errors.""" @@ -124,6 +143,11 @@ def start(self) -> str: return "engine already running" def _run_loop(self) -> None: + labels = { + "component_type": getattr(self, "component_type", "core"), + "component_id": self.settings.component_id + } + while self._running and not self._stop_event.is_set(): # recv phase @@ -133,6 +157,9 @@ def _run_loop(self) -> None: self.log.debug("Engine: Received empty message, skipping") continue + # TRACK read bytes + data_read_bytes_total.labels(**labels).inc(len(raw)) + self.log.debug(f"Engine: Received {len(raw)} bytes from socket") except pynng.Timeout: continue # Timeout occurred, check running flag and continue @@ -150,6 +177,9 @@ def _run_loop(self) -> None: try: self.log.debug("Engine: Calling processor...") out = self.processor(raw) + if out is not None: + # TRACK written bytes + data_written_bytes_total.labels(**labels).inc(len(out)) self.log.debug(f"Engine: Processor returned: {out!r}") except ProcessorException as e: self.log.error("Processor error: %s", e) @@ -174,6 +204,8 @@ def _run_loop(self) -> None: "sending reply back via engine socket" ) self._pair_sock.send(out) + # TRACK written bytes (Fallback mode) + data_written_bytes_total.labels(**labels).inc(len(out)) self.log.debug("Engine: Reply sent on engine socket") except pynng.NNGException as e: self.log.error("Engine error sending reply on engine socket: %s", e) @@ -181,6 +213,10 @@ def _run_loop(self) -> None: def _send_to_outputs(self, data: bytes) -> None: """Send processed data to all configured output destinations.""" + labels = { + "component_type": getattr(self, "component_type", "core"), + "component_id": self.settings.component_id + } if not self._out_sockets: self.log.debug("Engine: No output sockets configured, skipping send") return @@ -191,8 +227,12 @@ def _send_to_outputs(self, data: bytes) -> None: # Non-blocking send is preferred to avoid stalling the engine loop # Pair0 with block=False will raise TryAgain if the peer is disconnected sock.send(data, block=False) + # TRACK written bytes + data_written_bytes_total.labels(**labels).inc(len(data)) self.log.debug(f"Engine: Send completed to output socket {i}") except pynng.TryAgain: + # TRACK dropped bytes + data_dropped_bytes_total.labels(**labels).inc(len(data)) self.log.warning(f"Engine: Output socket {i} not ready or disconnected, dropping message") except pynng.NNGException as e: self.log.error(f"Engine error sending to output socket {i}: {e}") From 9870fc3dc2014f06eeeb894c7a08fbd08c4cc707 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 27 Jan 2026 13:32:32 +0100 Subject: [PATCH 26/78] avoid counter ducplcation in registry --- src/service/core.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index 7df035d..454e418 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -16,7 +16,8 @@ from service.features.config_loader import ConfigClassLoader from library.processor import BaseProcessor from detectmatelibrary.common.core import CoreComponent, CoreConfig -from prometheus_client import Counter, Gauge +from prometheus_client import REGISTRY, Counter, Gauge + engine_running = Gauge( "engine_running", @@ -30,23 +31,20 @@ ["component_type", "component_id"] ) -data_read_bytes_total = Counter( - "data_read_bytes_total", - "Total bytes read from input interfaces", - ["component_type", "component_id"] -) -data_processed_bytes_total = Counter( - "data_processed_bytes_total", - "Total bytes processed by the engine", - ["component_type", "component_id"] -) +def get_counter(name: str, documentation: str, labelnames: list[str]) -> Counter: + """Safely get or create a Prometheus counter.""" + # Search the registry for an existing collector with this name + for collector in REGISTRY._collector_to_names: + if name in REGISTRY._collector_to_names[collector]: + return collector + # If not found, create it + return Counter(name, documentation, labelnames) -data_written_bytes_total = Counter( - "data_written_bytes_total", - "Total bytes written to output interfaces", - ["component_type", "component_id"] -) + +data_processed_bytes_total = get_counter("data_processed_bytes_total", + "Total bytes processed by the engine", [ + "component_type", "component_id"]) class ServiceProcessorAdapter(BaseProcessor): @@ -171,6 +169,13 @@ def get_config_schema(self) -> Type[CoreConfig]: def process(self, raw_message: bytes) -> bytes | None | Any: """Process the raw message using the library component or default implementation.""" + + if raw_message: + data_processed_bytes_total.labels( + component_type=self.component_type, + component_id=self.component_id + ).inc(len(raw_message)) + if self.library_component: # use the library component's process method return self.library_component.process(raw_message) From 81c8a673fa7e0fb46d673f950894664f2bf9d548 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 27 Jan 2026 16:44:35 +0100 Subject: [PATCH 27/78] make service_running metric Enum --- src/service/core.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index 454e418..b75d4f1 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -16,13 +16,14 @@ from service.features.config_loader import ConfigClassLoader from library.processor import BaseProcessor from detectmatelibrary.common.core import CoreComponent, CoreConfig -from prometheus_client import REGISTRY, Counter, Gauge +from prometheus_client import REGISTRY, Counter, Enum -engine_running = Gauge( +engine_running = Enum( "engine_running", - "Whether the service engine is running (1 = running, 0 = stopped)", - ["component_type", "component_id"] + "Whether the service engine is running (running or stopped)", + ["component_type", "component_id"], + states=['running', 'stopped'], ) engine_starts_total = Counter( @@ -240,7 +241,7 @@ def start(self) -> str: engine_running.labels( component_type=self.component_type, component_id=self.component_id - ).set(1) + ).state('running') self.log.info(msg) return msg @@ -256,7 +257,7 @@ def stop(self) -> str: engine_running.labels( component_type=self.component_type, component_id=self.component_id - ).set(0) + ).state('stopped') self.log.info("Engine stopped successfully") return "engine stopped" except EngineException as e: From 812401c0aa44076fdbf488b55f43676f26c4f451 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Wed, 28 Jan 2026 10:42:55 +0100 Subject: [PATCH 28/78] Update package-ecosystem to 'UV' in dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1cd61df --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "UV" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From 63205f8642ec13a153b49daf41ceeb96dde40bf6 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Thu, 29 Jan 2026 10:56:56 +0100 Subject: [PATCH 29/78] Update dependabot.yml --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1cd61df..3bfe00c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ version: 2 updates: - - package-ecosystem: "UV" # See documentation for possible values + - package-ecosystem: "uv" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" From eabf38d8bca3d3ed604d784d7c74316ef7f8fcfe Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 29 Jan 2026 14:41:16 +0100 Subject: [PATCH 30/78] move run out of Engine init --- src/service/core.py | 10 +++++----- src/service/features/engine.py | 4 +--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/service/core.py b/src/service/core.py index bbaf448..6d01f8a 100644 --- a/src/service/core.py +++ b/src/service/core.py @@ -116,10 +116,9 @@ def __init__( # Create processor instance self.processor = self.create_processor() - # then init Engine with the processor (opens PAIR socket, may autostart) + # then init Engine with the processor (opens PAIR socket) Engine.__init__(self, settings=settings, processor=self.processor, logger=self.log) - - self.log.debug("%s[%s] created", self.component_type, self.component_id) + self.log.debug("%s[%s] created and fully initialized", self.component_type, self.component_id) def get_config_schema(self) -> Type[CoreConfig]: """Return the configuration schema for this service. @@ -164,12 +163,13 @@ def setup_io(self) -> None: def run(self) -> None: """Starts the WebServer and waits for the shutdown signal.""" - # 1. Start Web Server + # 1. Start Web Server (Admin API) if self.web_server: self.log.info(f"HTTP Admin active at {self.settings.http_host}:{self.settings.http_port}") self.web_server.start() # 2. Engine Start logic + # __init__ is 100% finished if self.settings.engine_autostart: self.log.info("Auto-starting engine...") self.start() @@ -183,7 +183,7 @@ def run(self) -> None: if self.web_server: self.web_server.stop() if getattr(self, "_running", False): - Engine.stop(self) + self.stop() # This calls the Service.stop which calls Engine.stop else: self.log.debug("Engine already stopped") diff --git a/src/service/features/engine.py b/src/service/features/engine.py index 3265c59..cbc9779 100644 --- a/src/service/features/engine.py +++ b/src/service/features/engine.py @@ -73,9 +73,7 @@ def __init__( self.log.warning("Failed to close engine input socket after setup failure: %s", e) raise - # autostart if enabled - if getattr(self.settings, "engine_autostart", True): - self.start() + self.log.debug("Engine initialized and ready.") def _setup_output_sockets(self) -> None: """Create and connect output sockets for all destinations in out_addr. From f1d987b133db34504b15a09f1e07dcbffe579eb5 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 29 Jan 2026 15:48:20 +0100 Subject: [PATCH 31/78] add docs on service library interface --- docs/index.md | 2 + docs/interfaces.md | 252 +++++++++++++++++++++++++++++++++++++++++++++ docs/library.md | 2 + docs/usage.md | 2 +- 4 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 docs/interfaces.md diff --git a/docs/index.md b/docs/index.md index fe1dc0b..8229b07 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,3 +17,5 @@ It uses NNG's messaging architecture to process data in real-time. Check out the [Installation](installation.md) guide to set up the service, and then proceed to [Configuration](configuration.md) and [Usage](usage.md) to learn how to run it. + +For library developers implementing custom components, see the [Library Interface Contract](interfaces.md). diff --git a/docs/interfaces.md b/docs/interfaces.md new file mode 100644 index 0000000..c8aa84b --- /dev/null +++ b/docs/interfaces.md @@ -0,0 +1,252 @@ +# Library Interface Contract + +This document describes the interface contract between DetectMateService and DetectMateLibrary. If you're implementing custom components in the library, your classes must adhere to these interfaces. + +## CoreComponent Interface + +All processing components (readers, parsers, detectors) must inherit from `CoreComponent`: + +```python +from detectmatelibrary.common.core import CoreComponent + +class MyComponent(CoreComponent): + def __init__(self, config=None): + """Initialize the component. + + Args: + config: Optional configuration dictionary or CoreConfig instance. + May be None if no configuration is provided. + """ + super().__init__(config) + # Your initialization here + + def process(self, data: bytes) -> bytes | None: + """Process incoming data. + + Args: + data: Raw bytes received from the upstream component. + + Returns: + bytes: Processed data to forward to downstream components. + None: Skip forwarding (filter out this message). + """ + # Your processing logic here + return processed_data +``` + +### Key Requirements + +- **Constructor**: Must accept an optional `config` parameter (can be `dict` or `CoreConfig` instance) +- **process() method**: Must accept `bytes` and return `bytes | None` +- **Return behavior**: + - Return `bytes` to forward output to downstream components + - Return `None` to skip/filter the message (no output sent) + +## CoreConfig Interface + +Configuration classes must inherit from `CoreConfig`, which extends Pydantic's `BaseModel`: + +```python +from detectmatelibrary.common.core import CoreConfig + +class MyComponentConfig(CoreConfig): + """Configuration for MyComponent.""" + threshold: float = 0.5 + window_size: int = 10 + enabled: bool = True +``` + +### Key Requirements + +- **Pydantic BaseModel**: Must support `model_validate()` and `model_dump()` methods +- **Type hints**: All fields should have type annotations +- **Defaults**: Provide sensible defaults where appropriate + +### Configuration Flow + +1. Service loads config from YAML file via `ConfigManager` +2. Schema identification: The service calls `get_config_schema()`, which uses `ConfigClassLoader` to dynamically import and verify the configuration class. + - Validation: It ensures the config class is a subclass of `CoreConfig`. +3. Component Instantiation: The service identifies the `component_type` from settings. It uses `ComponentLoader` to dynamically load the class. + - Validation: It ensures the component class is an instance of `CoreComponent` +4. Config from `ConfigManager` is passed to component constructor +5. The Library processes and validates the configuration internally + - Validation: The library checks if `auto_config` is enabled. If disabled and no `params` exist, it raises an AutoConfigError. + + - Type Checking: It ensures the method_type matches the expected component type (via `check_type`). + + - Formatting (`apply_format`): It iterates through the params dictionary. For every parameter, it applies a specific format. + + - Keyword Cleaning: If a parameter key starts with `all_`, the library processes it and strips the prefix (e.g., all_threshold becomes threshold). + + - Flattening: The library flattens the structure by updating the top-level config dictionary with the contents of params and then deleting the now-redundant `params` key. +6. Processor Adaptation: The service wraps the `CoreComponent` in a `LibraryComponentProcessor` (an adapter) to make it compatible with the `Engine` loop. +7. At runtime, `reconfigure` command can update configs dynamically + +## Component Loading + +Components are loaded dynamically by `ComponentLoader`. Specify components using a dot-separated path: + +### Path Format + +``` +module.ClassName +``` + +Examples: +- `detectors.RandomDetector` +- `parsers.JsonParser` +- `readers.FileReader` + +### Resolution Order + +1. **DetectMateLibrary-relative** (tried first): `detectmatelibrary.{path}` + - `detectors.RandomDetector` → `detectmatelibrary.detectors.RandomDetector` +2. **Absolute import** (fallback): `{path}` as-is + - `mypackage.detectors.CustomDetector` → `mypackage.detectors.CustomDetector` + +This allows you to use library components with short paths while still supporting custom components from external packages. + +### Service Settings + +In your service settings YAML, specify: + +```yaml +component_type: detectors.MyDetector # Component class path +component_config_class: detectors.MyDetectorConfig # Config class path +config_file: detector-config.yaml # Path to component config +``` + +## Data Flow Schemas + +Components in the processing pipeline use protobuf schemas for structured data exchange: + +| Stage | Input | Output Schema | +|-------|-------|---------------| +| Reader | Raw source (file, network, etc.) | `LogSchema` | +| Parser | `LogSchema` bytes | `ParserSchema` | +| Detector | `ParserSchema` bytes | `DetectorSchema` | + +Each component receives serialized protobuf bytes, deserializes them, processes the data, and serializes the output for the next stage. + +## Complete Example + +Here's a minimal detector component implementation: + +### 1. Config Class (`detectors/random_detector.py`) + +```python +from detectmatelibrary.common._config._formats import LogVariables, AllLogVariables + +from detectmatelibrary.common.detector import CoreDetector, CoreDetectorConfig + +from detectmatelibrary.utils.data_buffer import BufferMode + +import detectmatelibrary.schemas as schemas + +from typing_extensions import override +from typing import List, Any +import numpy as np + + +class RandomDetectorConfig(CoreDetectorConfig): + method_type: str = "random_detector" + + log_variables: LogVariables | AllLogVariables | dict[str, Any] = {} + + +class RandomDetector(CoreDetector): + """Detects anomalies randomly in logs, completely independent of the input + data.""" + + def __init__( + self, name: str = "RandomDetector", config: RandomDetectorConfig = RandomDetectorConfig() + ) -> None: + if isinstance(config, dict): + config = RandomDetectorConfig.from_dict(config, name) + super().__init__(name=name, buffer_mode=BufferMode.NO_BUF, config=config) + self.config: RandomDetectorConfig + + @override + def train(self, input_: List[schemas.ParserSchema] | schemas.ParserSchema) -> None: # type: ignore + """Training is not applicable for RandomDetector.""" + return + + @override + def detect( + self, input_: schemas.ParserSchema, output_: schemas.DetectorSchema # type: ignore + ) -> bool: + """Detect anomalies randomly in the input data.""" + overall_score = 0.0 + alerts = {} + + relevant_log_fields = self.config.log_variables[input_["EventID"]].get_all() # type: ignore + for log_variable in relevant_log_fields.values(): + score = 0.0 + random = np.random.rand() + if random > log_variable.params["threshold"]: + score = 1.0 + alerts.update({log_variable.name: str(score)}) # type: ignore + overall_score += score + + if overall_score > 0: + output_["score"] = overall_score + output_["alertsObtain"].update(alerts) + return True + + return False +``` + +### 2. Service Settings (`settings.yaml`) + +```yaml +component_name: random-detector +component_type: detectors.random_detector.RandomDetector +component_config_class: detectors.random_detector.RandomDetectorConfig +config_file: random-config.yaml +log_level: INFO +http_host: 127.0.0.1 +http_port: 8000 +engine_addr: ipc:///tmp/threshold.engine.ipc +``` + +### 3. Component Config (`random-config.yaml`) + +Component configuration uses a nested structure: + +```yaml +detectors: + RandomDetector: + method_type: random_detector + auto_config: False + params: + log_variables: + - id: test + event: 1 + template: dummy_template + variables: + - pos: 0 + name: var1 + params: + threshold: 0. + header_variables: + - pos: level + params: {} +``` + +This hierarchical format allows the library to correctly route parameters based on category and class name. + +### 4. Run the Service + +```bash +detectmate --settings settings.yaml --configs random-config.yaml +``` + +## Validation + +The service validates components at load time: + +1. **Component class**: Must be an instance of `CoreComponent` (in `ComponentLoader`) +2. **Config class**: Must be a subclass of `CoreConfig` (in `ConfigClassLoader`) + +If validation fails, the service raises an error. diff --git a/docs/library.md b/docs/library.md index 9d471b0..59d4718 100644 --- a/docs/library.md +++ b/docs/library.md @@ -1,3 +1,5 @@ +> **Note**: For implementing custom library components, see the [Library Interface Contract](interfaces.md). + ## Using a Library Component The Service can be run as any component imported from the [DetectMateLibrary](https://github.com/ait-detectmate/DetectMateLibrary). diff --git a/docs/usage.md b/docs/usage.md index aa2c799..e11d6cc 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -82,7 +82,7 @@ Output: You can update the component configuration of a running service without restarting it: ```bash -detectmate-client --url reconfigure new_config.yaml +detectmate-client --url reconfigure new_config.yaml ``` Add `--persist` to save the new configuration to the original config file (if supported). From f02d9ffd5cb22f16bcc5812de50c473266e4d13c Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 29 Jan 2026 16:45:17 +0100 Subject: [PATCH 32/78] add docs on library imports in service --- docs/library-imports.md | 155 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/library-imports.md diff --git a/docs/library-imports.md b/docs/library-imports.md new file mode 100644 index 0000000..6231ae8 --- /dev/null +++ b/docs/library-imports.md @@ -0,0 +1,155 @@ +# Library Import Points + +This document provides an overview of where DetectMateService imports from DetectMateLibrary and how those imports are used. For implementation details of the library classes, refer to the DetectMateLibrary documentation. + +## Summary of Imports + +| Import | Source Module | Used In | Purpose | +|--------|---------------|---------|---------| +| `CoreComponent` | `detectmatelibrary.common.core` | `core.py`, `component_loader.py` | Base class for all processing components | +| `CoreConfig` | `detectmatelibrary.common.core` | `core.py`, `config_loader.py`, `config_manager.py` | Base class for configuration schemas | +| `LogSchema` | `detectmatelibrary.schemas` | Integration tests | Reader output format | +| `ParserSchema` | `detectmatelibrary.schemas` | Integration tests | Parser output format | +| `DetectorSchema` | `detectmatelibrary.schemas` | Integration tests | Detector output format | + +## CoreComponent + +**Import location:** `src/service/core.py`, `src/service/features/component_loader.py` + +```python +from detectmatelibrary.common.core import CoreComponent +``` + +### Usage Points + +#### 1. Component Loading (`component_loader.py`) + +The `ComponentLoader` dynamically imports component classes and validates they inherit from `CoreComponent`: + +- **Instantiation**: Components are instantiated with an optional config parameter +- **Type checking**: `isinstance(instance, CoreComponent)` validates the loaded class + +```python +instance = component_class(config=config) +if not isinstance(instance, CoreComponent): + raise TypeError(...) +``` + +#### 2. Processor Adapter (`core.py`) + +The `LibraryComponentProcessor` wraps a `CoreComponent` to use it as the service's message processor: + +- **process() invocation**: The service calls `component.process(raw_message)` for each incoming message +- **Return handling**: `bytes` output is forwarded; `None` skips the message + +```python +result = self.component.process(raw_message) +``` + +### What the Service Expects from CoreComponent + + + +- Constructor accepts optional `config` parameter +- `process(data: bytes) -> bytes | None` method handles message processing +- See [Library Interface Contract](interfaces.md) for the full interface specification + +## CoreConfig + +**Import location:** `src/service/core.py`, `src/service/features/config_loader.py`, `src/service/features/config_manager.py` + +```python +from detectmatelibrary.common.core import CoreConfig +``` + +### Usage Points + +#### 1. Config Class Loading (`config_loader.py`) + +The `ConfigClassLoader` dynamically imports config classes and validates they inherit from `CoreConfig`: + +- **Subclass checking**: `issubclass(config_class, CoreConfig)` validates the class hierarchy + +```python +if not issubclass(config_class, CoreConfig): + raise TypeError(...) +``` + +#### 2. Schema for ConfigManager (`config_manager.py`) + +The `ConfigManager` uses `CoreConfig` subclasses as Pydantic schemas for validation: + +- **Default creation**: `self.schema()` creates default config instances +- **Validation**: `self.schema.model_validate(data)` validates incoming config data +- **Serialization**: `model_dump()` converts config to dict for YAML storage + +```python +# Validation +self._configs = self.schema.model_validate(new_configs) + +# Serialization +data = self._configs.model_dump() +``` + +#### 3. Service Initialization (`core.py`) + +The `Service.get_config_schema()` method returns the appropriate `CoreConfig` subclass for the component. + +### What the Service Expects from CoreConfig + + + +- Must be a Pydantic `BaseModel` subclass +- Must support `model_validate(data)` for validation +- Must support `model_dump()` for serialization +- See [Library Interface Contract](interfaces.md) for the full interface specification + +## Protobuf Schemas + +**Import location:** Integration tests only (`tests/library_integration/`) + +```python +from detectmatelibrary.schemas import LogSchema, ParserSchema, DetectorSchema +``` + +### Usage Points + +The schemas are used in integration tests to verify correct data flow between pipeline stages: + +- **LogSchema**: Serialized output from Reader components +- **ParserSchema**: Serialized output from Parser components +- **DetectorSchema**: Serialized output from Detector components + +### Data Flow + +``` +Reader Parser Detector + | | | + v v v +LogSchema bytes ---> ParserSchema bytes ---> DetectorSchema bytes +``` + +### What the Service Expects from Schemas + + + +- Protobuf message classes with `SerializeToString()` and `ParseFromString()` methods +- Consistent structure for pipeline interoperability + +## Import Resolution + +The service uses a two-step import resolution for library components: + +1. **DetectMateLibrary-relative** (tried first): Prepends `detectmatelibrary.` to the path +2. **Absolute import** (fallback): Uses the path as-is + +This allows short paths like `detectors.RandomDetector` to resolve to `detectmatelibrary.detectors.RandomDetector`, while still supporting custom components from external packages. + +## File Reference + +| Service File | Library Imports | Purpose | +|--------------|-----------------|---------| +| `src/service/core.py` | `CoreComponent`, `CoreConfig` | Service base class, processor adapter | +| `src/service/features/component_loader.py` | `CoreComponent` | Dynamic component loading | +| `src/service/features/config_loader.py` | `CoreConfig` | Dynamic config class loading | +| `src/service/features/config_manager.py` | `CoreConfig` | Configuration validation and persistence | From 7a24af443894a6936ada91f040d1e5bb1d1f0d5c Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 29 Jan 2026 16:52:32 +0100 Subject: [PATCH 33/78] add imports to index! --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 8229b07..5baacfd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,4 +18,6 @@ It uses NNG's messaging architecture to process data in real-time. Check out the [Installation](installation.md) guide to set up the service, and then proceed to [Configuration](configuration.md) and [Usage](usage.md) to learn how to run it. + +For a list of imports from the DetectMateLinbrary in the Service and their usage [Library Imports](library-imports.md). For library developers implementing custom components, see the [Library Interface Contract](interfaces.md). From 53c6cf7b00715ca8c7fe6c429cadcf2cb172021a Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 09:41:13 +0100 Subject: [PATCH 34/78] Updated docs --- docs/contribution.md | 127 +++++++++++++++++++++++++++++++ docs/index.md | 6 ++ images/GitHub-Contrib.drawio | 121 +++++++++++++++++++++++++++++ images/GitHub-Contrib.drawio.png | Bin 0 -> 88287 bytes 4 files changed, 254 insertions(+) create mode 100644 docs/contribution.md create mode 100644 images/GitHub-Contrib.drawio create mode 100644 images/GitHub-Contrib.drawio.png diff --git a/docs/contribution.md b/docs/contribution.md new file mode 100644 index 0000000..8f9dde5 --- /dev/null +++ b/docs/contribution.md @@ -0,0 +1,127 @@ +# Contributing + +We're happily taking patches and other contributions. Below is a summary of the processes we follow for any contribution. + +## Bug reports and enhancement requests + +Bug reports and enhancement requests are an important part of making `DetectMateService` more stable and are curated through Github issues. +Before reporting an issue, check our backlog of open issues to see if anybody else has already reported it. +If that is the case, you might be able to give additional information on that issue. +Bug reports are very helpful to us in improving the software, and therefore, they are very welcome. It is very important to give us +at least the following information in a bug report: + +1. Description of the bug. Describe the problem clearly. +2. Steps to reproduce. With the following configuration, go to.., click.., see error +3. Expected behavoir. What should happen? +4. Environment. What was the environment for the test(version, browser, etc..) + +*Please don't include any private/sensitive information in your issue! For reporting security-related issues, see [SECURITY.md](https://github.com/ait-detectmate/DetectMateService/blob/main/SECURITY.md)* + +## Working on the codebase + +To contribute to this project, you must fork the project and create a pull request to the upstream repository. The following figure shows the workflow: + +![GitHub Workflow]( images/GitHub-Contrib.drawio.png) + +### 1. Fork + +Go to [https://github.com/ait-detectmate/DetectMateService.git](https://github.com/ait-detectmate/DetectMateService.git) and click on fork. Please note that you must login first to GitHub. + +### 2. Clone + +After forking the repository into your own workspace, clone the development branch of that repository. + +```bash +git clone -b development git@github.com:YOURUSERNAME/DetectMateService.git +``` + +### 3. Create a feature branch + +Every single workpackage should be developed in it's own feature-branch. Use a name that describes the feature: + +```bash +cd DetectMateService +git checkout -b feature-some_important_work +``` + +### 4. Develop your feature and improvements in the feature-branch + +Please make sure that you commit only improvements that are related to the workpage you created the feature-branch for. See the section [Development](development.md) for detailed information about how to develope code for `DetectMateService`. + +*`DetectMateService` uses [prek](https://github.com/j178/prek) to ensure code quality. Make sure that you use it properly* + +### 5. Fetch and merge from the upstream + +If your work on this feature-branch is done, make sure that you are in sync with the branch of the upstream: + +```bash +git remote add upstream git@github.com:ait-detectmate/DetectMateService.git +git pull upstream development +``` + +If any conflicts occur, fix them and add them using `git add` and continue with the merge or fast-forward. + +Additional infos: + +- [https://www.atlassian.com/git/tutorials/merging-vs-rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) +- [https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing) +- [https://dev.to/toogoodyshoes/mastering-rebasing-and-fast-forwarding-in-git-2j19](https://dev.to/toogoodyshoes/mastering-rebasing-and-fast-forwarding-in-git-2j19) + +### 6. Push the changes to your GitHub-repository + +Before we can push our changes, we have to make sure that we don't have unnecessary commits. First checkout our commits: + +```bash +git log +``` + +After that we can squash the last n commits together: + +```bash +git rebase -i HEAD~n +``` + +Finally you can push the changes to YOUR github-repository: + +```bash +git push +``` + +Additional documentation: + +- [https://www.atlassian.com/git/tutorials/merging-vs-rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) + +### 7. Submit your pull-request + +Use the GitHub-Webinterface to create a pull-request. Make sure that the target-repository is `ait-detectmate/DetectMateService`. + +If your pull-request was accepted and merged into the development branch continue with "8. Update your local development branch". If it wasn't accepted, read the comments and fix the problems. Before pushing the changes make sure that you squashed them with your last commit: + +```bash +git rebase -i HEAD~2 +``` + +Delete your local feature-branch after the pull-request was merged into the development branch. + +### 8. Update your local main branch + +Update your local development branch: + +```bash +git fetch upstream development +git checkout -b development +git rebase upstream/development +``` + +Additional infos: + +- [https://www.atlassian.com/git/tutorials/merging-vs-rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) + +### 9. Update your main branch in your github-repository + +Please make sure that you updated your local development branch as described in section 8. above. After that push the changes to your github-repository to keep it up2date: + +```bash +git push +``` + diff --git a/docs/index.md b/docs/index.md index fe1dc0b..57615e8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,3 +17,9 @@ It uses NNG's messaging architecture to process data in real-time. Check out the [Installation](installation.md) guide to set up the service, and then proceed to [Configuration](configuration.md) and [Usage](usage.md) to learn how to run it. + +## Contribution + +We're happily taking patches and other contributions. Please see the following links for how to get started: + +- [Git Workflow](contribution.md) diff --git a/images/GitHub-Contrib.drawio b/images/GitHub-Contrib.drawio new file mode 100644 index 0000000..a591ed8 --- /dev/null +++ b/images/GitHub-Contrib.drawio @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/GitHub-Contrib.drawio.png b/images/GitHub-Contrib.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..07f44fb446353723d0b9939eb3f9a3c853fc2ff7 GIT binary patch literal 88287 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 Date: Mon, 2 Feb 2026 09:48:34 +0100 Subject: [PATCH 35/78] Moved images to docs --- {images => docs/images}/GitHub-Contrib.drawio | 0 {images => docs/images}/GitHub-Contrib.drawio.png | Bin 2 files changed, 0 insertions(+), 0 deletions(-) rename {images => docs/images}/GitHub-Contrib.drawio (100%) rename {images => docs/images}/GitHub-Contrib.drawio.png (100%) diff --git a/images/GitHub-Contrib.drawio b/docs/images/GitHub-Contrib.drawio similarity index 100% rename from images/GitHub-Contrib.drawio rename to docs/images/GitHub-Contrib.drawio diff --git a/images/GitHub-Contrib.drawio.png b/docs/images/GitHub-Contrib.drawio.png similarity index 100% rename from images/GitHub-Contrib.drawio.png rename to docs/images/GitHub-Contrib.drawio.png From 82bbb525d9a1015c206a67d1adc9a3879b88b2d3 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 09:52:59 +0100 Subject: [PATCH 36/78] Added SECURITY.md --- SECURITY.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..5829fed --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,32 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.x.x | :white_check_mark: | +| < 1.0.0 | :x: | + +> [!IMPORTANT] +> Currently DetectMateService is a work in progress and heavily under development. Possible vulnerabilities will not be treated any special and can be issued using [GitHub-Issues](https://github.com/ait-detectmate/DetectMateService/issues) + +## Reporting a Vulnerability + +Please email reports about any security related issues you find to aecid@ait.ac.at. This mail is delivered to a small developer team. Your email will be acknowledged within one business day, and you'll receive a more detailed response to your email within 7 days indicating the next steps in handling your report. + +Please use a descriptive subject line for your report email. After the initial reply to your report, our team will endeavor to keep you informed of the progress being made towards a fix and announcement. + +In addition, please include the following information along with your report: + +* Your name and affiliation (if any). +* A description of the technical details of the vulnerabilities. It is very important to let us know how we can reproduce your findings. +* An explanation who can exploit this vulnerability, and what they gain when doing so -- write an attack scenario. This will help us evaluate your report quickly, especially if the issue is complex. +* Whether this vulnerability public or known to third parties. If it is, please provide details. +* Whether we could mention your name in the changelogs. + +Once an issue is reported we use the following disclosure process: + +* When a report is received, we confirm the issue and determine its severity. +* If we know of specific third-party services or software based on DetectMateService that require mitigation before publication, those projects will be notified. +* Fixes are prepared for the last minor release of the latest major release. +* Patch releases are published for all fixed released versions. From f7227302f163aee81d9d1e4e66766210c9d00ae3 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 09:55:46 +0100 Subject: [PATCH 37/78] Updated README --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c01c087..34fddc1 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,13 @@ docker compose up demo ## Documentation -- [Project Documentation](https://ait-detectmate.github.io/DetectMateService/) +- [Project Documentation](https://ait-detectmate.github.io/DetectMateService/latest) + +## Contribution + +We're happily taking patches and other contributions. Please see the following links for how to get started: + +- [GitHub Workflow](https://ait-detectmate.github.io/DetectMateService/latest/Contribution) ## License From 6549b8859104f55ee07daeb87dd7d710d92489c0 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 10:13:03 +0100 Subject: [PATCH 38/78] Installed issue and pr-templates --- .github/ISSUE_TEMPLATE/01_bug_report.md | 21 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/02_feature_request.md | 21 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .github/pull_request_template.md | 18 +++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/01_bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/02_feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.md b/.github/ISSUE_TEMPLATE/01_bug_report.md new file mode 100644 index 0000000..a258c95 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01_bug_report.md @@ -0,0 +1,21 @@ +--- +name: 🐜 Bug report +about: If something isn't working 🔧 +--- + +### Subject of the issue +Describe your issue here. + +### Your environment +* Version of ruby +* Docker or manual installation? +* Which browser and its version + +### Steps to reproduce +Tell us how to reproduce this issue. + +### Expected behaviour +Tell us what should happen + +### Actual behaviour +Tell us what happens instead diff --git a/.github/ISSUE_TEMPLATE/02_feature_request.md b/.github/ISSUE_TEMPLATE/02_feature_request.md new file mode 100644 index 0000000..c06bb3b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02_feature_request.md @@ -0,0 +1,21 @@ +--- +name: 🚀 Feature request +about: If you have a feature request 💡 +--- + +**Context** + +What are you trying to do and how would you want to do it differently? Is it something you currently you cannot do? Is this related to an issue/problem? + +**Alternatives** + +Can you achieve the same result doing it in an alternative way? Is the alternative considerable? + +**Has the feature been requested before?** + +Please provide a link to the issue. + +**If the feature request is approved, would you be willing to submit a PR?** + +Yes / No _(Help can be provided if you need assistance submitting a PR)_ + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..a503370 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +# Task + + +# Description + + + + +# How Has This Been Tested? + + +# Checklist + + +- [ ] I have successfully run overcommit locally +- [ ] I have added tests to cover my changes +- [ ] I have linked the issue-id to the task-description +- [ ] I have performed a self-review of my own code From 911fb5463e07b781adcfd38a5f125537899ca36c Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 10:25:27 +0100 Subject: [PATCH 39/78] Added development.md --- docs/development.md | 17 +++++++++++++++++ docs/installation.md | 13 ------------- mkdocs.yml | 2 ++ 3 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 docs/development.md diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..f784452 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,17 @@ +# Development + +## Setup + +For development, you can install with optional dependencies: + +```bash +uv sync --dev +``` + +We are insisting to use [`prek`](https://github.com/j178/prek) to run basic checks at commit time. +`prek` is configured via the existing `.pre-commit-config.yaml` +and can be installed as part of the `dev` extras. To ensure pre-commit hooks run before each commit, run: +```bash +uv run prek install +``` + diff --git a/docs/installation.md b/docs/installation.md index 75d350b..5fba05a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -32,17 +32,4 @@ pip install . ``` -## Developer setup -For development, you can install with optional dependencies: - -```bash -uv sync --dev -``` - -We recommend using [`prek`](https://github.com/j178/prek) to manage Git -pre-commit hooks. `prek` is configured via the existing `.pre-commit-config.yaml` -and can be installed as part of the `dev` extras. To ensure pre-commit hooks run before each commit, run: -```bash -uv run prek install -``` diff --git a/mkdocs.yml b/mkdocs.yml index 3527466..287cf24 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -13,3 +13,5 @@ nav: - Quick Start: usage.md - Using a Library Component: library.md - Running a Pipeline: pipeline.md + - Contribution: contribution.md + - Development: development.md From 696997504966612353957b657b1fc6991208fb38 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 11:40:40 +0100 Subject: [PATCH 40/78] Improved development.md --- docs/development.md | 24 ++++++++++++-- docs/images/High-Level-Schema.drawio | 40 +++++++++++++++++++++++ docs/images/High-Level-Schema.drawio.png | Bin 0 -> 23394 bytes docs/index.md | 9 +++++ mkdocs.yml | 4 +++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 docs/images/High-Level-Schema.drawio create mode 100644 docs/images/High-Level-Schema.drawio.png diff --git a/docs/development.md b/docs/development.md index f784452..47617cb 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,6 +1,13 @@ # Development -## Setup +This section describes how to setup a development environment and how to contribute to `DetectMateService`. + +!!! note + + Read the [Contribution Guide](contribution.md) to follow and understand the development workflow. + + +## Setup a development environment For development, you can install with optional dependencies: @@ -8,10 +15,23 @@ For development, you can install with optional dependencies: uv sync --dev ``` -We are insisting to use [`prek`](https://github.com/j178/prek) to run basic checks at commit time. +*Please note that this step is not necessary. `uv run --dev` will automatically download all dependencies.* + + +## Use prek to run code checks + +Every code contributer must use [`prek`](https://github.com/j178/prek) to run basic checks at commit time. `prek` is configured via the existing `.pre-commit-config.yaml` and can be installed as part of the `dev` extras. To ensure pre-commit hooks run before each commit, run: + ```bash uv run prek install ``` +## Add tests and run pytest + +In oder to run the tests run the following command: + +```bash +uv run --dev pytest +``` diff --git a/docs/images/High-Level-Schema.drawio b/docs/images/High-Level-Schema.drawio new file mode 100644 index 0000000..48d283d --- /dev/null +++ b/docs/images/High-Level-Schema.drawio @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/High-Level-Schema.drawio.png b/docs/images/High-Level-Schema.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..596c06af61add00ebfd278c38bc7751a068e95b2 GIT binary patch literal 23394 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 Date: Mon, 2 Feb 2026 12:00:56 +0100 Subject: [PATCH 41/78] Updated README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 34fddc1..4ca65de 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ We're happily taking patches and other contributions. Please see the following l - [GitHub Workflow](https://ait-detectmate.github.io/DetectMateService/latest/Contribution) +If you encounter any bugs, please create an issue on [Github](https://github.com/ait-detectmate/DetectMateService/issues). + ## License [EUPL-1.2](https://github.com/ait-detectmate/DetectMateService/blob/main/LICENSE.md) From 8872ffc0d1983959ae91fb98a4ba608c92b029fd Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 12:03:03 +0100 Subject: [PATCH 42/78] Updated development.md --- docs/development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development.md b/docs/development.md index 47617cb..cfa4dca 100644 --- a/docs/development.md +++ b/docs/development.md @@ -9,7 +9,7 @@ This section describes how to setup a development environment and how to contrib ## Setup a development environment -For development, you can install with optional dependencies: +For development we recommend using [uv](https://docs.astral.sh/uv/). You can install all optional dependencies: ```bash uv sync --dev From 7e75e9d0a572620e361314f7cdb7c73252ad0146 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 12:23:29 +0100 Subject: [PATCH 43/78] prek: exclude docs --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 05f266f..b976e31 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks -exclude: '.*.log' +exclude: '.*.log|docs/.*' repos: # Core cleanup From c78d5c21c6eac74c5aef40ce9fb05059c69c76db Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 13:37:05 +0100 Subject: [PATCH 44/78] Update pre-commit config to exclude .github directory --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b976e31..0b6c730 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks -exclude: '.*.log|docs/.*' +exclude: '.*.log|.github/.*|docs/.*' repos: # Core cleanup From 91651e7d3a2f2c0d9548de1eabc61f400082e48d Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 13:41:55 +0100 Subject: [PATCH 45/78] updated uv.lock --- uv.lock | 1421 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 905 insertions(+), 516 deletions(-) diff --git a/uv.lock b/uv.lock index 8abad20..19277aa 100644 --- a/uv.lock +++ b/uv.lock @@ -1,23 +1,54 @@ version = 1 -revision = 1 +revision = 2 requires-python = ">=3.12" +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] [[package]] name = "cachetools" version = "4.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/17/5735dd9f015f03d2d928ea108f3c02075b784ceed05d32a98e7e44ddd114/cachetools-4.2.1.tar.gz", hash = "sha256:f469e29e7aa4cff64d8de4aad95ce76de8ea1125a16c68e0d93f65c3c3dc92e9", size = 24753 } +sdist = { url = "https://files.pythonhosted.org/packages/74/17/5735dd9f015f03d2d928ea108f3c02075b784ceed05d32a98e7e44ddd114/cachetools-4.2.1.tar.gz", hash = "sha256:f469e29e7aa4cff64d8de4aad95ce76de8ea1125a16c68e0d93f65c3c3dc92e9", size = 24753, upload-time = "2021-01-24T22:40:13.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/72/8df2e0dc991f1a1d2c6869404e7622e8ee50d80bff357dbb57c3df70305b/cachetools-4.2.1-py3-none-any.whl", hash = "sha256:1d9d5f567be80f7c07d765e21b814326d78c61eb0c3a637dffc0e5d1796cb2e2", size = 12003, upload-time = "2021-01-24T22:40:11.795Z" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/72/8df2e0dc991f1a1d2c6869404e7622e8ee50d80bff357dbb57c3df70305b/cachetools-4.2.1-py3-none-any.whl", hash = "sha256:1d9d5f567be80f7c07d765e21b814326d78c61eb0c3a637dffc0e5d1796cb2e2", size = 12003 }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] [[package]] @@ -27,30 +58,87 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] [[package]] @@ -60,82 +148,82 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "coverage" version = "7.10.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/2c/253cc41cd0f40b84c1c34c5363e0407d73d4a1cae005fed6db3b823175bd/coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619", size = 822936 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/62/13c0b66e966c43d7aa64dadc8cd2afa1f5a2bf9bb863bdabc21fb94e8b63/coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42", size = 216262 }, - { url = "https://files.pythonhosted.org/packages/b5/f0/59fdf79be7ac2f0206fc739032f482cfd3f66b18f5248108ff192741beae/coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294", size = 216496 }, - { url = "https://files.pythonhosted.org/packages/34/b1/bc83788ba31bde6a0c02eb96bbc14b2d1eb083ee073beda18753fa2c4c66/coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7", size = 247989 }, - { url = "https://files.pythonhosted.org/packages/0c/29/f8bdf88357956c844bd872e87cb16748a37234f7f48c721dc7e981145eb7/coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437", size = 250738 }, - { url = "https://files.pythonhosted.org/packages/ae/df/6396301d332b71e42bbe624670af9376f63f73a455cc24723656afa95796/coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587", size = 251868 }, - { url = "https://files.pythonhosted.org/packages/91/21/d760b2df6139b6ef62c9cc03afb9bcdf7d6e36ed4d078baacffa618b4c1c/coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea", size = 249790 }, - { url = "https://files.pythonhosted.org/packages/69/91/5dcaa134568202397fa4023d7066d4318dc852b53b428052cd914faa05e1/coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613", size = 247907 }, - { url = "https://files.pythonhosted.org/packages/38/ed/70c0e871cdfef75f27faceada461206c1cc2510c151e1ef8d60a6fedda39/coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb", size = 249344 }, - { url = "https://files.pythonhosted.org/packages/5f/55/c8a273ed503cedc07f8a00dcd843daf28e849f0972e4c6be4c027f418ad6/coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a", size = 218693 }, - { url = "https://files.pythonhosted.org/packages/94/58/dd3cfb2473b85be0b6eb8c5b6d80b6fc3f8f23611e69ef745cef8cf8bad5/coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5", size = 219501 }, - { url = "https://files.pythonhosted.org/packages/56/af/7cbcbf23d46de6f24246e3f76b30df099d05636b30c53c158a196f7da3ad/coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571", size = 218135 }, - { url = "https://files.pythonhosted.org/packages/0a/ff/239e4de9cc149c80e9cc359fab60592365b8c4cbfcad58b8a939d18c6898/coverage-7.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b99e87304ffe0eb97c5308447328a584258951853807afdc58b16143a530518a", size = 216298 }, - { url = "https://files.pythonhosted.org/packages/56/da/28717da68f8ba68f14b9f558aaa8f3e39ada8b9a1ae4f4977c8f98b286d5/coverage-7.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4af09c7574d09afbc1ea7da9dcea23665c01f3bc1b1feb061dac135f98ffc53a", size = 216546 }, - { url = "https://files.pythonhosted.org/packages/de/bb/e1ade16b9e3f2d6c323faeb6bee8e6c23f3a72760a5d9af102ef56a656cb/coverage-7.10.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:488e9b50dc5d2aa9521053cfa706209e5acf5289e81edc28291a24f4e4488f46", size = 247538 }, - { url = "https://files.pythonhosted.org/packages/ea/2f/6ae1db51dc34db499bfe340e89f79a63bd115fc32513a7bacdf17d33cd86/coverage-7.10.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:913ceddb4289cbba3a310704a424e3fb7aac2bc0c3a23ea473193cb290cf17d4", size = 250141 }, - { url = "https://files.pythonhosted.org/packages/4f/ed/33efd8819895b10c66348bf26f011dd621e804866c996ea6893d682218df/coverage-7.10.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b1f91cbc78c7112ab84ed2a8defbccd90f888fcae40a97ddd6466b0bec6ae8a", size = 251415 }, - { url = "https://files.pythonhosted.org/packages/26/04/cb83826f313d07dc743359c9914d9bc460e0798da9a0e38b4f4fabc207ed/coverage-7.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0bac054d45af7cd938834b43a9878b36ea92781bcb009eab040a5b09e9927e3", size = 249575 }, - { url = "https://files.pythonhosted.org/packages/2d/fd/ae963c7a8e9581c20fa4355ab8940ca272554d8102e872dbb932a644e410/coverage-7.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe72cbdd12d9e0f4aca873fa6d755e103888a7f9085e4a62d282d9d5b9f7928c", size = 247466 }, - { url = "https://files.pythonhosted.org/packages/99/e8/b68d1487c6af370b8d5ef223c6d7e250d952c3acfbfcdbf1a773aa0da9d2/coverage-7.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c1e2e927ab3eadd7c244023927d646e4c15c65bb2ac7ae3c3e9537c013700d21", size = 249084 }, - { url = "https://files.pythonhosted.org/packages/66/4d/a0bcb561645c2c1e21758d8200443669d6560d2a2fb03955291110212ec4/coverage-7.10.3-cp313-cp313-win32.whl", hash = "sha256:24d0c13de473b04920ddd6e5da3c08831b1170b8f3b17461d7429b61cad59ae0", size = 218735 }, - { url = "https://files.pythonhosted.org/packages/6a/c3/78b4adddbc0feb3b223f62761e5f9b4c5a758037aaf76e0a5845e9e35e48/coverage-7.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:3564aae76bce4b96e2345cf53b4c87e938c4985424a9be6a66ee902626edec4c", size = 219531 }, - { url = "https://files.pythonhosted.org/packages/70/1b/1229c0b2a527fa5390db58d164aa896d513a1fbb85a1b6b6676846f00552/coverage-7.10.3-cp313-cp313-win_arm64.whl", hash = "sha256:f35580f19f297455f44afcd773c9c7a058e52eb6eb170aa31222e635f2e38b87", size = 218162 }, - { url = "https://files.pythonhosted.org/packages/fc/26/1c1f450e15a3bf3eaecf053ff64538a2612a23f05b21d79ce03be9ff5903/coverage-7.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07009152f497a0464ffdf2634586787aea0e69ddd023eafb23fc38267db94b84", size = 217003 }, - { url = "https://files.pythonhosted.org/packages/29/96/4b40036181d8c2948454b458750960956a3c4785f26a3c29418bbbee1666/coverage-7.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd2ba5f0c7e7e8cc418be2f0c14c4d9e3f08b8fb8e4c0f83c2fe87d03eb655e", size = 217238 }, - { url = "https://files.pythonhosted.org/packages/62/23/8dfc52e95da20957293fb94d97397a100e63095ec1e0ef5c09dd8c6f591a/coverage-7.10.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1ae22b97003c74186e034a93e4f946c75fad8c0ce8d92fbbc168b5e15ee2841f", size = 258561 }, - { url = "https://files.pythonhosted.org/packages/59/95/00e7fcbeda3f632232f4c07dde226afe3511a7781a000aa67798feadc535/coverage-7.10.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb329f1046888a36b1dc35504d3029e1dd5afe2196d94315d18c45ee380f67d5", size = 260735 }, - { url = "https://files.pythonhosted.org/packages/9e/4c/f4666cbc4571804ba2a65b078ff0de600b0b577dc245389e0bc9b69ae7ca/coverage-7.10.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce01048199a91f07f96ca3074b0c14021f4fe7ffd29a3e6a188ac60a5c3a4af8", size = 262960 }, - { url = "https://files.pythonhosted.org/packages/c1/a5/8a9e8a7b12a290ed98b60f73d1d3e5e9ced75a4c94a0d1a671ce3ddfff2a/coverage-7.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08b989a06eb9dfacf96d42b7fb4c9a22bafa370d245dc22fa839f2168c6f9fa1", size = 260515 }, - { url = "https://files.pythonhosted.org/packages/86/11/bb59f7f33b2cac0c5b17db0d9d0abba9c90d9eda51a6e727b43bd5fce4ae/coverage-7.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:669fe0d4e69c575c52148511029b722ba8d26e8a3129840c2ce0522e1452b256", size = 258278 }, - { url = "https://files.pythonhosted.org/packages/cc/22/3646f8903743c07b3e53fded0700fed06c580a980482f04bf9536657ac17/coverage-7.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3262d19092771c83f3413831d9904b1ccc5f98da5de4ffa4ad67f5b20c7aaf7b", size = 259408 }, - { url = "https://files.pythonhosted.org/packages/d2/5c/6375e9d905da22ddea41cd85c30994b8b6f6c02e44e4c5744b76d16b026f/coverage-7.10.3-cp313-cp313t-win32.whl", hash = "sha256:cc0ee4b2ccd42cab7ee6be46d8a67d230cb33a0a7cd47a58b587a7063b6c6b0e", size = 219396 }, - { url = "https://files.pythonhosted.org/packages/33/3b/7da37fd14412b8c8b6e73c3e7458fef6b1b05a37f990a9776f88e7740c89/coverage-7.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:03db599f213341e2960430984e04cf35fb179724e052a3ee627a068653cf4a7c", size = 220458 }, - { url = "https://files.pythonhosted.org/packages/28/cc/59a9a70f17edab513c844ee7a5c63cf1057041a84cc725b46a51c6f8301b/coverage-7.10.3-cp313-cp313t-win_arm64.whl", hash = "sha256:46eae7893ba65f53c71284585a262f083ef71594f05ec5c85baf79c402369098", size = 218722 }, - { url = "https://files.pythonhosted.org/packages/2d/84/bb773b51a06edbf1231b47dc810a23851f2796e913b335a0fa364773b842/coverage-7.10.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bce8b8180912914032785850d8f3aacb25ec1810f5f54afc4a8b114e7a9b55de", size = 216280 }, - { url = "https://files.pythonhosted.org/packages/92/a8/4d8ca9c111d09865f18d56facff64d5fa076a5593c290bd1cfc5dceb8dba/coverage-7.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07790b4b37d56608536f7c1079bd1aa511567ac2966d33d5cec9cf520c50a7c8", size = 216557 }, - { url = "https://files.pythonhosted.org/packages/fe/b2/eb668bfc5060194bc5e1ccd6f664e8e045881cfee66c42a2aa6e6c5b26e8/coverage-7.10.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e79367ef2cd9166acedcbf136a458dfe9a4a2dd4d1ee95738fb2ee581c56f667", size = 247598 }, - { url = "https://files.pythonhosted.org/packages/fd/b0/9faa4ac62c8822219dd83e5d0e73876398af17d7305968aed8d1606d1830/coverage-7.10.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:419d2a0f769f26cb1d05e9ccbc5eab4cb5d70231604d47150867c07822acbdf4", size = 250131 }, - { url = "https://files.pythonhosted.org/packages/4e/90/203537e310844d4bf1bdcfab89c1e05c25025c06d8489b9e6f937ad1a9e2/coverage-7.10.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee221cf244757cdc2ac882e3062ab414b8464ad9c884c21e878517ea64b3fa26", size = 251485 }, - { url = "https://files.pythonhosted.org/packages/b9/b2/9d894b26bc53c70a1fe503d62240ce6564256d6d35600bdb86b80e516e7d/coverage-7.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c2079d8cdd6f7373d628e14b3357f24d1db02c9dc22e6a007418ca7a2be0435a", size = 249488 }, - { url = "https://files.pythonhosted.org/packages/b4/28/af167dbac5281ba6c55c933a0ca6675d68347d5aee39cacc14d44150b922/coverage-7.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bd8df1f83c0703fa3ca781b02d36f9ec67ad9cb725b18d486405924f5e4270bd", size = 247419 }, - { url = "https://files.pythonhosted.org/packages/f4/1c/9a4ddc9f0dcb150d4cd619e1c4bb39bcf694c6129220bdd1e5895d694dda/coverage-7.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b4e25e0fa335c8aa26e42a52053f3786a61cc7622b4d54ae2dad994aa754fec", size = 248917 }, - { url = "https://files.pythonhosted.org/packages/92/27/c6a60c7cbe10dbcdcd7fc9ee89d531dc04ea4c073800279bb269954c5a9f/coverage-7.10.3-cp314-cp314-win32.whl", hash = "sha256:d7c3d02c2866deb217dce664c71787f4b25420ea3eaf87056f44fb364a3528f5", size = 218999 }, - { url = "https://files.pythonhosted.org/packages/36/09/a94c1369964ab31273576615d55e7d14619a1c47a662ed3e2a2fe4dee7d4/coverage-7.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:9c8916d44d9e0fe6cdb2227dc6b0edd8bc6c8ef13438bbbf69af7482d9bb9833", size = 219801 }, - { url = "https://files.pythonhosted.org/packages/23/59/f5cd2a80f401c01cf0f3add64a7b791b7d53fd6090a4e3e9ea52691cf3c4/coverage-7.10.3-cp314-cp314-win_arm64.whl", hash = "sha256:1007d6a2b3cf197c57105cc1ba390d9ff7f0bee215ced4dea530181e49c65ab4", size = 218381 }, - { url = "https://files.pythonhosted.org/packages/73/3d/89d65baf1ea39e148ee989de6da601469ba93c1d905b17dfb0b83bd39c96/coverage-7.10.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ebc8791d346410d096818788877d675ca55c91db87d60e8f477bd41c6970ffc6", size = 217019 }, - { url = "https://files.pythonhosted.org/packages/7d/7d/d9850230cd9c999ce3a1e600f85c2fff61a81c301334d7a1faa1a5ba19c8/coverage-7.10.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f4e4d8e75f6fd3c6940ebeed29e3d9d632e1f18f6fb65d33086d99d4d073241", size = 217237 }, - { url = "https://files.pythonhosted.org/packages/36/51/b87002d417202ab27f4a1cd6bd34ee3b78f51b3ddbef51639099661da991/coverage-7.10.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:24581ed69f132b6225a31b0228ae4885731cddc966f8a33fe5987288bdbbbd5e", size = 258735 }, - { url = "https://files.pythonhosted.org/packages/1c/02/1f8612bfcb46fc7ca64a353fff1cd4ed932bb6e0b4e0bb88b699c16794b8/coverage-7.10.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec151569ddfccbf71bac8c422dce15e176167385a00cd86e887f9a80035ce8a5", size = 260901 }, - { url = "https://files.pythonhosted.org/packages/aa/3a/fe39e624ddcb2373908bd922756384bb70ac1c5009b0d1674eb326a3e428/coverage-7.10.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ae8e7c56290b908ee817200c0b65929b8050bc28530b131fe7c6dfee3e7d86b", size = 263157 }, - { url = "https://files.pythonhosted.org/packages/5e/89/496b6d5a10fa0d0691a633bb2b2bcf4f38f0bdfcbde21ad9e32d1af328ed/coverage-7.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb742309766d7e48e9eb4dc34bc95a424707bc6140c0e7d9726e794f11b92a0", size = 260597 }, - { url = "https://files.pythonhosted.org/packages/b6/a6/8b5bf6a9e8c6aaeb47d5fe9687014148efc05c3588110246d5fdeef9b492/coverage-7.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c65e2a5b32fbe1e499f1036efa6eb9cb4ea2bf6f7168d0e7a5852f3024f471b1", size = 258353 }, - { url = "https://files.pythonhosted.org/packages/c3/6d/ad131be74f8afd28150a07565dfbdc86592fd61d97e2dc83383d9af219f0/coverage-7.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d48d2cb07d50f12f4f18d2bb75d9d19e3506c26d96fffabf56d22936e5ed8f7c", size = 259504 }, - { url = "https://files.pythonhosted.org/packages/ec/30/fc9b5097092758cba3375a8cc4ff61774f8cd733bcfb6c9d21a60077a8d8/coverage-7.10.3-cp314-cp314t-win32.whl", hash = "sha256:dec0d9bc15ee305e09fe2cd1911d3f0371262d3cfdae05d79515d8cb712b4869", size = 219782 }, - { url = "https://files.pythonhosted.org/packages/72/9b/27fbf79451b1fac15c4bda6ec6e9deae27cf7c0648c1305aa21a3454f5c4/coverage-7.10.3-cp314-cp314t-win_amd64.whl", hash = "sha256:424ea93a323aa0f7f01174308ea78bde885c3089ec1bef7143a6d93c3e24ef64", size = 220898 }, - { url = "https://files.pythonhosted.org/packages/d1/cf/a32bbf92869cbf0b7c8b84325327bfc718ad4b6d2c63374fef3d58e39306/coverage-7.10.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f5983c132a62d93d71c9ef896a0b9bf6e6828d8d2ea32611f58684fba60bba35", size = 218922 }, - { url = "https://files.pythonhosted.org/packages/84/19/e67f4ae24e232c7f713337f3f4f7c9c58afd0c02866fb07c7b9255a19ed7/coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1", size = 207921 }, +sdist = { url = "https://files.pythonhosted.org/packages/f4/2c/253cc41cd0f40b84c1c34c5363e0407d73d4a1cae005fed6db3b823175bd/coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619", size = 822936, upload-time = "2025-08-10T21:27:39.968Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/62/13c0b66e966c43d7aa64dadc8cd2afa1f5a2bf9bb863bdabc21fb94e8b63/coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42", size = 216262, upload-time = "2025-08-10T21:25:55.367Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f0/59fdf79be7ac2f0206fc739032f482cfd3f66b18f5248108ff192741beae/coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294", size = 216496, upload-time = "2025-08-10T21:25:56.759Z" }, + { url = "https://files.pythonhosted.org/packages/34/b1/bc83788ba31bde6a0c02eb96bbc14b2d1eb083ee073beda18753fa2c4c66/coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7", size = 247989, upload-time = "2025-08-10T21:25:58.067Z" }, + { url = "https://files.pythonhosted.org/packages/0c/29/f8bdf88357956c844bd872e87cb16748a37234f7f48c721dc7e981145eb7/coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437", size = 250738, upload-time = "2025-08-10T21:25:59.406Z" }, + { url = "https://files.pythonhosted.org/packages/ae/df/6396301d332b71e42bbe624670af9376f63f73a455cc24723656afa95796/coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587", size = 251868, upload-time = "2025-08-10T21:26:00.65Z" }, + { url = "https://files.pythonhosted.org/packages/91/21/d760b2df6139b6ef62c9cc03afb9bcdf7d6e36ed4d078baacffa618b4c1c/coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea", size = 249790, upload-time = "2025-08-10T21:26:02.009Z" }, + { url = "https://files.pythonhosted.org/packages/69/91/5dcaa134568202397fa4023d7066d4318dc852b53b428052cd914faa05e1/coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613", size = 247907, upload-time = "2025-08-10T21:26:03.757Z" }, + { url = "https://files.pythonhosted.org/packages/38/ed/70c0e871cdfef75f27faceada461206c1cc2510c151e1ef8d60a6fedda39/coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb", size = 249344, upload-time = "2025-08-10T21:26:05.11Z" }, + { url = "https://files.pythonhosted.org/packages/5f/55/c8a273ed503cedc07f8a00dcd843daf28e849f0972e4c6be4c027f418ad6/coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a", size = 218693, upload-time = "2025-08-10T21:26:06.534Z" }, + { url = "https://files.pythonhosted.org/packages/94/58/dd3cfb2473b85be0b6eb8c5b6d80b6fc3f8f23611e69ef745cef8cf8bad5/coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5", size = 219501, upload-time = "2025-08-10T21:26:08.195Z" }, + { url = "https://files.pythonhosted.org/packages/56/af/7cbcbf23d46de6f24246e3f76b30df099d05636b30c53c158a196f7da3ad/coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571", size = 218135, upload-time = "2025-08-10T21:26:09.584Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ff/239e4de9cc149c80e9cc359fab60592365b8c4cbfcad58b8a939d18c6898/coverage-7.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b99e87304ffe0eb97c5308447328a584258951853807afdc58b16143a530518a", size = 216298, upload-time = "2025-08-10T21:26:10.973Z" }, + { url = "https://files.pythonhosted.org/packages/56/da/28717da68f8ba68f14b9f558aaa8f3e39ada8b9a1ae4f4977c8f98b286d5/coverage-7.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4af09c7574d09afbc1ea7da9dcea23665c01f3bc1b1feb061dac135f98ffc53a", size = 216546, upload-time = "2025-08-10T21:26:12.616Z" }, + { url = "https://files.pythonhosted.org/packages/de/bb/e1ade16b9e3f2d6c323faeb6bee8e6c23f3a72760a5d9af102ef56a656cb/coverage-7.10.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:488e9b50dc5d2aa9521053cfa706209e5acf5289e81edc28291a24f4e4488f46", size = 247538, upload-time = "2025-08-10T21:26:14.455Z" }, + { url = "https://files.pythonhosted.org/packages/ea/2f/6ae1db51dc34db499bfe340e89f79a63bd115fc32513a7bacdf17d33cd86/coverage-7.10.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:913ceddb4289cbba3a310704a424e3fb7aac2bc0c3a23ea473193cb290cf17d4", size = 250141, upload-time = "2025-08-10T21:26:15.787Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ed/33efd8819895b10c66348bf26f011dd621e804866c996ea6893d682218df/coverage-7.10.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b1f91cbc78c7112ab84ed2a8defbccd90f888fcae40a97ddd6466b0bec6ae8a", size = 251415, upload-time = "2025-08-10T21:26:17.535Z" }, + { url = "https://files.pythonhosted.org/packages/26/04/cb83826f313d07dc743359c9914d9bc460e0798da9a0e38b4f4fabc207ed/coverage-7.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0bac054d45af7cd938834b43a9878b36ea92781bcb009eab040a5b09e9927e3", size = 249575, upload-time = "2025-08-10T21:26:18.921Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fd/ae963c7a8e9581c20fa4355ab8940ca272554d8102e872dbb932a644e410/coverage-7.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe72cbdd12d9e0f4aca873fa6d755e103888a7f9085e4a62d282d9d5b9f7928c", size = 247466, upload-time = "2025-08-10T21:26:20.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/e8/b68d1487c6af370b8d5ef223c6d7e250d952c3acfbfcdbf1a773aa0da9d2/coverage-7.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c1e2e927ab3eadd7c244023927d646e4c15c65bb2ac7ae3c3e9537c013700d21", size = 249084, upload-time = "2025-08-10T21:26:21.638Z" }, + { url = "https://files.pythonhosted.org/packages/66/4d/a0bcb561645c2c1e21758d8200443669d6560d2a2fb03955291110212ec4/coverage-7.10.3-cp313-cp313-win32.whl", hash = "sha256:24d0c13de473b04920ddd6e5da3c08831b1170b8f3b17461d7429b61cad59ae0", size = 218735, upload-time = "2025-08-10T21:26:23.009Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c3/78b4adddbc0feb3b223f62761e5f9b4c5a758037aaf76e0a5845e9e35e48/coverage-7.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:3564aae76bce4b96e2345cf53b4c87e938c4985424a9be6a66ee902626edec4c", size = 219531, upload-time = "2025-08-10T21:26:24.474Z" }, + { url = "https://files.pythonhosted.org/packages/70/1b/1229c0b2a527fa5390db58d164aa896d513a1fbb85a1b6b6676846f00552/coverage-7.10.3-cp313-cp313-win_arm64.whl", hash = "sha256:f35580f19f297455f44afcd773c9c7a058e52eb6eb170aa31222e635f2e38b87", size = 218162, upload-time = "2025-08-10T21:26:25.847Z" }, + { url = "https://files.pythonhosted.org/packages/fc/26/1c1f450e15a3bf3eaecf053ff64538a2612a23f05b21d79ce03be9ff5903/coverage-7.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07009152f497a0464ffdf2634586787aea0e69ddd023eafb23fc38267db94b84", size = 217003, upload-time = "2025-08-10T21:26:27.231Z" }, + { url = "https://files.pythonhosted.org/packages/29/96/4b40036181d8c2948454b458750960956a3c4785f26a3c29418bbbee1666/coverage-7.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd2ba5f0c7e7e8cc418be2f0c14c4d9e3f08b8fb8e4c0f83c2fe87d03eb655e", size = 217238, upload-time = "2025-08-10T21:26:28.83Z" }, + { url = "https://files.pythonhosted.org/packages/62/23/8dfc52e95da20957293fb94d97397a100e63095ec1e0ef5c09dd8c6f591a/coverage-7.10.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1ae22b97003c74186e034a93e4f946c75fad8c0ce8d92fbbc168b5e15ee2841f", size = 258561, upload-time = "2025-08-10T21:26:30.475Z" }, + { url = "https://files.pythonhosted.org/packages/59/95/00e7fcbeda3f632232f4c07dde226afe3511a7781a000aa67798feadc535/coverage-7.10.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb329f1046888a36b1dc35504d3029e1dd5afe2196d94315d18c45ee380f67d5", size = 260735, upload-time = "2025-08-10T21:26:32.333Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4c/f4666cbc4571804ba2a65b078ff0de600b0b577dc245389e0bc9b69ae7ca/coverage-7.10.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce01048199a91f07f96ca3074b0c14021f4fe7ffd29a3e6a188ac60a5c3a4af8", size = 262960, upload-time = "2025-08-10T21:26:33.701Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a5/8a9e8a7b12a290ed98b60f73d1d3e5e9ced75a4c94a0d1a671ce3ddfff2a/coverage-7.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08b989a06eb9dfacf96d42b7fb4c9a22bafa370d245dc22fa839f2168c6f9fa1", size = 260515, upload-time = "2025-08-10T21:26:35.16Z" }, + { url = "https://files.pythonhosted.org/packages/86/11/bb59f7f33b2cac0c5b17db0d9d0abba9c90d9eda51a6e727b43bd5fce4ae/coverage-7.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:669fe0d4e69c575c52148511029b722ba8d26e8a3129840c2ce0522e1452b256", size = 258278, upload-time = "2025-08-10T21:26:36.539Z" }, + { url = "https://files.pythonhosted.org/packages/cc/22/3646f8903743c07b3e53fded0700fed06c580a980482f04bf9536657ac17/coverage-7.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3262d19092771c83f3413831d9904b1ccc5f98da5de4ffa4ad67f5b20c7aaf7b", size = 259408, upload-time = "2025-08-10T21:26:37.954Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/6375e9d905da22ddea41cd85c30994b8b6f6c02e44e4c5744b76d16b026f/coverage-7.10.3-cp313-cp313t-win32.whl", hash = "sha256:cc0ee4b2ccd42cab7ee6be46d8a67d230cb33a0a7cd47a58b587a7063b6c6b0e", size = 219396, upload-time = "2025-08-10T21:26:39.426Z" }, + { url = "https://files.pythonhosted.org/packages/33/3b/7da37fd14412b8c8b6e73c3e7458fef6b1b05a37f990a9776f88e7740c89/coverage-7.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:03db599f213341e2960430984e04cf35fb179724e052a3ee627a068653cf4a7c", size = 220458, upload-time = "2025-08-10T21:26:40.905Z" }, + { url = "https://files.pythonhosted.org/packages/28/cc/59a9a70f17edab513c844ee7a5c63cf1057041a84cc725b46a51c6f8301b/coverage-7.10.3-cp313-cp313t-win_arm64.whl", hash = "sha256:46eae7893ba65f53c71284585a262f083ef71594f05ec5c85baf79c402369098", size = 218722, upload-time = "2025-08-10T21:26:42.362Z" }, + { url = "https://files.pythonhosted.org/packages/2d/84/bb773b51a06edbf1231b47dc810a23851f2796e913b335a0fa364773b842/coverage-7.10.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bce8b8180912914032785850d8f3aacb25ec1810f5f54afc4a8b114e7a9b55de", size = 216280, upload-time = "2025-08-10T21:26:44.132Z" }, + { url = "https://files.pythonhosted.org/packages/92/a8/4d8ca9c111d09865f18d56facff64d5fa076a5593c290bd1cfc5dceb8dba/coverage-7.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07790b4b37d56608536f7c1079bd1aa511567ac2966d33d5cec9cf520c50a7c8", size = 216557, upload-time = "2025-08-10T21:26:45.598Z" }, + { url = "https://files.pythonhosted.org/packages/fe/b2/eb668bfc5060194bc5e1ccd6f664e8e045881cfee66c42a2aa6e6c5b26e8/coverage-7.10.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e79367ef2cd9166acedcbf136a458dfe9a4a2dd4d1ee95738fb2ee581c56f667", size = 247598, upload-time = "2025-08-10T21:26:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b0/9faa4ac62c8822219dd83e5d0e73876398af17d7305968aed8d1606d1830/coverage-7.10.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:419d2a0f769f26cb1d05e9ccbc5eab4cb5d70231604d47150867c07822acbdf4", size = 250131, upload-time = "2025-08-10T21:26:48.65Z" }, + { url = "https://files.pythonhosted.org/packages/4e/90/203537e310844d4bf1bdcfab89c1e05c25025c06d8489b9e6f937ad1a9e2/coverage-7.10.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee221cf244757cdc2ac882e3062ab414b8464ad9c884c21e878517ea64b3fa26", size = 251485, upload-time = "2025-08-10T21:26:50.368Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/9d894b26bc53c70a1fe503d62240ce6564256d6d35600bdb86b80e516e7d/coverage-7.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c2079d8cdd6f7373d628e14b3357f24d1db02c9dc22e6a007418ca7a2be0435a", size = 249488, upload-time = "2025-08-10T21:26:52.045Z" }, + { url = "https://files.pythonhosted.org/packages/b4/28/af167dbac5281ba6c55c933a0ca6675d68347d5aee39cacc14d44150b922/coverage-7.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bd8df1f83c0703fa3ca781b02d36f9ec67ad9cb725b18d486405924f5e4270bd", size = 247419, upload-time = "2025-08-10T21:26:53.533Z" }, + { url = "https://files.pythonhosted.org/packages/f4/1c/9a4ddc9f0dcb150d4cd619e1c4bb39bcf694c6129220bdd1e5895d694dda/coverage-7.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b4e25e0fa335c8aa26e42a52053f3786a61cc7622b4d54ae2dad994aa754fec", size = 248917, upload-time = "2025-08-10T21:26:55.11Z" }, + { url = "https://files.pythonhosted.org/packages/92/27/c6a60c7cbe10dbcdcd7fc9ee89d531dc04ea4c073800279bb269954c5a9f/coverage-7.10.3-cp314-cp314-win32.whl", hash = "sha256:d7c3d02c2866deb217dce664c71787f4b25420ea3eaf87056f44fb364a3528f5", size = 218999, upload-time = "2025-08-10T21:26:56.637Z" }, + { url = "https://files.pythonhosted.org/packages/36/09/a94c1369964ab31273576615d55e7d14619a1c47a662ed3e2a2fe4dee7d4/coverage-7.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:9c8916d44d9e0fe6cdb2227dc6b0edd8bc6c8ef13438bbbf69af7482d9bb9833", size = 219801, upload-time = "2025-08-10T21:26:58.207Z" }, + { url = "https://files.pythonhosted.org/packages/23/59/f5cd2a80f401c01cf0f3add64a7b791b7d53fd6090a4e3e9ea52691cf3c4/coverage-7.10.3-cp314-cp314-win_arm64.whl", hash = "sha256:1007d6a2b3cf197c57105cc1ba390d9ff7f0bee215ced4dea530181e49c65ab4", size = 218381, upload-time = "2025-08-10T21:26:59.707Z" }, + { url = "https://files.pythonhosted.org/packages/73/3d/89d65baf1ea39e148ee989de6da601469ba93c1d905b17dfb0b83bd39c96/coverage-7.10.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ebc8791d346410d096818788877d675ca55c91db87d60e8f477bd41c6970ffc6", size = 217019, upload-time = "2025-08-10T21:27:01.242Z" }, + { url = "https://files.pythonhosted.org/packages/7d/7d/d9850230cd9c999ce3a1e600f85c2fff61a81c301334d7a1faa1a5ba19c8/coverage-7.10.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f4e4d8e75f6fd3c6940ebeed29e3d9d632e1f18f6fb65d33086d99d4d073241", size = 217237, upload-time = "2025-08-10T21:27:03.442Z" }, + { url = "https://files.pythonhosted.org/packages/36/51/b87002d417202ab27f4a1cd6bd34ee3b78f51b3ddbef51639099661da991/coverage-7.10.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:24581ed69f132b6225a31b0228ae4885731cddc966f8a33fe5987288bdbbbd5e", size = 258735, upload-time = "2025-08-10T21:27:05.124Z" }, + { url = "https://files.pythonhosted.org/packages/1c/02/1f8612bfcb46fc7ca64a353fff1cd4ed932bb6e0b4e0bb88b699c16794b8/coverage-7.10.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec151569ddfccbf71bac8c422dce15e176167385a00cd86e887f9a80035ce8a5", size = 260901, upload-time = "2025-08-10T21:27:06.68Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3a/fe39e624ddcb2373908bd922756384bb70ac1c5009b0d1674eb326a3e428/coverage-7.10.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ae8e7c56290b908ee817200c0b65929b8050bc28530b131fe7c6dfee3e7d86b", size = 263157, upload-time = "2025-08-10T21:27:08.398Z" }, + { url = "https://files.pythonhosted.org/packages/5e/89/496b6d5a10fa0d0691a633bb2b2bcf4f38f0bdfcbde21ad9e32d1af328ed/coverage-7.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb742309766d7e48e9eb4dc34bc95a424707bc6140c0e7d9726e794f11b92a0", size = 260597, upload-time = "2025-08-10T21:27:10.237Z" }, + { url = "https://files.pythonhosted.org/packages/b6/a6/8b5bf6a9e8c6aaeb47d5fe9687014148efc05c3588110246d5fdeef9b492/coverage-7.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c65e2a5b32fbe1e499f1036efa6eb9cb4ea2bf6f7168d0e7a5852f3024f471b1", size = 258353, upload-time = "2025-08-10T21:27:11.773Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6d/ad131be74f8afd28150a07565dfbdc86592fd61d97e2dc83383d9af219f0/coverage-7.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d48d2cb07d50f12f4f18d2bb75d9d19e3506c26d96fffabf56d22936e5ed8f7c", size = 259504, upload-time = "2025-08-10T21:27:13.254Z" }, + { url = "https://files.pythonhosted.org/packages/ec/30/fc9b5097092758cba3375a8cc4ff61774f8cd733bcfb6c9d21a60077a8d8/coverage-7.10.3-cp314-cp314t-win32.whl", hash = "sha256:dec0d9bc15ee305e09fe2cd1911d3f0371262d3cfdae05d79515d8cb712b4869", size = 219782, upload-time = "2025-08-10T21:27:14.736Z" }, + { url = "https://files.pythonhosted.org/packages/72/9b/27fbf79451b1fac15c4bda6ec6e9deae27cf7c0648c1305aa21a3454f5c4/coverage-7.10.3-cp314-cp314t-win_amd64.whl", hash = "sha256:424ea93a323aa0f7f01174308ea78bde885c3089ec1bef7143a6d93c3e24ef64", size = 220898, upload-time = "2025-08-10T21:27:16.297Z" }, + { url = "https://files.pythonhosted.org/packages/d1/cf/a32bbf92869cbf0b7c8b84325327bfc718ad4b6d2c63374fef3d58e39306/coverage-7.10.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f5983c132a62d93d71c9ef896a0b9bf6e6828d8d2ea32611f58684fba60bba35", size = 218922, upload-time = "2025-08-10T21:27:18.22Z" }, + { url = "https://files.pythonhosted.org/packages/84/19/e67f4ae24e232c7f713337f3f4f7c9c58afd0c02866fb07c7b9255a19ed7/coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1", size = 207921, upload-time = "2025-08-10T21:27:38.254Z" }, ] [[package]] @@ -157,12 +245,16 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "detectmatelibrary" }, + { name = "fastapi" }, { name = "pathlib" }, + { name = "prometheus-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "pynng" }, { name = "pyyaml" }, + { name = "requests" }, { name = "types-pyyaml" }, + { name = "uvicorn", extra = ["standard"] }, ] [package.dev-dependencies] @@ -171,17 +263,22 @@ dev = [ { name = "prek" }, { name = "pytest" }, { name = "pytest-cov" }, + { name = "types-requests" }, ] [package.metadata] requires-dist = [ { name = "detectmatelibrary", git = "https://github.com/ait-detectmate/DetectMateLibrary.git" }, + { name = "fastapi", specifier = ">=0.115.0" }, { name = "pathlib", specifier = ">=1.0.1" }, + { name = "prometheus-client", specifier = ">=0.20.0" }, { name = "pydantic", specifier = ">=2.11.7" }, { name = "pydantic-settings", specifier = ">=2.10.1" }, { name = "pynng", specifier = ">=0.8.1" }, { name = "pyyaml", specifier = ">=6.0.2" }, + { name = "requests", specifier = ">=2.31.0" }, { name = "types-pyyaml", specifier = ">=6.0.12.20250915" }, + { name = "uvicorn", extras = ["standard"], specifier = ">=0.34.0" }, ] [package.metadata.requires-dev] @@ -190,6 +287,7 @@ dev = [ { name = "prek", specifier = ">=0.2.8" }, { name = "pytest", specifier = ">=8.4.1" }, { name = "pytest-cov", specifier = ">=6.2.1" }, + { name = "types-requests" }, ] [[package]] @@ -200,7 +298,22 @@ dependencies = [ { name = "cachetools" }, { name = "jsonpickle" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/83/4da2d3a11b5e0edf1a4f4c0c2dd42126d2eb1f31c733967edd3dfac1af94/drain3-0.9.11.tar.gz", hash = "sha256:9ab4b1407fad74f56554ae371ef019c3c7985861631f4bab46a0e92585125f75", size = 27960 } +sdist = { url = "https://files.pythonhosted.org/packages/dc/83/4da2d3a11b5e0edf1a4f4c0c2dd42126d2eb1f31c733967edd3dfac1af94/drain3-0.9.11.tar.gz", hash = "sha256:9ab4b1407fad74f56554ae371ef019c3c7985861631f4bab46a0e92585125f75", size = 27960, upload-time = "2022-07-17T06:40:11.433Z" } + +[[package]] +name = "fastapi" +version = "0.128.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/08/8c8508db6c7b9aae8f7175046af41baad690771c9bcde676419965e338c7/fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a", size = 365682, upload-time = "2025-12-27T15:21:13.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094, upload-time = "2025-12-27T15:21:12.154Z" }, +] [[package]] name = "ghp-import" @@ -209,9 +322,56 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 } +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httptools" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" }, + { url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" }, + { url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" }, + { url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" }, + { url = "https://files.pythonhosted.org/packages/09/8f/c77b1fcbfd262d422f12da02feb0d218fa228d52485b77b953832105bb90/httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6babce6cfa2a99545c60bfef8bee0cc0545413cb0018f617c8059a30ad985de3", size = 202889, upload-time = "2025-10-10T03:54:47.089Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1a/22887f53602feaa066354867bc49a68fc295c2293433177ee90870a7d517/httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:601b7628de7504077dd3dcb3791c6b8694bbd967148a6d1f01806509254fb1ca", size = 108180, upload-time = "2025-10-10T03:54:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/32/6a/6aaa91937f0010d288d3d124ca2946d48d60c3a5ee7ca62afe870e3ea011/httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:04c6c0e6c5fb0739c5b8a9eb046d298650a0ff38cf42537fc372b28dc7e4472c", size = 478596, upload-time = "2025-10-10T03:54:48.919Z" }, + { url = "https://files.pythonhosted.org/packages/6d/70/023d7ce117993107be88d2cbca566a7c1323ccbaf0af7eabf2064fe356f6/httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69d4f9705c405ae3ee83d6a12283dc9feba8cc6aaec671b412917e644ab4fa66", size = 473268, upload-time = "2025-10-10T03:54:49.993Z" }, + { url = "https://files.pythonhosted.org/packages/32/4d/9dd616c38da088e3f436e9a616e1d0cc66544b8cdac405cc4e81c8679fc7/httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44c8f4347d4b31269c8a9205d8a5ee2df5322b09bbbd30f8f862185bb6b05346", size = 455517, upload-time = "2025-10-10T03:54:51.066Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3a/a6c595c310b7df958e739aae88724e24f9246a514d909547778d776799be/httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:465275d76db4d554918aba40bf1cbebe324670f3dfc979eaffaa5d108e2ed650", size = 458337, upload-time = "2025-10-10T03:54:52.196Z" }, + { url = "https://files.pythonhosted.org/packages/fd/82/88e8d6d2c51edc1cc391b6e044c6c435b6aebe97b1abc33db1b0b24cd582/httptools-0.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:322d00c2068d125bd570f7bf78b2d367dad02b919d8581d7476d8b75b294e3e6", size = 85743, upload-time = "2025-10-10T03:54:53.448Z" }, + { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, + { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, + { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, + { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, + { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -221,27 +381,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865 }, + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, ] [[package]] name = "importlib-resources" version = "6.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693 } +sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461 }, + { url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" }, ] [[package]] name = "iniconfig" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] [[package]] @@ -251,99 +411,99 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "jsonpickle" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/62/31ef0b58050a3731b079af69932104a9443bff07fe2b9564c161e3ec4348/jsonpickle-1.5.1.tar.gz", hash = "sha256:060f97096559d1b86aa16cac2f4ea5f7b6da0c15d8a4de150b78013a886f9a51", size = 109560 } +sdist = { url = "https://files.pythonhosted.org/packages/af/62/31ef0b58050a3731b079af69932104a9443bff07fe2b9564c161e3ec4348/jsonpickle-1.5.1.tar.gz", hash = "sha256:060f97096559d1b86aa16cac2f4ea5f7b6da0c15d8a4de150b78013a886f9a51", size = 109560, upload-time = "2021-01-31T05:57:15.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/a7/c2f527ddce3155ae9e008385963c2325cbfd52969f8b38efa2723e2af4af/jsonpickle-1.5.1-py2.py3-none-any.whl", hash = "sha256:8eb8323f0e12cb40687f0445e2115d8165901e20ac670add55bb53a95c68c0e5", size = 37124 }, + { url = "https://files.pythonhosted.org/packages/77/a7/c2f527ddce3155ae9e008385963c2325cbfd52969f8b38efa2723e2af4af/jsonpickle-1.5.1-py2.py3-none-any.whl", hash = "sha256:8eb8323f0e12cb40687f0445e2115d8165901e20ac670add55bb53a95c68c0e5", size = 37124, upload-time = "2021-01-31T05:57:12.256Z" }, ] [[package]] name = "markdown" version = "3.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931, upload-time = "2025-11-03T19:51:15.007Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678 }, + { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678, upload-time = "2025-11-03T19:51:13.887Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615 }, - { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020 }, - { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332 }, - { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947 }, - { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962 }, - { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760 }, - { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529 }, - { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015 }, - { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540 }, - { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105 }, - { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906 }, - { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622 }, - { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029 }, - { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374 }, - { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980 }, - { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990 }, - { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784 }, - { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588 }, - { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041 }, - { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543 }, - { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113 }, - { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911 }, - { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658 }, - { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066 }, - { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639 }, - { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569 }, - { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284 }, - { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801 }, - { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769 }, - { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642 }, - { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612 }, - { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200 }, - { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973 }, - { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619 }, - { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029 }, - { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408 }, - { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005 }, - { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048 }, - { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821 }, - { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606 }, - { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043 }, - { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747 }, - { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341 }, - { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073 }, - { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661 }, - { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069 }, - { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670 }, - { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598 }, - { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261 }, - { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835 }, - { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733 }, - { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672 }, - { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819 }, - { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426 }, - { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146 }, +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] [[package]] name = "mergedeep" version = "1.3.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, ] [[package]] @@ -360,9 +520,9 @@ dependencies = [ { name = "pyyaml-env-tag" }, { name = "verspec" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/f7/2933f1a1fb0e0f077d5d6a92c6c7f8a54e6128241f116dff4df8b6050bbf/mike-2.1.3.tar.gz", hash = "sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810", size = 38119 } +sdist = { url = "https://files.pythonhosted.org/packages/ab/f7/2933f1a1fb0e0f077d5d6a92c6c7f8a54e6128241f116dff4df8b6050bbf/mike-2.1.3.tar.gz", hash = "sha256:abd79b8ea483fb0275b7972825d3082e5ae67a41820f8d8a0dc7a3f49944e810", size = 38119, upload-time = "2024-08-13T05:02:14.167Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/1a/31b7cd6e4e7a02df4e076162e9783620777592bea9e4bb036389389af99d/mike-2.1.3-py3-none-any.whl", hash = "sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a", size = 33754 }, + { url = "https://files.pythonhosted.org/packages/fd/1a/31b7cd6e4e7a02df4e076162e9783620777592bea9e4bb036389389af99d/mike-2.1.3-py3-none-any.whl", hash = "sha256:d90c64077e84f06272437b464735130d380703a76a5738b152932884c60c062a", size = 33754, upload-time = "2024-08-13T05:02:12.515Z" }, ] [[package]] @@ -384,9 +544,9 @@ dependencies = [ { name = "pyyaml-env-tag" }, { name = "watchdog" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451 }, + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, ] [[package]] @@ -398,81 +558,81 @@ dependencies = [ { name = "platformdirs" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 } +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 }, + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, ] [[package]] name = "numpy" version = "2.3.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873 }, - { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838 }, - { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378 }, - { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559 }, - { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702 }, - { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086 }, - { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985 }, - { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976 }, - { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274 }, - { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922 }, - { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667 }, - { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251 }, - { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652 }, - { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172 }, - { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990 }, - { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902 }, - { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430 }, - { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551 }, - { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275 }, - { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637 }, - { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090 }, - { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710 }, - { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292 }, - { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897 }, - { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391 }, - { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275 }, - { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855 }, - { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359 }, - { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374 }, - { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587 }, - { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940 }, - { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341 }, - { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507 }, - { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706 }, - { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507 }, - { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049 }, - { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603 }, - { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696 }, - { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350 }, - { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190 }, - { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749 }, - { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432 }, - { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388 }, - { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651 }, - { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503 }, - { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612 }, - { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042 }, - { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502 }, - { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962 }, - { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054 }, - { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613 }, - { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147 }, - { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806 }, - { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760 }, - { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459 }, +sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" }, + { url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" }, + { url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" }, + { url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" }, + { url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" }, + { url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" }, + { url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" }, + { url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" }, + { url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" }, + { url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" }, + { url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" }, + { url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" }, + { url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" }, + { url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" }, + { url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" }, + { url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" }, + { url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" }, + { url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" }, + { url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" }, + { url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" }, + { url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" }, + { url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" }, + { url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" }, + { url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" }, + { url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" }, + { url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" }, + { url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" }, + { url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" }, + { url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" }, + { url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" }, + { url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" }, + { url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" }, + { url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" }, + { url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" }, + { url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" }, + { url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" }, + { url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" }, + { url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" }, + { url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" }, ] [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] [[package]] @@ -485,127 +645,136 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846 }, - { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618 }, - { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212 }, - { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693 }, - { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002 }, - { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971 }, - { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722 }, - { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671 }, - { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807 }, - { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872 }, - { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371 }, - { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333 }, - { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120 }, - { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991 }, - { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227 }, - { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056 }, - { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189 }, - { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912 }, - { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160 }, - { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233 }, - { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635 }, - { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079 }, - { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049 }, - { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638 }, - { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834 }, - { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925 }, - { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071 }, - { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504 }, - { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702 }, - { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535 }, - { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582 }, - { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963 }, - { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175 }, +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, + { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, + { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, + { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, + { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, + { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, + { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, + { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, + { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, + { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, + { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, + { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, + { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, + { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, + { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, + { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, + { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, + { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, + { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, + { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, + { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, + { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, + { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, + { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, + { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, ] [[package]] name = "pathlib" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/aa/9b065a76b9af472437a0059f77e8f962fe350438b927cb80184c32f075eb/pathlib-1.0.1.tar.gz", hash = "sha256:6940718dfc3eff4258203ad5021090933e5c04707d5ca8cc9e73c94a7894ea9f", size = 49298 } +sdist = { url = "https://files.pythonhosted.org/packages/ac/aa/9b065a76b9af472437a0059f77e8f962fe350438b927cb80184c32f075eb/pathlib-1.0.1.tar.gz", hash = "sha256:6940718dfc3eff4258203ad5021090933e5c04707d5ca8cc9e73c94a7894ea9f", size = 49298, upload-time = "2014-09-03T15:41:57.18Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/f9/690a8600b93c332de3ab4a344a4ac34f00c8f104917061f779db6a918ed6/pathlib-1.0.1-py3-none-any.whl", hash = "sha256:f35f95ab8b0f59e6d354090350b44a80a80635d22efdedfa84c7ad1cf0a74147", size = 14363 }, + { url = "https://files.pythonhosted.org/packages/78/f9/690a8600b93c332de3ab4a344a4ac34f00c8f104917061f779db6a918ed6/pathlib-1.0.1-py3-none-any.whl", hash = "sha256:f35f95ab8b0f59e6d354090350b44a80a80635d22efdedfa84c7ad1cf0a74147", size = 14363, upload-time = "2022-05-04T13:37:20.585Z" }, ] [[package]] name = "pathspec" version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021 }, + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715 } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "prek" version = "0.2.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/d9/1472c512bc48cf0ab7d4348bd191ac404ed9d001fcf699e681518ecc6d09/prek-0.2.16.tar.gz", hash = "sha256:264b78996f36644948d5b897b7af21bedad36abd8678ba77fd200c4a9b3b3261", size = 341621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/fb/c54f1b6658ae36fd4d0ad36d968f60642b423e8d9b2e2e9fba8839f8d3d6/prek-0.2.16-py3-none-linux_armv6l.whl", hash = "sha256:e6bb33b336b0313b4a7de2874cb2361d3a368aa90f1c5a6dbaaa267dd4a32df5", size = 4820782 }, - { url = "https://files.pythonhosted.org/packages/f3/13/7050660c8bbb0b50cbc1054656f54d5c56573d29b6b500d932f7cf940085/prek-0.2.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dbd6baae9c418a61e0b62ce7db85d57865d2b4817f5c80c4db4547fa0b1a1d7b", size = 4901877 }, - { url = "https://files.pythonhosted.org/packages/18/4b/c1bf4eed7384b8161a31e451e5141268e3115c162eecae13936a3d7d4aaa/prek-0.2.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe902fbdc1b77133f6c799519002c5727b699dcf7d14237b3d94a4fc264d3181", size = 4619978 }, - { url = "https://files.pythonhosted.org/packages/4c/47/749ceb4df5c52ac6f40c3c4eec8e36515d4faaaf954fe45cc01af9f13279/prek-0.2.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3f2fba7dba9cace414f2b70c73e461400f9f83bbf14d9fc37b201fcc2842ff99", size = 4819906 }, - { url = "https://files.pythonhosted.org/packages/45/0e/54ddd434079f753e37ec58d1dfe64b1693f47b8540daf05db2b48b858645/prek-0.2.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f48db16d59f81f5d2a698d3e17b2ec1b375867decc11013c72dd4e2bca3b2aab", size = 4751379 }, - { url = "https://files.pythonhosted.org/packages/27/1f/12ad6e9130deb908f8287626539dac79e3563be743a66607863a2fc94503/prek-0.2.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f170d9b402f6d39545eaf12c0c86735fdebfcccb509156bf2580a4dad2888269", size = 5037742 }, - { url = "https://files.pythonhosted.org/packages/44/cc/e5247b66d497595424ab9c6f81bebc9fc7985d5c73479392d30cc46ea980/prek-0.2.16-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:484928299a51ba592065b7cf4e66e1e9c4e73b517d0cb3cf4d43d222ec36a37a", size = 5470035 }, - { url = "https://files.pythonhosted.org/packages/8e/a2/73316c372e106d24f2304d512b2065f80e47ec9bf7f0042e15ae99f64b2a/prek-0.2.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28140f063d4a2adeca27236a4d8c5d37203ec16c989a6b7c5a82c3a94256565f", size = 5419661 }, - { url = "https://files.pythonhosted.org/packages/27/06/ec8e2025a8e4c7d987c173bb762b763000986e87ccd65c7fa83deb362a43/prek-0.2.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94d0aebc0660a69216c4f769e48438a4efc9a804b69bd032be387ecd6b49a26f", size = 5462304 }, - { url = "https://files.pythonhosted.org/packages/45/a4/58658815c916ccc46bf35ae794a0c042bfcb9446a4579e707865e96f069d/prek-0.2.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f6a4ed975cfae0b038f6ecb3adace744fe34195db8a264c088f1c184c604775", size = 5088758 }, - { url = "https://files.pythonhosted.org/packages/43/7c/fa4e81d36e95a90a3ad3f5ce5f6b08636ee48e3522182ce63472ab5fdb1f/prek-0.2.16-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:2693880f3d9ab15bb8c20310873a1e5b97c14c00202813bed7364ac1a8b1a34c", size = 4829954 }, - { url = "https://files.pythonhosted.org/packages/02/c0/786acdf3b535cf806dd0f41f77afd4c3a5315214ad37f3beb845d6c6957b/prek-0.2.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:db4cc554cd7b9315d0fcabeca1f8781eb768ec93fa5c9ab41ee4b65fe0542128", size = 4856932 }, - { url = "https://files.pythonhosted.org/packages/37/9c/f3b8a0bec4b59a739142953f4aa90f332605d547f36b6aa90e62b457606b/prek-0.2.16-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:296711cffb2cb967e8c292bce4aee0f408ef81454613aedc06426e1e5aa39e58", size = 4736473 }, - { url = "https://files.pythonhosted.org/packages/62/95/24cd05d749d878ba4e1ff1dab6ca071fa53a21c1aa1153fb7547c56783af/prek-0.2.16-py3-none-musllinux_1_1_i686.whl", hash = "sha256:7366a97f802872c7570617ec55e3cea5e9cc85c00dcb8275e97e7052f7b50dbd", size = 4934890 }, - { url = "https://files.pythonhosted.org/packages/d9/34/38ddcadaee73bb74dd811667faf86810b34d8e359fdcca6eca941b9ff8b7/prek-0.2.16-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:a68a124caf1839619672cc813a3adc96f55253204e8bd36196a10faf933f845c", size = 5198632 }, - { url = "https://files.pythonhosted.org/packages/73/0f/25a291c923e8362e7c18632f7690941086d6949cf1e4911280f8aef9251b/prek-0.2.16-py3-none-win32.whl", hash = "sha256:98d1df55b2665cd83d6e91176a4ddcd305bbab52967842e2afffa5c564de09db", size = 4580648 }, - { url = "https://files.pythonhosted.org/packages/4d/49/dfa46f65fb59be2d3343b30f455f8df7dab186567b10040a6f5caa1479bc/prek-0.2.16-py3-none-win_amd64.whl", hash = "sha256:a41839d4fe26dd4fe057d9a2ddc39ec15221d74a6fd240fb2ece98c3b3a69509", size = 5250227 }, - { url = "https://files.pythonhosted.org/packages/a8/00/e2822644468bca8dc37435a456da826447a5c00ac46b6c3ac99e98114597/prek-0.2.16-py3-none-win_arm64.whl", hash = "sha256:950c2af27c8df9a1367b51a4686ae82d6b61db1a3ad2a2599872b9993ca062dc", size = 4930842 }, +sdist = { url = "https://files.pythonhosted.org/packages/96/d9/1472c512bc48cf0ab7d4348bd191ac404ed9d001fcf699e681518ecc6d09/prek-0.2.16.tar.gz", hash = "sha256:264b78996f36644948d5b897b7af21bedad36abd8678ba77fd200c4a9b3b3261", size = 341621, upload-time = "2025-11-18T10:02:12.615Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/fb/c54f1b6658ae36fd4d0ad36d968f60642b423e8d9b2e2e9fba8839f8d3d6/prek-0.2.16-py3-none-linux_armv6l.whl", hash = "sha256:e6bb33b336b0313b4a7de2874cb2361d3a368aa90f1c5a6dbaaa267dd4a32df5", size = 4820782, upload-time = "2025-11-18T10:01:45.372Z" }, + { url = "https://files.pythonhosted.org/packages/f3/13/7050660c8bbb0b50cbc1054656f54d5c56573d29b6b500d932f7cf940085/prek-0.2.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dbd6baae9c418a61e0b62ce7db85d57865d2b4817f5c80c4db4547fa0b1a1d7b", size = 4901877, upload-time = "2025-11-18T10:01:47.316Z" }, + { url = "https://files.pythonhosted.org/packages/18/4b/c1bf4eed7384b8161a31e451e5141268e3115c162eecae13936a3d7d4aaa/prek-0.2.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe902fbdc1b77133f6c799519002c5727b699dcf7d14237b3d94a4fc264d3181", size = 4619978, upload-time = "2025-11-18T10:01:48.569Z" }, + { url = "https://files.pythonhosted.org/packages/4c/47/749ceb4df5c52ac6f40c3c4eec8e36515d4faaaf954fe45cc01af9f13279/prek-0.2.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3f2fba7dba9cace414f2b70c73e461400f9f83bbf14d9fc37b201fcc2842ff99", size = 4819906, upload-time = "2025-11-18T10:01:50.224Z" }, + { url = "https://files.pythonhosted.org/packages/45/0e/54ddd434079f753e37ec58d1dfe64b1693f47b8540daf05db2b48b858645/prek-0.2.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f48db16d59f81f5d2a698d3e17b2ec1b375867decc11013c72dd4e2bca3b2aab", size = 4751379, upload-time = "2025-11-18T10:01:51.97Z" }, + { url = "https://files.pythonhosted.org/packages/27/1f/12ad6e9130deb908f8287626539dac79e3563be743a66607863a2fc94503/prek-0.2.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f170d9b402f6d39545eaf12c0c86735fdebfcccb509156bf2580a4dad2888269", size = 5037742, upload-time = "2025-11-18T10:01:53.715Z" }, + { url = "https://files.pythonhosted.org/packages/44/cc/e5247b66d497595424ab9c6f81bebc9fc7985d5c73479392d30cc46ea980/prek-0.2.16-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:484928299a51ba592065b7cf4e66e1e9c4e73b517d0cb3cf4d43d222ec36a37a", size = 5470035, upload-time = "2025-11-18T10:01:55.037Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a2/73316c372e106d24f2304d512b2065f80e47ec9bf7f0042e15ae99f64b2a/prek-0.2.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28140f063d4a2adeca27236a4d8c5d37203ec16c989a6b7c5a82c3a94256565f", size = 5419661, upload-time = "2025-11-18T10:01:56.357Z" }, + { url = "https://files.pythonhosted.org/packages/27/06/ec8e2025a8e4c7d987c173bb762b763000986e87ccd65c7fa83deb362a43/prek-0.2.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94d0aebc0660a69216c4f769e48438a4efc9a804b69bd032be387ecd6b49a26f", size = 5462304, upload-time = "2025-11-18T10:01:57.541Z" }, + { url = "https://files.pythonhosted.org/packages/45/a4/58658815c916ccc46bf35ae794a0c042bfcb9446a4579e707865e96f069d/prek-0.2.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f6a4ed975cfae0b038f6ecb3adace744fe34195db8a264c088f1c184c604775", size = 5088758, upload-time = "2025-11-18T10:01:59.295Z" }, + { url = "https://files.pythonhosted.org/packages/43/7c/fa4e81d36e95a90a3ad3f5ce5f6b08636ee48e3522182ce63472ab5fdb1f/prek-0.2.16-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:2693880f3d9ab15bb8c20310873a1e5b97c14c00202813bed7364ac1a8b1a34c", size = 4829954, upload-time = "2025-11-18T10:02:00.534Z" }, + { url = "https://files.pythonhosted.org/packages/02/c0/786acdf3b535cf806dd0f41f77afd4c3a5315214ad37f3beb845d6c6957b/prek-0.2.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:db4cc554cd7b9315d0fcabeca1f8781eb768ec93fa5c9ab41ee4b65fe0542128", size = 4856932, upload-time = "2025-11-18T10:02:02.134Z" }, + { url = "https://files.pythonhosted.org/packages/37/9c/f3b8a0bec4b59a739142953f4aa90f332605d547f36b6aa90e62b457606b/prek-0.2.16-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:296711cffb2cb967e8c292bce4aee0f408ef81454613aedc06426e1e5aa39e58", size = 4736473, upload-time = "2025-11-18T10:02:03.914Z" }, + { url = "https://files.pythonhosted.org/packages/62/95/24cd05d749d878ba4e1ff1dab6ca071fa53a21c1aa1153fb7547c56783af/prek-0.2.16-py3-none-musllinux_1_1_i686.whl", hash = "sha256:7366a97f802872c7570617ec55e3cea5e9cc85c00dcb8275e97e7052f7b50dbd", size = 4934890, upload-time = "2025-11-18T10:02:05.555Z" }, + { url = "https://files.pythonhosted.org/packages/d9/34/38ddcadaee73bb74dd811667faf86810b34d8e359fdcca6eca941b9ff8b7/prek-0.2.16-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:a68a124caf1839619672cc813a3adc96f55253204e8bd36196a10faf933f845c", size = 5198632, upload-time = "2025-11-18T10:02:07.142Z" }, + { url = "https://files.pythonhosted.org/packages/73/0f/25a291c923e8362e7c18632f7690941086d6949cf1e4911280f8aef9251b/prek-0.2.16-py3-none-win32.whl", hash = "sha256:98d1df55b2665cd83d6e91176a4ddcd305bbab52967842e2afffa5c564de09db", size = 4580648, upload-time = "2025-11-18T10:02:08.301Z" }, + { url = "https://files.pythonhosted.org/packages/4d/49/dfa46f65fb59be2d3343b30f455f8df7dab186567b10040a6f5caa1479bc/prek-0.2.16-py3-none-win_amd64.whl", hash = "sha256:a41839d4fe26dd4fe057d9a2ddc39ec15221d74a6fd240fb2ece98c3b3a69509", size = 5250227, upload-time = "2025-11-18T10:02:09.867Z" }, + { url = "https://files.pythonhosted.org/packages/a8/00/e2822644468bca8dc37435a456da826447a5c00ac46b6c3ac99e98114597/prek-0.2.16-py3-none-win_arm64.whl", hash = "sha256:950c2af27c8df9a1367b51a4686ae82d6b61db1a3ad2a2599872b9993ca062dc", size = 4930842, upload-time = "2025-11-18T10:02:11.392Z" }, +] + +[[package]] +name = "prometheus-client" +version = "0.24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" }, ] [[package]] name = "protobuf" version = "6.33.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/03/a1440979a3f74f16cab3b75b0da1a1a7f922d56a8ddea96092391998edc0/protobuf-6.33.1.tar.gz", hash = "sha256:97f65757e8d09870de6fd973aeddb92f85435607235d20b2dfed93405d00c85b", size = 443432 } +sdist = { url = "https://files.pythonhosted.org/packages/0a/03/a1440979a3f74f16cab3b75b0da1a1a7f922d56a8ddea96092391998edc0/protobuf-6.33.1.tar.gz", hash = "sha256:97f65757e8d09870de6fd973aeddb92f85435607235d20b2dfed93405d00c85b", size = 443432, upload-time = "2025-11-13T16:44:18.895Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/f1/446a9bbd2c60772ca36556bac8bfde40eceb28d9cc7838755bc41e001d8f/protobuf-6.33.1-cp310-abi3-win32.whl", hash = "sha256:f8d3fdbc966aaab1d05046d0240dd94d40f2a8c62856d41eaa141ff64a79de6b", size = 425593 }, - { url = "https://files.pythonhosted.org/packages/a6/79/8780a378c650e3df849b73de8b13cf5412f521ca2ff9b78a45c247029440/protobuf-6.33.1-cp310-abi3-win_amd64.whl", hash = "sha256:923aa6d27a92bf44394f6abf7ea0500f38769d4b07f4be41cb52bd8b1123b9ed", size = 436883 }, - { url = "https://files.pythonhosted.org/packages/cd/93/26213ff72b103ae55bb0d73e7fb91ea570ef407c3ab4fd2f1f27cac16044/protobuf-6.33.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe34575f2bdde76ac429ec7b570235bf0c788883e70aee90068e9981806f2490", size = 427522 }, - { url = "https://files.pythonhosted.org/packages/c2/32/df4a35247923393aa6b887c3b3244a8c941c32a25681775f96e2b418f90e/protobuf-6.33.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:f8adba2e44cde2d7618996b3fc02341f03f5bc3f2748be72dc7b063319276178", size = 324445 }, - { url = "https://files.pythonhosted.org/packages/8e/d0/d796e419e2ec93d2f3fa44888861c3f88f722cde02b7c3488fcc6a166820/protobuf-6.33.1-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:0f4cf01222c0d959c2b399142deb526de420be8236f22c71356e2a544e153c53", size = 339161 }, - { url = "https://files.pythonhosted.org/packages/1d/2a/3c5f05a4af06649547027d288747f68525755de692a26a7720dced3652c0/protobuf-6.33.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd7d5e0eb08cd5b87fd3df49bc193f5cfd778701f47e11d127d0afc6c39f1d1", size = 323171 }, - { url = "https://files.pythonhosted.org/packages/08/b4/46310463b4f6ceef310f8348786f3cff181cea671578e3d9743ba61a459e/protobuf-6.33.1-py3-none-any.whl", hash = "sha256:d595a9fd694fdeb061a62fbe10eb039cc1e444df81ec9bb70c7fc59ebcb1eafa", size = 170477 }, + { url = "https://files.pythonhosted.org/packages/06/f1/446a9bbd2c60772ca36556bac8bfde40eceb28d9cc7838755bc41e001d8f/protobuf-6.33.1-cp310-abi3-win32.whl", hash = "sha256:f8d3fdbc966aaab1d05046d0240dd94d40f2a8c62856d41eaa141ff64a79de6b", size = 425593, upload-time = "2025-11-13T16:44:06.275Z" }, + { url = "https://files.pythonhosted.org/packages/a6/79/8780a378c650e3df849b73de8b13cf5412f521ca2ff9b78a45c247029440/protobuf-6.33.1-cp310-abi3-win_amd64.whl", hash = "sha256:923aa6d27a92bf44394f6abf7ea0500f38769d4b07f4be41cb52bd8b1123b9ed", size = 436883, upload-time = "2025-11-13T16:44:09.222Z" }, + { url = "https://files.pythonhosted.org/packages/cd/93/26213ff72b103ae55bb0d73e7fb91ea570ef407c3ab4fd2f1f27cac16044/protobuf-6.33.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe34575f2bdde76ac429ec7b570235bf0c788883e70aee90068e9981806f2490", size = 427522, upload-time = "2025-11-13T16:44:10.475Z" }, + { url = "https://files.pythonhosted.org/packages/c2/32/df4a35247923393aa6b887c3b3244a8c941c32a25681775f96e2b418f90e/protobuf-6.33.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:f8adba2e44cde2d7618996b3fc02341f03f5bc3f2748be72dc7b063319276178", size = 324445, upload-time = "2025-11-13T16:44:11.869Z" }, + { url = "https://files.pythonhosted.org/packages/8e/d0/d796e419e2ec93d2f3fa44888861c3f88f722cde02b7c3488fcc6a166820/protobuf-6.33.1-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:0f4cf01222c0d959c2b399142deb526de420be8236f22c71356e2a544e153c53", size = 339161, upload-time = "2025-11-13T16:44:12.778Z" }, + { url = "https://files.pythonhosted.org/packages/1d/2a/3c5f05a4af06649547027d288747f68525755de692a26a7720dced3652c0/protobuf-6.33.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd7d5e0eb08cd5b87fd3df49bc193f5cfd778701f47e11d127d0afc6c39f1d1", size = 323171, upload-time = "2025-11-13T16:44:14.035Z" }, + { url = "https://files.pythonhosted.org/packages/08/b4/46310463b4f6ceef310f8348786f3cff181cea671578e3d9743ba61a459e/protobuf-6.33.1-py3-none-any.whl", hash = "sha256:d595a9fd694fdeb061a62fbe10eb039cc1e444df81ec9bb70c7fc59ebcb1eafa", size = 170477, upload-time = "2025-11-13T16:44:17.633Z" }, ] [[package]] name = "pycparser" version = "2.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, ] [[package]] @@ -618,9 +787,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350 } +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782 }, + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, ] [[package]] @@ -630,39 +799,39 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000 }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996 }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957 }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199 }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296 }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109 }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028 }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044 }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881 }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034 }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187 }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628 }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866 }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894 }, - { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688 }, - { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808 }, - { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580 }, - { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859 }, - { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810 }, - { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498 }, - { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611 }, - { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924 }, - { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196 }, - { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389 }, - { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223 }, - { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473 }, - { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269 }, - { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921 }, - { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162 }, - { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560 }, - { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777 }, +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, ] [[package]] @@ -674,18 +843,18 @@ dependencies = [ { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583 } +sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235 }, + { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] [[package]] @@ -696,31 +865,31 @@ dependencies = [ { name = "cffi" }, { name = "sniffio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/8c/23141a4b94fdb69c72fe54734a5da192ecbaf5c4965ba6d3a753e6a8ac34/pynng-0.8.1.tar.gz", hash = "sha256:60165f34bdf501885e0acceaeed79bc35a57f3ca3c913cb38c14919b9bd3656f", size = 6364925 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/8c/23141a4b94fdb69c72fe54734a5da192ecbaf5c4965ba6d3a753e6a8ac34/pynng-0.8.1.tar.gz", hash = "sha256:60165f34bdf501885e0acceaeed79bc35a57f3ca3c913cb38c14919b9bd3656f", size = 6364925, upload-time = "2025-01-16T03:42:32.848Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b7/243a4e919b2e58cb21ba3e39b9d139e6a58158e944a03b78304b0d2b2881/pynng-0.8.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df13ffa5a4953b85ed43c252f5e6a00b7791faa22b9d3040e0546d878fc921a4", size = 1089916 }, - { url = "https://files.pythonhosted.org/packages/cb/9e/d7c10e38ddaa7a2e3f59cd3a5d2b3978f28d7e3f5ae1167c9555e35f1c48/pynng-0.8.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fb8d43c23e9668fb3db3992b98b7364c2991027a79d6e66af850d70820a631c", size = 727667 }, - { url = "https://files.pythonhosted.org/packages/94/42/cf84ac7b60713af568ffaa8774eb41650e49ba3c0906107f9a889cf86d40/pynng-0.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915f4f8c39684dcf6028548110f647c44a517163db5f89ceeb0c17b9c3a37205", size = 938203 }, - { url = "https://files.pythonhosted.org/packages/41/2e/2196c9c3d8ad1af35faf942482fbfc1156898b0945e8412a33d3cfcbfbe8/pynng-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ead5f360a956bc7ccbe3b20701346cecf7d1098b8ad77b6979fd7c055b9226f1", size = 736244 }, - { url = "https://files.pythonhosted.org/packages/9b/eb/347e5626e3174992b4b4cf8ff3f7fe965a2e7c7703bf2765db828970f895/pynng-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6d8237ed1c49823695ea3e6ef2e521370426b67f2010850e1b6c66c52aa1f067", size = 941519 }, - { url = "https://files.pythonhosted.org/packages/9e/67/e1027872acbdd755994d9cdf3195a6329ce2a141943fbae0e9687c533a59/pynng-0.8.1-cp312-cp312-win32.whl", hash = "sha256:78fe08a000b6c7200c1ad0d6a26491c1ba5c9493975e218af0963b9ca03e5a7a", size = 370576 }, - { url = "https://files.pythonhosted.org/packages/4b/19/bd014dfc7cdaacdba15c61a591dc12e7d5307006013f8ceb949bed6d3c48/pynng-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:117552188abe448a467feedcc68f03f2d386e596c0e44a0849c05fca72d40d3f", size = 450454 }, - { url = "https://files.pythonhosted.org/packages/0d/fd/b6b43259bf87c7640824310c930761ea814eb4b726f2814ef847ad80d96d/pynng-0.8.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1013dc1773e8a4cee633a8516977d59c17711b56b0df9d6c174d8ac722b19d9", size = 1089913 }, - { url = "https://files.pythonhosted.org/packages/44/71/134faf3a6689898167c0b8a55b8a55069521bc79ae6eed1657b075545481/pynng-0.8.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a89b5d3f9801913a22c85cf320efdffc1a2eda925939a0e1a6edc0e194eab27", size = 727669 }, - { url = "https://files.pythonhosted.org/packages/72/3d/2d77349fa87671d31c5c57ea44365311338b0a8d984e8b095add62f18fda/pynng-0.8.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2f0a7fdd96c99eaf1a1fce755a6eb39e0ca1cf46cf81c01abe593adabc53b45", size = 938072 }, - { url = "https://files.pythonhosted.org/packages/04/91/580382d32fe90dd3cc0310358d449991070091b78a8f97df3f8e4b3d5fee/pynng-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cbda575215e854a241ae837aac613e88d197b0489ef61f4a42f2e9dd793f01", size = 736250 }, - { url = "https://files.pythonhosted.org/packages/b6/db/9bf6a8158187aa344c306c6037ff20d134132d83596dcbb8537faaad610d/pynng-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3f635d6361f9ad81d16ba794a5a9b3aa47ed92a7709b88396523676cb6bddb1f", size = 941514 }, - { url = "https://files.pythonhosted.org/packages/26/f3/9a7676e3d115834a5acf674590bb32e61f9caa5b8f0971628fc562670d35/pynng-0.8.1-cp313-cp313-win32.whl", hash = "sha256:6d5c51249ca221f0c4e27b13269a230b19fc5e10a60cbfa7a8109995b22e861e", size = 370575 }, - { url = "https://files.pythonhosted.org/packages/ff/0e/11d76f7aeb733e966024eb6b6adf73280d2c600f8fa8bdb6ea34d33e9a19/pynng-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:1f9c52bca0d063843178d6f43a302e0e2d6fbe20272de5b3c37f4873c3d55a42", size = 450453 }, + { url = "https://files.pythonhosted.org/packages/7a/b7/243a4e919b2e58cb21ba3e39b9d139e6a58158e944a03b78304b0d2b2881/pynng-0.8.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df13ffa5a4953b85ed43c252f5e6a00b7791faa22b9d3040e0546d878fc921a4", size = 1089916, upload-time = "2025-01-16T03:40:43.088Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9e/d7c10e38ddaa7a2e3f59cd3a5d2b3978f28d7e3f5ae1167c9555e35f1c48/pynng-0.8.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fb8d43c23e9668fb3db3992b98b7364c2991027a79d6e66af850d70820a631c", size = 727667, upload-time = "2025-01-16T03:40:44.875Z" }, + { url = "https://files.pythonhosted.org/packages/94/42/cf84ac7b60713af568ffaa8774eb41650e49ba3c0906107f9a889cf86d40/pynng-0.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915f4f8c39684dcf6028548110f647c44a517163db5f89ceeb0c17b9c3a37205", size = 938203, upload-time = "2025-01-16T03:40:48.421Z" }, + { url = "https://files.pythonhosted.org/packages/41/2e/2196c9c3d8ad1af35faf942482fbfc1156898b0945e8412a33d3cfcbfbe8/pynng-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ead5f360a956bc7ccbe3b20701346cecf7d1098b8ad77b6979fd7c055b9226f1", size = 736244, upload-time = "2025-01-16T03:40:51.06Z" }, + { url = "https://files.pythonhosted.org/packages/9b/eb/347e5626e3174992b4b4cf8ff3f7fe965a2e7c7703bf2765db828970f895/pynng-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6d8237ed1c49823695ea3e6ef2e521370426b67f2010850e1b6c66c52aa1f067", size = 941519, upload-time = "2025-01-16T03:40:53.761Z" }, + { url = "https://files.pythonhosted.org/packages/9e/67/e1027872acbdd755994d9cdf3195a6329ce2a141943fbae0e9687c533a59/pynng-0.8.1-cp312-cp312-win32.whl", hash = "sha256:78fe08a000b6c7200c1ad0d6a26491c1ba5c9493975e218af0963b9ca03e5a7a", size = 370576, upload-time = "2025-01-16T03:40:55.818Z" }, + { url = "https://files.pythonhosted.org/packages/4b/19/bd014dfc7cdaacdba15c61a591dc12e7d5307006013f8ceb949bed6d3c48/pynng-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:117552188abe448a467feedcc68f03f2d386e596c0e44a0849c05fca72d40d3f", size = 450454, upload-time = "2025-01-16T03:40:57.737Z" }, + { url = "https://files.pythonhosted.org/packages/0d/fd/b6b43259bf87c7640824310c930761ea814eb4b726f2814ef847ad80d96d/pynng-0.8.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1013dc1773e8a4cee633a8516977d59c17711b56b0df9d6c174d8ac722b19d9", size = 1089913, upload-time = "2025-01-16T03:41:01.543Z" }, + { url = "https://files.pythonhosted.org/packages/44/71/134faf3a6689898167c0b8a55b8a55069521bc79ae6eed1657b075545481/pynng-0.8.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a89b5d3f9801913a22c85cf320efdffc1a2eda925939a0e1a6edc0e194eab27", size = 727669, upload-time = "2025-01-16T03:41:04.936Z" }, + { url = "https://files.pythonhosted.org/packages/72/3d/2d77349fa87671d31c5c57ea44365311338b0a8d984e8b095add62f18fda/pynng-0.8.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2f0a7fdd96c99eaf1a1fce755a6eb39e0ca1cf46cf81c01abe593adabc53b45", size = 938072, upload-time = "2025-01-16T03:41:09.685Z" }, + { url = "https://files.pythonhosted.org/packages/04/91/580382d32fe90dd3cc0310358d449991070091b78a8f97df3f8e4b3d5fee/pynng-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cbda575215e854a241ae837aac613e88d197b0489ef61f4a42f2e9dd793f01", size = 736250, upload-time = "2025-01-16T03:41:11.304Z" }, + { url = "https://files.pythonhosted.org/packages/b6/db/9bf6a8158187aa344c306c6037ff20d134132d83596dcbb8537faaad610d/pynng-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3f635d6361f9ad81d16ba794a5a9b3aa47ed92a7709b88396523676cb6bddb1f", size = 941514, upload-time = "2025-01-16T03:41:13.156Z" }, + { url = "https://files.pythonhosted.org/packages/26/f3/9a7676e3d115834a5acf674590bb32e61f9caa5b8f0971628fc562670d35/pynng-0.8.1-cp313-cp313-win32.whl", hash = "sha256:6d5c51249ca221f0c4e27b13269a230b19fc5e10a60cbfa7a8109995b22e861e", size = 370575, upload-time = "2025-01-16T03:41:15.998Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/11d76f7aeb733e966024eb6b6adf73280d2c600f8fa8bdb6ea34d33e9a19/pynng-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:1f9c52bca0d063843178d6f43a302e0e2d6fbe20272de5b3c37f4873c3d55a42", size = 450453, upload-time = "2025-01-16T03:41:17.604Z" }, ] [[package]] name = "pyparsing" version = "3.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512 } +sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512, upload-time = "2025-12-23T03:14:04.391Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793 }, + { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, ] [[package]] @@ -734,9 +903,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714 } +sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474 }, + { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, ] [[package]] @@ -748,9 +917,9 @@ dependencies = [ { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432 } +sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644 }, + { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" }, ] [[package]] @@ -760,73 +929,73 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] name = "python-dotenv" version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556 }, + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, ] [[package]] name = "pytz" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669 }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252 }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081 }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159 }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626 }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613 }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115 }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814 }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809 }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454 }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355 }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175 }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228 }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194 }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108 }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641 }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901 }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132 }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261 }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272 }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923 }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] [[package]] @@ -836,123 +1005,163 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722 }, + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, ] [[package]] name = "regex" version = "2025.11.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/74/18f04cb53e58e3fb107439699bd8375cf5a835eec81084e0bddbd122e4c2/regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41", size = 489312 }, - { url = "https://files.pythonhosted.org/packages/78/3f/37fcdd0d2b1e78909108a876580485ea37c91e1acf66d3bb8e736348f441/regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36", size = 291256 }, - { url = "https://files.pythonhosted.org/packages/bf/26/0a575f58eb23b7ebd67a45fccbc02ac030b737b896b7e7a909ffe43ffd6a/regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1", size = 288921 }, - { url = "https://files.pythonhosted.org/packages/ea/98/6a8dff667d1af907150432cf5abc05a17ccd32c72a3615410d5365ac167a/regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7", size = 798568 }, - { url = "https://files.pythonhosted.org/packages/64/15/92c1db4fa4e12733dd5a526c2dd2b6edcbfe13257e135fc0f6c57f34c173/regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69", size = 864165 }, - { url = "https://files.pythonhosted.org/packages/f9/e7/3ad7da8cdee1ce66c7cd37ab5ab05c463a86ffeb52b1a25fe7bd9293b36c/regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48", size = 912182 }, - { url = "https://files.pythonhosted.org/packages/84/bd/9ce9f629fcb714ffc2c3faf62b6766ecb7a585e1e885eb699bcf130a5209/regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c", size = 803501 }, - { url = "https://files.pythonhosted.org/packages/7c/0f/8dc2e4349d8e877283e6edd6c12bdcebc20f03744e86f197ab6e4492bf08/regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695", size = 787842 }, - { url = "https://files.pythonhosted.org/packages/f9/73/cff02702960bc185164d5619c0c62a2f598a6abff6695d391b096237d4ab/regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98", size = 858519 }, - { url = "https://files.pythonhosted.org/packages/61/83/0e8d1ae71e15bc1dc36231c90b46ee35f9d52fab2e226b0e039e7ea9c10a/regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74", size = 850611 }, - { url = "https://files.pythonhosted.org/packages/c8/f5/70a5cdd781dcfaa12556f2955bf170cd603cb1c96a1827479f8faea2df97/regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0", size = 789759 }, - { url = "https://files.pythonhosted.org/packages/59/9b/7c29be7903c318488983e7d97abcf8ebd3830e4c956c4c540005fcfb0462/regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204", size = 266194 }, - { url = "https://files.pythonhosted.org/packages/1a/67/3b92df89f179d7c367be654ab5626ae311cb28f7d5c237b6bb976cd5fbbb/regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9", size = 277069 }, - { url = "https://files.pythonhosted.org/packages/d7/55/85ba4c066fe5094d35b249c3ce8df0ba623cfd35afb22d6764f23a52a1c5/regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26", size = 270330 }, - { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081 }, - { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123 }, - { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814 }, - { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592 }, - { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122 }, - { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272 }, - { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497 }, - { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892 }, - { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462 }, - { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528 }, - { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866 }, - { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189 }, - { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054 }, - { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325 }, - { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984 }, - { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673 }, - { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029 }, - { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437 }, - { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368 }, - { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921 }, - { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708 }, - { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472 }, - { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341 }, - { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666 }, - { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473 }, - { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792 }, - { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214 }, - { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469 }, - { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089 }, - { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059 }, - { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900 }, - { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010 }, - { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893 }, - { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522 }, - { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272 }, - { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958 }, - { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289 }, - { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026 }, - { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499 }, - { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604 }, - { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320 }, - { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372 }, - { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985 }, - { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669 }, - { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030 }, - { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674 }, - { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451 }, - { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980 }, - { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852 }, - { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566 }, - { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463 }, - { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694 }, - { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691 }, - { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583 }, - { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286 }, - { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741 }, +sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669, upload-time = "2025-11-03T21:34:22.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/74/18f04cb53e58e3fb107439699bd8375cf5a835eec81084e0bddbd122e4c2/regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41", size = 489312, upload-time = "2025-11-03T21:31:34.343Z" }, + { url = "https://files.pythonhosted.org/packages/78/3f/37fcdd0d2b1e78909108a876580485ea37c91e1acf66d3bb8e736348f441/regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36", size = 291256, upload-time = "2025-11-03T21:31:35.675Z" }, + { url = "https://files.pythonhosted.org/packages/bf/26/0a575f58eb23b7ebd67a45fccbc02ac030b737b896b7e7a909ffe43ffd6a/regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1", size = 288921, upload-time = "2025-11-03T21:31:37.07Z" }, + { url = "https://files.pythonhosted.org/packages/ea/98/6a8dff667d1af907150432cf5abc05a17ccd32c72a3615410d5365ac167a/regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7", size = 798568, upload-time = "2025-11-03T21:31:38.784Z" }, + { url = "https://files.pythonhosted.org/packages/64/15/92c1db4fa4e12733dd5a526c2dd2b6edcbfe13257e135fc0f6c57f34c173/regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69", size = 864165, upload-time = "2025-11-03T21:31:40.559Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e7/3ad7da8cdee1ce66c7cd37ab5ab05c463a86ffeb52b1a25fe7bd9293b36c/regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48", size = 912182, upload-time = "2025-11-03T21:31:42.002Z" }, + { url = "https://files.pythonhosted.org/packages/84/bd/9ce9f629fcb714ffc2c3faf62b6766ecb7a585e1e885eb699bcf130a5209/regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c", size = 803501, upload-time = "2025-11-03T21:31:43.815Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0f/8dc2e4349d8e877283e6edd6c12bdcebc20f03744e86f197ab6e4492bf08/regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695", size = 787842, upload-time = "2025-11-03T21:31:45.353Z" }, + { url = "https://files.pythonhosted.org/packages/f9/73/cff02702960bc185164d5619c0c62a2f598a6abff6695d391b096237d4ab/regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98", size = 858519, upload-time = "2025-11-03T21:31:46.814Z" }, + { url = "https://files.pythonhosted.org/packages/61/83/0e8d1ae71e15bc1dc36231c90b46ee35f9d52fab2e226b0e039e7ea9c10a/regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74", size = 850611, upload-time = "2025-11-03T21:31:48.289Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f5/70a5cdd781dcfaa12556f2955bf170cd603cb1c96a1827479f8faea2df97/regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0", size = 789759, upload-time = "2025-11-03T21:31:49.759Z" }, + { url = "https://files.pythonhosted.org/packages/59/9b/7c29be7903c318488983e7d97abcf8ebd3830e4c956c4c540005fcfb0462/regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204", size = 266194, upload-time = "2025-11-03T21:31:51.53Z" }, + { url = "https://files.pythonhosted.org/packages/1a/67/3b92df89f179d7c367be654ab5626ae311cb28f7d5c237b6bb976cd5fbbb/regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9", size = 277069, upload-time = "2025-11-03T21:31:53.151Z" }, + { url = "https://files.pythonhosted.org/packages/d7/55/85ba4c066fe5094d35b249c3ce8df0ba623cfd35afb22d6764f23a52a1c5/regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26", size = 270330, upload-time = "2025-11-03T21:31:54.514Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a7/dda24ebd49da46a197436ad96378f17df30ceb40e52e859fc42cac45b850/regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4", size = 489081, upload-time = "2025-11-03T21:31:55.9Z" }, + { url = "https://files.pythonhosted.org/packages/19/22/af2dc751aacf88089836aa088a1a11c4f21a04707eb1b0478e8e8fb32847/regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76", size = 291123, upload-time = "2025-11-03T21:31:57.758Z" }, + { url = "https://files.pythonhosted.org/packages/a3/88/1a3ea5672f4b0a84802ee9891b86743438e7c04eb0b8f8c4e16a42375327/regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a", size = 288814, upload-time = "2025-11-03T21:32:01.12Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8c/f5987895bf42b8ddeea1b315c9fedcfe07cadee28b9c98cf50d00adcb14d/regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361", size = 798592, upload-time = "2025-11-03T21:32:03.006Z" }, + { url = "https://files.pythonhosted.org/packages/99/2a/6591ebeede78203fa77ee46a1c36649e02df9eaa77a033d1ccdf2fcd5d4e/regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160", size = 864122, upload-time = "2025-11-03T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/94/d6/be32a87cf28cf8ed064ff281cfbd49aefd90242a83e4b08b5a86b38e8eb4/regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe", size = 912272, upload-time = "2025-11-03T21:32:06.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/11/9bcef2d1445665b180ac7f230406ad80671f0fc2a6ffb93493b5dd8cd64c/regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850", size = 803497, upload-time = "2025-11-03T21:32:08.162Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a7/da0dc273d57f560399aa16d8a68ae7f9b57679476fc7ace46501d455fe84/regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc", size = 787892, upload-time = "2025-11-03T21:32:09.769Z" }, + { url = "https://files.pythonhosted.org/packages/da/4b/732a0c5a9736a0b8d6d720d4945a2f1e6f38f87f48f3173559f53e8d5d82/regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9", size = 858462, upload-time = "2025-11-03T21:32:11.769Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f5/a2a03df27dc4c2d0c769220f5110ba8c4084b0bfa9ab0f9b4fcfa3d2b0fc/regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b", size = 850528, upload-time = "2025-11-03T21:32:13.906Z" }, + { url = "https://files.pythonhosted.org/packages/d6/09/e1cd5bee3841c7f6eb37d95ca91cdee7100b8f88b81e41c2ef426910891a/regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7", size = 789866, upload-time = "2025-11-03T21:32:15.748Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/702f5ea74e2a9c13d855a6a85b7f80c30f9e72a95493260193c07f3f8d74/regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c", size = 266189, upload-time = "2025-11-03T21:32:17.493Z" }, + { url = "https://files.pythonhosted.org/packages/8b/00/6e29bb314e271a743170e53649db0fdb8e8ff0b64b4f425f5602f4eb9014/regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5", size = 277054, upload-time = "2025-11-03T21:32:19.042Z" }, + { url = "https://files.pythonhosted.org/packages/25/f1/b156ff9f2ec9ac441710764dda95e4edaf5f36aca48246d1eea3f1fd96ec/regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467", size = 270325, upload-time = "2025-11-03T21:32:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/20/28/fd0c63357caefe5680b8ea052131acbd7f456893b69cc2a90cc3e0dc90d4/regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281", size = 491984, upload-time = "2025-11-03T21:32:23.466Z" }, + { url = "https://files.pythonhosted.org/packages/df/ec/7014c15626ab46b902b3bcc4b28a7bae46d8f281fc7ea9c95e22fcaaa917/regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39", size = 292673, upload-time = "2025-11-03T21:32:25.034Z" }, + { url = "https://files.pythonhosted.org/packages/23/ab/3b952ff7239f20d05f1f99e9e20188513905f218c81d52fb5e78d2bf7634/regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7", size = 291029, upload-time = "2025-11-03T21:32:26.528Z" }, + { url = "https://files.pythonhosted.org/packages/21/7e/3dc2749fc684f455f162dcafb8a187b559e2614f3826877d3844a131f37b/regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed", size = 807437, upload-time = "2025-11-03T21:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/1b/0b/d529a85ab349c6a25d1ca783235b6e3eedf187247eab536797021f7126c6/regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19", size = 873368, upload-time = "2025-11-03T21:32:30.4Z" }, + { url = "https://files.pythonhosted.org/packages/7d/18/2d868155f8c9e3e9d8f9e10c64e9a9f496bb8f7e037a88a8bed26b435af6/regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b", size = 914921, upload-time = "2025-11-03T21:32:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/2d/71/9d72ff0f354fa783fe2ba913c8734c3b433b86406117a8db4ea2bf1c7a2f/regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a", size = 812708, upload-time = "2025-11-03T21:32:34.305Z" }, + { url = "https://files.pythonhosted.org/packages/e7/19/ce4bf7f5575c97f82b6e804ffb5c4e940c62609ab2a0d9538d47a7fdf7d4/regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6", size = 795472, upload-time = "2025-11-03T21:32:36.364Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/fd1063a176ffb7b2315f9a1b08d17b18118b28d9df163132615b835a26ee/regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce", size = 868341, upload-time = "2025-11-03T21:32:38.042Z" }, + { url = "https://files.pythonhosted.org/packages/12/43/103fb2e9811205e7386366501bc866a164a0430c79dd59eac886a2822950/regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd", size = 854666, upload-time = "2025-11-03T21:32:40.079Z" }, + { url = "https://files.pythonhosted.org/packages/7d/22/e392e53f3869b75804762c7c848bd2dd2abf2b70fb0e526f58724638bd35/regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2", size = 799473, upload-time = "2025-11-03T21:32:42.148Z" }, + { url = "https://files.pythonhosted.org/packages/4f/f9/8bd6b656592f925b6845fcbb4d57603a3ac2fb2373344ffa1ed70aa6820a/regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a", size = 268792, upload-time = "2025-11-03T21:32:44.13Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/0e7d603467775ff65cd2aeabf1b5b50cc1c3708556a8b849a2fa4dd1542b/regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c", size = 280214, upload-time = "2025-11-03T21:32:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d0/2afc6f8e94e2b64bfb738a7c2b6387ac1699f09f032d363ed9447fd2bb57/regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e", size = 271469, upload-time = "2025-11-03T21:32:48.026Z" }, + { url = "https://files.pythonhosted.org/packages/31/e9/f6e13de7e0983837f7b6d238ad9458800a874bf37c264f7923e63409944c/regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6", size = 489089, upload-time = "2025-11-03T21:32:50.027Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5c/261f4a262f1fa65141c1b74b255988bd2fa020cc599e53b080667d591cfc/regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4", size = 291059, upload-time = "2025-11-03T21:32:51.682Z" }, + { url = "https://files.pythonhosted.org/packages/8e/57/f14eeb7f072b0e9a5a090d1712741fd8f214ec193dba773cf5410108bb7d/regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73", size = 288900, upload-time = "2025-11-03T21:32:53.569Z" }, + { url = "https://files.pythonhosted.org/packages/3c/6b/1d650c45e99a9b327586739d926a1cd4e94666b1bd4af90428b36af66dc7/regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f", size = 799010, upload-time = "2025-11-03T21:32:55.222Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/d66dcbc6b628ce4e3f7f0cbbb84603aa2fc0ffc878babc857726b8aab2e9/regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d", size = 864893, upload-time = "2025-11-03T21:32:57.239Z" }, + { url = "https://files.pythonhosted.org/packages/bf/2d/f238229f1caba7ac87a6c4153d79947fb0261415827ae0f77c304260c7d3/regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be", size = 911522, upload-time = "2025-11-03T21:32:59.274Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3d/22a4eaba214a917c80e04f6025d26143690f0419511e0116508e24b11c9b/regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db", size = 803272, upload-time = "2025-11-03T21:33:01.393Z" }, + { url = "https://files.pythonhosted.org/packages/84/b1/03188f634a409353a84b5ef49754b97dbcc0c0f6fd6c8ede505a8960a0a4/regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62", size = 787958, upload-time = "2025-11-03T21:33:03.379Z" }, + { url = "https://files.pythonhosted.org/packages/99/6a/27d072f7fbf6fadd59c64d210305e1ff865cc3b78b526fd147db768c553b/regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f", size = 859289, upload-time = "2025-11-03T21:33:05.374Z" }, + { url = "https://files.pythonhosted.org/packages/9a/70/1b3878f648e0b6abe023172dacb02157e685564853cc363d9961bcccde4e/regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02", size = 850026, upload-time = "2025-11-03T21:33:07.131Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d5/68e25559b526b8baab8e66839304ede68ff6727237a47727d240006bd0ff/regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed", size = 789499, upload-time = "2025-11-03T21:33:09.141Z" }, + { url = "https://files.pythonhosted.org/packages/fc/df/43971264857140a350910d4e33df725e8c94dd9dee8d2e4729fa0d63d49e/regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4", size = 271604, upload-time = "2025-11-03T21:33:10.9Z" }, + { url = "https://files.pythonhosted.org/packages/01/6f/9711b57dc6894a55faf80a4c1b5aa4f8649805cb9c7aef46f7d27e2b9206/regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad", size = 280320, upload-time = "2025-11-03T21:33:12.572Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7e/f6eaa207d4377481f5e1775cdeb5a443b5a59b392d0065f3417d31d80f87/regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f", size = 273372, upload-time = "2025-11-03T21:33:14.219Z" }, + { url = "https://files.pythonhosted.org/packages/c3/06/49b198550ee0f5e4184271cee87ba4dfd9692c91ec55289e6282f0f86ccf/regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc", size = 491985, upload-time = "2025-11-03T21:33:16.555Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bf/abdafade008f0b1c9da10d934034cb670432d6cf6cbe38bbb53a1cfd6cf8/regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49", size = 292669, upload-time = "2025-11-03T21:33:18.32Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ef/0c357bb8edbd2ad8e273fcb9e1761bc37b8acbc6e1be050bebd6475f19c1/regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536", size = 291030, upload-time = "2025-11-03T21:33:20.048Z" }, + { url = "https://files.pythonhosted.org/packages/79/06/edbb67257596649b8fb088d6aeacbcb248ac195714b18a65e018bf4c0b50/regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95", size = 807674, upload-time = "2025-11-03T21:33:21.797Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d9/ad4deccfce0ea336296bd087f1a191543bb99ee1c53093dcd4c64d951d00/regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009", size = 873451, upload-time = "2025-11-03T21:33:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/13/75/a55a4724c56ef13e3e04acaab29df26582f6978c000ac9cd6810ad1f341f/regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9", size = 914980, upload-time = "2025-11-03T21:33:25.999Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/a1657ee15bd9116f70d4a530c736983eed997b361e20ecd8f5ca3759d5c5/regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d", size = 812852, upload-time = "2025-11-03T21:33:27.852Z" }, + { url = "https://files.pythonhosted.org/packages/b8/6f/f7516dde5506a588a561d296b2d0044839de06035bb486b326065b4c101e/regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6", size = 795566, upload-time = "2025-11-03T21:33:32.364Z" }, + { url = "https://files.pythonhosted.org/packages/d9/dd/3d10b9e170cc16fb34cb2cef91513cf3df65f440b3366030631b2984a264/regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154", size = 868463, upload-time = "2025-11-03T21:33:34.459Z" }, + { url = "https://files.pythonhosted.org/packages/f5/8e/935e6beff1695aa9085ff83195daccd72acc82c81793df480f34569330de/regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267", size = 854694, upload-time = "2025-11-03T21:33:36.793Z" }, + { url = "https://files.pythonhosted.org/packages/92/12/10650181a040978b2f5720a6a74d44f841371a3d984c2083fc1752e4acf6/regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379", size = 799691, upload-time = "2025-11-03T21:33:39.079Z" }, + { url = "https://files.pythonhosted.org/packages/67/90/8f37138181c9a7690e7e4cb388debbd389342db3c7381d636d2875940752/regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38", size = 274583, upload-time = "2025-11-03T21:33:41.302Z" }, + { url = "https://files.pythonhosted.org/packages/8f/cd/867f5ec442d56beb56f5f854f40abcfc75e11d10b11fdb1869dd39c63aaf/regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de", size = 284286, upload-time = "2025-11-03T21:33:43.324Z" }, + { url = "https://files.pythonhosted.org/packages/20/31/32c0c4610cbc070362bf1d2e4ea86d1ea29014d400a6d6c2486fcfd57766/regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801", size = 274741, upload-time = "2025-11-03T21:33:45.557Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "sniffio" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "starlette" +version = "0.50.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, ] [[package]] name = "types-pyyaml" version = "6.0.12.20250915" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338 }, + { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20260107" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d", size = 20676, upload-time = "2026-01-07T03:20:52.929Z" }, ] [[package]] name = "typing-extensions" version = "4.14.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673 } +sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906 }, + { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, ] [[package]] @@ -962,58 +1171,238 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552 }, + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, ] [[package]] name = "tzdata" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 }, + { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, + { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, + { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, + { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, + { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, + { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, + { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, + { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, + { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, + { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, + { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, + { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, + { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, ] [[package]] name = "verspec" version = "0.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/44/8126f9f0c44319b2efc65feaad589cadef4d77ece200ae3c9133d58464d0/verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e", size = 27123 } +sdist = { url = "https://files.pythonhosted.org/packages/e7/44/8126f9f0c44319b2efc65feaad589cadef4d77ece200ae3c9133d58464d0/verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e", size = 27123, upload-time = "2020-11-30T02:24:09.646Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31", size = 19640 }, + { url = "https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31", size = 19640, upload-time = "2020-11-30T02:24:08.387Z" }, ] [[package]] name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" }, + { url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" }, + { url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" }, + { url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" }, + { url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" }, + { url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" }, + { url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" }, + { url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" }, + { url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/f750b29225fe77139f7ae5de89d4949f5a99f934c65a1f1c0b248f26f747/watchfiles-1.1.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:130e4876309e8686a5e37dba7d5e9bc77e6ed908266996ca26572437a5271e18", size = 404321, upload-time = "2025-10-14T15:05:02.063Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f9/f07a295cde762644aa4c4bb0f88921d2d141af45e735b965fb2e87858328/watchfiles-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f3bde70f157f84ece3765b42b4a52c6ac1a50334903c6eaf765362f6ccca88a", size = 391783, upload-time = "2025-10-14T15:05:03.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/11/fc2502457e0bea39a5c958d86d2cb69e407a4d00b85735ca724bfa6e0d1a/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b1fe858430fc0251737ef3824c54027bedb8c37c38114488b8e131cf8219", size = 449279, upload-time = "2025-10-14T15:05:04.004Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1f/d66bc15ea0b728df3ed96a539c777acfcad0eb78555ad9efcaa1274688f0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f27db948078f3823a6bb3b465180db8ebecf26dd5dae6f6180bd87383b6b4428", size = 459405, upload-time = "2025-10-14T15:05:04.942Z" }, + { url = "https://files.pythonhosted.org/packages/be/90/9f4a65c0aec3ccf032703e6db02d89a157462fbb2cf20dd415128251cac0/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059098c3a429f62fc98e8ec62b982230ef2c8df68c79e826e37b895bc359a9c0", size = 488976, upload-time = "2025-10-14T15:05:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/37/57/ee347af605d867f712be7029bb94c8c071732a4b44792e3176fa3c612d39/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfb5862016acc9b869bb57284e6cb35fdf8e22fe59f7548858e2f971d045f150", size = 595506, upload-time = "2025-10-14T15:05:06.906Z" }, + { url = "https://files.pythonhosted.org/packages/a8/78/cc5ab0b86c122047f75e8fc471c67a04dee395daf847d3e59381996c8707/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:319b27255aacd9923b8a276bb14d21a5f7ff82564c744235fc5eae58d95422ae", size = 474936, upload-time = "2025-10-14T15:05:07.906Z" }, + { url = "https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c755367e51db90e75b19454b680903631d41f9e3607fbd941d296a020c2d752d", size = 456147, upload-time = "2025-10-14T15:05:09.138Z" }, + { url = "https://files.pythonhosted.org/packages/57/99/da6573ba71166e82d288d4df0839128004c67d2778d3b566c138695f5c0b/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c22c776292a23bfc7237a98f791b9ad3144b02116ff10d820829ce62dff46d0b", size = 630007, upload-time = "2025-10-14T15:05:10.117Z" }, + { url = "https://files.pythonhosted.org/packages/a8/51/7439c4dd39511368849eb1e53279cd3454b4a4dbace80bab88feeb83c6b5/watchfiles-1.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:3a476189be23c3686bc2f4321dd501cb329c0a0469e77b7b534ee10129ae6374", size = 622280, upload-time = "2025-10-14T15:05:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/95/9c/8ed97d4bba5db6fdcdb2b298d3898f2dd5c20f6b73aee04eabe56c59677e/watchfiles-1.1.1-cp313-cp313-win32.whl", hash = "sha256:bf0a91bfb5574a2f7fc223cf95eeea79abfefa404bf1ea5e339c0c1560ae99a0", size = 272056, upload-time = "2025-10-14T15:05:12.156Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/c14e28429f744a260d8ceae18bf58c1d5fa56b50d006a7a9f80e1882cb0d/watchfiles-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:52e06553899e11e8074503c8e716d574adeeb7e68913115c4b3653c53f9bae42", size = 288162, upload-time = "2025-10-14T15:05:13.208Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/fe0e56c40d5cd29523e398d31153218718c5786b5e636d9ae8ae79453d27/watchfiles-1.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:ac3cc5759570cd02662b15fbcd9d917f7ecd47efe0d6b40474eafd246f91ea18", size = 277909, upload-time = "2025-10-14T15:05:14.49Z" }, + { url = "https://files.pythonhosted.org/packages/79/42/e0a7d749626f1e28c7108a99fb9bf524b501bbbeb9b261ceecde644d5a07/watchfiles-1.1.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:563b116874a9a7ce6f96f87cd0b94f7faf92d08d0021e837796f0a14318ef8da", size = 403389, upload-time = "2025-10-14T15:05:15.777Z" }, + { url = "https://files.pythonhosted.org/packages/15/49/08732f90ce0fbbc13913f9f215c689cfc9ced345fb1bcd8829a50007cc8d/watchfiles-1.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ad9fe1dae4ab4212d8c91e80b832425e24f421703b5a42ef2e4a1e215aff051", size = 389964, upload-time = "2025-10-14T15:05:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/7c315d4bd5f2538910491a0393c56bf70d333d51bc5b34bee8e68e8cea19/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce70f96a46b894b36eba678f153f052967a0d06d5b5a19b336ab0dbbd029f73e", size = 448114, upload-time = "2025-10-14T15:05:17.876Z" }, + { url = "https://files.pythonhosted.org/packages/c3/24/9e096de47a4d11bc4df41e9d1e61776393eac4cb6eb11b3e23315b78b2cc/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb467c999c2eff23a6417e58d75e5828716f42ed8289fe6b77a7e5a91036ca70", size = 460264, upload-time = "2025-10-14T15:05:18.962Z" }, + { url = "https://files.pythonhosted.org/packages/cc/0f/e8dea6375f1d3ba5fcb0b3583e2b493e77379834c74fd5a22d66d85d6540/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:836398932192dae4146c8f6f737d74baeac8b70ce14831a239bdb1ca882fc261", size = 487877, upload-time = "2025-10-14T15:05:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/df24cfc6424a12deb41503b64d42fbea6b8cb357ec62ca84a5a3476f654a/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:743185e7372b7bc7c389e1badcc606931a827112fbbd37f14c537320fca08620", size = 595176, upload-time = "2025-10-14T15:05:21.134Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b5/853b6757f7347de4e9b37e8cc3289283fb983cba1ab4d2d7144694871d9c/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afaeff7696e0ad9f02cbb8f56365ff4686ab205fcf9c4c5b6fdfaaa16549dd04", size = 473577, upload-time = "2025-10-14T15:05:22.306Z" }, + { url = "https://files.pythonhosted.org/packages/e1/f7/0a4467be0a56e80447c8529c9fce5b38eab4f513cb3d9bf82e7392a5696b/watchfiles-1.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7eb7da0eb23aa2ba036d4f616d46906013a68caf61b7fdbe42fc8b25132e77", size = 455425, upload-time = "2025-10-14T15:05:23.348Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/82583485ea00137ddf69bc84a2db88bd92ab4a6e3c405e5fb878ead8d0e7/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:831a62658609f0e5c64178211c942ace999517f5770fe9436be4c2faeba0c0ef", size = 628826, upload-time = "2025-10-14T15:05:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a785356fccf9fae84c0cc90570f11702ae9571036fb25932f1242c82191c/watchfiles-1.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f9a2ae5c91cecc9edd47e041a930490c31c3afb1f5e6d71de3dc671bfaca02bf", size = 622208, upload-time = "2025-10-14T15:05:25.45Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f4/0872229324ef69b2c3edec35e84bd57a1289e7d3fe74588048ed8947a323/watchfiles-1.1.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:d1715143123baeeaeadec0528bb7441103979a1d5f6fd0e1f915383fea7ea6d5", size = 404315, upload-time = "2025-10-14T15:05:26.501Z" }, + { url = "https://files.pythonhosted.org/packages/7b/22/16d5331eaed1cb107b873f6ae1b69e9ced582fcf0c59a50cd84f403b1c32/watchfiles-1.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:39574d6370c4579d7f5d0ad940ce5b20db0e4117444e39b6d8f99db5676c52fd", size = 390869, upload-time = "2025-10-14T15:05:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/b2/7e/5643bfff5acb6539b18483128fdc0ef2cccc94a5b8fbda130c823e8ed636/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7365b92c2e69ee952902e8f70f3ba6360d0d596d9299d55d7d386df84b6941fb", size = 449919, upload-time = "2025-10-14T15:05:28.701Z" }, + { url = "https://files.pythonhosted.org/packages/51/2e/c410993ba5025a9f9357c376f48976ef0e1b1aefb73b97a5ae01a5972755/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfff9740c69c0e4ed32416f013f3c45e2ae42ccedd1167ef2d805c000b6c71a5", size = 460845, upload-time = "2025-10-14T15:05:30.064Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a4/2df3b404469122e8680f0fcd06079317e48db58a2da2950fb45020947734/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b27cf2eb1dda37b2089e3907d8ea92922b673c0c427886d4edc6b94d8dfe5db3", size = 489027, upload-time = "2025-10-14T15:05:31.064Z" }, + { url = "https://files.pythonhosted.org/packages/ea/84/4587ba5b1f267167ee715b7f66e6382cca6938e0a4b870adad93e44747e6/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526e86aced14a65a5b0ec50827c745597c782ff46b571dbfe46192ab9e0b3c33", size = 595615, upload-time = "2025-10-14T15:05:32.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/0f/c6988c91d06e93cd0bb3d4a808bcf32375ca1904609835c3031799e3ecae/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04e78dd0b6352db95507fd8cb46f39d185cf8c74e4cf1e4fbad1d3df96faf510", size = 474836, upload-time = "2025-10-14T15:05:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/b4/36/ded8aebea91919485b7bbabbd14f5f359326cb5ec218cd67074d1e426d74/watchfiles-1.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c85794a4cfa094714fb9c08d4a218375b2b95b8ed1666e8677c349906246c05", size = 455099, upload-time = "2025-10-14T15:05:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/98/e0/8c9bdba88af756a2fce230dd365fab2baf927ba42cd47521ee7498fd5211/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:74d5012b7630714b66be7b7b7a78855ef7ad58e8650c73afc4c076a1f480a8d6", size = 630626, upload-time = "2025-10-14T15:05:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/2a/84/a95db05354bf2d19e438520d92a8ca475e578c647f78f53197f5a2f17aaf/watchfiles-1.1.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:8fbe85cb3201c7d380d3d0b90e63d520f15d6afe217165d7f98c9c649654db81", size = 622519, upload-time = "2025-10-14T15:05:36.259Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ce/d8acdc8de545de995c339be67711e474c77d643555a9bb74a9334252bd55/watchfiles-1.1.1-cp314-cp314-win32.whl", hash = "sha256:3fa0b59c92278b5a7800d3ee7733da9d096d4aabcfabb9a928918bd276ef9b9b", size = 272078, upload-time = "2025-10-14T15:05:37.63Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c9/a74487f72d0451524be827e8edec251da0cc1fcf111646a511ae752e1a3d/watchfiles-1.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:c2047d0b6cea13b3316bdbafbfa0c4228ae593d995030fda39089d36e64fc03a", size = 287664, upload-time = "2025-10-14T15:05:38.95Z" }, + { url = "https://files.pythonhosted.org/packages/df/b8/8ac000702cdd496cdce998c6f4ee0ca1f15977bba51bdf07d872ebdfc34c/watchfiles-1.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:842178b126593addc05acf6fce960d28bc5fae7afbaa2c6c1b3a7b9460e5be02", size = 277154, upload-time = "2025-10-14T15:05:39.954Z" }, + { url = "https://files.pythonhosted.org/packages/47/a8/e3af2184707c29f0f14b1963c0aace6529f9d1b8582d5b99f31bbf42f59e/watchfiles-1.1.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:88863fbbc1a7312972f1c511f202eb30866370ebb8493aef2812b9ff28156a21", size = 403820, upload-time = "2025-10-14T15:05:40.932Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55c7475190662e202c08c6c0f4d9e345a29367438cf8e8037f3155e10a88d5a5", size = 390510, upload-time = "2025-10-14T15:05:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/d5/a0/ad235642118090f66e7b2f18fd5c42082418404a79205cdfca50b6309c13/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f53fa183d53a1d7a8852277c92b967ae99c2d4dcee2bfacff8868e6e30b15f7", size = 448408, upload-time = "2025-10-14T15:05:43.385Z" }, + { url = "https://files.pythonhosted.org/packages/df/85/97fa10fd5ff3332ae17e7e40e20784e419e28521549780869f1413742e9d/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6aae418a8b323732fa89721d86f39ec8f092fc2af67f4217a2b07fd3e93c6101", size = 458968, upload-time = "2025-10-14T15:05:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/47/c2/9059c2e8966ea5ce678166617a7f75ecba6164375f3b288e50a40dc6d489/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f096076119da54a6080e8920cbdaac3dbee667eb91dcc5e5b78840b87415bd44", size = 488096, upload-time = "2025-10-14T15:05:45.398Z" }, + { url = "https://files.pythonhosted.org/packages/94/44/d90a9ec8ac309bc26db808a13e7bfc0e4e78b6fc051078a554e132e80160/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00485f441d183717038ed2e887a7c868154f216877653121068107b227a2f64c", size = 596040, upload-time = "2025-10-14T15:05:46.502Z" }, + { url = "https://files.pythonhosted.org/packages/95/68/4e3479b20ca305cfc561db3ed207a8a1c745ee32bf24f2026a129d0ddb6e/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a55f3e9e493158d7bfdb60a1165035f1cf7d320914e7b7ea83fe22c6023b58fc", size = 473847, upload-time = "2025-10-14T15:05:47.484Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/2af26693fd15165c4ff7857e38330e1b61ab8c37d15dc79118cdba115b7a/watchfiles-1.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c91ed27800188c2ae96d16e3149f199d62f86c7af5f5f4d2c61a3ed8cd3666c", size = 455072, upload-time = "2025-10-14T15:05:48.928Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/d0d200b10c9311ec25d2273f8aad8c3ef7cc7ea11808022501811208a750/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:311ff15a0bae3714ffb603e6ba6dbfba4065ab60865d15a6ec544133bdb21099", size = 629104, upload-time = "2025-10-14T15:05:49.908Z" }, + { url = "https://files.pythonhosted.org/packages/e3/bd/fa9bb053192491b3867ba07d2343d9f2252e00811567d30ae8d0f78136fe/watchfiles-1.1.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a916a2932da8f8ab582f242c065f5c81bed3462849ca79ee357dd9551b0e9b01", size = 622112, upload-time = "2025-10-14T15:05:50.941Z" }, +] + +[[package]] +name = "websockets" +version = "16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, - { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, - { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, - { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, + { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, + { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, + { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, + { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, + { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, + { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, + { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, + { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, + { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, + { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, + { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, + { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, + { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, + { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, + { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" }, + { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" }, + { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" }, + { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" }, + { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" }, + { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, + { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] [[package]] name = "zipp" version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] From 0538d3454cb97c285fec0474f1d45076fb6d6d2e Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 13:42:34 +0100 Subject: [PATCH 46/78] Fixed whitespaces --- SECURITY.md | 2 +- mkdocs.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 5829fed..e7cbac5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,7 @@ | 1.x.x | :white_check_mark: | | < 1.0.0 | :x: | -> [!IMPORTANT] +> [!IMPORTANT] > Currently DetectMateService is a work in progress and heavily under development. Possible vulnerabilities will not be treated any special and can be issued using [GitHub-Issues](https://github.com/ait-detectmate/DetectMateService/issues) ## Reporting a Vulnerability diff --git a/mkdocs.yml b/mkdocs.yml index 37375aa..6f07418 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,4 +18,3 @@ nav: markdown_extensions: - admonition - From 4cd1ab68a6a7906f5448b6ffc561066eaf188e8f Mon Sep 17 00:00:00 2001 From: whotwagner Date: Mon, 2 Feb 2026 15:34:59 +0100 Subject: [PATCH 47/78] Update development.md with manual check instructions Added instructions for running checks manually. --- docs/development.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/development.md b/docs/development.md index cfa4dca..94b8d7c 100644 --- a/docs/development.md +++ b/docs/development.md @@ -28,6 +28,12 @@ and can be installed as part of the `dev` extras. To ensure pre-commit hooks run uv run prek install ``` +To run the checks manually, you can execute: + +```bash +uv run prek run -a +``` + ## Add tests and run pytest In oder to run the tests run the following command: From 11625c6b58420060a0bee063dc1f0cc486a69130 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Tue, 3 Feb 2026 14:33:29 +0100 Subject: [PATCH 48/78] Added script to select proper library-version during tests --- .github/workflows/python-app.yml | 14 +++++++------- scripts/change_toml.sh | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100755 scripts/change_toml.sh diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index cec7492..67ac0cf 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -5,9 +5,9 @@ name: Python application on: push: - branches: [ "main" ] + branches: [ "main", "development" ] pull_request: - branches: [ "main" ] + branches: [ "main", "development" ] permissions: contents: read @@ -28,11 +28,11 @@ jobs: activate-environment: true enable-cache: true - - name: Install project deps - run: uv pip install -e .[dev] + - name: Use specific detematelibrary version + run: chmod +x scripts/change_toml.sh && scripts/change_toml.sh $GITHUB_BASE_REF - name: Run pre-commit with prek - run: uv run prek run -a - + run: uv run --dev prek run -a + - name: Test with pytest - run: uv run pytest + run: uv run --dev pytest diff --git a/scripts/change_toml.sh b/scripts/change_toml.sh new file mode 100755 index 0000000..59da0e7 --- /dev/null +++ b/scripts/change_toml.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +REPLACE=DetectMateLibrary.git + +if [ $# -eq 0 ] +then + echo "No branch selected. Keeping original pyproject.toml" + exit 0 +fi + +if [ "$1" != "main" ] +then + BRANCH="development" +else + BRANCH="main" +fi + + +sed -i "s/$REPLACE/$REPLACE@$BRANCH/g" pyproject.toml From 9db8c02d6a4948a076f700fe0f8b03f30cde4b82 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Tue, 3 Feb 2026 14:42:41 +0100 Subject: [PATCH 49/78] Added output for change_toml.sh --- scripts/change_toml.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/change_toml.sh b/scripts/change_toml.sh index 59da0e7..3f52413 100755 --- a/scripts/change_toml.sh +++ b/scripts/change_toml.sh @@ -15,5 +15,6 @@ else BRANCH="main" fi +echo "Using branch: $BRANCH" sed -i "s/$REPLACE/$REPLACE@$BRANCH/g" pyproject.toml From 9f662a74f277aa08f77b73ede2e120e398355c9d Mon Sep 17 00:00:00 2001 From: whotwagner Date: Tue, 3 Feb 2026 15:02:35 +0100 Subject: [PATCH 50/78] Deactivated integration-tests --- .github/workflows/python-app.yml | 2 +- tests/test_reconfigure_params.py | 2 +- uv.lock | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 67ac0cf..917a441 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -35,4 +35,4 @@ jobs: run: uv run --dev prek run -a - name: Test with pytest - run: uv run --dev pytest + run: uv run --dev pytest --ignore tests/library_integration diff --git a/tests/test_reconfigure_params.py b/tests/test_reconfigure_params.py index 4ff9e04..0e0ec4a 100644 --- a/tests/test_reconfigure_params.py +++ b/tests/test_reconfigure_params.py @@ -6,7 +6,7 @@ from pathlib import Path from unittest.mock import Mock, patch -from service.cli import reconfigure_service +#from service.cli import reconfigure_service from service.core import Service from service.settings import ServiceSettings from pydantic import Field diff --git a/uv.lock b/uv.lock index 19277aa..e18e296 100644 --- a/uv.lock +++ b/uv.lock @@ -229,9 +229,10 @@ wheels = [ [[package]] name = "detectmatelibrary" version = "0.1.0" -source = { git = "https://github.com/ait-detectmate/DetectMateLibrary.git#115d08409ccbf580d9b82128cb58d4dd9d467fa6" } +source = { git = "https://github.com/ait-detectmate/DetectMateLibrary.git?rev=development#4689b1c1cb55c87107a3286d5a3843213a9c7c88" } dependencies = [ { name = "drain3" }, + { name = "kafka-python" }, { name = "pandas" }, { name = "protobuf" }, { name = "pydantic" }, @@ -268,7 +269,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "detectmatelibrary", git = "https://github.com/ait-detectmate/DetectMateLibrary.git" }, + { name = "detectmatelibrary", git = "https://github.com/ait-detectmate/DetectMateLibrary.git?rev=development" }, { name = "fastapi", specifier = ">=0.115.0" }, { name = "pathlib", specifier = ">=1.0.1" }, { name = "prometheus-client", specifier = ">=0.20.0" }, @@ -425,6 +426,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/a7/c2f527ddce3155ae9e008385963c2325cbfd52969f8b38efa2723e2af4af/jsonpickle-1.5.1-py2.py3-none-any.whl", hash = "sha256:8eb8323f0e12cb40687f0445e2115d8165901e20ac670add55bb53a95c68c0e5", size = 37124, upload-time = "2021-01-31T05:57:12.256Z" }, ] +[[package]] +name = "kafka-python" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/5c/d3b6d93ed625d2cb0265e6fe0f507be544f6edde577c1b118f42566389bf/kafka_python-2.3.0.tar.gz", hash = "sha256:de65b596d26b5c894f227c35c7d29a65cea8f8a1c4f0f2b4e3e2ea60d503acc8", size = 358391, upload-time = "2025-11-21T00:47:34.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/db/694fd552295ed091e7418d02b6268ee36092d4c93211136c448fe061fe32/kafka_python-2.3.0-py2.py3-none-any.whl", hash = "sha256:831ba6dff28144d0f1145c874d391f3ebb3c2c3e940cc78d74e83f0183497c98", size = 326260, upload-time = "2025-11-21T00:47:32.561Z" }, +] + [[package]] name = "markdown" version = "3.10" From 95ed0ff06a47c8dd2150977e95c6e7f3c621785e Mon Sep 17 00:00:00 2001 From: whotwagner Date: Tue, 3 Feb 2026 15:07:05 +0100 Subject: [PATCH 51/78] Deactivated tests with reconfigure_service --- tests/test_reconfigure_params.py | 165 ++++++++++++++++--------------- uv.lock | 4 +- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/tests/test_reconfigure_params.py b/tests/test_reconfigure_params.py index 0e0ec4a..cb915f7 100644 --- a/tests/test_reconfigure_params.py +++ b/tests/test_reconfigure_params.py @@ -6,7 +6,7 @@ from pathlib import Path from unittest.mock import Mock, patch -#from service.cli import reconfigure_service +# from service.cli import reconfigure_service from service.core import Service from service.settings import ServiceSettings from pydantic import Field @@ -238,87 +238,88 @@ def test_reconfigure_with_persist(test_service_mocked, temp_params_file): for key, val in new_configs.items(): assert file_content[key] == val - -def test_cli_reconfigure_with_persist(temp_params_file): - """Test CLI reconfigure command with persist flag.""" - # Create a temporary settings file - with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: - yaml.dump({ - 'manager_addr': 'inproc://test_manager', - 'config_file': temp_params_file - }, f) - settings_path = f.name - - # Create a temporary new configs file - with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: - new_configs = { - 'threshold': 0.9, - 'enabled': False - } - yaml.dump(new_configs, f) - new_configs_path = f.name - - try: - # Mock the pynng request to avoid actual socket communication - with patch('pynng.Req0') as mock_req: - mock_socket = Mock() - mock_req.return_value.__enter__.return_value = mock_socket - mock_socket.recv.return_value = b"reconfigure: ok" - - # Call reconfigure with persist - reconfigure_service(Path(settings_path), Path(new_configs_path), persist=True) - - # Verify the request was sent with "persist" flag - call_args = mock_socket.send.call_args[0][0] - assert b"persist" in call_args - assert b'"threshold": 0.9' in call_args - - finally: - # Clean up - for path in [settings_path, new_configs_path]: - if os.path.exists(path): - os.unlink(path) - - -def test_cli_reconfigure_without_persist(temp_params_file): - """Test CLI reconfigure command without persist flag.""" - # Create a temporary settings file - with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: - yaml.dump({ - 'manager_addr': 'inproc://test_manager', - 'config_file': temp_params_file - }, f) - settings_path = f.name - - # Create a temporary new configs file - with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: - new_configs = { - 'threshold': 0.9, - 'enabled': False - } - yaml.dump(new_configs, f) - new_configs_path = f.name - - try: - # Mock the pynng request to avoid actual socket communication - with patch('pynng.Req0') as mock_req: - mock_socket = Mock() - mock_req.return_value.__enter__.return_value = mock_socket - mock_socket.recv.return_value = b"reconfigure: ok" - - # Call reconfigure without persist - reconfigure_service(Path(settings_path), Path(new_configs_path), persist=False) - - # Verify the request was sent without "persist" flag - call_args = mock_socket.send.call_args[0][0] - assert b"persist" not in call_args - assert b'"threshold": 0.9' in call_args - - finally: - # Clean up - for path in [settings_path, new_configs_path]: - if os.path.exists(path): - os.unlink(path) +# DEACTIVATED BECAUSE OF reconfigure_service +# def test_cli_reconfigure_with_persist(temp_params_file): +# """Test CLI reconfigure command with persist flag.""" +# # Create a temporary settings file +# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: +# yaml.dump({ +# 'manager_addr': 'inproc://test_manager', +# 'config_file': temp_params_file +# }, f) +# settings_path = f.name +# +# # Create a temporary new configs file +# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: +# new_configs = { +# 'threshold': 0.9, +# 'enabled': False +# } +# yaml.dump(new_configs, f) +# new_configs_path = f.name +# +# try: +# # Mock the pynng request to avoid actual socket communication +# with patch('pynng.Req0') as mock_req: +# mock_socket = Mock() +# mock_req.return_value.__enter__.return_value = mock_socket +# mock_socket.recv.return_value = b"reconfigure: ok" +# +# # Call reconfigure with persist +# reconfigure_service(Path(settings_path), Path(new_configs_path), persist=True) +# +# # Verify the request was sent with "persist" flag +# call_args = mock_socket.send.call_args[0][0] +# assert b"persist" in call_args +# assert b'"threshold": 0.9' in call_args +# +# finally: +# # Clean up +# for path in [settings_path, new_configs_path]: +# if os.path.exists(path): +# os.unlink(path) + + +# DEACTIVATED BECAUSE OF reconfigure_service +# def test_cli_reconfigure_without_persist(temp_params_file): +# """Test CLI reconfigure command without persist flag.""" +# # Create a temporary settings file +# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: +# yaml.dump({ +# 'manager_addr': 'inproc://test_manager', +# 'config_file': temp_params_file +# }, f) +# settings_path = f.name +# +# # Create a temporary new configs file +# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: +# new_configs = { +# 'threshold': 0.9, +# 'enabled': False +# } +# yaml.dump(new_configs, f) +# new_configs_path = f.name +# +# try: +# # Mock the pynng request to avoid actual socket communication +# with patch('pynng.Req0') as mock_req: +# mock_socket = Mock() +# mock_req.return_value.__enter__.return_value = mock_socket +# mock_socket.recv.return_value = b"reconfigure: ok" +# +# # Call reconfigure without persist +# reconfigure_service(Path(settings_path), Path(new_configs_path), persist=False) +# +# # Verify the request was sent without "persist" flag +# call_args = mock_socket.send.call_args[0][0] +# assert b"persist" not in call_args +# assert b'"threshold": 0.9' in call_args +# +# finally: +# # Clean up +# for path in [settings_path, new_configs_path]: +# if os.path.exists(path): +# os.unlink(path) # Integration test for persist functionality diff --git a/uv.lock b/uv.lock index e18e296..3bd10ff 100644 --- a/uv.lock +++ b/uv.lock @@ -229,7 +229,7 @@ wheels = [ [[package]] name = "detectmatelibrary" version = "0.1.0" -source = { git = "https://github.com/ait-detectmate/DetectMateLibrary.git?rev=development#4689b1c1cb55c87107a3286d5a3843213a9c7c88" } +source = { git = "https://github.com/ait-detectmate/DetectMateLibrary.git#ecdda5586965a091836cde050768c0d5d6adfd15" } dependencies = [ { name = "drain3" }, { name = "kafka-python" }, @@ -269,7 +269,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "detectmatelibrary", git = "https://github.com/ait-detectmate/DetectMateLibrary.git?rev=development" }, + { name = "detectmatelibrary", git = "https://github.com/ait-detectmate/DetectMateLibrary.git" }, { name = "fastapi", specifier = ">=0.115.0" }, { name = "pathlib", specifier = ">=1.0.1" }, { name = "prometheus-client", specifier = ">=0.20.0" }, From e574a73a01ce79accc2039a2a5a5699124935293 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Tue, 3 Feb 2026 15:09:51 +0100 Subject: [PATCH 52/78] Updated README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 24a398e..69cb977 100644 --- a/README.md +++ b/README.md @@ -24,19 +24,19 @@ If you plan to contribute to the development of this package, follow these steps ```bash uv sync --dev -uv run prek install +uv run --dev prek install ``` Run the tests: ```bash -uv run pytest -q +uv run --dev pytest -q ``` Run the tests with coverage (add `--cov-report=html` to generate an HTML report): ```bash -uv run pytest --cov=. --cov-report=term-missing +uv run --dev pytest --cov=. --cov-report=term-missing ``` From 710188d0f6437d5628dc6556ea045c83c9a32532 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 3 Feb 2026 15:42:09 +0100 Subject: [PATCH 53/78] use new service settings schema in engine multi output test --- tests/test_engine_multi_output.py | 53 ++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/tests/test_engine_multi_output.py b/tests/test_engine_multi_output.py index 4db71e3..c1d5ce1 100644 --- a/tests/test_engine_multi_output.py +++ b/tests/test_engine_multi_output.py @@ -4,6 +4,7 @@ import pynng from pydantic import ValidationError + from service.settings import ServiceSettings from service.features.engine import Engine from library.processor import BaseProcessor @@ -39,7 +40,6 @@ def temp_ipc_paths(tmp_path): 'out1': f"ipc://{tmp_path}/out1.ipc", 'out2': f"ipc://{tmp_path}/out2.ipc", 'out3': f"ipc://{tmp_path}/out3.ipc", - 'manager': f"ipc://{tmp_path}/manager.ipc", } @@ -60,7 +60,8 @@ def test_single_output_destination(self, temp_ipc_paths): """Test engine with a single output destination.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8001, out_addr=[temp_ipc_paths['out1']], engine_autostart=False, ) @@ -100,7 +101,8 @@ def test_multiple_output_destinations(self, temp_ipc_paths): """Test engine sending to multiple output destinations.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], temp_ipc_paths['out2'], @@ -155,7 +157,8 @@ def test_no_output_destinations(self, temp_ipc_paths): """Test engine with no output destinations configured.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[], # Empty list engine_autostart=False, ) @@ -188,7 +191,8 @@ def test_mixed_ipc_tcp_destinations(self, temp_ipc_paths): """Test engine with both IPC and TCP output destinations.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], 'tcp://127.0.0.1:15555', @@ -238,7 +242,8 @@ def test_processor_returns_none(self, temp_ipc_paths): """Test that no output is sent when processor returns None.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1']], engine_autostart=False, ) @@ -274,7 +279,8 @@ def test_output_socket_failure_resilience(self, temp_ipc_paths): """Engine continues with remaining sockets if one fails mid-run.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], temp_ipc_paths['out2'], @@ -328,7 +334,8 @@ def test_multiple_messages_sequence(self, temp_ipc_paths): """Test sending multiple messages in sequence to multiple outputs.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1'], temp_ipc_paths['out2']], engine_autostart=False, ) @@ -373,7 +380,8 @@ def test_engine_stop_closes_all_sockets(self, temp_ipc_paths): """Test that stopping engine closes all output sockets.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1'], temp_ipc_paths['out2']], engine_autostart=False, ) @@ -417,7 +425,8 @@ def test_settings_from_yaml(self, tmp_path): component_name: "test-component" component_type: "core" log_dir: "./logs" -manager_addr: "ipc:///tmp/test.cmd.ipc" +http_host: "127.0.0.1" +http_port: "8002" engine_addr: "ipc:///tmp/test.engine.ipc" out_addr: - "ipc:///tmp/out1.ipc" @@ -442,7 +451,8 @@ def test_concurrent_message_processing(self, temp_ipc_paths): """Test that messages are processed and sent correctly under load.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1']], engine_autostart=False, ) @@ -489,7 +499,8 @@ def test_invalid_output_address_validation(self, temp_ipc_paths): with pytest.raises(ValidationError): ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], # Valid "invalid://bad.address", # Invalid scheme -> rejected @@ -504,7 +515,8 @@ def test_output_socket_failure_resilience_runtime(self, temp_ipc_paths): during runtime.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], temp_ipc_paths['out2'], @@ -556,7 +568,8 @@ def test_unreachable_output_does_not_fail_startup(self, temp_ipc_paths): """Engine should start even if output is unreachable at startup.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], # acts as unreachable (no listener) ], @@ -573,7 +586,8 @@ def test_output_socket_unavailable_does_not_fail_startup(self, temp_ipc_paths): """Engine starts if one reachable and one unreachable output exist.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[ temp_ipc_paths['out1'], # available temp_ipc_paths['out2'], # unreachable @@ -599,7 +613,8 @@ def test_late_binding_output(self, temp_ipc_paths): engine start.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1']], engine_autostart=False, ) @@ -650,7 +665,8 @@ def test_empty_message_handling(self, temp_ipc_paths): """Test handling of empty messages.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1']], engine_autostart=False, ) @@ -686,7 +702,8 @@ def test_large_message_handling(self, temp_ipc_paths): """Test handling of large messages to multiple outputs.""" settings = ServiceSettings( engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=8002, out_addr=[temp_ipc_paths['out1'], temp_ipc_paths['out2']], engine_autostart=False, ) From 76159eb9232256c183037373ad9c7269d00fe88f Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 3 Feb 2026 16:25:23 +0100 Subject: [PATCH 54/78] mkdocs --- mkdocs.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 6f07418..4faf455 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,7 +14,12 @@ nav: - Using a Library Component: library.md - Running a Pipeline: pipeline.md - Contribution: contribution.md - - Development: development.md + - Development: + - Overview: development.md + - Library Imports: library-imports.md + - Interfaces: interfaces.md + + markdown_extensions: - admonition From 0183f543f8aa291a406c30920f3a8f3fe8904bc2 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 3 Feb 2026 16:54:52 +0100 Subject: [PATCH 55/78] use fastapi in serice multi output integrastion tests --- .../test_service_multi_output_integration.py | 160 ++++++++++++------ 1 file changed, 105 insertions(+), 55 deletions(-) diff --git a/tests/test_service_multi_output_integration.py b/tests/test_service_multi_output_integration.py index 85695fa..c30c503 100644 --- a/tests/test_service_multi_output_integration.py +++ b/tests/test_service_multi_output_integration.py @@ -1,7 +1,10 @@ """Integration tests for Service with multi-destination output.""" +import socket import pytest import time import pynng +import httpx +import threading from service.core import Service from service.settings import ServiceSettings @@ -12,27 +15,45 @@ class MockService(Service): component_type = "test_service" +@pytest.fixture +def free_port(): + """Find a free port on the system.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(('', 0)) + return s.getsockname()[1] + + @pytest.fixture def temp_ipc_paths(tmp_path): """Generate temporary IPC paths for testing.""" return { 'engine': f"ipc://{tmp_path}/engine.ipc", - 'manager': f"ipc://{tmp_path}/manager.ipc", 'out1': f"ipc://{tmp_path}/out1.ipc", 'out2': f"ipc://{tmp_path}/out2.ipc", 'out3': f"ipc://{tmp_path}/out3.ipc", } +def run_service_in_thread(service): + """Helper to start the service.run() in a background thread.""" + thread = threading.Thread(target=service.run, daemon=True) + thread.start() + # Wait for web server to likely be up + time.sleep(0.5) + return thread + + class TestServiceMultiOutputIntegration: """Integration tests for Service with multi-output functionality.""" - def test_service_with_multiple_outputs(self, temp_ipc_paths, tmp_path): + def test_service_with_multiple_outputs(self, temp_ipc_paths, tmp_path, free_port): + port = free_port """Test complete service flow with multiple outputs.""" settings = ServiceSettings( component_name="test-service", engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[temp_ipc_paths['out1'], temp_ipc_paths['out2']], log_dir=tmp_path / "logs", engine_autostart=True, @@ -48,6 +69,7 @@ def test_service_with_multiple_outputs(self, temp_ipc_paths, tmp_path): # Create service service = MockService(settings=settings) + run_service_in_thread(service) # Create input sender sender = pynng.Pair0() @@ -70,15 +92,20 @@ def test_service_with_multiple_outputs(self, temp_ipc_paths, tmp_path): sender.close() for receiver in receivers: receiver.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + except Exception: + pass # Server might already be down - def test_service_status_with_output_config(self, temp_ipc_paths, tmp_path): + def test_service_status_with_output_config(self, temp_ipc_paths, tmp_path, free_port): + port = free_port """Test that status command includes output configuration.""" - import json settings = ServiceSettings( component_name="status-test", engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[temp_ipc_paths['out1'], temp_ipc_paths['out2']], log_dir=tmp_path / "logs", engine_autostart=True, @@ -92,25 +119,18 @@ def test_service_status_with_output_config(self, temp_ipc_paths, tmp_path): r1.recv_timeout = r2.recv_timeout = 1000 service = MockService(settings=settings) - - # Create command client - cmd_client = pynng.Req0() - cmd_client.dial(temp_ipc_paths['manager']) - cmd_client.recv_timeout = 1000 + run_service_in_thread(service) try: - time.sleep(0.1) - - # Request status - cmd_client.send(b"status") - response = cmd_client.recv().decode() + time.sleep(0.5) - # Parse response - status_data = json.loads(response) + # Request status via HTTP instead of NNG Manager + response = httpx.get(f"http://127.0.0.1:{port}/admin/status") + assert response.status_code == 200 + status_data = response.json() # Verify output addresses are in settings assert 'settings' in status_data - assert 'out_addr' in status_data['settings'] assert status_data['settings']['out_addr'] == [ temp_ipc_paths['out1'], temp_ipc_paths['out2'] @@ -118,16 +138,21 @@ def test_service_status_with_output_config(self, temp_ipc_paths, tmp_path): finally: service.stop() - cmd_client.close() r1.close() r2.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + except Exception: + pass # Server might already be down - def test_service_context_manager_with_outputs(self, temp_ipc_paths, tmp_path): + def test_service_context_manager_with_outputs(self, temp_ipc_paths, tmp_path, free_port): + port = free_port """Test service as context manager with multiple outputs.""" settings = ServiceSettings( component_name="context-test", engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[temp_ipc_paths['out1']], log_dir=tmp_path / "logs", engine_autostart=True, @@ -140,27 +165,32 @@ def test_service_context_manager_with_outputs(self, temp_ipc_paths, tmp_path): sender = pynng.Pair0() sender.dial(temp_ipc_paths['engine']) + service = MockService(settings=settings) + run_service_in_thread(service) try: - with MockService(settings=settings): - time.sleep(0.1) - - # Send message - sender.send(b"context manager test") - - # Receive message - result = receiver.recv() - assert result == b"context manager test" + time.sleep(0.1) + # Send message + sender.send(b"context manager test") + # Receive message + result = receiver.recv() + assert result == b"context manager test" finally: sender.close() receiver.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + except Exception: + pass # Server might already be down - def test_service_stop_command_closes_outputs(self, temp_ipc_paths, tmp_path): + def test_service_stop_command_closes_outputs(self, temp_ipc_paths, tmp_path, free_port): + port = free_port """Test that stop command properly closes output sockets.""" settings = ServiceSettings( component_name="stop-test", engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[temp_ipc_paths['out1'], temp_ipc_paths['out2']], log_dir=tmp_path / "logs", engine_autostart=True, @@ -174,21 +204,14 @@ def test_service_stop_command_closes_outputs(self, temp_ipc_paths, tmp_path): r1.recv_timeout = r2.recv_timeout = 1000 service = MockService(settings=settings) - - # Create command client - cmd_client = pynng.Req0() - cmd_client.dial(temp_ipc_paths['manager']) - cmd_client.recv_timeout = 1000 + run_service_in_thread(service) try: - time.sleep(0.1) - # Verify service is running assert service._running # Send stop command - cmd_client.send(b"stop") - cmd_client.recv().decode() + httpx.post(f"http://127.0.0.1:{port}/admin/stop") time.sleep(0.2) # Give time to stop @@ -201,22 +224,28 @@ def test_service_stop_command_closes_outputs(self, temp_ipc_paths, tmp_path): sock.send(b"test") finally: - cmd_client.close() r1.close() r2.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + except Exception: + pass # Server might already be down - def test_service_with_no_outputs_still_works(self, temp_ipc_paths, tmp_path): + def test_service_with_no_outputs_still_works(self, temp_ipc_paths, tmp_path, free_port): + port = free_port """Test that service works normally with no output addresses.""" settings = ServiceSettings( component_name="no-output-test", engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[], # Empty list log_dir=tmp_path / "logs", engine_autostart=True, ) service = MockService(settings=settings) + run_service_in_thread(service) sender = pynng.Pair0() sender.dial(temp_ipc_paths['engine']) @@ -234,21 +263,27 @@ def test_service_with_no_outputs_still_works(self, temp_ipc_paths, tmp_path): finally: service.stop() sender.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + except Exception: + pass # Server might already be down - def test_yaml_config_loading_with_outputs(self, tmp_path): + def test_yaml_config_loading_with_outputs(self, tmp_path, free_port): + port = free_port """Test loading service settings from YAML with output addresses.""" yaml_content = """ component_name: "yaml-test" component_type: "test_service" log_dir: "{log_dir}" - manager_addr: "ipc://{tmp}/manager.ipc" + http_host: "127.0.0.1" + http_port: {port} engine_addr: "ipc://{tmp}/engine.ipc" out_addr: - "ipc://{tmp}/out1.ipc" - "ipc://{tmp}/out2.ipc" - "tcp://localhost:5555" engine_autostart: false - """.format(log_dir=str(tmp_path / "logs"), tmp=str(tmp_path)) + """.format(log_dir=str(tmp_path / "logs"), tmp=str(tmp_path), port=port) yaml_file = tmp_path / "settings.yaml" yaml_file.write_text(yaml_content) @@ -265,18 +300,19 @@ def test_yaml_config_loading_with_outputs(self, tmp_path): assert [a.scheme for a in settings.out_addr] == ["ipc", "ipc", "tcp"] - def test_concurrent_services_different_outputs(self, tmp_path): + def test_concurrent_services_different_outputs(self, tmp_path, free_port): + port = free_port """Test multiple services with different output destinations.""" # Service 1 setup service1_paths = { 'engine': f"ipc://{tmp_path}/service1_engine.ipc", - 'manager': f"ipc://{tmp_path}/service1_manager.ipc", 'out': f"ipc://{tmp_path}/service1_out.ipc", } settings1 = ServiceSettings( component_name="service-1", engine_addr=service1_paths['engine'], - manager_addr=service1_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[service1_paths['out']], log_dir=tmp_path / "logs1", engine_autostart=True, @@ -285,13 +321,13 @@ def test_concurrent_services_different_outputs(self, tmp_path): # Service 2 setup service2_paths = { 'engine': f"ipc://{tmp_path}/service2_engine.ipc", - 'manager': f"ipc://{tmp_path}/service2_manager.ipc", 'out': f"ipc://{tmp_path}/service2_out.ipc", } settings2 = ServiceSettings( component_name="service-2", engine_addr=service2_paths['engine'], - manager_addr=service2_paths['manager'], + http_host="127.0.0.1", + http_port=port+1, out_addr=[service2_paths['out']], log_dir=tmp_path / "logs2", engine_autostart=True, @@ -308,7 +344,9 @@ def test_concurrent_services_different_outputs(self, tmp_path): # Create services service1 = MockService(settings=settings1) + run_service_in_thread(service1) service2 = MockService(settings=settings2) + run_service_in_thread(service2) # Create senders sender1 = pynng.Pair0() @@ -338,17 +376,24 @@ def test_concurrent_services_different_outputs(self, tmp_path): sender2.close() receiver1.close() receiver2.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + httpx.post(f"http://127.0.0.1:{port+1}/admin/shutdown") + except Exception: + pass # Servers might already be down class TestServiceMultiOutputStressTests: """Stress tests for multi-output functionality.""" - def test_high_throughput_multiple_outputs(self, temp_ipc_paths, tmp_path): + def test_high_throughput_multiple_outputs(self, temp_ipc_paths, tmp_path, free_port): + port = free_port """Test handling high message throughput to multiple outputs.""" settings = ServiceSettings( component_name="stress-test", engine_addr=temp_ipc_paths['engine'], - manager_addr=temp_ipc_paths['manager'], + http_host="127.0.0.1", + http_port=port, out_addr=[ temp_ipc_paths['out1'], temp_ipc_paths['out2'], @@ -368,6 +413,7 @@ def test_high_throughput_multiple_outputs(self, temp_ipc_paths, tmp_path): receivers.append(receiver) service = MockService(settings=settings) + run_service_in_thread(service) sender = pynng.Pair0() sender.dial(temp_ipc_paths['engine']) @@ -400,3 +446,7 @@ def test_high_throughput_multiple_outputs(self, temp_ipc_paths, tmp_path): sender.close() for receiver in receivers: receiver.close() + try: + httpx.post(f"http://127.0.0.1:{port}/admin/shutdown") + except Exception: + pass # Server might already be down From d2d3f6af49e699570b6ac1ef34ffb72d4d3ed206 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 3 Feb 2026 17:04:18 +0100 Subject: [PATCH 56/78] uv lock --- uv.lock | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/uv.lock b/uv.lock index 3bd10ff..ed0b65b 100644 --- a/uv.lock +++ b/uv.lock @@ -247,6 +247,7 @@ source = { editable = "." } dependencies = [ { name = "detectmatelibrary" }, { name = "fastapi" }, + { name = "httpx" }, { name = "pathlib" }, { name = "prometheus-client" }, { name = "pydantic" }, @@ -271,6 +272,7 @@ dev = [ requires-dist = [ { name = "detectmatelibrary", git = "https://github.com/ait-detectmate/DetectMateLibrary.git" }, { name = "fastapi", specifier = ">=0.115.0" }, + { name = "httpx", specifier = ">=0.28.1" }, { name = "pathlib", specifier = ">=1.0.1" }, { name = "prometheus-client", specifier = ">=0.20.0" }, { name = "pydantic", specifier = ">=2.11.7" }, @@ -337,6 +339,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + [[package]] name = "httptools" version = "0.7.1" @@ -366,6 +381,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, ] +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + [[package]] name = "idna" version = "3.11" From 8a22a2614e9b7567f97255abf55e606a0ec53594 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Tue, 3 Feb 2026 17:04:59 +0100 Subject: [PATCH 57/78] add pyproject.toml --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3e81b33..3a7f9ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,8 @@ dependencies = [ "requests>=2.31.0", "prometheus-client>=0.20.0", "uvicorn[standard]>=0.34.0", - "fastapi>=0.115.0" + "fastapi>=0.115.0", + "httpx>=0.28.1", ] [dependency-groups] From d1e2af4e562cf55243e32a0dfc2d09b322c851e3 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Wed, 4 Feb 2026 13:13:17 +0100 Subject: [PATCH 58/78] update test component id --- tests/test_component_id.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_component_id.py b/tests/test_component_id.py index dee894a..c2373c6 100644 --- a/tests/test_component_id.py +++ b/tests/test_component_id.py @@ -31,16 +31,17 @@ def test_uuid5_from_addresses_expected_and_stable(): component_name=None, component_id=None, ) - expected = uuid5( - NAMESPACE_URL, - "detectmate/detector|ipc:///tmp/a.ipc|ipc:///tmp/b.ipc", - ).hex + + expected_input = "detectmate/detector|ipc:///tmp/b.ipc" + expected = uuid5(NAMESPACE_URL, expected_input).hex assert s1.component_id == expected # Recreate with same addresses -> same ID s2 = ServiceSettings( component_type="detector", engine_addr="ipc:///tmp/b.ipc", + component_name=None, + component_id=None, ) assert s2.component_id == expected From 700c4b0595d5f1df88200d4a2782596846736e52 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Wed, 4 Feb 2026 13:30:29 +0100 Subject: [PATCH 59/78] update egine looptest --- tests/test_engine_loop.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/tests/test_engine_loop.py b/tests/test_engine_loop.py index d5933f2..372a6dd 100644 --- a/tests/test_engine_loop.py +++ b/tests/test_engine_loop.py @@ -1,6 +1,7 @@ import time import threading import pynng +import httpx import pytest from service.settings import ServiceSettings @@ -26,20 +27,28 @@ def _log_engine_error(self, phase: str, exc: Exception) -> None: @pytest.fixture def comp(tmp_path): settings = ServiceSettings( - manager_addr=f"ipc://{tmp_path}/t_cmd.ipc", engine_addr=f"ipc://{tmp_path}/t_engine.ipc", engine_autostart=True, log_level="DEBUG", + http_port=8001 ) c = MockComponent(settings=settings) + t = threading.Thread(target=c.run, daemon=True) t.start() - # Give it a moment to spin up - time.sleep(0.2) + + time.sleep(0.3) yield c - c.stop() - time.sleep(0.1) - assert c._stop_event.is_set() + + if c._running: + # Trigger graceful shutdown + try: + httpx.post("http://127.0.0.1:8000/admin/shutdown", timeout=1.0) + except Exception: + c.stop() # Fallback + + # WAIT for the thread to actually die before Pytest closes the pipes + t.join(timeout=2.0) def test_normal_and_error_paths(comp): @@ -61,8 +70,12 @@ def test_normal_and_error_paths(comp): with pytest.raises(pynng.Timeout): sock.recv() - # Stop via manager - with pynng.Req0(dial=comp.settings.manager_addr) as req: - req.send(b"stop") - assert req.recv() == b"engine stopped" - assert comp._stop_event.is_set() + # Stop via HTTP Admin API --- + admin_url = f"http://{comp.settings.http_host}:{comp.settings.http_port}" + + # Send stop command to the engine + response = httpx.post(f"{admin_url}/admin/stop") + assert response.status_code == 200 + + time.sleep(0.1) + assert comp._running is False From 15dca7ef3b1c1436ec1473884bb432607d7a81db Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Wed, 4 Feb 2026 13:49:15 +0100 Subject: [PATCH 60/78] update smoe service test --- tests/test_smoke_service.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/test_smoke_service.py b/tests/test_smoke_service.py index 24ee0c0..e7da13b 100644 --- a/tests/test_smoke_service.py +++ b/tests/test_smoke_service.py @@ -1,12 +1,21 @@ import time import threading import pynng +import socket import pytest from service.core import Service from service.settings import ServiceSettings +@pytest.fixture +def free_port(): + """Find a free port on the system.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(('', 0)) + return s.getsockname()[1] + + class SmokeTestService(Service): """Simple service for smoke testing.""" component_type = "smoke_test" @@ -17,12 +26,12 @@ def process(self, raw_message: bytes) -> bytes | None: @pytest.fixture -def smoke_service(tmp_path): +def smoke_service(tmp_path, free_port): """Fixture to create a smoke test service.""" settings = ServiceSettings( - manager_addr=f"ipc://{tmp_path}/smoke_cmd.ipc", engine_addr=f"ipc://{tmp_path}/smoke_engine.ipc", engine_autostart=True, + http_port=free_port, log_level="ERROR", ) service = SmokeTestService(settings=settings) @@ -77,12 +86,8 @@ def test_engine_processing(smoke_service): def test_service_stop_command(smoke_service): """Test that the stop command works correctly.""" - with pynng.Req0(dial=smoke_service.settings.manager_addr) as req: - # Test stop - req.send(b"stop") - response = req.recv().decode() - assert "stopped" in response - assert smoke_service._stop_event.is_set() + smoke_service.stop() + assert smoke_service._stop_event.is_set() def test_service_id_stability(): @@ -91,14 +96,12 @@ def test_service_id_stability(): settings1 = ServiceSettings( component_name="test-service", component_type="test", - manager_addr="ipc:///tmp/test1.ipc", engine_addr="ipc:///tmp/test2.ipc", ) settings2 = ServiceSettings( component_name="test-service", component_type="test", - manager_addr="ipc:///tmp/test1.ipc", engine_addr="ipc:///tmp/test2.ipc", ) @@ -108,7 +111,6 @@ def test_service_id_stability(): settings3 = ServiceSettings( component_name="test-service-different", component_type="test", - manager_addr="ipc:///tmp/test1.ipc", engine_addr="ipc:///tmp/test2.ipc", ) From 7afa5a75e9666920991aad417d4a7ee69ea9794b Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Wed, 4 Feb 2026 15:10:57 +0100 Subject: [PATCH 61/78] update reconfigure tests --- tests/test_reconfigure_params.py | 430 ++++++++++--------------------- 1 file changed, 132 insertions(+), 298 deletions(-) diff --git a/tests/test_reconfigure_params.py b/tests/test_reconfigure_params.py index cb915f7..cf4e955 100644 --- a/tests/test_reconfigure_params.py +++ b/tests/test_reconfigure_params.py @@ -1,28 +1,34 @@ +from typing import Dict, Any import pytest -import tempfile import yaml -import json -import os -from pathlib import Path +import socket +import threading from unittest.mock import Mock, patch +from pydantic import BaseModel, Field -# from service.cli import reconfigure_service from service.core import Service from service.settings import ServiceSettings -from pydantic import Field - +from service.features.config_manager import ConfigManager from detectmatelibrary.common.core import CoreConfig -# CoreConfig from the library has start_id: int = 10 as default -# Test configs schema -class MockConfig(CoreConfig): - threshold: float = Field(default=0.5, ge=0.0, le=1.0) - enabled: bool = Field(default=True) +class MockConfig(BaseModel): # Your component's specific params + threshold: float = Field(default=0.5) + + +class MockDetectorEntry(BaseModel): + method_type: str = "random_detector" + params: Dict[str, Any] + + +class ServiceConfigWrapper(CoreConfig): + """Matches the actual YAML structure.""" + detectors: Dict[str, MockDetectorEntry] -# Test service that uses our test configs class MockService(Service): + """Service implementation that uses MockConfig.""" + def get_config_schema(self): return MockConfig @@ -31,325 +37,153 @@ def process(self, raw_message: bytes) -> bytes | None: @pytest.fixture -def temp_config_file(): - """Create a temporary config file for testing.""" - with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: - config_data = { - 'config_file': str(Path(f.name).with_suffix('.params.yaml')), - 'engine_autostart': False - } - yaml.dump(config_data, f) - yield f.name - # Clean up - if os.path.exists(f.name): - os.unlink(f.name) +def free_port(): + """Find a free port on the system.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(('', 0)) + return s.getsockname()[1] @pytest.fixture -def temp_params_file(): - """Create a temporary configs file for testing.""" - with tempfile.NamedTemporaryFile(mode='w', suffix='.params.yaml', delete=False) as f: - params_data = { - 'threshold': 0.7, - 'enabled': False +def temp_params_file(tmp_path): + """Create a temporary YAML file with nested structure.""" + params_path = tmp_path / "test_params.yaml" + initial_data = { + "detectors": { + "RandomDetector": { + "method_type": "random_detector", + "auto_config": False, + "params": { + "log_variables": [ + { + "id": "test", + "event": 1, + "template": "dummy_template", + "variables": [ + { + "pos": 0, + "name": "var1", + "params": {"threshold": 0.7} + } + ], + "header_variables": [] + } + ] + } + } } - yaml.dump(params_data, f) - yield f.name - # Clean up - if os.path.exists(f.name): - os.unlink(f.name) + } + params_path.write_text(yaml.dump(initial_data)) + return params_path @pytest.fixture -def test_service_mocked(temp_params_file): - """Create a mocked test service instance for unit testing.""" - from service.settings import ServiceSettings +def test_service_mocked(temp_params_file, free_port): + """Create a mocked service instance. - # Create settings with the temp configs file + We bypass __init__ to avoid starting real network sockets, but + manually inject the pieces the Service needs. + """ settings = ServiceSettings( - manager_addr="inproc://test_manager", + http_port=free_port, engine_addr="inproc://test_engine", - config_file=Path(temp_params_file), + config_file=temp_params_file, engine_autostart=False ) - # Mock the Manager and Engine initialization to avoid socket issues with patch.object(Service, '__init__', lambda self, settings: None): service = MockService(settings) service.settings = settings service.component_id = "test_id" - service._stop_event = Mock() + service.component_type = "core" service.log = Mock() - # Initialize config manager - from service.features.config_manager import ConfigManager + # Necessary for shutdown() and context manager cleanup + service._service_exit_event = threading.Event() + service.web_server = Mock() + + # Initialize real ConfigManager so we can test logic service.config_manager = ConfigManager( - temp_params_file, + str(temp_params_file), MockConfig, service.log ) - yield service -def test_reconfigure_command_valid(temp_config_file, temp_params_file): - """Test reconfigure command with valid configs.""" - # Update the config file to point to the params file - with open(temp_config_file, 'r') as f: - config_data = yaml.safe_load(f) - config_data['config_file'] = temp_params_file - with open(temp_config_file, 'w') as f: - yaml.dump(config_data, f) - - settings = ServiceSettings.from_yaml(temp_config_file) - - # Use context manager to ensure proper cleanup - with MockService(settings=settings) as service: - # Test valid reconfigure - new_configs = {'threshold': 0.8, 'enabled': True} - cmd = f'reconfigure {json.dumps(new_configs)}' - result = service._handle_cmd(cmd) - - assert result == "reconfigure: ok" - assert service.config_manager.get().threshold == 0.8 - assert service.config_manager.get().enabled is True - - -def test_reconfigure_command_invalid_json(temp_config_file, temp_params_file): - """Test reconfigure command with invalid JSON.""" - # Update the config file to point to the params file - with open(temp_config_file, 'r') as f: - config_data = yaml.safe_load(f) - config_data['config_file'] = temp_params_file - with open(temp_config_file, 'w') as f: - yaml.dump(config_data, f) - - settings = ServiceSettings.from_yaml(temp_config_file) - - with MockService(settings=settings) as service: - # Test invalid JSON - result = service._handle_cmd('reconfigure invalid{json') - assert "invalid JSON" in result - - -def test_reconfigure_command_validation_error(temp_config_file, temp_params_file): - """Test reconfigure command with invalid config values.""" - # Update the config file to point to the params file - with open(temp_config_file, 'r') as f: - config_data = yaml.safe_load(f) - config_data['config_file'] = temp_params_file - with open(temp_config_file, 'w') as f: - yaml.dump(config_data, f) - - settings = ServiceSettings.from_yaml(temp_config_file) - - with MockService(settings=settings) as service: - # Test invalid config value (threshold out of range) - invalid_params = {'threshold': 2.0, 'enabled': True} - cmd = f'reconfigure {json.dumps(invalid_params)}' - result = service._handle_cmd(cmd) - - assert "error" in result.lower() - # Should preserve original values - assert service.config_manager.get()['threshold'] == 0.7 - - -def test_reconfigure_command_no_config_manager(): - """Test reconfigure command when no config manager is configured.""" - settings = ServiceSettings(engine_autostart=False) # No config file - - with MockService(settings=settings) as service: - result = service._handle_cmd('reconfigure {"threshold": 0.8}') - assert "no config manager" in result - - -def test_reconfigure_command_no_payload(temp_config_file, temp_params_file): - """Test reconfigure command with no payload.""" - # Update the config file to point to the params file - with open(temp_config_file, 'r') as f: - config_data = yaml.safe_load(f) - config_data['config_file'] = temp_params_file - with open(temp_config_file, 'w') as f: - yaml.dump(config_data, f) - - settings = ServiceSettings.from_yaml(temp_config_file) - - with MockService(settings=settings) as service: - result = service._handle_cmd('reconfigure') - assert "no payload" in result - - -# Tests with the persist functionality -def test_reconfigure_without_persist(test_service_mocked, temp_params_file): - """Test reconfigure without persist flag - should update in memory but not save to file.""" - # Read original file content - with open(temp_params_file, 'r') as f: - original_content = yaml.safe_load(f) - - # New configs to test - new_configs = { - 'threshold': 0.8, - 'enabled': True +def test_reconfigure_deep_structure(test_service_mocked): + nested_config = { + "detectors": { + "RandomDetector": { + "params": { + "log_variables": [{"variables": [{"params": {"threshold": 0.8}}]}] + } + } + } } - - # Call reconfigure without persist - cmd = f'reconfigure {json.dumps(new_configs)}' - result = test_service_mocked.reconfigure(cmd) - - # Should succeed + result = test_service_mocked.reconfigure(config_data=nested_config) + # assert here if threshold got reconfigured in memory + current_config = test_service_mocked.config_manager.get() + updated_threshold = ( + current_config.detectors + ["RandomDetector"] + ["params"] + ["log_variables"][0] + ["variables"][0] + ["params"] + ["threshold"]) + assert updated_threshold == 0.8 assert result == "reconfigure: ok" - # configs should be updated in memory - current_params = test_service_mocked.config_manager.get() - assert current_params.threshold == 0.8 - assert current_params.enabled is True - - # File should not be changed (no persist) - with open(temp_params_file, 'r') as f: - file_content = yaml.safe_load(f) - assert file_content == original_content - def test_reconfigure_with_persist(test_service_mocked, temp_params_file): - """Test reconfigure with persist flag - should update both in memory and in file.""" - # New configs to test - new_configs = { - 'threshold': 0.8, - 'enabled': True, - 'start_id': 5 + """Test that persist=True actually writes the new values to the YAML + file.""" + nested_config = { + "detectors": { + "RandomDetector": { + "params": { + "log_variables": [{"variables": [{"params": {"threshold": 0.1}}]}] + } + } + } } - # Call reconfigure with persist - cmd = f'reconfigure persist {json.dumps(new_configs)}' - result = test_service_mocked.reconfigure(cmd) + # Act + result = test_service_mocked.reconfigure(config_data=nested_config, persist=True) - # Should succeed + # Assert assert result == "reconfigure: ok" - # configs should be updated in memory - current_params = test_service_mocked.config_manager.get() - assert current_params.threshold == 0.8 - assert current_params.enabled is True - assert current_params.start_id == 5 - - # File should be updated (with persist) + # Verify file content with open(temp_params_file, 'r') as f: - file_content = yaml.safe_load(f) - for key, val in new_configs.items(): - assert file_content[key] == val - -# DEACTIVATED BECAUSE OF reconfigure_service -# def test_cli_reconfigure_with_persist(temp_params_file): -# """Test CLI reconfigure command with persist flag.""" -# # Create a temporary settings file -# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: -# yaml.dump({ -# 'manager_addr': 'inproc://test_manager', -# 'config_file': temp_params_file -# }, f) -# settings_path = f.name -# -# # Create a temporary new configs file -# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: -# new_configs = { -# 'threshold': 0.9, -# 'enabled': False -# } -# yaml.dump(new_configs, f) -# new_configs_path = f.name -# -# try: -# # Mock the pynng request to avoid actual socket communication -# with patch('pynng.Req0') as mock_req: -# mock_socket = Mock() -# mock_req.return_value.__enter__.return_value = mock_socket -# mock_socket.recv.return_value = b"reconfigure: ok" -# -# # Call reconfigure with persist -# reconfigure_service(Path(settings_path), Path(new_configs_path), persist=True) -# -# # Verify the request was sent with "persist" flag -# call_args = mock_socket.send.call_args[0][0] -# assert b"persist" in call_args -# assert b'"threshold": 0.9' in call_args -# -# finally: -# # Clean up -# for path in [settings_path, new_configs_path]: -# if os.path.exists(path): -# os.unlink(path) - - -# DEACTIVATED BECAUSE OF reconfigure_service -# def test_cli_reconfigure_without_persist(temp_params_file): -# """Test CLI reconfigure command without persist flag.""" -# # Create a temporary settings file -# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: -# yaml.dump({ -# 'manager_addr': 'inproc://test_manager', -# 'config_file': temp_params_file -# }, f) -# settings_path = f.name -# -# # Create a temporary new configs file -# with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: -# new_configs = { -# 'threshold': 0.9, -# 'enabled': False -# } -# yaml.dump(new_configs, f) -# new_configs_path = f.name -# -# try: -# # Mock the pynng request to avoid actual socket communication -# with patch('pynng.Req0') as mock_req: -# mock_socket = Mock() -# mock_req.return_value.__enter__.return_value = mock_socket -# mock_socket.recv.return_value = b"reconfigure: ok" -# -# # Call reconfigure without persist -# reconfigure_service(Path(settings_path), Path(new_configs_path), persist=False) -# -# # Verify the request was sent without "persist" flag -# call_args = mock_socket.send.call_args[0][0] -# assert b"persist" not in call_args -# assert b'"threshold": 0.9' in call_args -# -# finally: -# # Clean up -# for path in [settings_path, new_configs_path]: -# if os.path.exists(path): -# os.unlink(path) - - -# Integration test for persist functionality -def test_reconfigure_command_with_persist_integration(temp_config_file, temp_params_file): - """Integration test for reconfigure command with persist flag.""" - # Update the config file to point to the params file - with open(temp_config_file, 'r') as f: - config_data = yaml.safe_load(f) - config_data['config_file'] = temp_params_file - with open(temp_config_file, 'w') as f: - yaml.dump(config_data, f) - - settings = ServiceSettings.from_yaml(temp_config_file) - - # Use context manager to ensure proper cleanup - with MockService(settings=settings) as service: - # Test reconfigure with persist - new_configs = {'threshold': 0.8, 'enabled': True, 'start_id': 5} - cmd = f'reconfigure persist {json.dumps(new_configs)}' - result = service._handle_cmd(cmd) - - assert result == "reconfigure: ok" - - # configs should be updated in memory - assert service.config_manager.get().threshold == 0.8 - assert service.config_manager.get().enabled is True - assert service.config_manager.get().start_id == 5 - - # File should be updated (with persist) - with open(temp_params_file, 'r') as f: - file_content = yaml.safe_load(f) - for key, val in new_configs.items(): - assert file_content[key] == val + disk_data = yaml.safe_load(f) + threshold_on_disk = ( + disk_data['detectors'] + ['RandomDetector'] + ['params'] + ['log_variables'][0] + ['variables'][0] + ['params'] + ['threshold']) + assert threshold_on_disk == 0.1 + + +def test_reconfigure_no_config_manager(): + """Test error handling when the service has no config_file/manager + initialized.""" + settings = ServiceSettings(config_file=None) + + # We use a real init here but avoid the sockets by just testing the method + with patch.object(Service, '__init__', lambda self, settings: None): + service = MockService(settings) + service.config_manager = None + + result = service.reconfigure(config_data={'a': 1}) + assert "no config manager" in result + + +def test_reconfigure_empty_payload(test_service_mocked): + """Test that an empty dictionary is handled as a no-op.""" + result = test_service_mocked.reconfigure(config_data={}) + assert "no-op" in result From 1e0f35ac28ae1383f8298dc02adf794e9f707158 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Wed, 4 Feb 2026 15:30:26 +0100 Subject: [PATCH 62/78] Update pull_request_template.md --- .github/pull_request_template.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a503370..53dec30 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,7 +12,8 @@ # Checklist -- [ ] I have successfully run overcommit locally -- [ ] I have added tests to cover my changes -- [ ] I have linked the issue-id to the task-description -- [ ] I have performed a self-review of my own code +- [ ] This Pull-Request goes to the **development** branch. +- [ ] I have successfully run prek locally. +- [ ] I have added tests to cover my changes. +- [ ] I have linked the issue-id to the task-description. +- [ ] I have performed a self-review of my own code. From 908eb17ebbd46aff4c23a0fae063b2e4f8cee331 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 5 Feb 2026 12:33:12 +0100 Subject: [PATCH 63/78] join thread before closing sockets in engine.stop --- src/service/features/engine.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/service/features/engine.py b/src/service/features/engine.py index 0f520ce..3f38ca9 100644 --- a/src/service/features/engine.py +++ b/src/service/features/engine.py @@ -129,6 +129,7 @@ def _setup_output_sockets(self) -> None: def start(self) -> str: if not self._running: self._running = True + self._stop_event.clear() # RECREATE THE THREAD if it's dead or doesn't exist if not self._thread.is_alive(): self._thread = threading.Thread( @@ -251,6 +252,12 @@ def stop(self) -> None | str: self._running = False self._stop_event.set() + # WAIT for engine loop to exit recv() + self._thread.join(timeout=2.0) + + if self._thread.is_alive(): + raise EngineException("Engine thread failed to stop cleanly") + # Close input socket try: self._pair_sock.close() @@ -265,12 +272,7 @@ def stop(self) -> None | str: except pynng.NNGException as e: self.log.error(f"Failed to close output socket {i}: {e}") - try: - self._thread.join(timeout=1.0) - if self._thread.is_alive(): - raise EngineException("Engine thread failed to stop within timeout") - elif self.log: - self.log.debug("Engine stopped successfully") - except Exception as e: - raise EngineException(f"Failed to join engine thread: {e}") from e + if self.log: + self.log.debug("Engine stopped successfully") + return None From 5894cce83f65e5c5d2ce894c53ff75eb4db9f2a4 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Thu, 5 Feb 2026 14:18:47 +0100 Subject: [PATCH 64/78] added metadata.py --- pyproject.toml | 6 +++++- src/service/metadata.py | 19 +++++++++++++++++++ uv.lock | 1 - 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/service/metadata.py diff --git a/pyproject.toml b/pyproject.toml index 3a7f9ce..60dac3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,11 @@ [project] name = "DetectMateService" -version = "0.1.0" description = "A modular framework for building log processing and anomaly detection services." readme = "README.md" requires-python = ">=3.12" +dynamic = ["version"] + dependencies = [ "detectmatelibrary @ git+https://github.com/ait-detectmate/DetectMateLibrary.git", "pathlib>=1.0.1", @@ -40,3 +41,6 @@ build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] namespaces = true where = ["src"] + +[tool.setuptools.dynamic] +version = {attr = "service.metadata.__version__"} diff --git a/src/service/metadata.py b/src/service/metadata.py new file mode 100644 index 0000000..b32350b --- /dev/null +++ b/src/service/metadata.py @@ -0,0 +1,19 @@ +__authors__ = ['Thorina Boenke', 'Anna Erdi', 'Viktor Beck', 'André García Gómez', 'Ernst Leierzopf', 'Wolfgang Hotwagner'] +__contact__ = 'aecid@ait.ac.at' +__copyright__ = 'Copyright 2026, AIT Austrian Institute of Technology GmbH' +__date__ = '2026/02/05' +__deprecated__ = False +__website__ = 'https://aecid.ait.ac.at' +__license__ = 'EUPL-1.2' +__status__ = 'Development' +__version__ = '0.1.0' +__all__ = [ + '__authors__', + '__contact__', + '__copyright__', + '__date__', + '__deprecated__', + '__website__', + '__license__', + '__status__', + '__version__'] diff --git a/uv.lock b/uv.lock index ed0b65b..f986be1 100644 --- a/uv.lock +++ b/uv.lock @@ -242,7 +242,6 @@ dependencies = [ [[package]] name = "detectmateservice" -version = "0.1.0" source = { editable = "." } dependencies = [ { name = "detectmatelibrary" }, From 65f57ecc26b1401a3466d9f8272214616d480a90 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Thu, 5 Feb 2026 14:22:23 +0100 Subject: [PATCH 65/78] style fixes --- src/service/metadata.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/service/metadata.py b/src/service/metadata.py index b32350b..27bf95f 100644 --- a/src/service/metadata.py +++ b/src/service/metadata.py @@ -1,4 +1,5 @@ -__authors__ = ['Thorina Boenke', 'Anna Erdi', 'Viktor Beck', 'André García Gómez', 'Ernst Leierzopf', 'Wolfgang Hotwagner'] +__authors__ = ['Thorina Boenke', 'Anna Erdi', 'Viktor Beck', + 'André García Gómez', 'Ernst Leierzopf', 'Wolfgang Hotwagner'] __contact__ = 'aecid@ait.ac.at' __copyright__ = 'Copyright 2026, AIT Austrian Institute of Technology GmbH' __date__ = '2026/02/05' From d2050a72724fc223c7a0588ad0d4436400ffbd05 Mon Sep 17 00:00:00 2001 From: whotwagner Date: Thu, 5 Feb 2026 14:32:04 +0100 Subject: [PATCH 66/78] Potential fix for pull request finding 'Statement has no effect' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> --- src/library/processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library/processor.py b/src/library/processor.py index 2344bb0..3dec72c 100644 --- a/src/library/processor.py +++ b/src/library/processor.py @@ -10,4 +10,4 @@ def __call__(self, _raw_message: bytes) -> bytes | None: class ProcessorException(Exception): """Custom exception for processor-related errors.""" - ... + pass From c2462fb800b1e50de0949482863e5650d814491b Mon Sep 17 00:00:00 2001 From: whotwagner Date: Thu, 5 Feb 2026 14:34:27 +0100 Subject: [PATCH 67/78] Style fix --- src/library/processor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library/processor.py b/src/library/processor.py index 3dec72c..066331f 100644 --- a/src/library/processor.py +++ b/src/library/processor.py @@ -10,4 +10,3 @@ def __call__(self, _raw_message: bytes) -> bytes | None: class ProcessorException(Exception): """Custom exception for processor-related errors.""" - pass From c76629be3617d0133ebc234e5ec893607d31148d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:33 +0000 Subject: [PATCH 68/78] Bump pytest from 8.4.1 to 9.0.2 Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.4.1 to 9.0.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.4.1...9.0.2) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- uv.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uv.lock b/uv.lock index f986be1..323cb6f 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -933,7 +933,7 @@ wheels = [ [[package]] name = "pytest" -version = "8.4.1" +version = "9.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -942,9 +942,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] [[package]] From 062684f4e2da3ebaaef74a7a46e83d423255eb4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:33 +0000 Subject: [PATCH 69/78] Bump pytest-cov from 6.2.1 to 7.0.0 Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 6.2.1 to 7.0.0. - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v6.2.1...v7.0.0) --- updated-dependencies: - dependency-name: pytest-cov dependency-version: 7.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- uv.lock | 138 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 74 insertions(+), 64 deletions(-) diff --git a/uv.lock b/uv.lock index f986be1..a245b98 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -164,66 +164,76 @@ wheels = [ [[package]] name = "coverage" -version = "7.10.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/2c/253cc41cd0f40b84c1c34c5363e0407d73d4a1cae005fed6db3b823175bd/coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619", size = 822936, upload-time = "2025-08-10T21:27:39.968Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/62/13c0b66e966c43d7aa64dadc8cd2afa1f5a2bf9bb863bdabc21fb94e8b63/coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42", size = 216262, upload-time = "2025-08-10T21:25:55.367Z" }, - { url = "https://files.pythonhosted.org/packages/b5/f0/59fdf79be7ac2f0206fc739032f482cfd3f66b18f5248108ff192741beae/coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294", size = 216496, upload-time = "2025-08-10T21:25:56.759Z" }, - { url = "https://files.pythonhosted.org/packages/34/b1/bc83788ba31bde6a0c02eb96bbc14b2d1eb083ee073beda18753fa2c4c66/coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7", size = 247989, upload-time = "2025-08-10T21:25:58.067Z" }, - { url = "https://files.pythonhosted.org/packages/0c/29/f8bdf88357956c844bd872e87cb16748a37234f7f48c721dc7e981145eb7/coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437", size = 250738, upload-time = "2025-08-10T21:25:59.406Z" }, - { url = "https://files.pythonhosted.org/packages/ae/df/6396301d332b71e42bbe624670af9376f63f73a455cc24723656afa95796/coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587", size = 251868, upload-time = "2025-08-10T21:26:00.65Z" }, - { url = "https://files.pythonhosted.org/packages/91/21/d760b2df6139b6ef62c9cc03afb9bcdf7d6e36ed4d078baacffa618b4c1c/coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea", size = 249790, upload-time = "2025-08-10T21:26:02.009Z" }, - { url = "https://files.pythonhosted.org/packages/69/91/5dcaa134568202397fa4023d7066d4318dc852b53b428052cd914faa05e1/coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613", size = 247907, upload-time = "2025-08-10T21:26:03.757Z" }, - { url = "https://files.pythonhosted.org/packages/38/ed/70c0e871cdfef75f27faceada461206c1cc2510c151e1ef8d60a6fedda39/coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb", size = 249344, upload-time = "2025-08-10T21:26:05.11Z" }, - { url = "https://files.pythonhosted.org/packages/5f/55/c8a273ed503cedc07f8a00dcd843daf28e849f0972e4c6be4c027f418ad6/coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a", size = 218693, upload-time = "2025-08-10T21:26:06.534Z" }, - { url = "https://files.pythonhosted.org/packages/94/58/dd3cfb2473b85be0b6eb8c5b6d80b6fc3f8f23611e69ef745cef8cf8bad5/coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5", size = 219501, upload-time = "2025-08-10T21:26:08.195Z" }, - { url = "https://files.pythonhosted.org/packages/56/af/7cbcbf23d46de6f24246e3f76b30df099d05636b30c53c158a196f7da3ad/coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571", size = 218135, upload-time = "2025-08-10T21:26:09.584Z" }, - { url = "https://files.pythonhosted.org/packages/0a/ff/239e4de9cc149c80e9cc359fab60592365b8c4cbfcad58b8a939d18c6898/coverage-7.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b99e87304ffe0eb97c5308447328a584258951853807afdc58b16143a530518a", size = 216298, upload-time = "2025-08-10T21:26:10.973Z" }, - { url = "https://files.pythonhosted.org/packages/56/da/28717da68f8ba68f14b9f558aaa8f3e39ada8b9a1ae4f4977c8f98b286d5/coverage-7.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4af09c7574d09afbc1ea7da9dcea23665c01f3bc1b1feb061dac135f98ffc53a", size = 216546, upload-time = "2025-08-10T21:26:12.616Z" }, - { url = "https://files.pythonhosted.org/packages/de/bb/e1ade16b9e3f2d6c323faeb6bee8e6c23f3a72760a5d9af102ef56a656cb/coverage-7.10.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:488e9b50dc5d2aa9521053cfa706209e5acf5289e81edc28291a24f4e4488f46", size = 247538, upload-time = "2025-08-10T21:26:14.455Z" }, - { url = "https://files.pythonhosted.org/packages/ea/2f/6ae1db51dc34db499bfe340e89f79a63bd115fc32513a7bacdf17d33cd86/coverage-7.10.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:913ceddb4289cbba3a310704a424e3fb7aac2bc0c3a23ea473193cb290cf17d4", size = 250141, upload-time = "2025-08-10T21:26:15.787Z" }, - { url = "https://files.pythonhosted.org/packages/4f/ed/33efd8819895b10c66348bf26f011dd621e804866c996ea6893d682218df/coverage-7.10.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b1f91cbc78c7112ab84ed2a8defbccd90f888fcae40a97ddd6466b0bec6ae8a", size = 251415, upload-time = "2025-08-10T21:26:17.535Z" }, - { url = "https://files.pythonhosted.org/packages/26/04/cb83826f313d07dc743359c9914d9bc460e0798da9a0e38b4f4fabc207ed/coverage-7.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0bac054d45af7cd938834b43a9878b36ea92781bcb009eab040a5b09e9927e3", size = 249575, upload-time = "2025-08-10T21:26:18.921Z" }, - { url = "https://files.pythonhosted.org/packages/2d/fd/ae963c7a8e9581c20fa4355ab8940ca272554d8102e872dbb932a644e410/coverage-7.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe72cbdd12d9e0f4aca873fa6d755e103888a7f9085e4a62d282d9d5b9f7928c", size = 247466, upload-time = "2025-08-10T21:26:20.263Z" }, - { url = "https://files.pythonhosted.org/packages/99/e8/b68d1487c6af370b8d5ef223c6d7e250d952c3acfbfcdbf1a773aa0da9d2/coverage-7.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c1e2e927ab3eadd7c244023927d646e4c15c65bb2ac7ae3c3e9537c013700d21", size = 249084, upload-time = "2025-08-10T21:26:21.638Z" }, - { url = "https://files.pythonhosted.org/packages/66/4d/a0bcb561645c2c1e21758d8200443669d6560d2a2fb03955291110212ec4/coverage-7.10.3-cp313-cp313-win32.whl", hash = "sha256:24d0c13de473b04920ddd6e5da3c08831b1170b8f3b17461d7429b61cad59ae0", size = 218735, upload-time = "2025-08-10T21:26:23.009Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c3/78b4adddbc0feb3b223f62761e5f9b4c5a758037aaf76e0a5845e9e35e48/coverage-7.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:3564aae76bce4b96e2345cf53b4c87e938c4985424a9be6a66ee902626edec4c", size = 219531, upload-time = "2025-08-10T21:26:24.474Z" }, - { url = "https://files.pythonhosted.org/packages/70/1b/1229c0b2a527fa5390db58d164aa896d513a1fbb85a1b6b6676846f00552/coverage-7.10.3-cp313-cp313-win_arm64.whl", hash = "sha256:f35580f19f297455f44afcd773c9c7a058e52eb6eb170aa31222e635f2e38b87", size = 218162, upload-time = "2025-08-10T21:26:25.847Z" }, - { url = "https://files.pythonhosted.org/packages/fc/26/1c1f450e15a3bf3eaecf053ff64538a2612a23f05b21d79ce03be9ff5903/coverage-7.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07009152f497a0464ffdf2634586787aea0e69ddd023eafb23fc38267db94b84", size = 217003, upload-time = "2025-08-10T21:26:27.231Z" }, - { url = "https://files.pythonhosted.org/packages/29/96/4b40036181d8c2948454b458750960956a3c4785f26a3c29418bbbee1666/coverage-7.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd2ba5f0c7e7e8cc418be2f0c14c4d9e3f08b8fb8e4c0f83c2fe87d03eb655e", size = 217238, upload-time = "2025-08-10T21:26:28.83Z" }, - { url = "https://files.pythonhosted.org/packages/62/23/8dfc52e95da20957293fb94d97397a100e63095ec1e0ef5c09dd8c6f591a/coverage-7.10.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1ae22b97003c74186e034a93e4f946c75fad8c0ce8d92fbbc168b5e15ee2841f", size = 258561, upload-time = "2025-08-10T21:26:30.475Z" }, - { url = "https://files.pythonhosted.org/packages/59/95/00e7fcbeda3f632232f4c07dde226afe3511a7781a000aa67798feadc535/coverage-7.10.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb329f1046888a36b1dc35504d3029e1dd5afe2196d94315d18c45ee380f67d5", size = 260735, upload-time = "2025-08-10T21:26:32.333Z" }, - { url = "https://files.pythonhosted.org/packages/9e/4c/f4666cbc4571804ba2a65b078ff0de600b0b577dc245389e0bc9b69ae7ca/coverage-7.10.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce01048199a91f07f96ca3074b0c14021f4fe7ffd29a3e6a188ac60a5c3a4af8", size = 262960, upload-time = "2025-08-10T21:26:33.701Z" }, - { url = "https://files.pythonhosted.org/packages/c1/a5/8a9e8a7b12a290ed98b60f73d1d3e5e9ced75a4c94a0d1a671ce3ddfff2a/coverage-7.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08b989a06eb9dfacf96d42b7fb4c9a22bafa370d245dc22fa839f2168c6f9fa1", size = 260515, upload-time = "2025-08-10T21:26:35.16Z" }, - { url = "https://files.pythonhosted.org/packages/86/11/bb59f7f33b2cac0c5b17db0d9d0abba9c90d9eda51a6e727b43bd5fce4ae/coverage-7.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:669fe0d4e69c575c52148511029b722ba8d26e8a3129840c2ce0522e1452b256", size = 258278, upload-time = "2025-08-10T21:26:36.539Z" }, - { url = "https://files.pythonhosted.org/packages/cc/22/3646f8903743c07b3e53fded0700fed06c580a980482f04bf9536657ac17/coverage-7.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3262d19092771c83f3413831d9904b1ccc5f98da5de4ffa4ad67f5b20c7aaf7b", size = 259408, upload-time = "2025-08-10T21:26:37.954Z" }, - { url = "https://files.pythonhosted.org/packages/d2/5c/6375e9d905da22ddea41cd85c30994b8b6f6c02e44e4c5744b76d16b026f/coverage-7.10.3-cp313-cp313t-win32.whl", hash = "sha256:cc0ee4b2ccd42cab7ee6be46d8a67d230cb33a0a7cd47a58b587a7063b6c6b0e", size = 219396, upload-time = "2025-08-10T21:26:39.426Z" }, - { url = "https://files.pythonhosted.org/packages/33/3b/7da37fd14412b8c8b6e73c3e7458fef6b1b05a37f990a9776f88e7740c89/coverage-7.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:03db599f213341e2960430984e04cf35fb179724e052a3ee627a068653cf4a7c", size = 220458, upload-time = "2025-08-10T21:26:40.905Z" }, - { url = "https://files.pythonhosted.org/packages/28/cc/59a9a70f17edab513c844ee7a5c63cf1057041a84cc725b46a51c6f8301b/coverage-7.10.3-cp313-cp313t-win_arm64.whl", hash = "sha256:46eae7893ba65f53c71284585a262f083ef71594f05ec5c85baf79c402369098", size = 218722, upload-time = "2025-08-10T21:26:42.362Z" }, - { url = "https://files.pythonhosted.org/packages/2d/84/bb773b51a06edbf1231b47dc810a23851f2796e913b335a0fa364773b842/coverage-7.10.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bce8b8180912914032785850d8f3aacb25ec1810f5f54afc4a8b114e7a9b55de", size = 216280, upload-time = "2025-08-10T21:26:44.132Z" }, - { url = "https://files.pythonhosted.org/packages/92/a8/4d8ca9c111d09865f18d56facff64d5fa076a5593c290bd1cfc5dceb8dba/coverage-7.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07790b4b37d56608536f7c1079bd1aa511567ac2966d33d5cec9cf520c50a7c8", size = 216557, upload-time = "2025-08-10T21:26:45.598Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b2/eb668bfc5060194bc5e1ccd6f664e8e045881cfee66c42a2aa6e6c5b26e8/coverage-7.10.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e79367ef2cd9166acedcbf136a458dfe9a4a2dd4d1ee95738fb2ee581c56f667", size = 247598, upload-time = "2025-08-10T21:26:47.081Z" }, - { url = "https://files.pythonhosted.org/packages/fd/b0/9faa4ac62c8822219dd83e5d0e73876398af17d7305968aed8d1606d1830/coverage-7.10.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:419d2a0f769f26cb1d05e9ccbc5eab4cb5d70231604d47150867c07822acbdf4", size = 250131, upload-time = "2025-08-10T21:26:48.65Z" }, - { url = "https://files.pythonhosted.org/packages/4e/90/203537e310844d4bf1bdcfab89c1e05c25025c06d8489b9e6f937ad1a9e2/coverage-7.10.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee221cf244757cdc2ac882e3062ab414b8464ad9c884c21e878517ea64b3fa26", size = 251485, upload-time = "2025-08-10T21:26:50.368Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b2/9d894b26bc53c70a1fe503d62240ce6564256d6d35600bdb86b80e516e7d/coverage-7.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c2079d8cdd6f7373d628e14b3357f24d1db02c9dc22e6a007418ca7a2be0435a", size = 249488, upload-time = "2025-08-10T21:26:52.045Z" }, - { url = "https://files.pythonhosted.org/packages/b4/28/af167dbac5281ba6c55c933a0ca6675d68347d5aee39cacc14d44150b922/coverage-7.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bd8df1f83c0703fa3ca781b02d36f9ec67ad9cb725b18d486405924f5e4270bd", size = 247419, upload-time = "2025-08-10T21:26:53.533Z" }, - { url = "https://files.pythonhosted.org/packages/f4/1c/9a4ddc9f0dcb150d4cd619e1c4bb39bcf694c6129220bdd1e5895d694dda/coverage-7.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b4e25e0fa335c8aa26e42a52053f3786a61cc7622b4d54ae2dad994aa754fec", size = 248917, upload-time = "2025-08-10T21:26:55.11Z" }, - { url = "https://files.pythonhosted.org/packages/92/27/c6a60c7cbe10dbcdcd7fc9ee89d531dc04ea4c073800279bb269954c5a9f/coverage-7.10.3-cp314-cp314-win32.whl", hash = "sha256:d7c3d02c2866deb217dce664c71787f4b25420ea3eaf87056f44fb364a3528f5", size = 218999, upload-time = "2025-08-10T21:26:56.637Z" }, - { url = "https://files.pythonhosted.org/packages/36/09/a94c1369964ab31273576615d55e7d14619a1c47a662ed3e2a2fe4dee7d4/coverage-7.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:9c8916d44d9e0fe6cdb2227dc6b0edd8bc6c8ef13438bbbf69af7482d9bb9833", size = 219801, upload-time = "2025-08-10T21:26:58.207Z" }, - { url = "https://files.pythonhosted.org/packages/23/59/f5cd2a80f401c01cf0f3add64a7b791b7d53fd6090a4e3e9ea52691cf3c4/coverage-7.10.3-cp314-cp314-win_arm64.whl", hash = "sha256:1007d6a2b3cf197c57105cc1ba390d9ff7f0bee215ced4dea530181e49c65ab4", size = 218381, upload-time = "2025-08-10T21:26:59.707Z" }, - { url = "https://files.pythonhosted.org/packages/73/3d/89d65baf1ea39e148ee989de6da601469ba93c1d905b17dfb0b83bd39c96/coverage-7.10.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ebc8791d346410d096818788877d675ca55c91db87d60e8f477bd41c6970ffc6", size = 217019, upload-time = "2025-08-10T21:27:01.242Z" }, - { url = "https://files.pythonhosted.org/packages/7d/7d/d9850230cd9c999ce3a1e600f85c2fff61a81c301334d7a1faa1a5ba19c8/coverage-7.10.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f4e4d8e75f6fd3c6940ebeed29e3d9d632e1f18f6fb65d33086d99d4d073241", size = 217237, upload-time = "2025-08-10T21:27:03.442Z" }, - { url = "https://files.pythonhosted.org/packages/36/51/b87002d417202ab27f4a1cd6bd34ee3b78f51b3ddbef51639099661da991/coverage-7.10.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:24581ed69f132b6225a31b0228ae4885731cddc966f8a33fe5987288bdbbbd5e", size = 258735, upload-time = "2025-08-10T21:27:05.124Z" }, - { url = "https://files.pythonhosted.org/packages/1c/02/1f8612bfcb46fc7ca64a353fff1cd4ed932bb6e0b4e0bb88b699c16794b8/coverage-7.10.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec151569ddfccbf71bac8c422dce15e176167385a00cd86e887f9a80035ce8a5", size = 260901, upload-time = "2025-08-10T21:27:06.68Z" }, - { url = "https://files.pythonhosted.org/packages/aa/3a/fe39e624ddcb2373908bd922756384bb70ac1c5009b0d1674eb326a3e428/coverage-7.10.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ae8e7c56290b908ee817200c0b65929b8050bc28530b131fe7c6dfee3e7d86b", size = 263157, upload-time = "2025-08-10T21:27:08.398Z" }, - { url = "https://files.pythonhosted.org/packages/5e/89/496b6d5a10fa0d0691a633bb2b2bcf4f38f0bdfcbde21ad9e32d1af328ed/coverage-7.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb742309766d7e48e9eb4dc34bc95a424707bc6140c0e7d9726e794f11b92a0", size = 260597, upload-time = "2025-08-10T21:27:10.237Z" }, - { url = "https://files.pythonhosted.org/packages/b6/a6/8b5bf6a9e8c6aaeb47d5fe9687014148efc05c3588110246d5fdeef9b492/coverage-7.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c65e2a5b32fbe1e499f1036efa6eb9cb4ea2bf6f7168d0e7a5852f3024f471b1", size = 258353, upload-time = "2025-08-10T21:27:11.773Z" }, - { url = "https://files.pythonhosted.org/packages/c3/6d/ad131be74f8afd28150a07565dfbdc86592fd61d97e2dc83383d9af219f0/coverage-7.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d48d2cb07d50f12f4f18d2bb75d9d19e3506c26d96fffabf56d22936e5ed8f7c", size = 259504, upload-time = "2025-08-10T21:27:13.254Z" }, - { url = "https://files.pythonhosted.org/packages/ec/30/fc9b5097092758cba3375a8cc4ff61774f8cd733bcfb6c9d21a60077a8d8/coverage-7.10.3-cp314-cp314t-win32.whl", hash = "sha256:dec0d9bc15ee305e09fe2cd1911d3f0371262d3cfdae05d79515d8cb712b4869", size = 219782, upload-time = "2025-08-10T21:27:14.736Z" }, - { url = "https://files.pythonhosted.org/packages/72/9b/27fbf79451b1fac15c4bda6ec6e9deae27cf7c0648c1305aa21a3454f5c4/coverage-7.10.3-cp314-cp314t-win_amd64.whl", hash = "sha256:424ea93a323aa0f7f01174308ea78bde885c3089ec1bef7143a6d93c3e24ef64", size = 220898, upload-time = "2025-08-10T21:27:16.297Z" }, - { url = "https://files.pythonhosted.org/packages/d1/cf/a32bbf92869cbf0b7c8b84325327bfc718ad4b6d2c63374fef3d58e39306/coverage-7.10.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f5983c132a62d93d71c9ef896a0b9bf6e6828d8d2ea32611f58684fba60bba35", size = 218922, upload-time = "2025-08-10T21:27:18.22Z" }, - { url = "https://files.pythonhosted.org/packages/84/19/e67f4ae24e232c7f713337f3f4f7c9c58afd0c02866fb07c7b9255a19ed7/coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1", size = 207921, upload-time = "2025-08-10T21:27:38.254Z" }, +version = "7.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/43/3e4ac666cc35f231fa70c94e9f38459299de1a152813f9d2f60fc5f3ecaf/coverage-7.13.3.tar.gz", hash = "sha256:f7f6182d3dfb8802c1747eacbfe611b669455b69b7c037484bb1efbbb56711ac", size = 826832, upload-time = "2026-02-03T14:02:30.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/44/330f8e83b143f6668778ed61d17ece9dc48459e9e74669177de02f45fec5/coverage-7.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ed48b4170caa2c4420e0cd27dc977caaffc7eecc317355751df8373dddcef595", size = 219441, upload-time = "2026-02-03T14:00:22.585Z" }, + { url = "https://files.pythonhosted.org/packages/08/e7/29db05693562c2e65bdf6910c0af2fd6f9325b8f43caf7a258413f369e30/coverage-7.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8f2adf4bcffbbec41f366f2e6dffb9d24e8172d16e91da5799c9b7ed6b5716e6", size = 219801, upload-time = "2026-02-03T14:00:24.186Z" }, + { url = "https://files.pythonhosted.org/packages/90/ae/7f8a78249b02b0818db46220795f8ac8312ea4abd1d37d79ea81db5cae81/coverage-7.13.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01119735c690786b6966a1e9f098da4cd7ca9174c4cfe076d04e653105488395", size = 251306, upload-time = "2026-02-03T14:00:25.798Z" }, + { url = "https://files.pythonhosted.org/packages/62/71/a18a53d1808e09b2e9ebd6b47dad5e92daf4c38b0686b4c4d1b2f3e42b7f/coverage-7.13.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8bb09e83c603f152d855f666d70a71765ca8e67332e5829e62cb9466c176af23", size = 254051, upload-time = "2026-02-03T14:00:27.474Z" }, + { url = "https://files.pythonhosted.org/packages/4a/0a/eb30f6455d04c5a3396d0696cad2df0269ae7444bb322f86ffe3376f7bf9/coverage-7.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b607a40cba795cfac6d130220d25962931ce101f2f478a29822b19755377fb34", size = 255160, upload-time = "2026-02-03T14:00:29.024Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/a45baac86274ce3ed842dbb84f14560c673ad30535f397d89164ec56c5df/coverage-7.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:44f14a62f5da2e9aedf9080e01d2cda61df39197d48e323538ec037336d68da8", size = 251709, upload-time = "2026-02-03T14:00:30.641Z" }, + { url = "https://files.pythonhosted.org/packages/c0/df/dd0dc12f30da11349993f3e218901fdf82f45ee44773596050c8f5a1fb25/coverage-7.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:debf29e0b157769843dff0981cc76f79e0ed04e36bb773c6cac5f6029054bd8a", size = 253083, upload-time = "2026-02-03T14:00:32.14Z" }, + { url = "https://files.pythonhosted.org/packages/ab/32/fc764c8389a8ce95cb90eb97af4c32f392ab0ac23ec57cadeefb887188d3/coverage-7.13.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:824bb95cd71604031ae9a48edb91fd6effde669522f960375668ed21b36e3ec4", size = 251227, upload-time = "2026-02-03T14:00:34.721Z" }, + { url = "https://files.pythonhosted.org/packages/dd/ca/d025e9da8f06f24c34d2da9873957cfc5f7e0d67802c3e34d0caa8452130/coverage-7.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8f1010029a5b52dc427c8e2a8dbddb2303ddd180b806687d1acd1bb1d06649e7", size = 250794, upload-time = "2026-02-03T14:00:36.278Z" }, + { url = "https://files.pythonhosted.org/packages/45/c7/76bf35d5d488ec8f68682eb8e7671acc50a6d2d1c1182de1d2b6d4ffad3b/coverage-7.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cd5dee4fd7659d8306ffa79eeaaafd91fa30a302dac3af723b9b469e549247e0", size = 252671, upload-time = "2026-02-03T14:00:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/bf/10/1921f1a03a7c209e1cb374f81a6b9b68b03cdb3ecc3433c189bc90e2a3d5/coverage-7.13.3-cp312-cp312-win32.whl", hash = "sha256:f7f153d0184d45f3873b3ad3ad22694fd73aadcb8cdbc4337ab4b41ea6b4dff1", size = 221986, upload-time = "2026-02-03T14:00:40.442Z" }, + { url = "https://files.pythonhosted.org/packages/3c/7c/f5d93297f8e125a80c15545edc754d93e0ed8ba255b65e609b185296af01/coverage-7.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:03a6e5e1e50819d6d7436f5bc40c92ded7e484e400716886ac921e35c133149d", size = 222793, upload-time = "2026-02-03T14:00:42.106Z" }, + { url = "https://files.pythonhosted.org/packages/43/59/c86b84170015b4555ebabca8649bdf9f4a1f737a73168088385ed0f947c4/coverage-7.13.3-cp312-cp312-win_arm64.whl", hash = "sha256:51c4c42c0e7d09a822b08b6cf79b3c4db8333fffde7450da946719ba0d45730f", size = 221410, upload-time = "2026-02-03T14:00:43.726Z" }, + { url = "https://files.pythonhosted.org/packages/81/f3/4c333da7b373e8c8bfb62517e8174a01dcc373d7a9083698e3b39d50d59c/coverage-7.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:853c3d3c79ff0db65797aad79dee6be020efd218ac4510f15a205f1e8d13ce25", size = 219468, upload-time = "2026-02-03T14:00:45.829Z" }, + { url = "https://files.pythonhosted.org/packages/d6/31/0714337b7d23630c8de2f4d56acf43c65f8728a45ed529b34410683f7217/coverage-7.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f75695e157c83d374f88dcc646a60cb94173304a9258b2e74ba5a66b7614a51a", size = 219839, upload-time = "2026-02-03T14:00:47.407Z" }, + { url = "https://files.pythonhosted.org/packages/12/99/bd6f2a2738144c98945666f90cae446ed870cecf0421c767475fcf42cdbe/coverage-7.13.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2d098709621d0819039f3f1e471ee554f55a0b2ac0d816883c765b14129b5627", size = 250828, upload-time = "2026-02-03T14:00:49.029Z" }, + { url = "https://files.pythonhosted.org/packages/6f/99/97b600225fbf631e6f5bfd3ad5bcaf87fbb9e34ff87492e5a572ff01bbe2/coverage-7.13.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:16d23d6579cf80a474ad160ca14d8b319abaa6db62759d6eef53b2fc979b58c8", size = 253432, upload-time = "2026-02-03T14:00:50.655Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5c/abe2b3490bda26bd4f5e3e799be0bdf00bd81edebedc2c9da8d3ef288fa8/coverage-7.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00d34b29a59d2076e6f318b30a00a69bf63687e30cd882984ed444e753990cc1", size = 254672, upload-time = "2026-02-03T14:00:52.757Z" }, + { url = "https://files.pythonhosted.org/packages/31/ba/5d1957c76b40daff53971fe0adb84d9c2162b614280031d1d0653dd010c1/coverage-7.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ab6d72bffac9deb6e6cb0f61042e748de3f9f8e98afb0375a8e64b0b6e11746b", size = 251050, upload-time = "2026-02-03T14:00:54.332Z" }, + { url = "https://files.pythonhosted.org/packages/69/dc/dffdf3bfe9d32090f047d3c3085378558cb4eb6778cda7de414ad74581ed/coverage-7.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e129328ad1258e49cae0123a3b5fcb93d6c2fa90d540f0b4c7cdcdc019aaa3dc", size = 252801, upload-time = "2026-02-03T14:00:56.121Z" }, + { url = "https://files.pythonhosted.org/packages/87/51/cdf6198b0f2746e04511a30dc9185d7b8cdd895276c07bdb538e37f1cd50/coverage-7.13.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2213a8d88ed35459bda71597599d4eec7c2ebad201c88f0bfc2c26fd9b0dd2ea", size = 250763, upload-time = "2026-02-03T14:00:58.719Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1a/596b7d62218c1d69f2475b69cc6b211e33c83c902f38ee6ae9766dd422da/coverage-7.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:00dd3f02de6d5f5c9c3d95e3e036c3c2e2a669f8bf2d3ceb92505c4ce7838f67", size = 250587, upload-time = "2026-02-03T14:01:01.197Z" }, + { url = "https://files.pythonhosted.org/packages/f7/46/52330d5841ff660f22c130b75f5e1dd3e352c8e7baef5e5fef6b14e3e991/coverage-7.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9bada7bc660d20b23d7d312ebe29e927b655cf414dadcdb6335a2075695bd86", size = 252358, upload-time = "2026-02-03T14:01:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/36/8a/e69a5be51923097ba7d5cff9724466e74fe486e9232020ba97c809a8b42b/coverage-7.13.3-cp313-cp313-win32.whl", hash = "sha256:75b3c0300f3fa15809bd62d9ca8b170eb21fcf0100eb4b4154d6dc8b3a5bbd43", size = 222007, upload-time = "2026-02-03T14:01:04.876Z" }, + { url = "https://files.pythonhosted.org/packages/0a/09/a5a069bcee0d613bdd48ee7637fa73bc09e7ed4342b26890f2df97cc9682/coverage-7.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:a2f7589c6132c44c53f6e705e1a6677e2b7821378c22f7703b2cf5388d0d4587", size = 222812, upload-time = "2026-02-03T14:01:07.296Z" }, + { url = "https://files.pythonhosted.org/packages/3d/4f/d62ad7dfe32f9e3d4a10c178bb6f98b10b083d6e0530ca202b399371f6c1/coverage-7.13.3-cp313-cp313-win_arm64.whl", hash = "sha256:123ceaf2b9d8c614f01110f908a341e05b1b305d6b2ada98763b9a5a59756051", size = 221433, upload-time = "2026-02-03T14:01:09.156Z" }, + { url = "https://files.pythonhosted.org/packages/04/b2/4876c46d723d80b9c5b695f1a11bf5f7c3dabf540ec00d6edc076ff025e6/coverage-7.13.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:cc7fd0f726795420f3678ac82ff882c7fc33770bd0074463b5aef7293285ace9", size = 220162, upload-time = "2026-02-03T14:01:11.409Z" }, + { url = "https://files.pythonhosted.org/packages/fc/04/9942b64a0e0bdda2c109f56bda42b2a59d9d3df4c94b85a323c1cae9fc77/coverage-7.13.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d358dc408edc28730aed5477a69338e444e62fba0b7e9e4a131c505fadad691e", size = 220510, upload-time = "2026-02-03T14:01:13.038Z" }, + { url = "https://files.pythonhosted.org/packages/5a/82/5cfe1e81eae525b74669f9795f37eb3edd4679b873d79d1e6c1c14ee6c1c/coverage-7.13.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5d67b9ed6f7b5527b209b24b3df9f2e5bf0198c1bbf99c6971b0e2dcb7e2a107", size = 261801, upload-time = "2026-02-03T14:01:14.674Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ec/a553d7f742fd2cd12e36a16a7b4b3582d5934b496ef2b5ea8abeb10903d4/coverage-7.13.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59224bfb2e9b37c1335ae35d00daa3a5b4e0b1a20f530be208fff1ecfa436f43", size = 263882, upload-time = "2026-02-03T14:01:16.343Z" }, + { url = "https://files.pythonhosted.org/packages/e1/58/8f54a2a93e3d675635bc406de1c9ac8d551312142ff52c9d71b5e533ad45/coverage-7.13.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9306b5299e31e31e0d3b908c66bcb6e7e3ddca143dea0266e9ce6c667346d3", size = 266306, upload-time = "2026-02-03T14:01:18.02Z" }, + { url = "https://files.pythonhosted.org/packages/1a/be/e593399fd6ea1f00aee79ebd7cc401021f218d34e96682a92e1bae092ff6/coverage-7.13.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:343aaeb5f8bb7bcd38620fd7bc56e6ee8207847d8c6103a1e7b72322d381ba4a", size = 261051, upload-time = "2026-02-03T14:01:19.757Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e5/e9e0f6138b21bcdebccac36fbfde9cf15eb1bbcea9f5b1f35cd1f465fb91/coverage-7.13.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2182129f4c101272ff5f2f18038d7b698db1bf8e7aa9e615cb48440899ad32e", size = 263868, upload-time = "2026-02-03T14:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bf/de72cfebb69756f2d4a2dde35efcc33c47d85cd3ebdf844b3914aac2ef28/coverage-7.13.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:94d2ac94bd0cc57c5626f52f8c2fffed1444b5ae8c9fc68320306cc2b255e155", size = 261498, upload-time = "2026-02-03T14:01:23.097Z" }, + { url = "https://files.pythonhosted.org/packages/f2/91/4a2d313a70fc2e98ca53afd1c8ce67a89b1944cd996589a5b1fe7fbb3e5c/coverage-7.13.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:65436cde5ecabe26fb2f0bf598962f0a054d3f23ad529361326ac002c61a2a1e", size = 260394, upload-time = "2026-02-03T14:01:24.949Z" }, + { url = "https://files.pythonhosted.org/packages/40/83/25113af7cf6941e779eb7ed8de2a677865b859a07ccee9146d4cc06a03e3/coverage-7.13.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:db83b77f97129813dbd463a67e5335adc6a6a91db652cc085d60c2d512746f96", size = 262579, upload-time = "2026-02-03T14:01:26.703Z" }, + { url = "https://files.pythonhosted.org/packages/1e/19/a5f2b96262977e82fb9aabbe19b4d83561f5d063f18dde3e72f34ffc3b2f/coverage-7.13.3-cp313-cp313t-win32.whl", hash = "sha256:dfb428e41377e6b9ba1b0a32df6db5409cb089a0ed1d0a672dc4953ec110d84f", size = 222679, upload-time = "2026-02-03T14:01:28.553Z" }, + { url = "https://files.pythonhosted.org/packages/81/82/ef1747b88c87a5c7d7edc3704799ebd650189a9158e680a063308b6125ef/coverage-7.13.3-cp313-cp313t-win_amd64.whl", hash = "sha256:5badd7e596e6b0c89aa8ec6d37f4473e4357f982ce57f9a2942b0221cd9cf60c", size = 223740, upload-time = "2026-02-03T14:01:30.776Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4c/a67c7bb5b560241c22736a9cb2f14c5034149ffae18630323fde787339e4/coverage-7.13.3-cp313-cp313t-win_arm64.whl", hash = "sha256:989aa158c0eb19d83c76c26f4ba00dbb272485c56e452010a3450bdbc9daafd9", size = 221996, upload-time = "2026-02-03T14:01:32.495Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b3/677bb43427fed9298905106f39c6520ac75f746f81b8f01104526a8026e4/coverage-7.13.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c6f6169bbdbdb85aab8ac0392d776948907267fcc91deeacf6f9d55f7a83ae3b", size = 219513, upload-time = "2026-02-03T14:01:34.29Z" }, + { url = "https://files.pythonhosted.org/packages/42/53/290046e3bbf8986cdb7366a42dab3440b9983711eaff044a51b11006c67b/coverage-7.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2f5e731627a3d5ef11a2a35aa0c6f7c435867c7ccbc391268eb4f2ca5dbdcc10", size = 219850, upload-time = "2026-02-03T14:01:35.984Z" }, + { url = "https://files.pythonhosted.org/packages/ea/2b/ab41f10345ba2e49d5e299be8663be2b7db33e77ac1b85cd0af985ea6406/coverage-7.13.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9db3a3285d91c0b70fab9f39f0a4aa37d375873677efe4e71e58d8321e8c5d39", size = 250886, upload-time = "2026-02-03T14:01:38.287Z" }, + { url = "https://files.pythonhosted.org/packages/72/2d/b3f6913ee5a1d5cdd04106f257e5fac5d048992ffc2d9995d07b0f17739f/coverage-7.13.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06e49c5897cb12e3f7ecdc111d44e97c4f6d0557b81a7a0204ed70a8b038f86f", size = 253393, upload-time = "2026-02-03T14:01:40.118Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f6/b1f48810ffc6accf49a35b9943636560768f0812330f7456aa87dc39aff5/coverage-7.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb25061a66802df9fc13a9ba1967d25faa4dae0418db469264fd9860a921dde4", size = 254740, upload-time = "2026-02-03T14:01:42.413Z" }, + { url = "https://files.pythonhosted.org/packages/57/d0/e59c54f9be0b61808f6bc4c8c4346bd79f02dd6bbc3f476ef26124661f20/coverage-7.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:99fee45adbb1caeb914da16f70e557fb7ff6ddc9e4b14de665bd41af631367ef", size = 250905, upload-time = "2026-02-03T14:01:44.163Z" }, + { url = "https://files.pythonhosted.org/packages/d5/f7/5291bcdf498bafbee3796bb32ef6966e9915aebd4d0954123c8eae921c32/coverage-7.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:318002f1fd819bdc1651c619268aa5bc853c35fa5cc6d1e8c96bd9cd6c828b75", size = 252753, upload-time = "2026-02-03T14:01:45.974Z" }, + { url = "https://files.pythonhosted.org/packages/a0/a9/1dcafa918c281554dae6e10ece88c1add82db685be123e1b05c2056ff3fb/coverage-7.13.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:71295f2d1d170b9977dc386d46a7a1b7cbb30e5405492529b4c930113a33f895", size = 250716, upload-time = "2026-02-03T14:01:48.844Z" }, + { url = "https://files.pythonhosted.org/packages/44/bb/4ea4eabcce8c4f6235df6e059fbc5db49107b24c4bdffc44aee81aeca5a8/coverage-7.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5b1ad2e0dc672625c44bc4fe34514602a9fd8b10d52ddc414dc585f74453516c", size = 250530, upload-time = "2026-02-03T14:01:50.793Z" }, + { url = "https://files.pythonhosted.org/packages/6d/31/4a6c9e6a71367e6f923b27b528448c37f4e959b7e4029330523014691007/coverage-7.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b2beb64c145593a50d90db5c7178f55daeae129123b0d265bdb3cbec83e5194a", size = 252186, upload-time = "2026-02-03T14:01:52.607Z" }, + { url = "https://files.pythonhosted.org/packages/27/92/e1451ef6390a4f655dc42da35d9971212f7abbbcad0bdb7af4407897eb76/coverage-7.13.3-cp314-cp314-win32.whl", hash = "sha256:3d1aed4f4e837a832df2f3b4f68a690eede0de4560a2dbc214ea0bc55aabcdb4", size = 222253, upload-time = "2026-02-03T14:01:55.071Z" }, + { url = "https://files.pythonhosted.org/packages/8a/98/78885a861a88de020c32a2693487c37d15a9873372953f0c3c159d575a43/coverage-7.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f9efbbaf79f935d5fbe3ad814825cbce4f6cdb3054384cb49f0c0f496125fa0", size = 223069, upload-time = "2026-02-03T14:01:56.95Z" }, + { url = "https://files.pythonhosted.org/packages/eb/fb/3784753a48da58a5337972abf7ca58b1fb0f1bda21bc7b4fae992fd28e47/coverage-7.13.3-cp314-cp314-win_arm64.whl", hash = "sha256:31b6e889c53d4e6687ca63706148049494aace140cffece1c4dc6acadb70a7b3", size = 221633, upload-time = "2026-02-03T14:01:58.758Z" }, + { url = "https://files.pythonhosted.org/packages/40/f9/75b732d9674d32cdbffe801ed5f770786dd1c97eecedef2125b0d25102dc/coverage-7.13.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c5e9787cec750793a19a28df7edd85ac4e49d3fb91721afcdc3b86f6c08d9aa8", size = 220243, upload-time = "2026-02-03T14:02:01.109Z" }, + { url = "https://files.pythonhosted.org/packages/cf/7e/2868ec95de5a65703e6f0c87407ea822d1feb3619600fbc3c1c4fa986090/coverage-7.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5b86db331c682fd0e4be7098e6acee5e8a293f824d41487c667a93705d415ca", size = 220515, upload-time = "2026-02-03T14:02:02.862Z" }, + { url = "https://files.pythonhosted.org/packages/7d/eb/9f0d349652fced20bcaea0f67fc5777bd097c92369f267975732f3dc5f45/coverage-7.13.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:edc7754932682d52cf6e7a71806e529ecd5ce660e630e8bd1d37109a2e5f63ba", size = 261874, upload-time = "2026-02-03T14:02:04.727Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a5/6619bc4a6c7b139b16818149a3e74ab2e21599ff9a7b6811b6afde99f8ec/coverage-7.13.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3a16d6398666510a6886f67f43d9537bfd0e13aca299688a19daa84f543122f", size = 264004, upload-time = "2026-02-03T14:02:06.634Z" }, + { url = "https://files.pythonhosted.org/packages/29/b7/90aa3fc645a50c6f07881fca4fd0ba21e3bfb6ce3a7078424ea3a35c74c9/coverage-7.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:303d38b19626c1981e1bb067a9928236d88eb0e4479b18a74812f05a82071508", size = 266408, upload-time = "2026-02-03T14:02:09.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/55/08bb2a1e4dcbae384e638f0effef486ba5987b06700e481691891427d879/coverage-7.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:284e06eadfe15ddfee2f4ee56631f164ef897a7d7d5a15bca5f0bb88889fc5ba", size = 260977, upload-time = "2026-02-03T14:02:11.755Z" }, + { url = "https://files.pythonhosted.org/packages/9b/76/8bd4ae055a42d8fb5dd2230e5cf36ff2e05f85f2427e91b11a27fea52ed7/coverage-7.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d401f0864a1d3198422816878e4e84ca89ec1c1bf166ecc0ae01380a39b888cd", size = 263868, upload-time = "2026-02-03T14:02:13.565Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f9/ba000560f11e9e32ec03df5aa8477242c2d95b379c99ac9a7b2e7fbacb1a/coverage-7.13.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3f379b02c18a64de78c4ccdddf1c81c2c5ae1956c72dacb9133d7dd7809794ab", size = 261474, upload-time = "2026-02-03T14:02:16.069Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/4de4de8f9ca7af4733bfcf4baa440121b7dbb3856daf8428ce91481ff63b/coverage-7.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:7a482f2da9086971efb12daca1d6547007ede3674ea06e16d7663414445c683e", size = 260317, upload-time = "2026-02-03T14:02:17.996Z" }, + { url = "https://files.pythonhosted.org/packages/05/71/5cd8436e2c21410ff70be81f738c0dddea91bcc3189b1517d26e0102ccb3/coverage-7.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:562136b0d401992118d9b49fbee5454e16f95f85b120a4226a04d816e33fe024", size = 262635, upload-time = "2026-02-03T14:02:20.405Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f8/2834bb45bdd70b55a33ec354b8b5f6062fc90e5bb787e14385903a979503/coverage-7.13.3-cp314-cp314t-win32.whl", hash = "sha256:ca46e5c3be3b195098dd88711890b8011a9fa4feca942292bb84714ce5eab5d3", size = 223035, upload-time = "2026-02-03T14:02:22.323Z" }, + { url = "https://files.pythonhosted.org/packages/26/75/f8290f0073c00d9ae14056d2b84ab92dff21d5370e464cb6cb06f52bf580/coverage-7.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:06d316dbb3d9fd44cca05b2dbcfbef22948493d63a1f28e828d43e6cc505fed8", size = 224142, upload-time = "2026-02-03T14:02:24.143Z" }, + { url = "https://files.pythonhosted.org/packages/03/01/43ac78dfea8946c4a9161bbc034b5549115cb2b56781a4b574927f0d141a/coverage-7.13.3-cp314-cp314t-win_arm64.whl", hash = "sha256:299d66e9218193f9dc6e4880629ed7c4cd23486005166247c283fb98531656c3", size = 222166, upload-time = "2026-02-03T14:02:26.005Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fb/70af542d2d938c778c9373ce253aa4116dbe7c0a5672f78b2b2ae0e1b94b/coverage-7.13.3-py3-none-any.whl", hash = "sha256:90a8af9dba6429b2573199622d72e0ebf024d6276f16abce394ad4d181bb0910", size = 211237, upload-time = "2026-02-03T14:02:27.986Z" }, ] [[package]] @@ -949,16 +959,16 @@ wheels = [ [[package]] name = "pytest-cov" -version = "6.2.1" +version = "7.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage" }, { name = "pluggy" }, { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432, upload-time = "2025-06-12T10:47:47.684Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644, upload-time = "2025-06-12T10:47:45.932Z" }, + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, ] [[package]] From 52f4af6eb902b2714e8a610eed951de9fbc59134 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:38 +0000 Subject: [PATCH 70/78] Bump pydantic from 2.11.7 to 2.12.5 Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.11.7 to 2.12.5. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md) - [Commits](https://github.com/pydantic/pydantic/compare/v2.11.7...v2.12.5) --- updated-dependencies: - dependency-name: pydantic dependency-version: 2.12.5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- uv.lock | 111 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 41 deletions(-) diff --git a/uv.lock b/uv.lock index f986be1..e7c472f 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -818,7 +818,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.7" +version = "2.12.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -826,51 +826,80 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] [[package]] name = "pydantic-core" -version = "2.33.2" +version = "2.41.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, - { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, - { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, - { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, - { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, - { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, - { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, - { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, - { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, - { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, ] [[package]] @@ -1205,14 +1234,14 @@ wheels = [ [[package]] name = "typing-inspection" -version = "0.4.1" +version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] From d066f006937b3985d47803b610e354801e1f4b8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:38 +0000 Subject: [PATCH 71/78] Bump pydantic-settings from 2.10.1 to 2.12.0 Bumps [pydantic-settings](https://github.com/pydantic/pydantic-settings) from 2.10.1 to 2.12.0. - [Release notes](https://github.com/pydantic/pydantic-settings/releases) - [Commits](https://github.com/pydantic/pydantic-settings/compare/2.10.1...v2.12.0) --- updated-dependencies: - dependency-name: pydantic-settings dependency-version: 2.12.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- uv.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uv.lock b/uv.lock index f986be1..29f38ad 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -875,16 +875,16 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.10.1" +version = "2.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] [[package]] From b675e2614098b259b5c45cc68a1796df8f8909c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:41 +0000 Subject: [PATCH 72/78] Bump protobuf from 6.33.1 to 6.33.5 Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 6.33.1 to 6.33.5. - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Commits](https://github.com/protocolbuffers/protobuf/commits) --- updated-dependencies: - dependency-name: protobuf dependency-version: 6.33.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- uv.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/uv.lock b/uv.lock index f986be1..7b6ce04 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -794,17 +794,17 @@ wheels = [ [[package]] name = "protobuf" -version = "6.33.1" +version = "6.33.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/03/a1440979a3f74f16cab3b75b0da1a1a7f922d56a8ddea96092391998edc0/protobuf-6.33.1.tar.gz", hash = "sha256:97f65757e8d09870de6fd973aeddb92f85435607235d20b2dfed93405d00c85b", size = 443432, upload-time = "2025-11-13T16:44:18.895Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/f1/446a9bbd2c60772ca36556bac8bfde40eceb28d9cc7838755bc41e001d8f/protobuf-6.33.1-cp310-abi3-win32.whl", hash = "sha256:f8d3fdbc966aaab1d05046d0240dd94d40f2a8c62856d41eaa141ff64a79de6b", size = 425593, upload-time = "2025-11-13T16:44:06.275Z" }, - { url = "https://files.pythonhosted.org/packages/a6/79/8780a378c650e3df849b73de8b13cf5412f521ca2ff9b78a45c247029440/protobuf-6.33.1-cp310-abi3-win_amd64.whl", hash = "sha256:923aa6d27a92bf44394f6abf7ea0500f38769d4b07f4be41cb52bd8b1123b9ed", size = 436883, upload-time = "2025-11-13T16:44:09.222Z" }, - { url = "https://files.pythonhosted.org/packages/cd/93/26213ff72b103ae55bb0d73e7fb91ea570ef407c3ab4fd2f1f27cac16044/protobuf-6.33.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:fe34575f2bdde76ac429ec7b570235bf0c788883e70aee90068e9981806f2490", size = 427522, upload-time = "2025-11-13T16:44:10.475Z" }, - { url = "https://files.pythonhosted.org/packages/c2/32/df4a35247923393aa6b887c3b3244a8c941c32a25681775f96e2b418f90e/protobuf-6.33.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:f8adba2e44cde2d7618996b3fc02341f03f5bc3f2748be72dc7b063319276178", size = 324445, upload-time = "2025-11-13T16:44:11.869Z" }, - { url = "https://files.pythonhosted.org/packages/8e/d0/d796e419e2ec93d2f3fa44888861c3f88f722cde02b7c3488fcc6a166820/protobuf-6.33.1-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:0f4cf01222c0d959c2b399142deb526de420be8236f22c71356e2a544e153c53", size = 339161, upload-time = "2025-11-13T16:44:12.778Z" }, - { url = "https://files.pythonhosted.org/packages/1d/2a/3c5f05a4af06649547027d288747f68525755de692a26a7720dced3652c0/protobuf-6.33.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd7d5e0eb08cd5b87fd3df49bc193f5cfd778701f47e11d127d0afc6c39f1d1", size = 323171, upload-time = "2025-11-13T16:44:14.035Z" }, - { url = "https://files.pythonhosted.org/packages/08/b4/46310463b4f6ceef310f8348786f3cff181cea671578e3d9743ba61a459e/protobuf-6.33.1-py3-none-any.whl", hash = "sha256:d595a9fd694fdeb061a62fbe10eb039cc1e444df81ec9bb70c7fc59ebcb1eafa", size = 170477, upload-time = "2025-11-13T16:44:17.633Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, + { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, + { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, + { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, ] [[package]] From e7bc30308e408b9ee4df99245ef4da930bbc35d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 13:40:41 +0000 Subject: [PATCH 73/78] Bump prek from 0.2.16 to 0.3.0 Bumps [prek](https://github.com/j178/prek) from 0.2.16 to 0.3.0. - [Release notes](https://github.com/j178/prek/releases) - [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md) - [Commits](https://github.com/j178/prek/compare/v0.2.16...v0.3.0) --- updated-dependencies: - dependency-name: prek dependency-version: 0.3.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- uv.lock | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/uv.lock b/uv.lock index f986be1..b13b52e 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.12" [[package]] @@ -759,28 +759,26 @@ wheels = [ [[package]] name = "prek" -version = "0.2.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/d9/1472c512bc48cf0ab7d4348bd191ac404ed9d001fcf699e681518ecc6d09/prek-0.2.16.tar.gz", hash = "sha256:264b78996f36644948d5b897b7af21bedad36abd8678ba77fd200c4a9b3b3261", size = 341621, upload-time = "2025-11-18T10:02:12.615Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/fb/c54f1b6658ae36fd4d0ad36d968f60642b423e8d9b2e2e9fba8839f8d3d6/prek-0.2.16-py3-none-linux_armv6l.whl", hash = "sha256:e6bb33b336b0313b4a7de2874cb2361d3a368aa90f1c5a6dbaaa267dd4a32df5", size = 4820782, upload-time = "2025-11-18T10:01:45.372Z" }, - { url = "https://files.pythonhosted.org/packages/f3/13/7050660c8bbb0b50cbc1054656f54d5c56573d29b6b500d932f7cf940085/prek-0.2.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dbd6baae9c418a61e0b62ce7db85d57865d2b4817f5c80c4db4547fa0b1a1d7b", size = 4901877, upload-time = "2025-11-18T10:01:47.316Z" }, - { url = "https://files.pythonhosted.org/packages/18/4b/c1bf4eed7384b8161a31e451e5141268e3115c162eecae13936a3d7d4aaa/prek-0.2.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe902fbdc1b77133f6c799519002c5727b699dcf7d14237b3d94a4fc264d3181", size = 4619978, upload-time = "2025-11-18T10:01:48.569Z" }, - { url = "https://files.pythonhosted.org/packages/4c/47/749ceb4df5c52ac6f40c3c4eec8e36515d4faaaf954fe45cc01af9f13279/prek-0.2.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3f2fba7dba9cace414f2b70c73e461400f9f83bbf14d9fc37b201fcc2842ff99", size = 4819906, upload-time = "2025-11-18T10:01:50.224Z" }, - { url = "https://files.pythonhosted.org/packages/45/0e/54ddd434079f753e37ec58d1dfe64b1693f47b8540daf05db2b48b858645/prek-0.2.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f48db16d59f81f5d2a698d3e17b2ec1b375867decc11013c72dd4e2bca3b2aab", size = 4751379, upload-time = "2025-11-18T10:01:51.97Z" }, - { url = "https://files.pythonhosted.org/packages/27/1f/12ad6e9130deb908f8287626539dac79e3563be743a66607863a2fc94503/prek-0.2.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f170d9b402f6d39545eaf12c0c86735fdebfcccb509156bf2580a4dad2888269", size = 5037742, upload-time = "2025-11-18T10:01:53.715Z" }, - { url = "https://files.pythonhosted.org/packages/44/cc/e5247b66d497595424ab9c6f81bebc9fc7985d5c73479392d30cc46ea980/prek-0.2.16-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:484928299a51ba592065b7cf4e66e1e9c4e73b517d0cb3cf4d43d222ec36a37a", size = 5470035, upload-time = "2025-11-18T10:01:55.037Z" }, - { url = "https://files.pythonhosted.org/packages/8e/a2/73316c372e106d24f2304d512b2065f80e47ec9bf7f0042e15ae99f64b2a/prek-0.2.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28140f063d4a2adeca27236a4d8c5d37203ec16c989a6b7c5a82c3a94256565f", size = 5419661, upload-time = "2025-11-18T10:01:56.357Z" }, - { url = "https://files.pythonhosted.org/packages/27/06/ec8e2025a8e4c7d987c173bb762b763000986e87ccd65c7fa83deb362a43/prek-0.2.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94d0aebc0660a69216c4f769e48438a4efc9a804b69bd032be387ecd6b49a26f", size = 5462304, upload-time = "2025-11-18T10:01:57.541Z" }, - { url = "https://files.pythonhosted.org/packages/45/a4/58658815c916ccc46bf35ae794a0c042bfcb9446a4579e707865e96f069d/prek-0.2.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f6a4ed975cfae0b038f6ecb3adace744fe34195db8a264c088f1c184c604775", size = 5088758, upload-time = "2025-11-18T10:01:59.295Z" }, - { url = "https://files.pythonhosted.org/packages/43/7c/fa4e81d36e95a90a3ad3f5ce5f6b08636ee48e3522182ce63472ab5fdb1f/prek-0.2.16-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:2693880f3d9ab15bb8c20310873a1e5b97c14c00202813bed7364ac1a8b1a34c", size = 4829954, upload-time = "2025-11-18T10:02:00.534Z" }, - { url = "https://files.pythonhosted.org/packages/02/c0/786acdf3b535cf806dd0f41f77afd4c3a5315214ad37f3beb845d6c6957b/prek-0.2.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:db4cc554cd7b9315d0fcabeca1f8781eb768ec93fa5c9ab41ee4b65fe0542128", size = 4856932, upload-time = "2025-11-18T10:02:02.134Z" }, - { url = "https://files.pythonhosted.org/packages/37/9c/f3b8a0bec4b59a739142953f4aa90f332605d547f36b6aa90e62b457606b/prek-0.2.16-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:296711cffb2cb967e8c292bce4aee0f408ef81454613aedc06426e1e5aa39e58", size = 4736473, upload-time = "2025-11-18T10:02:03.914Z" }, - { url = "https://files.pythonhosted.org/packages/62/95/24cd05d749d878ba4e1ff1dab6ca071fa53a21c1aa1153fb7547c56783af/prek-0.2.16-py3-none-musllinux_1_1_i686.whl", hash = "sha256:7366a97f802872c7570617ec55e3cea5e9cc85c00dcb8275e97e7052f7b50dbd", size = 4934890, upload-time = "2025-11-18T10:02:05.555Z" }, - { url = "https://files.pythonhosted.org/packages/d9/34/38ddcadaee73bb74dd811667faf86810b34d8e359fdcca6eca941b9ff8b7/prek-0.2.16-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:a68a124caf1839619672cc813a3adc96f55253204e8bd36196a10faf933f845c", size = 5198632, upload-time = "2025-11-18T10:02:07.142Z" }, - { url = "https://files.pythonhosted.org/packages/73/0f/25a291c923e8362e7c18632f7690941086d6949cf1e4911280f8aef9251b/prek-0.2.16-py3-none-win32.whl", hash = "sha256:98d1df55b2665cd83d6e91176a4ddcd305bbab52967842e2afffa5c564de09db", size = 4580648, upload-time = "2025-11-18T10:02:08.301Z" }, - { url = "https://files.pythonhosted.org/packages/4d/49/dfa46f65fb59be2d3343b30f455f8df7dab186567b10040a6f5caa1479bc/prek-0.2.16-py3-none-win_amd64.whl", hash = "sha256:a41839d4fe26dd4fe057d9a2ddc39ec15221d74a6fd240fb2ece98c3b3a69509", size = 5250227, upload-time = "2025-11-18T10:02:09.867Z" }, - { url = "https://files.pythonhosted.org/packages/a8/00/e2822644468bca8dc37435a456da826447a5c00ac46b6c3ac99e98114597/prek-0.2.16-py3-none-win_arm64.whl", hash = "sha256:950c2af27c8df9a1367b51a4686ae82d6b61db1a3ad2a2599872b9993ca062dc", size = 4930842, upload-time = "2025-11-18T10:02:11.392Z" }, +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/62/4b91c8a343e21fcefabc569a91d08cf8756c554332521af78294acef7c27/prek-0.3.1.tar.gz", hash = "sha256:45abc4ffd3cb2d39c478f47e92e88f050e5a4b7a20915d78e54b1a3d3619ebe4", size = 323141, upload-time = "2026-01-31T13:25:58.128Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/c1/e0e545048e4190245fb4ae375d67684108518f3c69b67b81d62e1cd855c6/prek-0.3.1-py3-none-linux_armv6l.whl", hash = "sha256:1f77d0845cc63cad9c447f7f7d554c1ad188d07dbe02741823d20d58c7312eaf", size = 4285460, upload-time = "2026-01-31T13:25:42.066Z" }, + { url = "https://files.pythonhosted.org/packages/10/fe/7636d10e2dafdf2a4a927c989f32ce3f08e99d62ebad7563f0272e74b7f4/prek-0.3.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e21142300d139e8c7f3970dd8aa66391cb43cd17c0c4ee65ff1af48856bb6a4b", size = 4287085, upload-time = "2026-01-31T13:25:40.193Z" }, + { url = "https://files.pythonhosted.org/packages/a3/7f/62ed57340071e04c02057d64276ec3986baca3ad4759523e2f433dc9be55/prek-0.3.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c09391de7d1994f9402c46cb31671800ea309b1668d839614965706206da3655", size = 3936188, upload-time = "2026-01-31T13:25:47.314Z" }, + { url = "https://files.pythonhosted.org/packages/6b/17/cb24f462c255f76d130ca110f4fcec09b041c3c770e43960cc3fc9dcc9ce/prek-0.3.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:a0b0a012ef6ef28dee019cf81a95c5759b2c03287c32c1f2adcb5f5fb097138e", size = 4275214, upload-time = "2026-01-31T13:25:38.053Z" }, + { url = "https://files.pythonhosted.org/packages/f2/85/db155b59d73cf972c8467e4d95def635f9976d5fcbcc790a4bbe9d2e049a/prek-0.3.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4a0e40785d39b8feae0d7ecf5534789811a2614114ab47f4e344a2ebd75ac10", size = 4197982, upload-time = "2026-01-31T13:25:50.034Z" }, + { url = "https://files.pythonhosted.org/packages/06/cf/d35c32436692928a9ca53eed3334e30148a60f0faa33c42e8d11b6028fa6/prek-0.3.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5c2f5e377e3cc5a5ea191deb8255a5823fbaa01b424417fe18ff12c7c800f3", size = 4458572, upload-time = "2026-01-31T13:25:51.46Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c0/eb36fecb21fe30baa72fb87ccf3a791c32932786c287f95f8972402e9245/prek-0.3.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fe70e97f4dfca57ce142caecd77b90a435abd1c855f9e96041078415d80e89a", size = 4999230, upload-time = "2026-01-31T13:25:44.055Z" }, + { url = "https://files.pythonhosted.org/packages/e4/f3/ad1a25ea16320e6acd1fedd6bd96a0d22526f5132d9b5adc045996ccca4c/prek-0.3.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b28e921d893771bdd7533cd94d46a10e0cf2855c5e6bf6809b598b5e45baa73", size = 4510376, upload-time = "2026-01-31T13:25:48.563Z" }, + { url = "https://files.pythonhosted.org/packages/39/b7/91afdd24be808ccf3b9119f4cf2bd6d02e30683143a62a08f432a3435861/prek-0.3.1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:555610a53c4541976f4fe8602177ecd7a86a931dcb90a89e5826cfc4a6c8f2cb", size = 4273229, upload-time = "2026-01-31T13:25:56.362Z" }, + { url = "https://files.pythonhosted.org/packages/5a/bb/636c77c5c9fc5eadcc2af975a95b48eeeff2dc833021e222b0e9479b9b47/prek-0.3.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:663a15a31b705db5d01a1c9eb28c6ea417628e6cb68de2dc7b3016ca2f959a99", size = 4301166, upload-time = "2026-01-31T13:25:36.281Z" }, + { url = "https://files.pythonhosted.org/packages/4e/cf/c928a36173e71b21b252943404a5b3d1ddc1f08c9e0f1d7282a2c62c7325/prek-0.3.1-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:1d03fb5fa37177dc37ccbe474252473adcbde63287a63e9fa3d5745470f95bd8", size = 4188473, upload-time = "2026-01-31T13:25:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/98/4c/af8f6a40cb094e88225514b89e8ae05ac69fc479d6b500e4b984f9ef8ae3/prek-0.3.1-py3-none-musllinux_1_1_i686.whl", hash = "sha256:3e20a5b704c06944dca9555a39f1de3622edc8ed2becaf8b3564925d1b7c1c0d", size = 4342239, upload-time = "2026-01-31T13:25:55.179Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ba/6b0f725c0cf96182ab9622b4d122a01f04de9b2b6e4a6516874390218510/prek-0.3.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6889acf0c9b0dd7b9cd3510ec36af10a739826d2b9de1e2d021ae6a9f130959a", size = 4618674, upload-time = "2026-01-31T13:25:59.175Z" }, + { url = "https://files.pythonhosted.org/packages/d8/49/caa320893640c9e72ed3d3e2bab7959faba54cefeea09be18c33d5f75baf/prek-0.3.1-py3-none-win32.whl", hash = "sha256:cc62a4bff79ed835d448098f0667c1a91915cec9cfac6c6246b675f0da46eded", size = 3928699, upload-time = "2026-01-31T13:25:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/59/19/15907abe245ae9a120abcebb0c50c6d456ba719eb640f7c57e4f5b2f00e3/prek-0.3.1-py3-none-win_amd64.whl", hash = "sha256:3515140def20bab85e53585b0beb90d894ff2915d2fdb4451b6a4588e16516d8", size = 4296106, upload-time = "2026-01-31T13:25:45.606Z" }, + { url = "https://files.pythonhosted.org/packages/a6/5e/9b994b5de36d6aa5caaf09a018d8fe4820db46e4da577c2fd7a1e176b56c/prek-0.3.1-py3-none-win_arm64.whl", hash = "sha256:cfa58365eb36753cff684dc3b00196c1163bb135fe72c6a1c6ebb1a179f5dbdf", size = 4021714, upload-time = "2026-01-31T13:25:34.993Z" }, ] [[package]] From 8a8d01f64377b701ee4d26efb2811d6a5fc56efd Mon Sep 17 00:00:00 2001 From: Thorina Boenke <68156005+thorinaboenke@users.noreply.github.com> Date: Thu, 5 Feb 2026 14:52:16 +0100 Subject: [PATCH 74/78] Bump version from 0.1.0 to 0.1.1 --- src/service/metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/metadata.py b/src/service/metadata.py index 27bf95f..8069814 100644 --- a/src/service/metadata.py +++ b/src/service/metadata.py @@ -7,7 +7,7 @@ __website__ = 'https://aecid.ait.ac.at' __license__ = 'EUPL-1.2' __status__ = 'Development' -__version__ = '0.1.0' +__version__ = '0.1.1' __all__ = [ '__authors__', '__contact__', From d2c89a1243d9b18e43619a72dac71f6db90a0d87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:28:22 +0000 Subject: [PATCH 75/78] Bump pynng from 0.8.1 to 0.9.0 Bumps [pynng](https://github.com/codypiersall/pynng) from 0.8.1 to 0.9.0. - [Release notes](https://github.com/codypiersall/pynng/releases) - [Commits](https://github.com/codypiersall/pynng/compare/v0.8.1...v0.9.0) --- updated-dependencies: - dependency-name: pynng dependency-version: 0.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- uv.lock | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/uv.lock b/uv.lock index e1f4028..9b4c233 100644 --- a/uv.lock +++ b/uv.lock @@ -935,28 +935,43 @@ wheels = [ [[package]] name = "pynng" -version = "0.8.1" +version = "0.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, { name = "sniffio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/8c/23141a4b94fdb69c72fe54734a5da192ecbaf5c4965ba6d3a753e6a8ac34/pynng-0.8.1.tar.gz", hash = "sha256:60165f34bdf501885e0acceaeed79bc35a57f3ca3c913cb38c14919b9bd3656f", size = 6364925, upload-time = "2025-01-16T03:42:32.848Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b7/243a4e919b2e58cb21ba3e39b9d139e6a58158e944a03b78304b0d2b2881/pynng-0.8.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df13ffa5a4953b85ed43c252f5e6a00b7791faa22b9d3040e0546d878fc921a4", size = 1089916, upload-time = "2025-01-16T03:40:43.088Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9e/d7c10e38ddaa7a2e3f59cd3a5d2b3978f28d7e3f5ae1167c9555e35f1c48/pynng-0.8.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fb8d43c23e9668fb3db3992b98b7364c2991027a79d6e66af850d70820a631c", size = 727667, upload-time = "2025-01-16T03:40:44.875Z" }, - { url = "https://files.pythonhosted.org/packages/94/42/cf84ac7b60713af568ffaa8774eb41650e49ba3c0906107f9a889cf86d40/pynng-0.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915f4f8c39684dcf6028548110f647c44a517163db5f89ceeb0c17b9c3a37205", size = 938203, upload-time = "2025-01-16T03:40:48.421Z" }, - { url = "https://files.pythonhosted.org/packages/41/2e/2196c9c3d8ad1af35faf942482fbfc1156898b0945e8412a33d3cfcbfbe8/pynng-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ead5f360a956bc7ccbe3b20701346cecf7d1098b8ad77b6979fd7c055b9226f1", size = 736244, upload-time = "2025-01-16T03:40:51.06Z" }, - { url = "https://files.pythonhosted.org/packages/9b/eb/347e5626e3174992b4b4cf8ff3f7fe965a2e7c7703bf2765db828970f895/pynng-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6d8237ed1c49823695ea3e6ef2e521370426b67f2010850e1b6c66c52aa1f067", size = 941519, upload-time = "2025-01-16T03:40:53.761Z" }, - { url = "https://files.pythonhosted.org/packages/9e/67/e1027872acbdd755994d9cdf3195a6329ce2a141943fbae0e9687c533a59/pynng-0.8.1-cp312-cp312-win32.whl", hash = "sha256:78fe08a000b6c7200c1ad0d6a26491c1ba5c9493975e218af0963b9ca03e5a7a", size = 370576, upload-time = "2025-01-16T03:40:55.818Z" }, - { url = "https://files.pythonhosted.org/packages/4b/19/bd014dfc7cdaacdba15c61a591dc12e7d5307006013f8ceb949bed6d3c48/pynng-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:117552188abe448a467feedcc68f03f2d386e596c0e44a0849c05fca72d40d3f", size = 450454, upload-time = "2025-01-16T03:40:57.737Z" }, - { url = "https://files.pythonhosted.org/packages/0d/fd/b6b43259bf87c7640824310c930761ea814eb4b726f2814ef847ad80d96d/pynng-0.8.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1013dc1773e8a4cee633a8516977d59c17711b56b0df9d6c174d8ac722b19d9", size = 1089913, upload-time = "2025-01-16T03:41:01.543Z" }, - { url = "https://files.pythonhosted.org/packages/44/71/134faf3a6689898167c0b8a55b8a55069521bc79ae6eed1657b075545481/pynng-0.8.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a89b5d3f9801913a22c85cf320efdffc1a2eda925939a0e1a6edc0e194eab27", size = 727669, upload-time = "2025-01-16T03:41:04.936Z" }, - { url = "https://files.pythonhosted.org/packages/72/3d/2d77349fa87671d31c5c57ea44365311338b0a8d984e8b095add62f18fda/pynng-0.8.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2f0a7fdd96c99eaf1a1fce755a6eb39e0ca1cf46cf81c01abe593adabc53b45", size = 938072, upload-time = "2025-01-16T03:41:09.685Z" }, - { url = "https://files.pythonhosted.org/packages/04/91/580382d32fe90dd3cc0310358d449991070091b78a8f97df3f8e4b3d5fee/pynng-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cbda575215e854a241ae837aac613e88d197b0489ef61f4a42f2e9dd793f01", size = 736250, upload-time = "2025-01-16T03:41:11.304Z" }, - { url = "https://files.pythonhosted.org/packages/b6/db/9bf6a8158187aa344c306c6037ff20d134132d83596dcbb8537faaad610d/pynng-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3f635d6361f9ad81d16ba794a5a9b3aa47ed92a7709b88396523676cb6bddb1f", size = 941514, upload-time = "2025-01-16T03:41:13.156Z" }, - { url = "https://files.pythonhosted.org/packages/26/f3/9a7676e3d115834a5acf674590bb32e61f9caa5b8f0971628fc562670d35/pynng-0.8.1-cp313-cp313-win32.whl", hash = "sha256:6d5c51249ca221f0c4e27b13269a230b19fc5e10a60cbfa7a8109995b22e861e", size = 370575, upload-time = "2025-01-16T03:41:15.998Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0e/11d76f7aeb733e966024eb6b6adf73280d2c600f8fa8bdb6ea34d33e9a19/pynng-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:1f9c52bca0d063843178d6f43a302e0e2d6fbe20272de5b3c37f4873c3d55a42", size = 450453, upload-time = "2025-01-16T03:41:17.604Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/4a/58/ec352db5f82a3fe56856fa9510dd051cdfba03c490dd58c0bbca0bdf7771/pynng-0.9.0.tar.gz", hash = "sha256:fcd839abf82a2934fa8c27ff57b574b41810458e35895bac6288814defa8fb4e", size = 7211228, upload-time = "2026-02-04T17:13:23.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/a6/6e0bd577deb868909e9fb3d655c6a281b0cf1b6d277ad3bb3d2fd7d0bc62/pynng-0.9.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ccf5df1b79c1cae3d7a05bb23711ab7df88d61ec575b4f7299bd043d472755e9", size = 1206091, upload-time = "2026-02-04T17:12:15.687Z" }, + { url = "https://files.pythonhosted.org/packages/1e/81/e74eb1d62035d684cb8ab1503f1df417f7798889f3b02b44bc4c874eb2a9/pynng-0.9.0-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46a4c86c8e133e112678bbfd63ccb7bf13338c1392074097feae14dbe9353ee6", size = 995659, upload-time = "2026-02-04T17:12:16.937Z" }, + { url = "https://files.pythonhosted.org/packages/9b/bf/f9b48037fca704fe95bbb5e95b2ce26ce899c1dacfeba83e2c3c95b37017/pynng-0.9.0-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb609459737e80f5b30c00437438f9a6939bcd3437166f2dbc17222e1fe67421", size = 1029272, upload-time = "2026-02-04T17:12:18.799Z" }, + { url = "https://files.pythonhosted.org/packages/af/9b/06cf1d7804b6f632cfa6249012ed0f501e98123ccbc6ee79d65055574e58/pynng-0.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d1ba1550de4d80349bb5d13cb121b168660f93fa2eee2bbeda3f2e56ea5b9a4e", size = 1012740, upload-time = "2026-02-04T17:12:20.563Z" }, + { url = "https://files.pythonhosted.org/packages/a9/eb/14c8b777f7d200168e25e7a93d20a2a082bbf3803e57d17dc6d12ddf0c2d/pynng-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:42d6f1ea7b9359f027c53e067f5410b4e0bcae1c76c0d2c851b41fa6d3b4b846", size = 1033463, upload-time = "2026-02-04T17:12:21.839Z" }, + { url = "https://files.pythonhosted.org/packages/7e/5e/c12ec0ffeeb821bd6397e219a924ac8398e7d94baca38e3fe83c42da302a/pynng-0.9.0-cp312-cp312-win32.whl", hash = "sha256:1d964829641d169c978ffa4c63940b97729493662d487ff5cc20d9175d63a054", size = 444459, upload-time = "2026-02-04T17:12:24.815Z" }, + { url = "https://files.pythonhosted.org/packages/6c/c6/112a6c44020bad15054d3e0654977b92bbaf793ab32dc6455027d0a44fbe/pynng-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:23129170829c9aa682b23000737b4a45c6700a703114a60bb8ed2562872c88c9", size = 542609, upload-time = "2026-02-04T17:12:25.92Z" }, + { url = "https://files.pythonhosted.org/packages/94/8a/0ef201e8090e522b3c2a56465416d7b7ea30268fd18ede8b8c750f0a0f61/pynng-0.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:7911287becc00d2c195d040473e0359c69f20609262960379966cb754e119d52", size = 479390, upload-time = "2026-02-04T17:12:27.115Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ad/6889109cb1ad783064f2d23e897a6ce48ad52194e13366c52992ea10e2cb/pynng-0.9.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:49609fa318685a2b5ebd0f03fd6225267a498a703af3a6cd10ef8bc490b24411", size = 1206090, upload-time = "2026-02-04T17:12:29.587Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d7/dcffcd2311691a84430e645a06661d004bf0468f01604cdbd82c64138039/pynng-0.9.0-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3953af95d9d576eff704c7a66543eb73f6cc83f2fa762bb2f57a8613808c48d", size = 995632, upload-time = "2026-02-04T17:12:30.985Z" }, + { url = "https://files.pythonhosted.org/packages/ed/50/55d03d897326203a29d7f928eb31f3238f605036528da96499b42b3b8c41/pynng-0.9.0-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:641dec283530ed8f8516a0e2851380126820001fb663a2bc3596361fcd2787bd", size = 1029219, upload-time = "2026-02-04T17:12:32.522Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2f/595ccb0011b73bec17e52ec24fda235421de85cbdb130867622c9b21d2db/pynng-0.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4c6f79a12c0366489ea1b2fa7eb4835c0585983e054d7cd4be2a3c2f8bf8edae", size = 1012724, upload-time = "2026-02-04T17:12:33.965Z" }, + { url = "https://files.pythonhosted.org/packages/a3/a6/98d54639734645a9ce24780ce1887e7193a8ef926f2806978dbf94098e60/pynng-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0d40f8652b39cde28814af367503529429037cebc9dde4fa2ed03b36fd9923fb", size = 1033442, upload-time = "2026-02-04T17:12:35.617Z" }, + { url = "https://files.pythonhosted.org/packages/d3/88/f732d9b71cce7c89fa5d71e53c0319ada35e9e1cd27c9fe824c2c4db441c/pynng-0.9.0-cp313-cp313-win32.whl", hash = "sha256:2591b5b27a2fb4c65b3f16c8986d8429e6ed84ca1c37fd52a981092de511fcac", size = 444456, upload-time = "2026-02-04T17:12:36.781Z" }, + { url = "https://files.pythonhosted.org/packages/d3/3e/96cb37f17f95719a6878e2bc281962a722d268e704cefb41871332151d36/pynng-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:7d58d7576e125319cfe73f191abf577b30943c70d53fc5db44daf6de2acc632b", size = 542607, upload-time = "2026-02-04T17:12:38.112Z" }, + { url = "https://files.pythonhosted.org/packages/72/4e/e0b6eddd2c0b652215bf4d1e186fc441d2a35464974ea19e22aa6d1fba7f/pynng-0.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:809492124eeb633ad9804a9b43e497ddeb59d3a787770475395bca06f73cf9e7", size = 479385, upload-time = "2026-02-04T17:12:39.545Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c1/91f81d20aafd2e10f529368a066416ba2337960d47d9b0a9d152daa958ef/pynng-0.9.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:f14ad58d663ac65aab637ec5a248e75668e8b1051c634df5fa69b53f34ab2e63", size = 1209722, upload-time = "2026-02-04T17:12:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/bc/7e/b05ffc3a6a38a2006c5674ed18abde4f6bc773ac487cd890d00dbc40b6f8/pynng-0.9.0-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1eeb60a484ac1f8f148d8340d7c120e075b205fda008860c0c53b19c72e23285", size = 995122, upload-time = "2026-02-04T17:12:42.253Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a3/713c16a496c3d6cff74857c815a358939a43448985a63105500a38fc56b9/pynng-0.9.0-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4efd1ecb821248b7843f343564da056c0dec20a1474d260e94aab09f5fcb1567", size = 1028717, upload-time = "2026-02-04T17:12:43.555Z" }, + { url = "https://files.pythonhosted.org/packages/34/48/9b3271e2c5ebf7c7197121f1578255276e1c416b848696f4c296803af896/pynng-0.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bc7c572cf9e511483f25bd026eed83b23d897fea01fe0998a13f19e9589943b8", size = 1012349, upload-time = "2026-02-04T17:12:44.767Z" }, + { url = "https://files.pythonhosted.org/packages/7c/46/447ba91701b5960d13e5ef211842d9dd3d7256d8def69265c1da53234696/pynng-0.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7872e1538a6bac233fa7529b0b4819e6d15366f31e902bc2169aa4b182915c6d", size = 1032710, upload-time = "2026-02-04T17:12:46.094Z" }, + { url = "https://files.pythonhosted.org/packages/91/8a/4831da593c9f3375c593770bcc49da0bc864520b134c541da531f809186d/pynng-0.9.0-cp314-cp314-win32.whl", hash = "sha256:8cb552d57898745c105ff3f0764d3a9bda31077126425fd6937ca4d5d910aa69", size = 454072, upload-time = "2026-02-04T17:12:55.306Z" }, + { url = "https://files.pythonhosted.org/packages/48/5c/7c60dc6298147c571b1cc0796c3a5610a08a5cf1b519dcb71611352a1817/pynng-0.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:bb867ed8c6f646ce06441547fdfd912789ecd6651906977a666628bb3540e979", size = 559551, upload-time = "2026-02-04T17:12:56.538Z" }, + { url = "https://files.pythonhosted.org/packages/5c/d1/9095acfd3d1d3addeab33a914a59df0e66e26eb31eed5de341f166296068/pynng-0.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:160c73208363849d019ef0b9a21d2a58c4bc94085e0a519af10a02de14f60a1d", size = 496372, upload-time = "2026-02-04T17:12:57.729Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d3/01a6783030f4c9eefb67c0aa98d0f522b4374e1973a6adc5eb4d06233366/pynng-0.9.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ce65dc749a71d7c850e9310cc28836cd140769a37cba69069dc13bc2c3a9f3e9", size = 1211592, upload-time = "2026-02-04T17:12:47.918Z" }, + { url = "https://files.pythonhosted.org/packages/07/b7/dc03b816d96d2492617fa5b94df163aee437db24ead15d2294c51f088183/pynng-0.9.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0a2810c035c39e29c690afbbe58ce433255d817bb267323d90dff7d3c31f3fc", size = 1010817, upload-time = "2026-02-04T17:12:49.416Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a2/57dcb2b25d29457cc89c323b00e651db60e3ea61eb597c7dcd8132b7b519/pynng-0.9.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f2d14dff98750f19f8552cb25fe5c988852cdfe2da5bc29aa224d306ba01ac4", size = 1040274, upload-time = "2026-02-04T17:12:51.002Z" }, + { url = "https://files.pythonhosted.org/packages/f2/73/b5d8870f2ed58113b44682c92323985a8234b3ec0813a33800bea8fc9c00/pynng-0.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c7e8b0d5c2102e3f393525c991f2424e601406f4d25ebc45fded952a5e64cfbd", size = 1027454, upload-time = "2026-02-04T17:12:52.52Z" }, + { url = "https://files.pythonhosted.org/packages/2e/55/983791f771c21e6501142392521c07d2ac10cf58ef1114cb10d79b87873f/pynng-0.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e60dc91e58727597e722b228c3031ebba530c3a92bf76f40e55764053c52512d", size = 1046397, upload-time = "2026-02-04T17:12:53.935Z" }, ] [[package]] From 71e2be4aa638d1427d035d8be44ecb0632623ba8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:28:33 +0000 Subject: [PATCH 76/78] Bump prek from 0.3.1 to 0.3.2 Bumps [prek](https://github.com/j178/prek) from 0.3.1 to 0.3.2. - [Release notes](https://github.com/j178/prek/releases) - [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md) - [Commits](https://github.com/j178/prek/compare/v0.3.1...v0.3.2) --- updated-dependencies: - dependency-name: prek dependency-version: 0.3.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- uv.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/uv.lock b/uv.lock index e1f4028..a26b200 100644 --- a/uv.lock +++ b/uv.lock @@ -769,26 +769,26 @@ wheels = [ [[package]] name = "prek" -version = "0.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/62/4b91c8a343e21fcefabc569a91d08cf8756c554332521af78294acef7c27/prek-0.3.1.tar.gz", hash = "sha256:45abc4ffd3cb2d39c478f47e92e88f050e5a4b7a20915d78e54b1a3d3619ebe4", size = 323141, upload-time = "2026-01-31T13:25:58.128Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/c1/e0e545048e4190245fb4ae375d67684108518f3c69b67b81d62e1cd855c6/prek-0.3.1-py3-none-linux_armv6l.whl", hash = "sha256:1f77d0845cc63cad9c447f7f7d554c1ad188d07dbe02741823d20d58c7312eaf", size = 4285460, upload-time = "2026-01-31T13:25:42.066Z" }, - { url = "https://files.pythonhosted.org/packages/10/fe/7636d10e2dafdf2a4a927c989f32ce3f08e99d62ebad7563f0272e74b7f4/prek-0.3.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e21142300d139e8c7f3970dd8aa66391cb43cd17c0c4ee65ff1af48856bb6a4b", size = 4287085, upload-time = "2026-01-31T13:25:40.193Z" }, - { url = "https://files.pythonhosted.org/packages/a3/7f/62ed57340071e04c02057d64276ec3986baca3ad4759523e2f433dc9be55/prek-0.3.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c09391de7d1994f9402c46cb31671800ea309b1668d839614965706206da3655", size = 3936188, upload-time = "2026-01-31T13:25:47.314Z" }, - { url = "https://files.pythonhosted.org/packages/6b/17/cb24f462c255f76d130ca110f4fcec09b041c3c770e43960cc3fc9dcc9ce/prek-0.3.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:a0b0a012ef6ef28dee019cf81a95c5759b2c03287c32c1f2adcb5f5fb097138e", size = 4275214, upload-time = "2026-01-31T13:25:38.053Z" }, - { url = "https://files.pythonhosted.org/packages/f2/85/db155b59d73cf972c8467e4d95def635f9976d5fcbcc790a4bbe9d2e049a/prek-0.3.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4a0e40785d39b8feae0d7ecf5534789811a2614114ab47f4e344a2ebd75ac10", size = 4197982, upload-time = "2026-01-31T13:25:50.034Z" }, - { url = "https://files.pythonhosted.org/packages/06/cf/d35c32436692928a9ca53eed3334e30148a60f0faa33c42e8d11b6028fa6/prek-0.3.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5c2f5e377e3cc5a5ea191deb8255a5823fbaa01b424417fe18ff12c7c800f3", size = 4458572, upload-time = "2026-01-31T13:25:51.46Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c0/eb36fecb21fe30baa72fb87ccf3a791c32932786c287f95f8972402e9245/prek-0.3.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fe70e97f4dfca57ce142caecd77b90a435abd1c855f9e96041078415d80e89a", size = 4999230, upload-time = "2026-01-31T13:25:44.055Z" }, - { url = "https://files.pythonhosted.org/packages/e4/f3/ad1a25ea16320e6acd1fedd6bd96a0d22526f5132d9b5adc045996ccca4c/prek-0.3.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b28e921d893771bdd7533cd94d46a10e0cf2855c5e6bf6809b598b5e45baa73", size = 4510376, upload-time = "2026-01-31T13:25:48.563Z" }, - { url = "https://files.pythonhosted.org/packages/39/b7/91afdd24be808ccf3b9119f4cf2bd6d02e30683143a62a08f432a3435861/prek-0.3.1-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:555610a53c4541976f4fe8602177ecd7a86a931dcb90a89e5826cfc4a6c8f2cb", size = 4273229, upload-time = "2026-01-31T13:25:56.362Z" }, - { url = "https://files.pythonhosted.org/packages/5a/bb/636c77c5c9fc5eadcc2af975a95b48eeeff2dc833021e222b0e9479b9b47/prek-0.3.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:663a15a31b705db5d01a1c9eb28c6ea417628e6cb68de2dc7b3016ca2f959a99", size = 4301166, upload-time = "2026-01-31T13:25:36.281Z" }, - { url = "https://files.pythonhosted.org/packages/4e/cf/c928a36173e71b21b252943404a5b3d1ddc1f08c9e0f1d7282a2c62c7325/prek-0.3.1-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:1d03fb5fa37177dc37ccbe474252473adcbde63287a63e9fa3d5745470f95bd8", size = 4188473, upload-time = "2026-01-31T13:25:53.341Z" }, - { url = "https://files.pythonhosted.org/packages/98/4c/af8f6a40cb094e88225514b89e8ae05ac69fc479d6b500e4b984f9ef8ae3/prek-0.3.1-py3-none-musllinux_1_1_i686.whl", hash = "sha256:3e20a5b704c06944dca9555a39f1de3622edc8ed2becaf8b3564925d1b7c1c0d", size = 4342239, upload-time = "2026-01-31T13:25:55.179Z" }, - { url = "https://files.pythonhosted.org/packages/b7/ba/6b0f725c0cf96182ab9622b4d122a01f04de9b2b6e4a6516874390218510/prek-0.3.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:6889acf0c9b0dd7b9cd3510ec36af10a739826d2b9de1e2d021ae6a9f130959a", size = 4618674, upload-time = "2026-01-31T13:25:59.175Z" }, - { url = "https://files.pythonhosted.org/packages/d8/49/caa320893640c9e72ed3d3e2bab7959faba54cefeea09be18c33d5f75baf/prek-0.3.1-py3-none-win32.whl", hash = "sha256:cc62a4bff79ed835d448098f0667c1a91915cec9cfac6c6246b675f0da46eded", size = 3928699, upload-time = "2026-01-31T13:25:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/59/19/15907abe245ae9a120abcebb0c50c6d456ba719eb640f7c57e4f5b2f00e3/prek-0.3.1-py3-none-win_amd64.whl", hash = "sha256:3515140def20bab85e53585b0beb90d894ff2915d2fdb4451b6a4588e16516d8", size = 4296106, upload-time = "2026-01-31T13:25:45.606Z" }, - { url = "https://files.pythonhosted.org/packages/a6/5e/9b994b5de36d6aa5caaf09a018d8fe4820db46e4da577c2fd7a1e176b56c/prek-0.3.1-py3-none-win_arm64.whl", hash = "sha256:cfa58365eb36753cff684dc3b00196c1163bb135fe72c6a1c6ebb1a179f5dbdf", size = 4021714, upload-time = "2026-01-31T13:25:34.993Z" }, +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/f5/ee52def928dd1355c20bcfcf765e1e61434635c33f3075e848e7b83a157b/prek-0.3.2.tar.gz", hash = "sha256:dce0074ff1a21290748ca567b4bda7553ee305a8c7b14d737e6c58364a499364", size = 334229, upload-time = "2026-02-06T13:49:47.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/69/70a5fc881290a63910494df2677c0fb241d27cfaa435bbcd0de5cd2e2443/prek-0.3.2-py3-none-linux_armv6l.whl", hash = "sha256:4f352f9c3fc98aeed4c8b2ec4dbf16fc386e45eea163c44d67e5571489bd8e6f", size = 4614960, upload-time = "2026-02-06T13:50:05.818Z" }, + { url = "https://files.pythonhosted.org/packages/c0/15/a82d5d32a2207ccae5d86ea9e44f2b93531ed000faf83a253e8d1108e026/prek-0.3.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4a000cfbc3a6ec7d424f8be3c3e69ccd595448197f92daac8652382d0acc2593", size = 4622889, upload-time = "2026-02-06T13:49:53.662Z" }, + { url = "https://files.pythonhosted.org/packages/89/75/ea833b58a12741397017baef9b66a6e443bfa8286ecbd645d14111446280/prek-0.3.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5436bdc2702cbd7bcf9e355564ae66f8131211e65fefae54665a94a07c3d450a", size = 4239653, upload-time = "2026-02-06T13:50:02.88Z" }, + { url = "https://files.pythonhosted.org/packages/10/b4/d9c3885987afac6e20df4cb7db14e3b0d5a08a77ae4916488254ebac4d0b/prek-0.3.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:0161b5f584f9e7f416d6cf40a17b98f17953050ff8d8350ec60f20fe966b86b6", size = 4595101, upload-time = "2026-02-06T13:49:49.813Z" }, + { url = "https://files.pythonhosted.org/packages/21/a6/1a06473ed83dbc898de22838abdb13954e2583ce229f857f61828384634c/prek-0.3.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e641e8533bca38797eebb49aa89ed0e8db0e61225943b27008c257e3af4d631", size = 4521978, upload-time = "2026-02-06T13:49:41.266Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5e/c38390d5612e6d86b32151c1d2fdab74a57913473193591f0eb00c894c21/prek-0.3.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfca1810d49d3f9ef37599c958c4e716bc19a1d78a7e88cbdcb332e0b008994f", size = 4829108, upload-time = "2026-02-06T13:49:44.598Z" }, + { url = "https://files.pythonhosted.org/packages/80/a6/cecce2ab623747ff65ed990bb0d95fa38449ee19b348234862acf9392fff/prek-0.3.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d69d754299a95a85dc20196f633232f306bee7e7c8cba61791f49ce70404ec", size = 5357520, upload-time = "2026-02-06T13:49:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/a5/18/d6bcb29501514023c76d55d5cd03bdbc037737c8de8b6bc41cdebfb1682c/prek-0.3.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:539dcb90ad9b20837968539855df6a29493b328a1ae87641560768eed4f313b0", size = 4852635, upload-time = "2026-02-06T13:49:58.347Z" }, + { url = "https://files.pythonhosted.org/packages/1b/0a/ae46f34ba27ba87aea5c9ad4ac9cd3e07e014fd5079ae079c84198f62118/prek-0.3.2-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:1998db3d0cbe243984736c82232be51318f9192e2433919a6b1c5790f600b5fd", size = 4599484, upload-time = "2026-02-06T13:49:43.296Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a9/73bfb5b3f7c3583f9b0d431924873928705cdef6abb3d0461c37254a681b/prek-0.3.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:07ab237a5415a3e8c0db54de9d63899bcd947624bdd8820d26f12e65f8d19eb7", size = 4657694, upload-time = "2026-02-06T13:50:01.074Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/0994bc176e1a80110fad3babce2c98b0ac4007630774c9e18fc200a34781/prek-0.3.2-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:0ced19701d69c14a08125f14a5dd03945982edf59e793c73a95caf4697a7ac30", size = 4509337, upload-time = "2026-02-06T13:49:54.891Z" }, + { url = "https://files.pythonhosted.org/packages/f9/13/e73f85f65ba8f626468e5d1694ab3763111513da08e0074517f40238c061/prek-0.3.2-py3-none-musllinux_1_1_i686.whl", hash = "sha256:ffb28189f976fa111e770ee94e4f298add307714568fb7d610c8a7095cb1ce59", size = 4697350, upload-time = "2026-02-06T13:50:04.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/47/98c46dcd580305b9960252a4eb966f1a7b1035c55c363f378d85662ba400/prek-0.3.2-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f63134b3eea14421789a7335d86f99aee277cb520427196f2923b9260c60e5c5", size = 4955860, upload-time = "2026-02-06T13:49:56.581Z" }, + { url = "https://files.pythonhosted.org/packages/73/42/1bb4bba3ff47897df11e9dfd774027cdfa135482c961a54e079af0faf45a/prek-0.3.2-py3-none-win32.whl", hash = "sha256:58c806bd1344becd480ef5a5ba348846cc000af0e1fbe854fef91181a2e06461", size = 4267619, upload-time = "2026-02-06T13:49:39.503Z" }, + { url = "https://files.pythonhosted.org/packages/97/11/6665f47a7c350d83de17403c90bbf7a762ef50876ece456a86f64f46fbfb/prek-0.3.2-py3-none-win_amd64.whl", hash = "sha256:70114b48e9eb8048b2c11b4c7715ce618529c6af71acc84dd8877871a2ef71a6", size = 4624324, upload-time = "2026-02-06T13:49:45.922Z" }, + { url = "https://files.pythonhosted.org/packages/22/e7/740997ca82574d03426f897fd88afe3fc8a7306b8c7ea342a8bc1c538488/prek-0.3.2-py3-none-win_arm64.whl", hash = "sha256:9144d176d0daa2469a25c303ef6f6fa95a8df015eb275232f5cb53551ecefef0", size = 4336008, upload-time = "2026-02-06T13:49:52.27Z" }, ] [[package]] From 02905147342e824f33e0fe5ecb733b30900261dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:28:44 +0000 Subject: [PATCH 77/78] Bump fastapi from 0.128.0 to 0.128.8 Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.128.0 to 0.128.8. - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](https://github.com/fastapi/fastapi/compare/0.128.0...0.128.8) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.128.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- uv.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index e1f4028..4586251 100644 --- a/uv.lock +++ b/uv.lock @@ -314,17 +314,18 @@ sdist = { url = "https://files.pythonhosted.org/packages/dc/83/4da2d3a11b5e0edf1 [[package]] name = "fastapi" -version = "0.128.0" +version = "0.128.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, + { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/08/8c8508db6c7b9aae8f7175046af41baad690771c9bcde676419965e338c7/fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a", size = 365682, upload-time = "2025-12-27T15:21:13.714Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/72/0df5c58c954742f31a7054e2dd1143bae0b408b7f36b59b85f928f9b456c/fastapi-0.128.8.tar.gz", hash = "sha256:3171f9f328c4a218f0a8d2ba8310ac3a55d1ee12c28c949650288aee25966007", size = 375523, upload-time = "2026-02-11T15:19:36.69Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094, upload-time = "2025-12-27T15:21:12.154Z" }, + { url = "https://files.pythonhosted.org/packages/9f/37/37b07e276f8923c69a5df266bfcb5bac4ba8b55dfe4a126720f8c48681d1/fastapi-0.128.8-py3-none-any.whl", hash = "sha256:5618f492d0fe973a778f8fec97723f598aa9deee495040a8d51aaf3cf123ecf1", size = 103630, upload-time = "2026-02-11T15:19:35.209Z" }, ] [[package]] From e3b0fb4e7164ed6197c50c4cb349f84d3541a82c Mon Sep 17 00:00:00 2001 From: whotwagner Date: Thu, 12 Feb 2026 14:57:38 +0000 Subject: [PATCH 78/78] Bump version from 0.1.1 to 0.1.2 --- src/service/metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/metadata.py b/src/service/metadata.py index 8069814..7be6f97 100644 --- a/src/service/metadata.py +++ b/src/service/metadata.py @@ -7,7 +7,7 @@ __website__ = 'https://aecid.ait.ac.at' __license__ = 'EUPL-1.2' __status__ = 'Development' -__version__ = '0.1.1' +__version__ = '0.1.2' __all__ = [ '__authors__', '__contact__',