diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a01724..a715c1b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -55,7 +55,7 @@ repos: pass_filenames: true - id: eslint-osprey-ui name: eslint (osprey_ui) - entry: npx --prefix osprey_ui eslint + entry: npx --prefix osprey_ui eslint --config osprey_ui/eslint.config.mjs files: ^osprey_ui/src/.*\.(jsx?|tsx?)$ language: system pass_filenames: true diff --git a/example_plugins/src/register_plugins.py b/example_plugins/src/register_plugins.py index 369b237..82e5423 100644 --- a/example_plugins/src/register_plugins.py +++ b/example_plugins/src/register_plugins.py @@ -1,4 +1,5 @@ -from typing import Any, Sequence, Type +from collections.abc import Sequence +from typing import Any, Type from osprey.engine.udf.base import UDFBase from osprey.worker.adaptor.plugin_manager import hookimpl_osprey diff --git a/example_plugins/src/services/labels_service.py b/example_plugins/src/services/labels_service.py index f2048da..40f18cb 100644 --- a/example_plugins/src/services/labels_service.py +++ b/example_plugins/src/services/labels_service.py @@ -1,5 +1,6 @@ +from collections.abc import Generator from contextlib import contextmanager -from typing import Any, Generator +from typing import Any from osprey.engine.language_types.entities import EntityT from osprey.worker.lib.osprey_shared.labels import EntityLabels diff --git a/example_plugins/src/udfs/ban_user.py b/example_plugins/src/udfs/ban_user.py index 24fd80c..0e61c19 100644 --- a/example_plugins/src/udfs/ban_user.py +++ b/example_plugins/src/udfs/ban_user.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Self, cast +from typing import Self, cast from osprey.engine.executor.custom_extracted_features import CustomExtractedFeature from osprey.engine.executor.execution_context import ExecutionContext @@ -16,7 +16,7 @@ class BanUserArguments(ArgumentsBase): @dataclass -class BanUserEffect(EffectToCustomExtractedFeatureBase[List[str]]): +class BanUserEffect(EffectToCustomExtractedFeatureBase[list[str]]): """Adds a 'ban user' effect to the action.""" entity: str @@ -29,20 +29,20 @@ class BanUserEffect(EffectToCustomExtractedFeatureBase[List[str]]): return f'{self.entity}|{self.comment}' @classmethod - def build_custom_extracted_feature_from_list(cls, values: List[Self]) -> CustomExtractedFeature[List[str]]: - return BanEffectsExtractedFeature(effects=cast(List[BanUserEffect], values)) + def build_custom_extracted_feature_from_list(cls, values: list[Self]) -> CustomExtractedFeature[list[str]]: + return BanEffectsExtractedFeature(effects=cast(list[BanUserEffect], values)) @add_slots @dataclass -class BanEffectsExtractedFeature(CustomExtractedFeature[List[str]]): - effects: List[BanUserEffect] +class BanEffectsExtractedFeature(CustomExtractedFeature[list[str]]): + effects: list[BanUserEffect] @classmethod def feature_name(cls) -> str: return 'ban_user' - def get_serializable_feature(self) -> List[str] | None: + def get_serializable_feature(self) -> list[str] | None: return [effect.to_str() for effect in self.effects] diff --git a/osprey_async_worker/src/osprey/async_worker/cli/main.py b/osprey_async_worker/src/osprey/async_worker/cli/main.py index 06663f7..313f373 100644 --- a/osprey_async_worker/src/osprey/async_worker/cli/main.py +++ b/osprey_async_worker/src/osprey/async_worker/cli/main.py @@ -8,9 +8,9 @@ import asyncio import json import logging import signal +from collections.abc import AsyncIterator from datetime import datetime, timezone from pathlib import Path -from typing import AsyncIterator, Optional, Tuple import click from osprey.async_worker.adaptor.interfaces import AsyncBaseOutputSink @@ -46,7 +46,7 @@ def init_config() -> Config: return config -def bootstrap_stdlib_engine(rules_path: str) -> Tuple[AsyncOspreyEngine, UDFHelpers]: +def bootstrap_stdlib_engine(rules_path: str) -> tuple[AsyncOspreyEngine, UDFHelpers]: """Bootstrap engine with only stdlib UDFs — no external plugins, no Postgres, no labels. This avoids loading example_plugins or any third-party plugins that require database connections. @@ -74,7 +74,7 @@ def bootstrap_stdlib_engine(rules_path: str) -> Tuple[AsyncOspreyEngine, UDFHelp return engine, udf_helpers -def bootstrap_plugin_engine(rules_path: str) -> Tuple[AsyncOspreyEngine, UDFHelpers, AsyncBaseOutputSink]: +def bootstrap_plugin_engine(rules_path: str) -> tuple[AsyncOspreyEngine, UDFHelpers, AsyncBaseOutputSink]: """Bootstrap the async engine with all async plugins loaded. Loads UDFs, AST validators, and output sinks from the ``osprey_async_plugin`` @@ -129,7 +129,7 @@ class AsyncFileInputStream(AsyncBaseInputStream[BaseAckingContext[Action]]): def build_kafka_input_stream( topic: str, bootstrap_servers: str, - group_id: Optional[str], + group_id: str | None, offset_reset: str, ) -> AsyncKafkaInputStream: """Build a Kafka-backed async input stream. @@ -184,13 +184,13 @@ def cli() -> None: ) def run( rules_path: str, - input_file: Optional[str], + input_file: str | None, max_concurrent: int, with_plugins: bool, input_source: str, kafka_topic: str, kafka_bootstrap_servers: str, - kafka_group_id: Optional[str], + kafka_group_id: str | None, kafka_offset_reset: str, ) -> None: """Run the async rules worker with a static rules file and optional input file.""" @@ -257,7 +257,7 @@ def run( if not stop_task.done(): stop_task.cancel() - sink_error: Optional[BaseException] = None + sink_error: BaseException | None = None if sink_task.done(): # The sink finished on its own rather than via a shutdown signal — # surface any fatal error instead of reporting a clean shutdown. diff --git a/osprey_async_worker/src/osprey/async_worker/engine.py b/osprey_async_worker/src/osprey/async_worker/engine.py index 45c318f..af304ef 100644 --- a/osprey_async_worker/src/osprey/async_worker/engine.py +++ b/osprey_async_worker/src/osprey/async_worker/engine.py @@ -5,13 +5,16 @@ concurrent.futures.ThreadPoolExecutor for rule compilation. Provides async execute() that calls the async executor directly. """ +from __future__ import annotations + import asyncio import gc import logging +from collections.abc import Callable from concurrent.futures import ThreadPoolExecutor from pathlib import Path from time import time -from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Set, Type, TypedDict, cast +from typing import TYPE_CHECKING, TypedDict, cast if TYPE_CHECKING: from osprey.worker.lib.data_exporters.validation_result_exporter import BaseValidationResultExporter @@ -87,7 +90,7 @@ class AsyncOspreyEngine: sources_provider: BaseSourcesProvider, udf_registry: UDFRegistry, should_yield_during_compilation: bool = False, - validation_exporter: Optional['BaseValidationResultExporter'] = None, + validation_exporter: 'BaseValidationResultExporter' | None = None, ): self._sources_provider = sources_provider self._udf_registry = udf_registry @@ -282,9 +285,9 @@ class AsyncOspreyEngine: self, udf_helpers: UDFHelpers, action: Action, - max_concurrent: Optional[int] = None, + max_concurrent: int | None = None, sample_rate: int = 100, - parent_tracer_span: Optional[TracerSpan] = None, + parent_tracer_span: TracerSpan | None = None, ) -> ExecutionResult: """Execute an action against the rules using the async executor.""" if max_concurrent is None: @@ -300,13 +303,13 @@ class AsyncOspreyEngine: parent_tracer_span=parent_tracer_span, ) - def get_config_subkey(self, model_class: Type[ModelT]) -> ModelT: + def get_config_subkey(self, model_class: type[ModelT]) -> ModelT: return self._config_subkey_handler.get_config_subkey(model_class) - def watch_config_subkey(self, model_class: Type[ModelT], update_callback: Callable[[ModelT], None]) -> None: + def watch_config_subkey(self, model_class: type[ModelT], update_callback: Callable[[ModelT], None]) -> None: self._config_subkey_handler.watch_config_subkey(model_class, update_callback) - def get_known_feature_locations(self) -> List[FeatureLocation]: + def get_known_feature_locations(self) -> list[FeatureLocation]: """Return locations of named identifiers that the rules engine extracts. Mirrors osprey.worker.lib.osprey_engine.OspreyEngine.get_known_feature_locations: @@ -337,19 +340,19 @@ class AsyncOspreyEngine: if _should_extract(span) ] - def get_known_action_names(self) -> Set[str]: + def get_known_action_names(self) -> set[str]: return { Path(source.path).stem for source in self.execution_graph.validated_sources.sources.glob('actions/*.sml') } - def get_rule_to_info_mapping(self) -> Dict[str, str]: + def get_rule_to_info_mapping(self) -> dict[str, str]: return self._execution_graph.validated_sources.get_validator_result(RuleNameToDescriptionMapping) - def get_feature_name_to_entity_type_mapping(self) -> Dict[str, str]: + def get_feature_name_to_entity_type_mapping(self) -> dict[str, str]: """Returns a mapping from 'feature name' -> 'entity type' for each feature that holds an entity.""" return self._execution_graph.validated_sources.get_validator_result(FeatureNameToEntityTypeMapping) - def get_post_execution_feature_name_to_value_type_mapping(self) -> Dict[str, type]: + def get_post_execution_feature_name_to_value_type_mapping(self) -> dict[str, type]: """Returns a mapping from 'feature name' -> 'value type' for each feature.""" post_execution_name_to_type_and_span = ValidateStaticTypes.to_post_execution_types( self._execution_graph.validated_sources.get_validator_result(ValidateStaticTypes) diff --git a/osprey_async_worker/src/osprey/async_worker/executor.py b/osprey_async_worker/src/osprey/async_worker/executor.py index bb7d1be..a29221a 100644 --- a/osprey_async_worker/src/osprey/async_worker/executor.py +++ b/osprey_async_worker/src/osprey/async_worker/executor.py @@ -11,7 +11,8 @@ primitives will NOT work here — they must be ported to AsyncUDFBase. import asyncio import os from collections import defaultdict -from typing import Any, Dict, List, Optional, Sequence, Set, Tuple +from collections.abc import Sequence +from typing import Any import sentry_sdk from ddtrace import tracer @@ -51,7 +52,7 @@ _DEFAULT_MAX_ASYNC_PER_EXECUTION = 12 def _get_ready_sync_and_async( allow_async: bool, context: ExecutionContext -) -> Tuple[Sequence[DependencyChain], Sequence[DependencyChain]]: +) -> tuple[Sequence[DependencyChain], Sequence[DependencyChain]]: _ready_sync = [] _ready_async = [] for ready_chain in context.get_ready_to_execute(): @@ -65,7 +66,7 @@ def _get_ready_sync_and_async( _SUPPRESS_IN_PROD = (ExpectedUdfException, NodeFailurePropagationException, MissingJsonPath, TypeError) -def _is_spammy_exception(e: Optional[Exception]) -> bool: +def _is_spammy_exception(e: Exception | None) -> bool: if e is None: return True if os.environ.get('ENVIRONMENT') in ('staging', 'development'): @@ -74,8 +75,8 @@ def _is_spammy_exception(e: Optional[Exception]) -> bool: def _get_metric_tags( - context: ExecutionContext, batchable_udf: Optional[BatchableUDFBase[Any, Any, Any]] = None -) -> List[str]: + context: ExecutionContext, batchable_udf: BatchableUDFBase[Any, Any, Any] | None = None +) -> list[str]: return [ f'action:{context.get_action_name()}', f'encoding:{context.get_data_encoding()}', @@ -91,9 +92,9 @@ def _get_metric_tags( def _record_udf_metric( - metric_tags: List[str], + metric_tags: list[str], execution_result: NodeResult, - caught_exception: Optional[Exception], + caught_exception: Exception | None, ) -> None: """Emit UDF execution metrics. Shared by sync and async paths.""" if execution_result.is_ok(): @@ -115,7 +116,7 @@ def _record_udf_metric( def _execute_sync( chain: DependencyChain, context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> NodeResult: """Execute a sync UDF inline. For pure computation only — no I/O.""" execution_result: NodeResult = Err(None) @@ -134,14 +135,14 @@ def _execute_sync( def _execute_legacy_sync( chain: DependencyChain, context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> NodeResult: """Execute a legacy sync UDF that has execute_async=True but is not AsyncUDFBase. Runs in a thread pool via run_in_executor. May fail if the UDF uses gevent primitives (no monkey patching), but errors are captured gracefully. """ - caught_exception: Optional[Exception] = None + caught_exception: Exception | None = None metric_tags = _get_metric_tags(context) if isinstance(chain.executor, CallExecutor): call_node: CallExecutor = chain.executor @@ -167,7 +168,7 @@ async def _execute_legacy_in_executor( semaphore: asyncio.Semaphore, chain: DependencyChain, context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> NodeResult: """Run a legacy sync UDF in the thread pool with semaphore.""" async with semaphore: @@ -179,7 +180,7 @@ def _execute_legacy_batch_sync( nodes: Sequence[ASTNode], batchable_args: Sequence[Any], context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> Sequence[NodeResult]: """Execute a batch of legacy sync batchable UDFs in thread pool.""" assert len(udfs) == len(nodes) == len(batchable_args) @@ -225,7 +226,7 @@ async def _execute_async_udf( semaphore: asyncio.Semaphore, chain: DependencyChain, context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> NodeResult: """Execute a native async UDF. Awaited directly on the event loop.""" async with semaphore: @@ -233,7 +234,7 @@ async def _execute_async_udf( udf: AsyncUDFBase[Any, Any] = call_executor._udf # type: ignore metric_tags = _get_metric_tags(context) + [f'udf:{udf.__class__.__name__}'] - caught_exception: Optional[Exception] = None + caught_exception: Exception | None = None execution_result: NodeResult = Err(None) try: resolved_arguments = udf.resolve_arguments(context, call_executor) @@ -256,7 +257,7 @@ async def _execute_async_batch( nodes: Sequence[ASTNode], batchable_args: Sequence[Any], context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> Sequence[NodeResult]: """Execute a batch of native async batchable UDFs.""" async with semaphore: @@ -317,15 +318,15 @@ async def _enqueue_batches( loop: asyncio.AbstractEventLoop, semaphore: asyncio.Semaphore, context: ExecutionContext, - error_infos: List[NodeErrorInfo], + error_infos: list[NodeErrorInfo], ready_async: Sequence[DependencyChain], -) -> Tuple[Sequence[DependencyChain], Dict[asyncio.Task[Sequence[NodeResult]], Sequence[DependencyChain]]]: +) -> tuple[Sequence[DependencyChain], dict[asyncio.Task[Sequence[NodeResult]], Sequence[DependencyChain]]]: """Collect batchable async chains and launch them as tasks. Returns (remaining non-batched chains, dict of batch tasks -> chains). """ - batch_chains: Dict[Tuple[type, str], List[Tuple[DependencyChain, Any]]] = defaultdict(list) - chains_to_remove: List[DependencyChain] = [] + batch_chains: dict[tuple[type, str], list[tuple[DependencyChain, Any]]] = defaultdict(list) + chains_to_remove: list[DependencyChain] = [] for async_chain in ready_async: if not isinstance(async_chain.executor, CallExecutor): @@ -347,7 +348,7 @@ async def _enqueue_batches( chains_to_remove.append(async_chain) context.set_resolved_value(async_chain, Err(None)) - new_batch_tasks: Dict[asyncio.Task[Sequence[NodeResult]], Sequence[DependencyChain]] = {} + new_batch_tasks: dict[asyncio.Task[Sequence[NodeResult]], Sequence[DependencyChain]] = {} for _, chains_and_args in batch_chains.items(): if len(chains_and_args) < 2: @@ -387,7 +388,7 @@ async def execute( action: Action, max_concurrent: int = _DEFAULT_MAX_ASYNC_PER_EXECUTION, sample_rate: int = 100, - parent_tracer_span: Optional[TracerSpan] = None, + parent_tracer_span: TracerSpan | None = None, ) -> ExecutionResult: """Async executor for the osprey rules engine. @@ -404,10 +405,10 @@ async def execute( allow_async = max_concurrent > 0 semaphore = asyncio.Semaphore(max_concurrent) loop = asyncio.get_running_loop() - error_infos: List[NodeErrorInfo] = [] + error_infos: list[NodeErrorInfo] = [] - in_progress_singlets: Dict[asyncio.Task[NodeResult], DependencyChain] = {} - in_progress_batches: Dict[asyncio.Task[Sequence[NodeResult]], Sequence[DependencyChain]] = {} + in_progress_singlets: dict[asyncio.Task[NodeResult], DependencyChain] = {} + in_progress_batches: dict[asyncio.Task[Sequence[NodeResult]], Sequence[DependencyChain]] = {} ready_sync, ready_async = _get_ready_sync_and_async(allow_async, context) @@ -418,7 +419,7 @@ async def execute( if not ready_sync and not ready_async and not finished_singlets and not finished_batches: # Block until at least one async task finishes - all_pending: Set[asyncio.Task[Any]] = set(in_progress_singlets.keys()) | set(in_progress_batches.keys()) + all_pending: set[asyncio.Task[Any]] = set(in_progress_singlets.keys()) | set(in_progress_batches.keys()) if all_pending: with tracer.start_span('osprey.rules.async_wait_nodes', child_of=parent_tracer_span): done, _ = await asyncio.wait(all_pending, return_when=asyncio.FIRST_COMPLETED) diff --git a/osprey_async_worker/src/osprey/async_worker/lib/coordinator_input_stream.py b/osprey_async_worker/src/osprey/async_worker/lib/coordinator_input_stream.py index 5061486..dc4056b 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/coordinator_input_stream.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/coordinator_input_stream.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import asyncio import json import random import time -from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Dict, Optional, Tuple, Union +from collections.abc import AsyncIterator, Callable +from typing import TYPE_CHECKING, Any import grpc import grpc.aio @@ -69,8 +72,8 @@ class GrpcConnectionDiscoveryPool: # (from_async_discovery), or None (from_static — no discovery). The async-only # methods (ensure_initialized) are only reached when _needs_async_init is True, # which is only set by from_async_discovery (AsyncServiceWatcher). - _service_watcher: Union['ServiceWatcher', AsyncServiceWatcher, None] - _handle_service_change_fn: Optional[Callable[[str, Service], None]] + _service_watcher: 'ServiceWatcher' | AsyncServiceWatcher | None + _handle_service_change_fn: Callable[[str, Service], None] | None def __init__(self, service_name: str) -> None: # Lazy import: Directory uses gevent-based service discovery. The async worker @@ -81,7 +84,7 @@ class GrpcConnectionDiscoveryPool: self._needs_async_init = False directory = Directory.instance(secure=False) - self._grpc_channels: Dict[Service, Tuple[grpc.aio.Channel, Service]] = { + self._grpc_channels: dict[Service, tuple[grpc.aio.Channel, Service]] = { service: (self._create_async_channel(service), service) for service in directory.select_all(self._service_name) } @@ -163,7 +166,7 @@ class GrpcConnectionDiscoveryPool: if self._grpc_channels.get(service): del self._grpc_channels[service] - async def get_connection(self) -> Tuple[grpc.aio.Channel, Service]: + async def get_connection(self) -> tuple[grpc.aio.Channel, Service]: """Gets an async gRPC channel to a coordinator instance. If no services are registered, polls with exponential backoff until one becomes available. @@ -204,10 +207,10 @@ class OspreyCoordinatorBiDirectionalStream: def __init__(self, client_id: str, channel: grpc.aio.Channel, service: Service) -> None: self._client_id = client_id - self._outgoing_queue: asyncio.Queue[Optional[Request]] = asyncio.Queue() + self._outgoing_queue: asyncio.Queue[Request | None] = asyncio.Queue() self._stub = OspreyCoordinatorServiceStub(channel=channel) self._tags = [f'coordinator_connection_address:{service.connection_address}'] - self._connect_time: Optional[float] = None + self._connect_time: float | None = None self._last_action_request_time: float = 0.0 self._stopped = False @@ -228,9 +231,7 @@ class OspreyCoordinatorBiDirectionalStream: async def _enqueue_stop_signal(self) -> None: await self._outgoing_queue.put(None) - async def send_graceful_disconnect( - self, ack_id: int, ack: bool = True, verdicts: Optional[Verdicts] = None - ) -> None: + async def send_graceful_disconnect(self, ack_id: int, ack: bool = True, verdicts: Verdicts | None = None) -> None: ack_or_nack = ( AckOrNack(ack_id=ack_id, ack=Ack(verdicts=verdicts if verdicts else None)) if ack @@ -241,7 +242,7 @@ class OspreyCoordinatorBiDirectionalStream: await self._outgoing_queue.put(Request(disconnect=Disconnect(ack_or_nack=ack_or_nack))) await self._enqueue_stop_signal() - def send_ack_or_nack(self, ack_id: int, ack: bool = True, verdicts: Optional[Verdicts] = None) -> None: + def send_ack_or_nack(self, ack_id: int, ack: bool = True, verdicts: Verdicts | None = None) -> None: """Fire-and-forget ack — uses put_nowait to match gevent's non-blocking Queue.put().""" ack_or_nack = ( AckOrNack(ack_id=ack_id, ack=Ack(verdicts=verdicts if verdicts else None)) @@ -310,12 +311,12 @@ class OspreyCoordinatorInputStream(AsyncBaseInputStream[BaseAckingContext[Osprey self, client_id: str, coordinator_service_name: str = 'osprey_coordinator', - input_stream_ready_signaler: Optional[AsyncInputStreamReadySignaler] = None, + input_stream_ready_signaler: AsyncInputStreamReadySignaler | None = None, ) -> None: self._client_id = client_id self._channel_pool = GrpcConnectionDiscoveryPool(coordinator_service_name) self._shutdown_event = asyncio.Event() - self._current_execution_result: Optional[ExecutionResult] = None + self._current_execution_result: ExecutionResult | None = None self._input_stream_ready_signaler = input_stream_ready_signaler @classmethod @@ -324,7 +325,7 @@ class OspreyCoordinatorInputStream(AsyncBaseInputStream[BaseAckingContext[Osprey client_id: str, address: str, service_name: str = 'osprey_coordinator', - input_stream_ready_signaler: Optional[AsyncInputStreamReadySignaler] = None, + input_stream_ready_signaler: AsyncInputStreamReadySignaler | None = None, ) -> 'OspreyCoordinatorInputStream': """Create an input stream connected directly to a coordinator address. @@ -343,7 +344,7 @@ class OspreyCoordinatorInputStream(AsyncBaseInputStream[BaseAckingContext[Osprey cls, client_id: str, service_name: str = 'osprey_coordinator', - input_stream_ready_signaler: Optional[AsyncInputStreamReadySignaler] = None, + input_stream_ready_signaler: AsyncInputStreamReadySignaler | None = None, ) -> 'OspreyCoordinatorInputStream': """Create an input stream using async etcd discovery (no gevent). @@ -367,11 +368,11 @@ class OspreyCoordinatorInputStream(AsyncBaseInputStream[BaseAckingContext[Osprey def _create_osprey_engine_action( self, osprey_coordinator_action: OspreyCoordinatorAction - ) -> Optional[OspreyEngineAction]: + ) -> OspreyEngineAction | None: try: tags = [f'action_name:{osprey_coordinator_action.action_name}'] - secret_data: Dict[str, Any] = {} + secret_data: dict[str, Any] = {} which_of_action_data = osprey_coordinator_action.WhichOneof('action_data') if which_of_action_data == 'json_action_data': info_log_osprey_action( diff --git a/osprey_async_worker/src/osprey/async_worker/lib/discovery/async_directory.py b/osprey_async_worker/src/osprey/async_worker/lib/discovery/async_directory.py index bf19373..a371542 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/discovery/async_directory.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/discovery/async_directory.py @@ -10,9 +10,11 @@ import asyncio import collections import json import logging +from collections import deque +from collections.abc import Callable from random import randint, uniform from time import time -from typing import Any, Callable, ClassVar, Deque, Dict, List, Optional, Tuple +from typing import Any, ClassVar from osprey.async_worker.lib.discovery.hash_ring import HashRing, HashRingNode from osprey.worker.lib import etcd @@ -43,10 +45,10 @@ class _AsyncHashRing: self._key = key self._default_num_replicas = default_num_replicas self._ring: HashRing = HashRing(default_num_replicas) - self._members: Dict[bytes, HashRingNode] = {} - self._overrides: Dict[Any, Any] = {} + self._members: dict[bytes, HashRingNode] = {} + self._overrides: dict[Any, Any] = {} self._initialized = False - self._watch_task: Optional[asyncio.Task[None]] = None + self._watch_task: asyncio.Task[None] | None = None async def ensure_initialized(self) -> None: if self._initialized: @@ -93,8 +95,8 @@ class _AsyncHashRing: def _update_from_value(self, value: str) -> None: data = json.loads(value) - members: List[HashRingNode] = [] - overrides: Dict[Any, Any] = {} + members: list[HashRingNode] = [] + overrides: dict[Any, Any] = {} if isinstance(data, list): members = self._read_members(data) @@ -108,7 +110,7 @@ class _AsyncHashRing: self._members = {m.name: m for m in members} self._overrides = overrides - def _read_members(self, raw: List[Any]) -> List[HashRingNode]: + def _read_members(self, raw: list[Any]) -> list[HashRingNode]: members = [] for item in raw: if isinstance(item, str): @@ -121,7 +123,7 @@ class _AsyncHashRing: return members @staticmethod - def _read_overrides(raw: List[Any]) -> Dict[Any, Any]: + def _read_overrides(raw: list[Any]) -> dict[Any, Any]: result = {} for items in raw: if len(items) >= 2: @@ -165,7 +167,7 @@ class _AsyncHashRing: class _ServiceWrapper: __slots__ = ('service', 'visible_at') - def __init__(self, service: Service, visible_at: Optional[float]) -> None: + def __init__(self, service: Service, visible_at: float | None) -> None: self.service = service self.visible_at = visible_at @@ -191,12 +193,12 @@ class AsyncServiceWatcher: self._etcd_client = etcd_client self._key = f'{base_key}/{service_name}/instances' self._service_name = service_name - self._instances: Dict[str, _ServiceWrapper] = {} - self._rotation: Deque[str] = collections.deque() + self._instances: dict[str, _ServiceWrapper] = {} + self._rotation: deque[str] = collections.deque() self._ring = _AsyncHashRing(etcd_client, f'{base_key}/{service_name}/ring') - self._listeners: List[ListenerFn] = [] + self._listeners: list[ListenerFn] = [] self._initialized = False - self._watch_task: Optional[asyncio.Task[None]] = None + self._watch_task: asyncio.Task[None] | None = None async def ensure_initialized(self) -> None: if self._initialized: @@ -259,7 +261,7 @@ class AsyncServiceWatcher: f'instances={list(self._instances.keys())}' ) - def select_all(self, tolerate_draining: bool = False) -> List[Service]: + def select_all(self, tolerate_draining: bool = False) -> list[Service]: services = [] for service_id in self._rotation: wrapper = self._instances[service_id] @@ -354,7 +356,7 @@ class AsyncDirectory: Uses the sync EtcdClient via run_in_executor for etcd reads. """ - _instances: ClassVar[Dict[Tuple[Any, ...], 'AsyncDirectory']] = {} + _instances: ClassVar[dict[tuple[Any, ...], 'AsyncDirectory']] = {} @classmethod def instance(cls, secure: bool = False) -> 'AsyncDirectory': @@ -366,14 +368,14 @@ class AsyncDirectory: def __init__(self, base_key: str = '/discovery', secure: bool = False) -> None: self._base_key = base_key self._etcd_client = EtcdClient(secure=secure) - self._watchers: Dict[str, AsyncServiceWatcher] = {} + self._watchers: dict[str, AsyncServiceWatcher] = {} def get_watcher(self, service_name: str) -> AsyncServiceWatcher: if service_name not in self._watchers: self._watchers[service_name] = AsyncServiceWatcher(self._etcd_client, self._base_key, service_name) return self._watchers[service_name] - def select_all(self, service_name: str) -> List[Service]: + def select_all(self, service_name: str) -> list[Service]: watcher = self.get_watcher(service_name) return watcher.select_all() diff --git a/osprey_async_worker/src/osprey/async_worker/lib/discovery/hash_ring.py b/osprey_async_worker/src/osprey/async_worker/lib/discovery/hash_ring.py index d2434ba..26912c5 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/discovery/hash_ring.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/discovery/hash_ring.py @@ -6,8 +6,8 @@ discovery layer relies on: - ``HashRingNode(name: bytes, num_replicas: int)`` with ``.name`` / ``.num_replicas`` - ``HashRing(default_num_replicas).add_nodes([...])`` - - ``HashRing.find_node(key: bytes) -> Optional[bytes]`` (the node *name*) - - ``HashRing.find_nodes(key: bytes, count: int) -> List[bytes]`` (distinct names) + - ``HashRing.find_node(key: bytes) -> bytes | None`` (the node *name*) + - ``HashRing.find_nodes(key: bytes, count: int) -> list[bytes]`` (distinct names) Placement is deterministic (MD5 over ``:`` virtual points) so every worker computes the same ring for the same membership. Exact placement is an @@ -18,7 +18,7 @@ from __future__ import annotations import bisect import hashlib -from typing import Dict, List, Optional, Sequence, Set +from collections.abc import Sequence class HashRingNode: @@ -37,9 +37,9 @@ def _hash(data: bytes) -> int: class HashRing: def __init__(self, default_num_replicas: int = 512) -> None: self._default_num_replicas = default_num_replicas - self._points: List[int] = [] # sorted virtual-point hashes - self._owner: Dict[int, bytes] = {} # point hash -> node name - self._names: Set[bytes] = set() + self._points: list[int] = [] # sorted virtual-point hashes + self._owner: dict[int, bytes] = {} # point hash -> node name + self._names: set[bytes] = set() def add_node(self, node: HashRingNode) -> None: if node.name in self._names: @@ -57,19 +57,19 @@ class HashRing: for node in nodes: self.add_node(node) - def find_node(self, key: bytes) -> Optional[bytes]: + def find_node(self, key: bytes) -> bytes | None: if not self._points: return None idx = bisect.bisect(self._points, _hash(key)) % len(self._points) return self._owner[self._points[idx]] - def find_nodes(self, key: bytes, count: int) -> List[bytes]: + def find_nodes(self, key: bytes, count: int) -> list[bytes]: if not self._points or count <= 0: return [] start = bisect.bisect(self._points, _hash(key)) total = len(self._points) - result: List[bytes] = [] - seen: Set[bytes] = set() + result: list[bytes] = [] + seen: set[bytes] = set() for offset in range(total): name = self._owner[self._points[(start + offset) % total]] if name not in seen: diff --git a/osprey_async_worker/src/osprey/async_worker/lib/etcd/sources_provider.py b/osprey_async_worker/src/osprey/async_worker/lib/etcd/sources_provider.py index 7ea59ce..d004874 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/etcd/sources_provider.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/etcd/sources_provider.py @@ -11,7 +11,8 @@ import inspect import json import logging import random -from typing import Any, Awaitable, Callable, Dict, Iterator, Optional, Union +from collections.abc import Awaitable, Callable, Iterator +from typing import Any from osprey.engine.ast.sources import Sources from osprey.worker.lib.etcd import BaseWatcher, EtcdClient, FullSyncOne, FullSyncOneNoKey @@ -20,7 +21,7 @@ from osprey.worker.lib.sources_provider_base import BaseSourcesProvider # The async engine's _handle_updated_sources is a coroutine function so the # compile can run in a thread pool while the event loop continues servicing # in-flight tasks. We accept either a sync or async callable for back-compat. -SourcesWatcherCallback = Callable[[], Union[None, Awaitable[None]]] +SourcesWatcherCallback = Callable[[], Awaitable[None] | None] class AsyncInputStreamReadySignaler: @@ -63,29 +64,29 @@ class AsyncEtcdSourcesProvider(BaseSourcesProvider): def __init__( self, etcd_key: str, - etcd_client: Optional[EtcdClient] = None, - input_stream_ready_signaler: Optional[AsyncInputStreamReadySignaler] = None, + etcd_client: EtcdClient | None = None, + input_stream_ready_signaler: AsyncInputStreamReadySignaler | None = None, ): self._etcd_key = etcd_key self._client = etcd_client or EtcdClient() - self._current_sources: Optional[Sources] = None + self._current_sources: Sources | None = None # The hash the engine has actually compiled and swapped in. Dedup keys off # this (not the last *received* sources) so a failed/dropped compile leaves # it behind and the next identical etcd re-delivery re-fires the recompile # instead of being suppressed (which would wedge the worker on stale rules). # Advanced only from mark_sources_applied(); seeded None so every event # before the first successful apply triggers a compile attempt. - self._applied_sources_hash: Optional[str] = None - self._sources_watcher_callback: Optional[SourcesWatcherCallback] = None + self._applied_sources_hash: str | None = None + self._sources_watcher_callback: SourcesWatcherCallback | None = None self._input_stream_ready_signaler = input_stream_ready_signaler - self._watcher: Optional[BaseWatcher] = None + self._watcher: BaseWatcher | None = None # Long-lived iterator over the watcher's event stream. continue_watching() # is a generator function — every call creates a new generator with a # fresh WatchMux and a reset _index, which defeats the watcher's built-in # dedup of redundant FullSyncOne events. Iterate one generator persistently # to match how ReadOnlyEtcdDict drives the gevent watcher. - self._watcher_iter: Optional[Iterator[Any]] = None - self._watcher_task: Optional[asyncio.Task[None]] = None + self._watcher_iter: Iterator[Any] | None = None + self._watcher_task: asyncio.Task[None] | None = None async def start(self) -> None: """Initialize sources from etcd and start watching for changes.""" @@ -98,14 +99,14 @@ class AsyncEtcdSourcesProvider(BaseSourcesProvider): # Start watcher loop as an async task self._watcher_task = asyncio.create_task(self._watch_loop()) - def _load_initial(self) -> Dict[str, str]: + def _load_initial(self) -> dict[str, str]: """Load initial sources from etcd. Runs in thread pool.""" watcher = self._client.get_watcher(self._etcd_key, recursive=False) initial_event = watcher.begin_watching() self._watcher = watcher return self._parse_event(initial_event) - def _parse_event(self, event) -> Dict[str, str]: + def _parse_event(self, event) -> dict[str, str]: """Parse an etcd event into a sources dict.""" if isinstance(event, FullSyncOne): return json.loads(str(event.value)) @@ -194,7 +195,7 @@ class AsyncEtcdSourcesProvider(BaseSourcesProvider): # test_provider_get_current_sources_default_none). Widening the base return type # to Optional[Sources] is the correct fix but lives in sources_provider_base.py # (a shared file outside this change). Keep the precise return type here. - def get_current_sources(self) -> Optional[Sources]: # type: ignore[override] + def get_current_sources(self) -> Sources | None: # type: ignore[override] return self._current_sources def mark_sources_applied(self, sources_hash: str) -> None: diff --git a/osprey_async_worker/src/osprey/async_worker/lib/external_service.py b/osprey_async_worker/src/osprey/async_worker/lib/external_service.py index 93f8f59..7f4c913 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/external_service.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/external_service.py @@ -6,8 +6,9 @@ Uses asyncio.Future instead of gevent.event.AsyncResult for cache entries. import asyncio from abc import ABC, abstractmethod +from collections.abc import Sequence from datetime import datetime, timedelta -from typing import Dict, Generic, Hashable, Optional, Sequence, Tuple, TypeVar, cast +from typing import Generic, Hashable, TypeVar, cast from result import Err, Ok, Result @@ -24,7 +25,7 @@ class AsyncExternalService(ABC, Generic[KeyT, ValueT]): async def batch_get_from_service(self, keys: Sequence[KeyT]) -> Sequence[Result[ValueT, Exception]]: raise NotImplementedError - def cache_ttl(self) -> Optional[timedelta]: + def cache_ttl(self) -> timedelta | None: """ Returns a time to live for items in the cache. By default, KVs are cached indefinitely. @@ -55,9 +56,9 @@ class ExternalServiceAccessor(Generic[KeyT, ValueT]): def __init__(self, service: AsyncExternalService[KeyT, ValueT]): self._service = service # Key -> Tuple[ Future[ValueT], Expiration datetime ] - self._cache: Dict[KeyT, Tuple[asyncio.Future[ValueT], Optional[datetime]]] = {} + self._cache: dict[KeyT, tuple[asyncio.Future[ValueT], datetime | None]] = {} - def _is_past_cache_expiration(self, cache_expiration: Optional[datetime]) -> bool: + def _is_past_cache_expiration(self, cache_expiration: datetime | None) -> bool: """ Helper method to perform a time check on an optional datetime. """ @@ -65,7 +66,7 @@ class ExternalServiceAccessor(Generic[KeyT, ValueT]): return False return datetime.now() > cache_expiration - def _get_cache_expiration_datetime(self) -> Optional[datetime]: + def _get_cache_expiration_datetime(self) -> datetime | None: """ Helper method to generate an optional cache expiration datetime based on the cache TTL. """ @@ -82,7 +83,7 @@ class ExternalServiceAccessor(Generic[KeyT, ValueT]): The new value is then used to update the cache entry for subsequent `get` calls. """ future: asyncio.Future[ValueT] = self._make_future() - cache_entry: Tuple[asyncio.Future[ValueT], Optional[datetime]] = ( + cache_entry: tuple[asyncio.Future[ValueT], datetime | None] = ( future, self._get_cache_expiration_datetime(), ) diff --git a/osprey_async_worker/src/osprey/async_worker/lib/pigeon/client.py b/osprey_async_worker/src/osprey/async_worker/lib/pigeon/client.py index 55d7b8c..69d46e5 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/pigeon/client.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/pigeon/client.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import asyncio import copy import itertools @@ -7,7 +9,7 @@ from collections import defaultdict from collections.abc import Mapping from dataclasses import dataclass from time import time_ns -from typing import Any, Dict, Generic, List, Optional, Set, Tuple, Type, TypeVar, Union, cast +from typing import Any, Generic, TypeVar, cast import grpc import grpc.aio @@ -38,7 +40,7 @@ DOWN = 'down' class ServiceDefinition(TypedDict): address: str - ip: Optional[str] + ip: str | None port: int @@ -85,7 +87,7 @@ class RoutedClient(Generic[T]): self, service_name, read_timeout, - stub_cls: Type[T], + stub_cls: type[T], request_field=None, request_field_routing_value_transform=None, routing_type=RoutingType.CHUNKED, @@ -99,18 +101,18 @@ class RoutedClient(Generic[T]): acceptable_duration_ms=None, baggage_header=None, baggage=None, - envoy_endpoint: Optional[ServiceDefinition] = None, + envoy_endpoint: ServiceDefinition | None = None, use_peer_service_name=False, - default_retry_policy: Optional['RetryPolicy'] = None, + default_retry_policy: 'RetryPolicy' | None = None, ): self._service_name = service_name self._peer_service = f'{service_name}-client' if use_peer_service_name else service_name - self._stub_cls: Type[T] = stub_cls + self._stub_cls: type[T] = stub_cls self._request_field = request_field self._request_field_routing_value_transform = request_field_routing_value_transform self._routing_type = routing_type - self._open_channels: Dict[Tuple[Tuple[str, Optional[str]], int], weakref.ReferenceType[grpc.aio.Channel]] = {} - self._clients: Dict[Tuple[Tuple[str, Optional[str]], int], T] = {} + self._open_channels: dict[tuple[tuple[str, str | None], int], weakref.ReferenceType[grpc.aio.Channel]] = {} + self._clients: dict[tuple[tuple[str, str | None], int], T] = {} self._secondaries = secondaries self._chunk_size = chunk_size self._semaphore = asyncio.Semaphore(pool_size) @@ -118,9 +120,9 @@ class RoutedClient(Generic[T]): grpc_options = {'grpc.keepalive_time_ms': 300_000, **(grpc_options or dict())} self._grpc_options = list(grpc_options.items()) self._connect_eagerly = False - self._acceptable_duration_ms: Optional[int] = acceptable_duration_ms - self._default_retry_policy: Optional['RetryPolicy'] = default_retry_policy - self._interceptors: List[Any] = [BaggageInterceptor(baggage_header=baggage_header, baggage=baggage)] + self._acceptable_duration_ms: int | None = acceptable_duration_ms + self._default_retry_policy: 'RetryPolicy' | None = default_retry_policy + self._interceptors: list[Any] = [BaggageInterceptor(baggage_header=baggage_header, baggage=baggage)] if metadata: self._interceptors.append(MetadataInterceptor(metadata)) @@ -150,7 +152,7 @@ class RoutedClient(Generic[T]): return AsyncUnaryUnaryRpcCallable(service_name=self._service_name, method_name=method_name, client=self) @property - def acceptable_duration_ms(self) -> Optional[int]: + def acceptable_duration_ms(self) -> int | None: return self._acceptable_duration_ms async def _ensure_watcher_initialized(self) -> None: @@ -179,10 +181,10 @@ class RoutedClient(Generic[T]): self, method_name: str, message: Message, - request_field: Optional[str] = None, - routing_type: Optional[int] = None, - timeout: Optional[float] = None, - metadata: Optional[List[Tuple[str, str]]] = None, + request_field: str | None = None, + routing_type: int | None = None, + timeout: float | None = None, + metadata: list[tuple[str, str]] | None = None, instances_to_skip: int = 0, ): await self._ensure_watcher_initialized() @@ -212,8 +214,8 @@ class RoutedClient(Generic[T]): method_name: str, message: Message, request_field: str, - timeout: Optional[float] = None, - metadata: Optional[List[Tuple[str, str]]] = None, + timeout: float | None = None, + metadata: list[tuple[str, str]] | None = None, ): """Call a remote service concurrently. Route based on a routing key.""" calls = self._generate_routed_calls(request_field, message) @@ -252,8 +254,8 @@ class RoutedClient(Generic[T]): message: Message, request_field: str, routing_type: int, - timeout: Optional[float] = None, - metadata: Optional[List[Tuple[str, str]]] = None, + timeout: float | None = None, + metadata: list[tuple[str, str]] | None = None, instances_to_skip: int = 0, ): """Request from a remote service.""" @@ -267,10 +269,10 @@ class RoutedClient(Generic[T]): method_name: str, message_template: Message, request_field: str, - timeout: Optional[float], - metadata: Optional[List[Tuple[str, str]]], + timeout: float | None, + metadata: list[tuple[str, str]] | None, service_and_routing_values, - ) -> Optional[Message]: + ) -> Message | None: """Request from remote service.""" (service, routing_values) = service_and_routing_values with maybe_start_span('pigeon.routed_request', self._peer_service, method_name): @@ -365,7 +367,7 @@ class RoutedClient(Generic[T]): del self._clients[service_key] @staticmethod - def _get_service_key(service: Service) -> Tuple[Tuple[str, Optional[str]], int]: + def _get_service_key(service: Service) -> tuple[tuple[str, str | None], int]: return (service.connection_key, service.grpc_port) def _get_client(self, service: Service) -> T: @@ -394,8 +396,8 @@ class RoutedClient(Generic[T]): def _make_message( message_template: Message, request_field: str, - routing_values: Union[List[Any], Dict[Any, Any]], - routing_values_chunk: List[Any], + routing_values: list[Any] | dict[Any, Any], + routing_values_chunk: list[Any], ): message = copy.copy(message_template) field = getattr(message, request_field) @@ -416,7 +418,7 @@ Response = TypeVar('Response') class RetryPolicy(TypedDict): - retryable_grpc_status_codes: Set[grpc.StatusCode] + retryable_grpc_status_codes: set[grpc.StatusCode] max_secondaries_to_retry: int @@ -429,12 +431,12 @@ class AsyncUnaryUnaryRpcCallable(Generic[T, Request, Response]): async def __call__( self, message: Request, - request_field: Optional[str] = None, - routing_type: Optional[int] = None, - timeout: Optional[float] = None, - acceptable_duration_ms: Optional[int] = None, - metadata: Optional[List[Tuple[str, str]]] = None, - retry_policy: Optional[RetryPolicy] = None, + request_field: str | None = None, + routing_type: int | None = None, + timeout: float | None = None, + acceptable_duration_ms: int | None = None, + metadata: list[tuple[str, str]] | None = None, + retry_policy: RetryPolicy | None = None, ) -> Response: retry_policy = retry_policy or self.client._default_retry_policy try_count = 0 @@ -480,11 +482,11 @@ class AsyncUnaryUnaryRpcCallable(Generic[T, Request, Response]): async def request( self, message: Request, - request_field: Optional[str] = None, - routing_type: Optional[int] = None, - timeout: Optional[float] = None, - acceptable_duration_ms: Optional[int] = None, - metadata: Optional[List[Tuple[str, str]]] = None, + request_field: str | None = None, + routing_type: int | None = None, + timeout: float | None = None, + acceptable_duration_ms: int | None = None, + metadata: list[tuple[str, str]] | None = None, instances_to_skip: int = 0, ) -> Response: pb2_message = self._to_proto(message) diff --git a/osprey_async_worker/src/osprey/async_worker/lib/pigeon/exceptions.py b/osprey_async_worker/src/osprey/async_worker/lib/pigeon/exceptions.py index 5274c8e..b229d60 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/pigeon/exceptions.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/pigeon/exceptions.py @@ -1,4 +1,4 @@ -from typing import Optional, cast +from typing import cast import grpc @@ -58,7 +58,7 @@ class RPCException(PigeonException, grpc.RpcError, grpc.Call): # type: ignore[m def is_active(self) -> bool: return cast(bool, self.inner.is_active()) - def time_remaining(self) -> Optional[float]: + def time_remaining(self) -> float | None: return self.inner.time_remaining() def cancel(self): diff --git a/osprey_async_worker/src/osprey/async_worker/lib/pigeon/interceptors/baggage.py b/osprey_async_worker/src/osprey/async_worker/lib/pigeon/interceptors/baggage.py index 99ceb05..fa80500 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/pigeon/interceptors/baggage.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/pigeon/interceptors/baggage.py @@ -1,5 +1,4 @@ import collections -from typing import Dict, Optional import grpc from osprey.worker.lib.ddtrace_utils import ( @@ -31,7 +30,7 @@ class BaggageInterceptor( https://opentelemetry.io/docs/reference/specification/baggage/api/ """ - def __init__(self, baggage_header: Optional[str] = None, baggage: Optional[Dict[str, str]] = None): + def __init__(self, baggage_header: str | None = None, baggage: dict[str, str] | None = None): self._baggage_header = baggage_header or BAGGAGE_HEADER self._baggage = baggage or {} diff --git a/osprey_async_worker/src/osprey/async_worker/lib/publisher.py b/osprey_async_worker/src/osprey/async_worker/lib/publisher.py index f6ebb2f..9b1e641 100644 --- a/osprey_async_worker/src/osprey/async_worker/lib/publisher.py +++ b/osprey_async_worker/src/osprey/async_worker/lib/publisher.py @@ -6,7 +6,6 @@ flushing. No threading locks, no gevent, no background threads. import asyncio import logging -from typing import List, Optional from google.api_core.retry import Retry from google.cloud import pubsub_v1 @@ -46,7 +45,7 @@ class AsyncPubSubPublisher: self._queue: asyncio.Queue[bytes] = asyncio.Queue() self._max_messages = max_messages self._max_latency = max_latency_seconds - self._flush_task: Optional[asyncio.Task[None]] = None + self._flush_task: asyncio.Task[None] | None = None self._started = False self._metric_tags = [f'project:{project_id}', f'topic:{topic_id}'] @@ -66,7 +65,7 @@ class AsyncPubSubPublisher: """Background task that flushes the buffer periodically.""" while True: try: - batch: List[bytes] = [] + batch: list[bytes] = [] # Wait for first message or timeout try: @@ -88,7 +87,7 @@ class AsyncPubSubPublisher: except asyncio.CancelledError: # Flush remaining on shutdown - remaining: List[bytes] = [] + remaining: list[bytes] = [] while not self._queue.empty(): try: remaining.append(self._queue.get_nowait()) @@ -100,12 +99,12 @@ class AsyncPubSubPublisher: except Exception: logger.exception('Error in flush loop') - async def _flush_batch(self, batch: List[bytes]) -> None: + async def _flush_batch(self, batch: list[bytes]) -> None: """Publish a batch of messages. Runs sync publishes in executor.""" loop = asyncio.get_running_loop() await loop.run_in_executor(None, self._sync_flush, batch) - def _sync_flush(self, batch: List[bytes]) -> None: + def _sync_flush(self, batch: list[bytes]) -> None: """Synchronous batch publish.""" futures = [] for data in batch: diff --git a/osprey_async_worker/src/osprey/async_worker/sinks/sink/rules_sink.py b/osprey_async_worker/src/osprey/async_worker/sinks/sink/rules_sink.py index fc72e9d..22f97a9 100644 --- a/osprey_async_worker/src/osprey/async_worker/sinks/sink/rules_sink.py +++ b/osprey_async_worker/src/osprey/async_worker/sinks/sink/rules_sink.py @@ -4,7 +4,6 @@ import asyncio import logging from dataclasses import dataclass from random import randint -from typing import Optional import sentry_sdk from ddtrace import tracer @@ -74,8 +73,8 @@ class AsyncRulesRunner: self, action: Action, tag: str, - parent_tracer_span: Optional[TracerSpan] = None, - ) -> Optional[ExecutionResult]: + parent_tracer_span: TracerSpan | None = None, + ) -> ExecutionResult | None: sample_config = self._sampler.sample(action) tags = [ tag, @@ -88,7 +87,7 @@ class AsyncRulesRunner: metrics.increment('dropped_message', tags=tags) return None - result: Optional[ExecutionResult] = None + result: ExecutionResult | None = None try: with metrics.timed('handled_message', tags=tags, use_ms=True): result = await async_execute( diff --git a/osprey_async_worker/src/osprey/async_worker/stdlib_udfs/async_mx_lookup.py b/osprey_async_worker/src/osprey/async_worker/stdlib_udfs/async_mx_lookup.py index 666c835..3ff9ca8 100644 --- a/osprey_async_worker/src/osprey/async_worker/stdlib_udfs/async_mx_lookup.py +++ b/osprey_async_worker/src/osprey/async_worker/stdlib_udfs/async_mx_lookup.py @@ -8,7 +8,6 @@ Class named `MXLookup` to shadow the sync version in the UDF registry. """ import asyncio -from typing import Optional import aiodns import pycares @@ -18,7 +17,7 @@ from osprey.engine.stdlib.udfs.mx_lookup import Arguments from osprey.engine.stdlib.udfs.mx_lookup import MXLookup as SyncMXLookup _DNS_TIMEOUT = 5.0 -_resolver: Optional[aiodns.DNSResolver] = None +_resolver: aiodns.DNSResolver | None = None def _get_resolver() -> aiodns.DNSResolver: diff --git a/osprey_async_worker/src/osprey/async_worker/tests/conftest.py b/osprey_async_worker/src/osprey/async_worker/tests/conftest.py index 071836c..2ce36a1 100644 --- a/osprey_async_worker/src/osprey/async_worker/tests/conftest.py +++ b/osprey_async_worker/src/osprey/async_worker/tests/conftest.py @@ -6,7 +6,6 @@ using the async executor instead of the gevent one. from datetime import datetime from textwrap import dedent -from typing import Dict, Optional, Union import pytest from osprey.async_worker.executor import execute as async_execute @@ -21,7 +20,7 @@ from osprey.engine.stdlib import get_config_registry from osprey.engine.udf.registry import UDFRegistry from osprey.worker.lib.singletons import CONFIG -SourcesDict = Union[Sources, str, Dict[str, str]] +SourcesDict = Sources | str | dict[str, str] def _into_sources(sources_dict: SourcesDict) -> Sources: @@ -61,13 +60,13 @@ def async_execute_with_result(stdlib_udf_registry: UDFRegistry): async def _execute( sources_dict: SourcesDict, - data: Optional[Dict[str, object]] = None, + data: dict[str, object] | None = None, action_name: str = 'test', action_id: int = 1, - udf_helpers: Optional[UDFHelpers] = None, - udf_registry: Optional[UDFRegistry] = None, + udf_helpers: UDFHelpers | None = None, + udf_registry: UDFRegistry | None = None, max_concurrent: int = 12, - action_time: Optional[datetime] = None, + action_time: datetime | None = None, ) -> ExecutionResult: registry = udf_registry or stdlib_udf_registry sources = _into_sources(sources_dict) @@ -99,14 +98,14 @@ def async_execute_fn(async_execute_with_result): async def _execute( sources_dict: SourcesDict, - data: Optional[Dict[str, object]] = None, + data: dict[str, object] | None = None, action_name: str = 'test', action_id: int = 1, - udf_helpers: Optional[UDFHelpers] = None, - udf_registry: Optional[UDFRegistry] = None, + udf_helpers: UDFHelpers | None = None, + udf_registry: UDFRegistry | None = None, max_concurrent: int = 12, allow_errors: bool = False, - ) -> Dict[str, object]: + ) -> dict[str, object]: result = await async_execute_with_result( sources_dict=sources_dict, data=data, diff --git a/osprey_async_worker/src/osprey/async_worker/tests/test_external_service.py b/osprey_async_worker/src/osprey/async_worker/tests/test_external_service.py index 26e2ccd..5c553f1 100644 --- a/osprey_async_worker/src/osprey/async_worker/tests/test_external_service.py +++ b/osprey_async_worker/src/osprey/async_worker/tests/test_external_service.py @@ -1,8 +1,8 @@ """Tests for the async external service cache.""" import asyncio +from collections.abc import Sequence from datetime import timedelta -from typing import Optional, Sequence import pytest from osprey.async_worker.lib.external_service import AsyncExternalService, ExternalServiceAccessor @@ -30,7 +30,7 @@ class FailingService(AsyncExternalService[str, str]): raise ValueError(f'service error for {key}') -class FailOnceService(AsyncExternalService[str, Optional[str]]): +class FailOnceService(AsyncExternalService[str, str | None]): """Raises on first call per key, succeeds after.""" def __init__(self): @@ -39,7 +39,7 @@ class FailOnceService(AsyncExternalService[str, Optional[str]]): def count_error_once(self) -> bool: return True - async def get_from_service(self, key: str) -> Optional[str]: + async def get_from_service(self, key: str) -> str | None: if key not in self.seen: self.seen.add(key) raise ValueError('first call fails') @@ -51,7 +51,7 @@ class TTLService(AsyncExternalService[str, str]): self._ttl = ttl self.call_count = 0 - def cache_ttl(self) -> Optional[timedelta]: + def cache_ttl(self) -> timedelta | None: return self._ttl async def get_from_service(self, key: str) -> str: diff --git a/osprey_ui/eslint.config.mjs b/osprey_ui/eslint.config.mjs index 3480441..f46ed9a 100644 --- a/osprey_ui/eslint.config.mjs +++ b/osprey_ui/eslint.config.mjs @@ -1,22 +1,22 @@ -import globals from "globals"; -import js from "@eslint/js"; -import tseslint from "typescript-eslint"; -import react from "eslint-plugin-react"; -import reactHooks from "eslint-plugin-react-hooks"; -import jsxA11y from "eslint-plugin-jsx-a11y"; +import globals from 'globals'; +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import react from 'eslint-plugin-react'; +import reactHooks from 'eslint-plugin-react-hooks'; +import jsxA11y from 'eslint-plugin-jsx-a11y'; export default [ { - ignores: ["build/", "node_modules/", "public/", "coverage/"], + ignores: ['build/', 'node_modules/', 'public/', 'coverage/'], }, js.configs.recommended, ...tseslint.configs.recommended, react.configs.flat.recommended, - react.configs.flat["jsx-runtime"], + react.configs.flat['jsx-runtime'], reactHooks.configs.flat.recommended, jsxA11y.flatConfigs.recommended, { - files: ["**/*.{js,jsx,ts,tsx}"], + files: ['**/*.{js,jsx,ts,tsx}'], languageOptions: { globals: { ...globals.browser, @@ -24,20 +24,20 @@ export default [ }, parserOptions: { ecmaVersion: 2024, - sourceType: "module", + sourceType: 'module', ecmaFeatures: { jsx: true }, }, }, settings: { - react: { version: "detect" }, + react: { version: 'detect' }, }, rules: { - "@typescript-eslint/no-unused-vars": [ - "error", + '@typescript-eslint/no-unused-vars': [ + 'error', { - argsIgnorePattern: "^_", - varsIgnorePattern: "^_", - caughtErrorsIgnorePattern: "^_", + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', }, ], }, diff --git a/osprey_worker/Dockerfile b/osprey_worker/Dockerfile index 725f081..afaa68d 100644 --- a/osprey_worker/Dockerfile +++ b/osprey_worker/Dockerfile @@ -50,7 +50,7 @@ RUN mkdir -p /osprey/osprey_worker /osprey/osprey_rpc /osprey/example_plugins/sr # image, so the gevent worker stays free of it (osprey.async_worker is not importable # here, so execution_context's optional async import cleanly falls back to None). RUN pip install --upgrade pip uv && \ - uv sync --locked --no-install-package osprey-async-worker --python=$(which python3.11) && \ + uv sync --frozen --no-install-package osprey-async-worker --python=$(which python3.11) && \ pip cache purge && uv cache clean # https://tld.readthedocs.io/en/latest/#update-the-list-of-tld-names diff --git a/osprey_worker/src/osprey/engine/ast/ast_utils.py b/osprey_worker/src/osprey/engine/ast/ast_utils.py index 443865b..54dda33 100644 --- a/osprey_worker/src/osprey/engine/ast/ast_utils.py +++ b/osprey_worker/src/osprey/engine/ast/ast_utils.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import copy -from typing import Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union +from collections.abc import Callable, Iterator, Sequence +from typing import Any, Type, TypeVar # from osprey.engine.utils.periodic_execution_yielder import maybe_periodic_yield from .grammar import ASTNode, Root, Statement @@ -26,7 +29,7 @@ def iter_fields(node: 'ASTNode') -> Iterator[str]: traverse_mro(node.__class__) - seen_fields: Set[str] = set() + seen_fields: set[str] = set() for klass in ordered_mro: for field in getattr(klass, '__annotations__', ()): @@ -39,11 +42,11 @@ def iter_fields(node: 'ASTNode') -> Iterator[str]: def _make_memoized_field_values_iterator() -> Callable[ - ['ASTNode'], Iterator[Tuple[str, Union['ASTNode', Sequence['ASTNode']]]] + ['ASTNode'], Iterator[tuple[str, 'ASTNode' | Sequence['ASTNode']]] ]: - _field_cache: Dict[Type['ASTNode'], List[str]] = {} + _field_cache: dict[Type['ASTNode'], list[str]] = {} - def _iter_field_values(node: ASTNode) -> Iterator[Tuple[str, Union['ASTNode', Sequence['ASTNode']]]]: + def _iter_field_values(node: ASTNode) -> Iterator[tuple[str, 'ASTNode' | Sequence['ASTNode']]]: # To avoid the cost of iterating fields over known node classes, # perform simple memoization. @@ -87,7 +90,7 @@ def iter_nodes(root: 'ASTNode') -> Iterator['ASTNode']: return _iter_inner(root) -def filter_nodes(root: 'ASTNode', ty: Type[T], filter_fn: Optional[Callable[[T], bool]] = None) -> Iterator[T]: +def filter_nodes(root: 'ASTNode', ty: Type[T], filter_fn: Callable[[T], bool] | None = None) -> Iterator[T]: """Given a root, iterate over nodes, filtering out those who's type do not match the given `ty`. diff --git a/osprey_worker/src/osprey/engine/ast/error_utils.py b/osprey_worker/src/osprey/engine/ast/error_utils.py index ca2d13a..ca01999 100644 --- a/osprey_worker/src/osprey/engine/ast/error_utils.py +++ b/osprey_worker/src/osprey/engine/ast/error_utils.py @@ -1,6 +1,6 @@ import math +from collections.abc import Sequence from dataclasses import dataclass -from typing import Optional, Sequence, Union from osprey.engine.utils.types import add_slots @@ -38,7 +38,7 @@ def render_span_context_with_message( span: Span, hint: str = '', additional_spans_message: str = '', - additional_spans: Sequence[Union[Span, SpanWithHint]] = tuple(), + additional_spans: Sequence[Span | SpanWithHint] = tuple(), message_type: str = 'error', ) -> str: """Given a span, a message, and a hint, print out a human readable error @@ -71,7 +71,7 @@ def render_span_context_with_message( # TODO: Colors?! parts = [f'{message_type}: {_assert_valid_message(message)}'] - def append_span(span_: Span, hint_: str, num_prefix: Optional[int] = None) -> None: + def append_span(span_: Span, hint_: str, num_prefix: int | None = None) -> None: if num_prefix: num_prefix_str = f'({num_prefix}) ' else: diff --git a/osprey_worker/src/osprey/engine/ast/grammar.py b/osprey_worker/src/osprey/engine/ast/grammar.py index 88ec69d..6db8366 100644 --- a/osprey_worker/src/osprey/engine/ast/grammar.py +++ b/osprey_worker/src/osprey/engine/ast/grammar.py @@ -1,11 +1,12 @@ from __future__ import annotations from collections import defaultdict +from collections.abc import Sequence from dataclasses import dataclass, field, replace from enum import Enum from pathlib import Path from threading import Lock -from typing import ClassVar, Dict, Optional, Sequence, TypeVar, Union +from typing import ClassVar, TypeVar # TODO: Uncomment logging when we have a logging system # from osprey.worker.ui_api.lib.osprey_shared.logging import get_logger @@ -14,8 +15,8 @@ from osprey.engine.utils.types import add_slots, cached_property # Keep these outside `Source` so we don't break pickling/hashing/eq # Will this leak memory? Maybe # TODO(old): put this stuff back in cached_property -parsed_ast_root_cache: Dict['Source', 'Root'] = {} -ast_root_lock_cache: Dict['Source', Lock] = defaultdict(Lock) +parsed_ast_root_cache: dict['Source', 'Root'] = {} +ast_root_lock_cache: dict['Source', Lock] = defaultdict(Lock) # logger = get_logger() @@ -34,7 +35,7 @@ class Source: """The contents of the source file. """ - actual_path: Optional[Path] = field(default=None, compare=False) + actual_path: Path | None = field(default=None, compare=False) """If the source file was loaded from disk, rather than a virtual source, this will be Some path, where the file exists. Useful if we want to provide a jump to source functionality. """ @@ -87,7 +88,7 @@ class Span: start_pos: int """The position in the start-line that the span starts.""" - _ast_node: Optional['ASTNode'] = None + _ast_node: 'ASTNode' | None = None def __repr__(self) -> str: return f'' @@ -101,14 +102,14 @@ class Span: def copy(self, ast_node: 'ASTNode') -> 'Span': return replace(self, _ast_node=ast_node) - def parent_ast_node(self, n: int = 1) -> Optional['ASTNode']: + def parent_ast_node(self, n: int = 1) -> 'ASTNode' | None: """Helper for node traversal, gets the parent value off the n^th generation ast_node. >>> self.get_parent_ast_node(n=0) == self.ast_node >>> self.get_parent_ast_node(n=1) == self.ast_node.parent >>> self.get_parent_ast_node(n=2) == self.ast_node.parent.parent """ - node: Optional[ASTNode] = self.ast_node + node: ASTNode | None = self.ast_node while n > 0 and node is not None: n -= 1 node = node.parent @@ -156,7 +157,7 @@ class IsExtractable: class ASTNode: """This is the base-class of all AST nodes.""" - parent: Optional['ASTNode'] = field(default=None, init=False, repr=False, compare=False) + parent: 'ASTNode' | None = field(default=None, init=False, repr=False, compare=False) span: Span = field(repr=False, compare=False) """The location of this AST node, in a given source file.""" @@ -255,7 +256,7 @@ class Name(Expression, IsExtractable): identifier: str context: Context - _source_annotation: Union[None, _Sentinel, 'Annotation', 'AnnotationWithVariants'] = field( + _source_annotation: _Sentinel | 'Annotation' | 'AnnotationWithVariants' | None = field( default=_SOURCE_ANNOTATION_UNSET, repr=False, compare=False, @@ -274,7 +275,7 @@ class Name(Expression, IsExtractable): else: return self.identifier - def set_source_annotation(self, annotation: Union[None, 'Annotation', 'AnnotationWithVariants']) -> None: + def set_source_annotation(self, annotation: 'Annotation' | 'AnnotationWithVariants' | None) -> None: self._source_annotation = annotation @property @@ -314,7 +315,7 @@ class String(Literal): class Number(Literal): """Represents a number parsed from ast.""" - value: Union[int, float] + value: int | float @add_slots @@ -348,12 +349,12 @@ class Assign(Statement, IsConstant, IsExtractable): target: Name value: Expression - annotation: Optional[Union['Annotation', 'AnnotationWithVariants']] = None + annotation: 'Annotation' | 'AnnotationWithVariants' | None = None @cached_property def should_extract(self) -> bool: """ - Should the target node should be extracted? + Should the target node be extracted? A false value for should_extract only applies to the current feature. An fstring using a feature with `should_extract == False` would be extractable. @@ -406,17 +407,17 @@ class Call(Expression, Statement): ``` """ - func: Union[Name, 'Attribute'] + func: Name | 'Attribute' arguments: Sequence['Keyword'] - def find_argument(self, name: str) -> Optional['Keyword']: + def find_argument(self, name: str) -> 'Keyword' | None: for argument in self.arguments: if argument.name == name: return argument return None - def argument_dict(self) -> Dict[str, Expression]: + def argument_dict(self) -> dict[str, Expression]: return {arg.name: arg.value for arg in self.arguments} @property @@ -835,15 +836,16 @@ class AnnotationWithVariants(Expression): For example, - X: Union[X, Y] = 1 - ^ ^ ^ - | | | - | these are the variants, - '- this is the annotation. + X: X | Y = 1 + ^ ^ ^ + | | | + | | | + '- this is the annotation, but they're treated as variants, + this is to maintain existing behaviour. """ identifier: str - variants: Sequence[Union[Annotation, 'AnnotationWithVariants']] + variants: Sequence[Annotation | 'AnnotationWithVariants'] @property def can_extract(self) -> bool: diff --git a/osprey_worker/src/osprey/engine/ast/py_ast.py b/osprey_worker/src/osprey/engine/ast/py_ast.py index c08176d..d69b81e 100644 --- a/osprey_worker/src/osprey/engine/ast/py_ast.py +++ b/osprey_worker/src/osprey/engine/ast/py_ast.py @@ -1,8 +1,7 @@ """This implements the Python AST -> Osprey AST transformer.""" import ast -from typing import Any, Optional, Type, TypeVar, Union -from typing import List as ListT +from typing import Any, Type, TypeVar from .ast_utils import iter_field_values from .errors import OspreySyntaxError @@ -98,7 +97,7 @@ class OspreyAstNodeTransformer: def __init__(self, source: Source): self.source = source - self.current_node: Optional[ast.AST] = None + self.current_node: ast.AST | None = None def transform(self, node: ast.AST) -> ASTNode: # Store current node here, so that invariant will work in given node's context. @@ -151,7 +150,7 @@ class OspreyAstNodeTransformer: Literal, FormatString, value, - hint=f'`{annotation.identifier}` assignment expects an rvalue of type `Union[Literal, FormatString]`', + hint=f'`{annotation.identifier}` assignment expects an rvalue of type `Literal | FormatString`', ) return Assign(span=self.span_for(node), target=target, value=value, annotation=annotation) @@ -160,7 +159,7 @@ class OspreyAstNodeTransformer: context = pyast_context_to_osprey_context(self, node.ctx, span=span) return Name(span=span, identifier=node.id, context=context) - def transform_NameConstant(self, node: ast.NameConstant) -> Union[Boolean, None_]: + def transform_NameConstant(self, node: ast.NameConstant) -> Boolean | None_: self.invariant(node.value in (True, False, None), 'unexpected name constant', node=node) if node.value is None: return None_(span=self.span_for(node)) @@ -170,7 +169,7 @@ class OspreyAstNodeTransformer: # typeshed is missing ast.Constant as it is new in python 3.8 # so we are typing as Any until it gains that definition. - def transform_Constant(self, node: Any) -> Union[String, Number, Boolean, None_]: + def transform_Constant(self, node: Any) -> String | Number | Boolean | None_: span = self.span_for(node) if isinstance(node.value, str): return String(span=span, value=node.value) @@ -287,7 +286,7 @@ class OspreyAstNodeTransformer: return List(span=self.span_for(node), items=items) def transform_JoinedStr(self, node: ast.JoinedStr) -> FormatString: - format_string_parts: ListT[str] = [] + format_string_parts: list[str] = [] names = [] # Tracks the unescaped length of the parts seen so far, so error carets stay positioned # the same way even though literal braces are doubled in `format_string_parts` below. @@ -342,8 +341,8 @@ class OspreyAstNodeTransformer: return FormatString(span=self.span_for(node), format_string=format_string, names=names) def span_for(self, node: ast.AST, offset_by: int = 0) -> Span: - start_line: Optional[int] = getattr(node, 'lineno', None) - start_pos: Optional[int] = getattr(node, 'col_offset', None) + start_line: int | None = getattr(node, 'lineno', None) + start_pos: int | None = getattr(node, 'col_offset', None) assert start_line is not None, f'Every AST node should have a span, but {node!r} did not.' assert start_pos is not None, f'Every AST node should have a span, but {node!r} did not.' return Span(source=self.source, start_line=start_line, start_pos=start_pos + offset_by) @@ -385,7 +384,7 @@ class OspreyAstNodeTransformer: return expr - def expect_pyast_union(self, ty: Type[T], ty2: Type[V], node: ASTNode, hint: str = '') -> Union[T, V]: + def expect_pyast_union(self, ty: Type[T], ty2: Type[V], node: ASTNode, hint: str = '') -> T | V: # This function is a bit hacky, but lets us convince mypy that we have a union type. if not (isinstance(node, ty) or isinstance(node, ty2)): if isinstance(node, ASTNode): @@ -483,7 +482,7 @@ def pyast_context_to_osprey_context( def fixup_parents(root: Root) -> None: """Traverses the AST, updating the nodes to point to their parent nodes.""" - def recursively_insert_parents(parent_node: Optional[ASTNode], current_node: ASTNode) -> None: + def recursively_insert_parents(parent_node: ASTNode | None, current_node: ASTNode) -> None: assert isinstance(current_node, ASTNode) current_node.parent = parent_node @@ -500,7 +499,7 @@ def fixup_parents(root: Root) -> None: # noinspection PyPep8Naming def pyast_ann_assign_annotation_to_annotation( transformer: OspreyAstNodeTransformer, annotation: ast.expr -) -> Union[Annotation, AnnotationWithVariants]: +) -> Annotation | AnnotationWithVariants: annotation_hint: str = ( 'annotation must be in the form of `Target: Annotation = Value`, where `Annotation` is a `Name` ' 'or `Name[Name, ...]`' @@ -512,7 +511,7 @@ def pyast_ann_assign_annotation_to_annotation( return Annotation(identifier='None', span=transformer.span_for(annotation)) if isinstance(annotation, ast.Subscript): - variants: ListT[Union[Annotation, AnnotationWithVariants]] = [] + variants: list[Annotation | AnnotationWithVariants] = [] value = transformer.expect_pyast_ty(ast.Name, annotation.value, hint=annotation_hint) slice = annotation.slice @@ -528,6 +527,28 @@ def pyast_ann_assign_annotation_to_annotation( return AnnotationWithVariants(identifier=value.id, variants=variants, span=transformer.span_for(annotation)) + if isinstance(annotation, ast.BinOp): + variants: list[Annotation | AnnotationWithVariants] = [] # type: ignore[no-redef] + + left_variant = pyast_ann_assign_annotation_to_annotation(transformer, annotation.left) + right_variant = pyast_ann_assign_annotation_to_annotation(transformer, annotation.right) + + if isinstance(left_variant, AnnotationWithVariants): + variants.extend(left_variant.variants) + else: + variants.append(left_variant) + variants.append(right_variant) + + # Optional arguments are internally represented as a Union, but + # they can only wrap a single type with None. + identifier: str = '' + if variants[-1].identifier == 'None': + identifier = 'Optional' + else: + identifier = 'Union' + + return AnnotationWithVariants(identifier=identifier, variants=variants, span=transformer.span_for(annotation)) + raise transformer.make_syntax_error( error=f'unexpected node: `{annotation.__class__.__name__}`', span=transformer.span_for(annotation), diff --git a/osprey_worker/src/osprey/engine/ast/sources.py b/osprey_worker/src/osprey/engine/ast/sources.py index 289b0d9..ccc6674 100644 --- a/osprey_worker/src/osprey/engine/ast/sources.py +++ b/osprey_worker/src/osprey/engine/ast/sources.py @@ -1,9 +1,12 @@ +from __future__ import annotations + import fnmatch +from collections.abc import Iterator, Sequence from functools import reduce from hashlib import sha256 from itertools import chain from pathlib import Path -from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Union +from typing import Any import deepmerge import yaml @@ -19,19 +22,19 @@ class Sources: """A collection of sources, and an arbitrary configuration which describes a set of imported rules and perhaps additional configuration that will be executed by the engine.""" - def __init__(self, sources: Dict[str, Source], config: Optional['SourcesConfig'] = None): + def __init__(self, sources: dict[str, Source], config: 'SourcesConfig' | None = None): assert SOURCE_ENTRY_POINT_PATH in sources, ( "Sources requires a file with the `path` 'main.sml' to be present as the entry-point" ) self._sources = sources self._config = config if config is not None else SourcesConfig(Source(path=CONFIG_PATH, contents='')) - self._hash: Optional[str] = None + self._hash: str | None = None @property def config(self) -> 'SourcesConfig': return self._config - def get_by_path(self, path: str) -> Optional[Source]: + def get_by_path(self, path: str) -> Source | None: """Gets a source that belongs to a given path, if it exists.""" return self._sources.get(path) @@ -45,16 +48,16 @@ class Sources: def __len__(self) -> int: return len(self._sources) - def paths(self) -> Set[str]: + def paths(self) -> set[str]: """Returns the set of paths within this sources collection.""" return set(self._sources.keys()) - def glob(self, pattern: str) -> List[Source]: + def glob(self, pattern: str) -> list[Source]: """Returns a list of sources that match the given pattern.""" matches = fnmatch.filter(self._sources.keys(), pattern) return [self._sources[k] for k in matches] - def to_dict(self) -> Dict[str, str]: + def to_dict(self) -> dict[str, str]: """The inverse of from_dict, serializes this Sources collection to a dictionary.""" sources = list(self) if self._config.source.contents: @@ -63,7 +66,7 @@ class Sources: return {source.path: source.contents for source in sources} @staticmethod - def from_dict(sources_dict: Dict[str, str]) -> 'Sources': + def from_dict(sources_dict: dict[str, str]) -> 'Sources': """Creates a Sources object from a dict of path -> contents.""" builder = SourcesBuilder() @@ -123,9 +126,9 @@ class SourcesBuilder: at which you can mutate sources.""" def __init__(self) -> None: - self._sources: Dict[str, Source] = {} - self._config: Optional['SourcesConfig'] = None - self._config_sources: Dict[str, Source] = {} + self._sources: dict[str, Source] = {} + self._config: 'SourcesConfig' | None = None + self._config_sources: dict[str, Source] = {} def add_source(self, source: Source) -> 'SourcesBuilder': """Adds a source to the sources collection.""" @@ -150,7 +153,7 @@ class SourcesBuilder: return Sources(self._sources, config=self._config) -class SourcesConfig(Dict[str, Any]): +class SourcesConfig(dict[str, Any]): """Wraps a configuration provided by a source, performing preliminary validation of its parsed contents, but not interpreting the content. This lets us side-load a "config" within the sources, that will generally have additional meaning outside of the rules engine, for example, doing event sampling @@ -174,7 +177,7 @@ class SourcesConfig(Dict[str, Any]): if not all(isinstance(config, dict) for config in configs): raise TypeError('Config is not a yaml serialized dictionary.') - config: Dict[str, Any] = reduce(deepmerge.merge_or_raise.merge, configs, {}) + config: dict[str, Any] = reduce(deepmerge.merge_or_raise.merge, configs, {}) if not isinstance(config, dict): raise TypeError('Config is not a yaml serialized dictionary.') @@ -193,10 +196,10 @@ class SourcesConfig(Dict[str, Any]): return self._source @property - def sources(self) -> List[Source]: + def sources(self) -> list[Source]: return self._sources - def closest_span_for_location(self, location: Sequence[Union[int, str]], key_only: bool) -> Span: + def closest_span_for_location(self, location: Sequence[int | str], key_only: bool) -> Span: """Given a location in the config, returns the span for the beginning of that location in the original source, or if we can't get the span for that element returns the span for the nearest possible parent. diff --git a/osprey_worker/src/osprey/engine/ast/yaml.py b/osprey_worker/src/osprey/engine/ast/yaml.py index 341d415..4be7ee7 100644 --- a/osprey_worker/src/osprey/engine/ast/yaml.py +++ b/osprey_worker/src/osprey/engine/ast/yaml.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, ClassVar, Dict, Hashable, Iterator, List, Type, TypeVar +from collections.abc import Hashable, Iterator +from typing import TYPE_CHECKING, Any, ClassVar, Type, TypeVar import yaml from osprey.engine.ast.grammar import Source @@ -37,11 +38,11 @@ class WithLineAndCol: return instance -class _ListWithLineAndCol(List[object], WithLineAndCol): +class _ListWithLineAndCol(list[object], WithLineAndCol): __slots__ = ('line_num', 'column_num', 'source') -class _DictWithLineAndCol(Dict[Hashable, Any], WithLineAndCol): +class _DictWithLineAndCol(dict[Hashable, Any], WithLineAndCol): __slots__ = ('line_num', 'column_num', 'source') diff --git a/osprey_worker/src/osprey/engine/ast_validator/base_validator.py b/osprey_worker/src/osprey/engine/ast_validator/base_validator.py index 8828451..d1d224d 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/base_validator.py +++ b/osprey_worker/src/osprey/engine/ast_validator/base_validator.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Dict, Generic, Type, TypeVar +from typing import TYPE_CHECKING, Generic, Type, TypeVar from osprey.engine.utils.periodic_execution_yielder import maybe_periodic_yield from pydantic import BaseModel @@ -72,5 +72,5 @@ class HasInput(Generic[T]): """Mixin to indicate that the validator may take data as an input.""" -class ConfigValidatorBase(BaseValidator, HasResult[Dict[Type[BaseModel], BaseModel]], ABC): +class ConfigValidatorBase(BaseValidator, HasResult[dict[Type[BaseModel], BaseModel]], ABC): """Validates that a subkey of the config is compatible with a given Pydantic model.""" diff --git a/osprey_worker/src/osprey/engine/ast_validator/validation_context.py b/osprey_worker/src/osprey/engine/ast_validator/validation_context.py index 2f33b17..fd47319 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validation_context.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validation_context.py @@ -1,5 +1,8 @@ +from __future__ import annotations + from abc import ABC -from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Sequence, Tuple, Type, Union, cast +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, ClassVar, Type, cast from osprey.engine.ast.error_utils import SpanWithHint, render_span_context_with_message from osprey.engine.ast.errors import OspreySyntaxError @@ -26,16 +29,16 @@ class ValidationContext: sources: Sources """The sources this validator is validating.""" - _validation_results: Dict[Union[Type[BaseValidator], Type[HasResult[Any]]], Any] + _validation_results: dict[Type[BaseValidator] | Type[HasResult[Any]], Any] """The stored results of a given validator.""" - _errors: List['ValidationError'] + _errors: list['ValidationError'] """Errors emitted by the validators that have run.""" - _warnings: List['ValidationWarning'] + _warnings: list['ValidationWarning'] """Warnings emitted by the validators that have run.""" - _validator_stack: List[Type[BaseValidator]] + _validator_stack: list[Type[BaseValidator]] """Stack of the currently running validators.""" _validator_registry: ValidatorRegistry @@ -44,7 +47,7 @@ class ValidationContext: _udf_registry: 'UDFRegistry' """The registry holding the user defined functions that may be used by validators.""" - _validator_inputs: Dict[Type[HasInput[Any]], Any] + _validator_inputs: dict[Type[HasInput[Any]], Any] """Holds any dynamic inputs that the validators might need.""" _warning_as_error: bool @@ -54,7 +57,7 @@ class ValidationContext: self, sources: Sources, udf_registry: 'UDFRegistry', - validator_registry: Optional[ValidatorRegistry] = None, + validator_registry: ValidatorRegistry | None = None, warning_as_error: bool = False, ): self.sources = sources @@ -83,7 +86,7 @@ class ValidationContext: span: Span, hint: str = '', additional_spans_message: str = '', - additional_spans: Sequence[Union[Span, SpanWithHint]] = tuple(), + additional_spans: Sequence[Span | SpanWithHint] = tuple(), ) -> None: """Adds an error message from the currently running validator. A validator can add many errors. Once an error is added, the validation is considered as failed. This means that any dependent validators will not run, @@ -104,7 +107,7 @@ class ValidationContext: span: Span, hint: str = '', additional_spans_message: str = '', - additional_spans: Sequence[Union[Span, SpanWithHint]] = tuple(), + additional_spans: Sequence[Span | SpanWithHint] = tuple(), ) -> None: """Adds a warning from the current running validator. A validator can add many warnings. Warnings are not fatal, and will not mark the validation as failed.""" @@ -118,7 +121,7 @@ class ValidationContext: ) ) - def add_message(self, message: Union['ValidationWarning', 'ValidationError']) -> None: + def add_message(self, message: 'ValidationWarning' | 'ValidationError') -> None: """Adds a given validation message to the validation context. It's preferred to use `add_warning` or `add_error` instead.""" # If we have a currently running validator at the top of the stack, we'll tag the @@ -135,7 +138,7 @@ class ValidationContext: raise ValueError(f'Unexpected message: {message!r}') @property - def current_validator(self) -> Optional[Type[BaseValidator]]: + def current_validator(self) -> Type[BaseValidator] | None: """Returns the currently running validator, or None if there is no current validator.""" if not self._validator_stack: return None @@ -173,7 +176,7 @@ class ValidationContext: if self._errors or (self._warning_as_error and self._warnings): raise ValidationFailed(self._errors, self._warnings) - validation_results: Dict[Type[HasResult[Any]], Any] = {} + validation_results: dict[Type[HasResult[Any]], Any] = {} for k, v in self._validation_results.items(): if issubclass(k, HasResult): validation_results[k] = v @@ -228,7 +231,7 @@ class ValidationContext: return cast(T_co, result) - def validator_depends_on(self, validator_classes: List[Type[BaseValidator]]) -> None: + def validator_depends_on(self, validator_classes: list[Type[BaseValidator]]) -> None: """Call from a validator's `.run()` or `__init__()` function, marking it as being dependent on the provided `validator_classes` to have run first.""" @@ -294,9 +297,9 @@ class _ValidationMessage(ABC): message: str, hint: str, span: Span, - source: Optional[Source] = None, + source: Source | None = None, additional_spans_message: str = '', - additional_spans: Sequence[Union[Span, SpanWithHint]] = tuple(), + additional_spans: Sequence[Span | SpanWithHint] = tuple(), ): if source is None: source = span.source @@ -307,7 +310,7 @@ class _ValidationMessage(ABC): self.source = source self.additional_spans_message = additional_spans_message self.additional_spans = additional_spans - self.validator_class: Optional[Type[BaseValidator]] = None + self.validator_class: Type[BaseValidator] | None = None def __repr__(self) -> str: return f'<{self.__class__.__name__} message={self.message!r} hint={self.hint!r} span={self.span!r}>' @@ -367,7 +370,7 @@ class ValidatedSources: def __init__( self, sources: Sources, - validation_results: Dict[Type[HasResult[Any]], Any], + validation_results: dict[Type[HasResult[Any]], Any], warnings: Sequence[ValidationWarning], ): self.sources = sources @@ -375,7 +378,7 @@ class ValidatedSources: self._validation_results = validation_results @property - def validation_results(self) -> Dict[Type[HasResult[Any]], Any]: + def validation_results(self) -> dict[Type[HasResult[Any]], Any]: return self._validation_results def get_validator_result(self, validator_class: Type[HasResult[T_co]]) -> T_co: @@ -403,7 +406,7 @@ def _render_validation_messages(messages: Sequence[_ValidationMessage], message_ parts = [f'{total} {message_type}s occurred while validating:'] - def sorting_key(validation_message: _ValidationMessage) -> Tuple[Union[str, int], ...]: + def sorting_key(validation_message: _ValidationMessage) -> tuple[str | int, ...]: return ( validation_message.source.path, validation_message.span.start_line, diff --git a/osprey_worker/src/osprey/engine/ast_validator/validation_utils.py b/osprey_worker/src/osprey/engine/ast_validator/validation_utils.py index 295a4e7..bdeff2a 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validation_utils.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validation_utils.py @@ -1,5 +1,3 @@ -from typing import Optional - from osprey.engine.ast import ast_utils, grammar, printer from .validation_context import ValidationContext @@ -10,7 +8,7 @@ def add_must_assign_to_variable_error( message: str, node: grammar.ASTNode, example_variable_name: str = 'SomeVariable', - type_annotation: Optional[str] = None, + type_annotation: str | None = None, ) -> None: parent = node.parent type_annotation_str = '' if type_annotation is None else f': {type_annotation}' diff --git a/osprey_worker/src/osprey/engine/ast_validator/validator_registry.py b/osprey_worker/src/osprey/engine/ast_validator/validator_registry.py index 9b79414..a4143fc 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validator_registry.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validator_registry.py @@ -1,4 +1,7 @@ -from typing import ClassVar, Iterator, Optional, Set, Type +from __future__ import annotations + +from collections.abc import Iterator +from typing import ClassVar, Type from .base_validator import BaseValidator @@ -6,7 +9,7 @@ from .base_validator import BaseValidator class ValidatorRegistry: """Holds all the registered validators.""" - _instance: ClassVar[Optional['ValidatorRegistry']] = None + _instance: ClassVar['ValidatorRegistry' | None] = None @classmethod def get_instance(cls) -> 'ValidatorRegistry': @@ -33,7 +36,7 @@ class ValidatorRegistry: return instance_clone def __init__(self) -> None: - self._validators: Set[Type[BaseValidator]] = set() + self._validators: set[Type[BaseValidator]] = set() def get_validators(self) -> Iterator[Type[BaseValidator]]: """Return the registered validators.""" @@ -49,7 +52,7 @@ class ValidatorRegistry: return validator_class in self._validators @classmethod - def from_validator_classes(cls, validator_classes: Set[Type[BaseValidator]]) -> 'ValidatorRegistry': + def from_validator_classes(cls, validator_classes: set[Type[BaseValidator]]) -> 'ValidatorRegistry': """Convenience method to construct a validator registry from a list of validator classes.""" validator_registry = cls() for validator_class in validator_classes: diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/feature_name_to_entity_type_mapping.py b/osprey_worker/src/osprey/engine/ast_validator/validators/feature_name_to_entity_type_mapping.py index 0ffba66..471a240 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/feature_name_to_entity_type_mapping.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/feature_name_to_entity_type_mapping.py @@ -1,5 +1,3 @@ -from typing import Dict - from osprey.engine.ast import grammar from osprey.engine.stdlib.udfs.entity import EntityArgumentsBase @@ -8,10 +6,10 @@ from ..validation_context import ValidationContext from .validate_call_kwargs import UDFNodeMapping, ValidateCallKwargs -class FeatureNameToEntityTypeMapping(SourceValidator, HasResult[Dict[str, str]]): +class FeatureNameToEntityTypeMapping(SourceValidator, HasResult[dict[str, str]]): def __init__(self, context: 'ValidationContext'): super().__init__(context) - self._feature_name_to_entity_type: Dict[str, str] = {} + self._feature_name_to_entity_type: dict[str, str] = {} self._udf_node_mapping: UDFNodeMapping = context.get_validator_result(ValidateCallKwargs) def validate_source(self, source: 'grammar.Source') -> None: @@ -25,5 +23,5 @@ class FeatureNameToEntityTypeMapping(SourceValidator, HasResult[Dict[str, str]]) if isinstance(args, EntityArgumentsBase): self._feature_name_to_entity_type[statement.target.identifier] = args.type.value - def get_result(self) -> Dict[str, str]: + def get_result(self) -> dict[str, str]: return self._feature_name_to_entity_type diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/imports_must_not_have_cycles.py b/osprey_worker/src/osprey/engine/ast_validator/validators/imports_must_not_have_cycles.py index 5dc6b0d..3bfc84c 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/imports_must_not_have_cycles.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/imports_must_not_have_cycles.py @@ -1,5 +1,6 @@ +from collections.abc import Sequence from dataclasses import dataclass -from typing import TYPE_CHECKING, Dict, List, Sequence, Tuple, cast +from typing import TYPE_CHECKING, cast from osprey.engine.ast.ast_utils import filter_nodes from osprey.engine.ast.grammar import Call, Source, Span @@ -33,7 +34,7 @@ class ImportsMustNotHaveCycles(BaseValidator, HasResult[ImportGraphResult]): _udf_node_mapping: UDFNodeMapping """Cached result of ValidateCallKwargs""" - _pairs: Dict[Tuple[Source, Source], Span] + _pairs: dict[tuple[Source, Source], Span] """A mapping of XSource imported YSource -> Span, that will be used to build the error message if a cyclic dependency is found.""" @@ -55,14 +56,14 @@ class ImportsMustNotHaveCycles(BaseValidator, HasResult[ImportGraphResult]): except CyclicDependencyError as e: # We have our cycle path, and we're going to transform that into a coherent # error that can then be displayed to the end user. - cycle_path = cast(List[Source], list(e.path)) + cycle_path = cast(list[Source], list(e.path)) # In order to do that, we need to figure out all the spans we're going to point to # in the error message. This means that we need to map the cycle back to the spans # which the import happened. The mapping of "x imported y" -> span is maintained in `_pairs` and # is built as we're iterating over the sources. - spans: List[Span] = [] + spans: list[Span] = [] # So, we're going to loop over the cycle. Assuming we have the sources "foo", "bar" and "baz", and the # path is: foo -> bar -> baz, we want to get the spans that show where: diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/no_unused_locals.py b/osprey_worker/src/osprey/engine/ast_validator/validators/no_unused_locals.py index f1a5e18..e06544b 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/no_unused_locals.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/no_unused_locals.py @@ -1,5 +1,3 @@ -from typing import Dict, Tuple - from osprey.engine.ast.ast_utils import filter_nodes from osprey.engine.ast.grammar import Load, Name, Source, Store @@ -12,7 +10,7 @@ class NoUnusedLocals(SourceValidator): """ def validate_source(self, source: 'Source') -> None: - seen_locals: Dict[str, Tuple[int, Name]] = {} + seen_locals: dict[str, tuple[int, Name]] = {} # Walk AST for all name nodes, finding nodes that are stored, but never loaded, # by maintaining a counter of identifier -> load count. diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/rule_name_to_description_mapping.py b/osprey_worker/src/osprey/engine/ast_validator/validators/rule_name_to_description_mapping.py index a731599..a275043 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/rule_name_to_description_mapping.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/rule_name_to_description_mapping.py @@ -1,15 +1,13 @@ -from typing import Dict - from osprey.engine.ast.grammar import Assign, Call, FormatString, Source, String from ..base_validator import HasResult, SourceValidator from ..validation_context import ValidationContext -class RuleNameToDescriptionMapping(SourceValidator, HasResult[Dict[str, str]]): +class RuleNameToDescriptionMapping(SourceValidator, HasResult[dict[str, str]]): def __init__(self, context: 'ValidationContext'): super().__init__(context) - self._rule_to_info_mapping: Dict[str, str] = {} + self._rule_to_info_mapping: dict[str, str] = {} def validate_source(self, source: 'Source') -> None: for statement in source.ast_root.statements: @@ -28,5 +26,5 @@ class RuleNameToDescriptionMapping(SourceValidator, HasResult[Dict[str, str]]): elif isinstance(description.value, String): self._rule_to_info_mapping[rule_name] = description.value.value - def get_result(self) -> Dict[str, str]: + def get_result(self) -> dict[str, str]: return self._rule_to_info_mapping diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_imports_must_not_have_cycles.py b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_imports_must_not_have_cycles.py index e4e34c2..4dab127 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_imports_must_not_have_cycles.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_imports_must_not_have_cycles.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.imports_must_not_have_cycles import ImportsMustNotHaveCycles @@ -11,7 +12,7 @@ from osprey.engine.conftest import CheckFailureFunction, RunValidationFunction from osprey.engine.stdlib.udfs.import_ import Import from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators( [ValidateCallKwargs, ImportsMustNotHaveCycles, ValidateDynamicCallsHaveAnnotatedRValue, UniqueStoredNames] ), diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs.py b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs.py index 73679a5..72db42a 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Any, Callable, Dict, List, Type +from collections.abc import Callable +from typing import Any, Type import pytest from osprey.engine.ast_validator.validation_context import ValidationContext @@ -12,7 +13,7 @@ from osprey.engine.udf.arguments import ArgumentsBase, ConstExpr from osprey.engine.udf.base import UDFBase from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_osprey_stdlib, ] @@ -113,11 +114,11 @@ def test_missing_keyword_argument(run_validation: RunValidationFunction, check_f class UnexpectedArgsArguments(ArgumentsBase): required: str optional: str = 'hello' - extra_arguments: Dict[str, str] + extra_arguments: dict[str, str] class UnexpectedArgsUdfBase: - def execute(self, execution_context: ExecutionContext, arguments: UnexpectedArgsArguments) -> List[str]: + def execute(self, execution_context: ExecutionContext, arguments: UnexpectedArgsArguments) -> list[str]: return [ i for kv in { @@ -134,10 +135,10 @@ class UnexpectedArgsUdfBase: [{'required': 'hi'}, {'required': 'hi', 'optional': 'hi'}, {'required': 'hi', 'unexpected': 'world'}], ) def test_allow_unexpected_args( - extra_arguments: Dict[str, str], execute: ExecuteFunction, udf_registry: UDFRegistry + extra_arguments: dict[str, str], execute: ExecuteFunction, udf_registry: UDFRegistry ) -> None: @udf_registry.register - class UnexpectedArgsUdf(UnexpectedArgsUdfBase, UDFBase[UnexpectedArgsArguments, List[str]]): + class UnexpectedArgsUdf(UnexpectedArgsUdfBase, UDFBase[UnexpectedArgsArguments, list[str]]): pass extra_arguments_str = ', '.join(f'{k}={v!r}' for k, v in extra_arguments.items()) @@ -160,13 +161,13 @@ def test_allow_unexpected_args( ], ) def test_allow_unexpected_respects_type( - extra_arguments: Dict[str, str], + extra_arguments: dict[str, str], execute: ExecuteFunction, check_failure: CheckFailureFunction, udf_registry: UDFRegistry, ) -> None: @udf_registry.register - class ValidatingUnexpectedArgsUdf(UnexpectedArgsUdfBase, UDFBase[UnexpectedArgsArguments, List[str]]): + class ValidatingUnexpectedArgsUdf(UnexpectedArgsUdfBase, UDFBase[UnexpectedArgsArguments, list[str]]): def __init__(self, validation_context: ValidationContext, arguments: UnexpectedArgsArguments): assert set(arguments.get_extra_arguments_ast().keys()) == {'unexpected'} diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs/test_allow_unexpected_respects_type[extra_arguments3].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs/test_allow_unexpected_respects_type[extra_arguments3].txt index 646dc2b..a9bc9e3 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs/test_allow_unexpected_respects_type[extra_arguments3].txt +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_call_kwargs/test_allow_unexpected_respects_type[extra_arguments3].txt @@ -2,4 +2,4 @@ error: argument `unexpected` to `ValidatingUnexpectedArgsUdf` has incompatible t --> main.sml:1:60 | 1 | Ret = ValidatingUnexpectedArgsUdf(required='hi', unexpected=['hello']) - | ^ has type `List[str]`, expected `str` \ No newline at end of file + | ^ has type `list[str]`, expected `str` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue.py b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue.py index b867948..e3a7e91 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue.py @@ -28,16 +28,16 @@ def test_missing_annotation_and_argument( 'annotation', ( 'wut', # Invalid type - 'Union[str, str]', # Duplicate arg - 'Union[str, wut]', # Invalid arg type + 'str | str', # Duplicate arg + 'str | wut', # Invalid arg type 'Union', # Missing arg - 'List[str, str]', # Extra arg - 'List[str, int, float]', # Extra args with different types - 'List[wut]', # Invalid arg type - 'List', # Missing arg - 'Optional[str, str]', # Extra arg - 'Optional[str, int, float]', # Extra args with different types - 'Optional[wut]', # Invalid arg type + 'list[str, str]', # Extra arg + 'list[str, int, float]', # Extra args with different types + 'list[wut]', # Invalid arg type + 'list', # Missing arg + 'str | str | None', # Extra arg + 'str | int | float | None', # Extra args with different types + 'wut | None', # Invalid arg type 'Optional', # Missing arg ), ) diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[str, int, float]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[str, int, float]].txt deleted file mode 100644 index 50ab82b..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[str, int, float]].txt +++ /dev/null @@ -1,10 +0,0 @@ -error: unexpected additional variants to `List[...]` ---> main.sml:1:15 - | - 1 | Foo: List[str, int, float] = JsonData(path='$.foo') - | ^ -~~~ also: ---> (1) main.sml:1:20 - | - 1 | Foo: List[str, int, float] = JsonData(path='$.foo') - | ^ \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[str, str]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[str, str]].txt deleted file mode 100644 index f0f1b0a..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[str, str]].txt +++ /dev/null @@ -1,5 +0,0 @@ -error: unexpected additional variants to `List[...]` ---> main.sml:1:15 - | - 1 | Foo: List[str, str] = JsonData(path='$.foo') - | ^ \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[wut]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[wut]].txt deleted file mode 100644 index be21c83..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List[wut]].txt +++ /dev/null @@ -1,5 +0,0 @@ -error: expected simple type in `List` ---> main.sml:1:10 - | - 1 | Foo: List[wut] = JsonData(path='$.foo') - | ^ got unknown non-generic type `wut` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[str, int, float]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[str, int, float]].txt deleted file mode 100644 index 651aa91..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[str, int, float]].txt +++ /dev/null @@ -1,5 +0,0 @@ -error: `Optional` must have exactly one argument ---> main.sml:1:5 - | - 1 | Foo: Optional[str, int, float] = JsonData(path='$.foo') - | ^ got 3 arguments \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[str, str]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[str, str]].txt deleted file mode 100644 index c938a76..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[str, str]].txt +++ /dev/null @@ -1,5 +0,0 @@ -error: `Optional` must have exactly one argument ---> main.sml:1:5 - | - 1 | Foo: Optional[str, str] = JsonData(path='$.foo') - | ^ got 2 arguments \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[wut]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[wut]].txt deleted file mode 100644 index 24ac7ee..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Optional[wut]].txt +++ /dev/null @@ -1,5 +0,0 @@ -error: expected simple type in `Optional` ---> main.sml:1:14 - | - 1 | Foo: Optional[wut] = JsonData(path='$.foo') - | ^ got unknown non-generic type `wut` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Union[str, str]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Union[str, str]].txt deleted file mode 100644 index e95817b..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Union[str, str]].txt +++ /dev/null @@ -1,10 +0,0 @@ -error: duplicated type `str` seen in `Union[...]` ---> main.sml:1:16 - | - 1 | Foo: Union[str, str] = JsonData(path='$.foo') - | ^ -~~~ union variant already specified here: ---> (1) main.sml:1:11 - | - 1 | Foo: Union[str, str] = JsonData(path='$.foo') - | ^ \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Union[str, wut]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Union[str, wut]].txt deleted file mode 100644 index 9db5e7b..0000000 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[Union[str, wut]].txt +++ /dev/null @@ -1,5 +0,0 @@ -error: expected simple type in `Union` ---> main.sml:1:16 - | - 1 | Foo: Union[str, wut] = JsonData(path='$.foo') - | ^ got unknown non-generic type `wut` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[str, int, float]].txt similarity index 58% rename from osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List].txt rename to osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[str, int, float]].txt index cd8220a..9956b43 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[List].txt +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[str, int, float]].txt @@ -1,5 +1,5 @@ error: can only check dynamic return values of simple types or `Entity`, `ExtractLiteral`, `ExtractSecret`, `List`, `Optional`, `Secret`, `Union` generics --> main.sml:1:5 | - 1 | Foo: List = JsonData(path='$.foo') - | ^ `List` is generic, try `List[T]` where `T` is a type like `str` or `int` \ No newline at end of file + 1 | Foo: list[str, int, float] = JsonData(path='$.foo') + | ^ got unknown generic type `list[...]` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[str, str]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[str, str]].txt new file mode 100644 index 0000000..8dabeaf --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[str, str]].txt @@ -0,0 +1,5 @@ +error: can only check dynamic return values of simple types or `Entity`, `ExtractLiteral`, `ExtractSecret`, `List`, `Optional`, `Secret`, `Union` generics +--> main.sml:1:5 + | + 1 | Foo: list[str, str] = JsonData(path='$.foo') + | ^ got unknown generic type `list[...]` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[wut]].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[wut]].txt new file mode 100644 index 0000000..de4df93 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list[wut]].txt @@ -0,0 +1,5 @@ +error: can only check dynamic return values of simple types or `Entity`, `ExtractLiteral`, `ExtractSecret`, `List`, `Optional`, `Secret`, `Union` generics +--> main.sml:1:5 + | + 1 | Foo: list[wut] = JsonData(path='$.foo') + | ^ got unknown generic type `list[...]` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list].txt new file mode 100644 index 0000000..a8de084 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[list].txt @@ -0,0 +1,5 @@ +error: can only check dynamic return values of simple types or `Entity`, `ExtractLiteral`, `ExtractSecret`, `List`, `Optional`, `Secret`, `Union` generics +--> main.sml:1:5 + | + 1 | Foo: list = JsonData(path='$.foo') + | ^ got unknown non-generic type `list` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] int [or] float [or] None].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] int [or] float [or] None].txt new file mode 100644 index 0000000..a4aef65 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] int [or] float [or] None].txt @@ -0,0 +1,5 @@ +error: `Optional` must have one or two arguments +--> main.sml:1:5 + | + 1 | Foo: str | int | float | None = JsonData(path='$.foo') + | ^ got 4 arguments \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] str [or] None].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] str [or] None].txt new file mode 100644 index 0000000..5aa8148 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] str [or] None].txt @@ -0,0 +1,5 @@ +error: `Optional` must have one or two arguments +--> main.sml:1:5 + | + 1 | Foo: str | str | None = JsonData(path='$.foo') + | ^ got 3 arguments \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] str].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] str].txt new file mode 100644 index 0000000..276a845 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] str].txt @@ -0,0 +1,10 @@ +error: duplicated type `str` seen in `Union[...]` +--> main.sml:1:11 + | + 1 | Foo: str | str = JsonData(path='$.foo') + | ^ +~~~ union variant already specified here: +--> (1) main.sml:1:5 + | + 1 | Foo: str | str = JsonData(path='$.foo') + | ^ \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] wut].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] wut].txt new file mode 100644 index 0000000..d0717e9 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[str [or] wut].txt @@ -0,0 +1,5 @@ +error: expected simple type in `Union` +--> main.sml:1:11 + | + 1 | Foo: str | wut = JsonData(path='$.foo') + | ^ got unknown non-generic type `wut` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[wut [or] None].txt b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[wut [or] None].txt new file mode 100644 index 0000000..a135241 --- /dev/null +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/tests/test_validate_dynamic_calls_have_annotated_rvalue/test_invalid_annotation[wut [or] None].txt @@ -0,0 +1,5 @@ +error: expected simple type in `Optional` +--> main.sml:1:5 + | + 1 | Foo: wut | None = JsonData(path='$.foo') + | ^ got unknown non-generic type `wut` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/unique_stored_names.py b/osprey_worker/src/osprey/engine/ast_validator/validators/unique_stored_names.py index 75f7fde..00cebe0 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/unique_stored_names.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/unique_stored_names.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import TYPE_CHECKING, DefaultDict, Dict, List +from typing import TYPE_CHECKING from osprey.engine.ast.ast_utils import filter_nodes from osprey.engine.ast.grammar import Name, Span, Store @@ -10,7 +10,7 @@ if TYPE_CHECKING: from ..validation_context import ValidationContext -IdentifierIndex = Dict[str, Span] +IdentifierIndex = dict[str, Span] class UniqueStoredNames(BaseValidator, HasResult[IdentifierIndex]): @@ -23,8 +23,8 @@ class UniqueStoredNames(BaseValidator, HasResult[IdentifierIndex]): self.identifier_index: IdentifierIndex = {} def run(self) -> None: - stored_global_names: DefaultDict[str, List[Span]] = defaultdict(list) - stored_local_names_by_file: DefaultDict[str, DefaultDict[str, List[Span]]] = defaultdict( + stored_global_names: defaultdict[str, list[Span]] = defaultdict(list) + stored_local_names_by_file: defaultdict[str, defaultdict[str, list[Span]]] = defaultdict( lambda: defaultdict(list) ) # Iterate over the ast, finding name nodes that are using the Store context. diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/validate_call_kwargs.py b/osprey_worker/src/osprey/engine/ast_validator/validators/validate_call_kwargs.py index 0a7b0c5..f1f12f3 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/validate_call_kwargs.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/validate_call_kwargs.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Dict, Mapping, Tuple +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any from osprey.engine.ast.ast_utils import filter_nodes from osprey.engine.ast.grammar import Assign, Call, Literal, Name, Source, Store, UnaryOperation @@ -22,7 +23,7 @@ if TYPE_CHECKING: from ..validation_context import ValidationContext -UDFNodeMapping = Dict[int, Tuple[UDFBase[Any, Any], ArgumentsBase]] +UDFNodeMapping = dict[int, tuple[UDFBase[Any, Any], ArgumentsBase]] class ValidateCallKwargs(SourceValidator, HasResult[UDFNodeMapping]): diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/validate_experiments.py b/osprey_worker/src/osprey/engine/ast_validator/validators/validate_experiments.py index f775b48..888fdae 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/validate_experiments.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/validate_experiments.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from functools import lru_cache -from typing import Dict, List, Optional, cast +from typing import cast from osprey.engine.ast import grammar from osprey.engine.ast_validator.base_validator import BaseValidator, HasInput, HasResult @@ -13,36 +13,36 @@ from .validate_call_kwargs import ValidateCallKwargs @dataclass class ExperimentValidationResult: name: str - buckets: List[str] - bucket_sizes: List[float] + buckets: list[str] + bucket_sizes: list[float] version: int revision: int experiment_type: str class ValidateExperimentsResult: - def __init__(self, experiment_validation_results: Dict[str, ExperimentValidationResult]): + def __init__(self, experiment_validation_results: dict[str, ExperimentValidationResult]): self._experiments = experiment_validation_results - def get_experiment(self, experiment_name: str) -> Optional[ExperimentValidationResult]: + def get_experiment(self, experiment_name: str) -> ExperimentValidationResult | None: return self._experiments.get(experiment_name) @property - def experiments(self) -> Dict[str, ExperimentValidationResult]: + def experiments(self) -> dict[str, ExperimentValidationResult]: return self._experiments # NEED FOR MVP (not really but no harm !) -class ValidateExperiments(BaseValidator, HasInput[Dict[str, grammar.Call]], HasResult[ValidateExperimentsResult]): +class ValidateExperiments(BaseValidator, HasInput[dict[str, grammar.Call]], HasResult[ValidateExperimentsResult]): def __init__(self, context: 'ValidationContext'): super().__init__(context) def run(self) -> None: # all the needed validation is done in the experiment UDFs which is called from ValidateCallKwargs self.context.validator_depends_on(validator_classes=[ValidateCallKwargs, FeatureNameToEntityTypeMapping]) - self._experiment_nodes: Dict[str, grammar.Call] = self.context.get_validator_input(type(self), {}) + self._experiment_nodes: dict[str, grammar.Call] = self.context.get_validator_input(type(self), {}) @lru_cache(maxsize=1) def get_result(self) -> ValidateExperimentsResult: @@ -51,7 +51,7 @@ class ValidateExperiments(BaseValidator, HasInput[Dict[str, grammar.Call]], HasR def get_entity_type(self, name: str) -> str: return self.context.get_validator_result(FeatureNameToEntityTypeMapping)[name] - def _get_validation_results(self) -> Dict[str, ExperimentValidationResult]: + def _get_validation_results(self) -> dict[str, ExperimentValidationResult]: return { k: ExperimentValidationResult( name=k, @@ -65,9 +65,9 @@ class ValidateExperiments(BaseValidator, HasInput[Dict[str, grammar.Call]], HasR } @staticmethod - def _unwrap_string_list(string_list: grammar.List) -> List[str]: - return [s.value for s in cast(List[grammar.String], string_list.items)] + def _unwrap_string_list(string_list: grammar.List) -> list[str]: + return [s.value for s in cast(list[grammar.String], string_list.items)] @staticmethod - def _unwrap_float_list(string_list: grammar.List) -> List[float]: - return [s.value for s in cast(List[grammar.Number], string_list.items)] + def _unwrap_float_list(string_list: grammar.List) -> list[float]: + return [s.value for s in cast(list[grammar.Number], string_list.items)] diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/validate_static_types.py b/osprey_worker/src/osprey/engine/ast_validator/validators/validate_static_types.py index ed698d6..e5545d2 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/validate_static_types.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/validate_static_types.py @@ -1,6 +1,9 @@ +import operator +from collections.abc import Callable, Sequence from dataclasses import dataclass, replace -from functools import lru_cache -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Set, Type, Union, cast +from functools import lru_cache, reduce +from types import UnionType +from typing import TYPE_CHECKING, Any, Type, Union, cast from osprey.engine.ast import grammar from osprey.engine.ast.error_utils import SpanWithHint @@ -37,17 +40,17 @@ class _TypeAndSpan: span: grammar.Span should_extract: bool = True can_extract: bool = True - source_annotation: Union[None, grammar.Annotation, grammar.AnnotationWithVariants] = None + source_annotation: None | grammar.Annotation | grammar.AnnotationWithVariants = None - def copy(self, type: Optional[Type[Any]] = None) -> '_TypeAndSpan': + def copy(self, type: Type[Any] | None = None) -> '_TypeAndSpan': return replace(self, type=type or self.type) @add_slots @dataclass class ValidateStaticTypesResult: - name_type_and_span_cache: Dict[str, _TypeAndSpan] - nodes_to_unwrap: Set[int] + name_type_and_span_cache: dict[str, _TypeAndSpan] + nodes_to_unwrap: set[int] @add_slots @@ -58,16 +61,16 @@ class _ValidTwoArgTypeTransition: resulting_type: type -_INT_OR_FLOAT_T = cast(type, Union[int, float]) +_INT_OR_FLOAT_T = cast(type, int | float) -class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], HasResult[ValidateStaticTypesResult]): +class ValidateStaticTypes(SourceValidator, HasInput[dict[str, _TypeAndSpan]], HasResult[ValidateStaticTypesResult]): def __init__(self, context: 'ValidationContext'): super().__init__(context) # Get type information passed in from previous runs, used to type check queries. - self._name_type_and_span_cache: Dict[str, _TypeAndSpan] = context.get_validator_input(type(self), {}) - self._nodes_to_unwrap: Set[int] = set() - self._checked_sources: Set[grammar.Source] = set() + self._name_type_and_span_cache: dict[str, _TypeAndSpan] = context.get_validator_input(type(self), {}) + self._nodes_to_unwrap: set[int] = set() + self._checked_sources: set[grammar.Source] = set() self._udf_node_mapping: UDFNodeMapping = context.get_validator_result(ValidateCallKwargs) # Allows us to skip cycle checking, assume unique/existing names, have rtype checkers set @@ -81,7 +84,7 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha ) @classmethod - def to_post_execution_types(cls, result: ValidateStaticTypesResult) -> Dict[str, _TypeAndSpan]: + def to_post_execution_types(cls, result: ValidateStaticTypesResult) -> dict[str, _TypeAndSpan]: """Converts a given result with the assumption that we are no longer in the primary rules execution context. Useful for type checking queries that run on execution results.""" types = result.name_type_and_span_cache @@ -126,7 +129,7 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha node: grammar.ASTNode, hint: str = '', additional_spans_message: str = '', - additional_spans: Sequence[Union[grammar.Span, SpanWithHint]] = tuple(), + additional_spans: Sequence[grammar.Span | SpanWithHint] = tuple(), ) -> None: compatible_type_result = is_compatible_type(type_t, accepted_by_t) if compatible_type_result.is_ok(): @@ -281,7 +284,7 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha list_.span, hint=f'has types {child_type_strs}', ) - return List[Any] + return list[Any] if len(child_types) == 0: # Can be list of any type, it's empty # If we're assigning this to a variable, make sure that has an annotation. @@ -293,12 +296,12 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha ), span=list_.parent.span, hint=( - f'give this variable a type annotation, eg:\n`{list_.parent.target.identifier}: List[str] = []`' + f'give this variable a type annotation, eg:\n`{list_.parent.target.identifier}: list[str] = []`' ), ) - return List[Any] + return list[Any] (child_type,) = child_types - return List[child_type] # type: ignore # Doesn't like runtime types like this + return list[child_type] # type: ignore # Doesn't like runtime types like this def _validate_call(self, call: grammar.Call) -> type: udf, arguments = self._udf_node_mapping[id(call)] @@ -451,14 +454,14 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha # We allow Entities to typecheck as optional in order to avoid having to update the type system # to support Optional[Entity[str]] - if origin is Optional or origin is EntityT: + if origin is None or origin is EntityT: return True - elif origin is Union: + elif origin is UnionType or origin is Union: return type(None) in t.__args__ # type: ignore[attr-defined] return False - def _get_non_none_type(self, t: type) -> Optional[type]: + def _get_non_none_type(self, t: type) -> type | None: """Extract the non-None type from an Optional[T] type. Returns T if t is Optional[T], otherwise returns None. @@ -478,13 +481,13 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha return non_none_args[0] elif len(non_none_args) > 1: # Multiple non-None types, return a Union of them - return cast(type, Union[tuple(non_none_args)]) + return cast(type, reduce(operator.or_, non_none_args)) return None def _get_type_narrowing_from_expression( self, expr: grammar.Expression, operand: grammar.BooleanOperand - ) -> Dict[str, type]: + ) -> dict[str, type]: """Detect type narrowing from null-check patterns. For 'and' operations: X != None narrows X from Optional[T] to T @@ -492,7 +495,7 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha Returns a dict of identifier_key -> narrowed type """ - narrowed_types: Dict[str, type] = {} + narrowed_types: dict[str, type] = {} if not isinstance(expr, grammar.BinaryComparison): return narrowed_types @@ -662,11 +665,11 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha # # Apply type narrowing: for 'and' operations, X != None narrows X from Optional[T] to T # for subsequent expressions. For 'or' operations, X == None narrows X. - narrowed_types: Dict[str, type] = {} + narrowed_types: dict[str, type] = {} for value in boolean_operation.values: # Temporarily apply any accumulated type narrowings for this expression - original_types: Dict[str, _TypeAndSpan] = {} + original_types: dict[str, _TypeAndSpan] = {} for identifier_key, narrowed_type in narrowed_types.items(): if identifier_key in self._name_type_and_span_cache: original_types[identifier_key] = self._name_type_and_span_cache[identifier_key] @@ -734,9 +737,9 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha transitioner: str, left: grammar.Expression, right: grammar.Expression, - valid_type_transitions_by_transitioner: Dict[str, Sequence[_ValidTwoArgTypeTransition]], + valid_type_transitions_by_transitioner: dict[str, Sequence[_ValidTwoArgTypeTransition]], allow_any: bool, - valid_transition_hook: Optional[Callable[[type, type], None]] = None, + valid_transition_hook: Callable[[type, type], None] | None = None, ) -> type: """Utility to help handle something that takes two args. @@ -804,7 +807,7 @@ class ValidateStaticTypes(SourceValidator, HasInput[Dict[str, _TypeAndSpan]], Ha @lru_cache() -def _get_binary_operation_transitions() -> Dict[str, Sequence[_ValidTwoArgTypeTransition]]: +def _get_binary_operation_transitions() -> dict[str, Sequence[_ValidTwoArgTypeTransition]]: # Both ints yields an int int_transition = _ValidTwoArgTypeTransition(valid_left_type=int, valid_right_type=int, resulting_type=int) # At least one float yields a float @@ -842,7 +845,7 @@ def _get_binary_operation_transitions() -> Dict[str, Sequence[_ValidTwoArgTypeTr @lru_cache() -def _get_binary_comparison_transitions() -> Dict[str, Sequence[_ValidTwoArgTypeTransition]]: +def _get_binary_comparison_transitions() -> dict[str, Sequence[_ValidTwoArgTypeTransition]]: any_to_bool_transition = _ValidTwoArgTypeTransition( valid_left_type=AnyType, valid_right_type=AnyType, resulting_type=bool ) @@ -856,7 +859,7 @@ def _get_binary_comparison_transitions() -> Dict[str, Sequence[_ValidTwoArgTypeT in_transitions = [ _ValidTwoArgTypeTransition(valid_left_type=str, valid_right_type=str, resulting_type=bool), _ValidTwoArgTypeTransition( - valid_left_type=AnyType, valid_right_type=cast(type, List[Any]), resulting_type=bool + valid_left_type=AnyType, valid_right_type=cast(type, list[Any]), resulting_type=bool ), ] diff --git a/osprey_worker/src/osprey/engine/ast_validator/validators/variables_must_be_defined.py b/osprey_worker/src/osprey/engine/ast_validator/validators/variables_must_be_defined.py index c953504..093808c 100644 --- a/osprey_worker/src/osprey/engine/ast_validator/validators/variables_must_be_defined.py +++ b/osprey_worker/src/osprey/engine/ast_validator/validators/variables_must_be_defined.py @@ -1,5 +1,6 @@ from collections import defaultdict -from typing import DefaultDict, Mapping, Sequence, Set, cast +from collections.abc import Mapping, Sequence +from typing import cast from osprey.engine.ast.ast_utils import filter_nodes, iter_nodes from osprey.engine.ast.grammar import Assign, ASTNode, Call, Load, Name, Source, Store @@ -12,7 +13,7 @@ from .unique_stored_names import UniqueStoredNames from .validate_call_kwargs import ValidateCallKwargs -class VariablesMustBeDefined(BaseValidator, HasInput[Set[str]], HasResult[Mapping[Source, Set[str]]]): +class VariablesMustBeDefined(BaseValidator, HasInput[set[str]], HasResult[Mapping[Source, set[str]]]): """ Checks that values are defined before being used. """ @@ -21,17 +22,17 @@ class VariablesMustBeDefined(BaseValidator, HasInput[Set[str]], HasResult[Mappin # We need to ensure that call kwargs are validated before we run this. self.context.validator_depends_on(validator_classes=[ValidateCallKwargs, ImportsMustNotHaveCycles]) # Allow the validator to insert a set of known-available names. - global_names: Set[str] = self.context.get_validator_input(type(self), set()) + global_names: set[str] = self.context.get_validator_input(type(self), set()) identifier_index = self.context.get_validator_result(UniqueStoredNames) - identifiers_by_source: DefaultDict[Source, Set[str]] = defaultdict(set) + identifiers_by_source: defaultdict[Source, set[str]] = defaultdict(set) for identifier, span in identifier_index.items(): identifiers_by_source[span.source].add(identifier) - self.known_identifiers_by_source: Mapping[Source, Set[str]] = {} + self.known_identifiers_by_source: Mapping[Source, set[str]] = {} for source in self.context.sources: - known_identifiers: Set[str] = set(global_names) + known_identifiers: set[str] = set(global_names) for node in iter_nodes(source.ast_root): if is_import(node): imported_sources = self.get_imported_sources(cast(Call, node)) @@ -124,7 +125,7 @@ class VariablesMustBeDefined(BaseValidator, HasInput[Set[str]], HasResult[Mappin self.known_identifiers_by_source[source] = known_identifiers - def get_result(self) -> Mapping[Source, Set[str]]: + def get_result(self) -> Mapping[Source, set[str]]: if not hasattr(self, 'known_identifiers_by_source'): raise RuntimeError('Validator must be run before `get_result` is called') return self.known_identifiers_by_source diff --git a/osprey_worker/src/osprey/engine/config/config_registry.py b/osprey_worker/src/osprey/engine/config/config_registry.py index 83b9e63..b9ddafc 100644 --- a/osprey_worker/src/osprey/engine/config/config_registry.py +++ b/osprey_worker/src/osprey/engine/config/config_registry.py @@ -1,5 +1,6 @@ +from collections.abc import Sequence from dataclasses import dataclass -from typing import TYPE_CHECKING, Dict, Optional, Sequence, Set, Type +from typing import TYPE_CHECKING, Type from osprey.engine.utils.types import add_slots from pydantic import ValidationError as PydanticValidationError @@ -25,8 +26,8 @@ class ConfigRegistry: """Holds all of the subkeys for the sources configuration that we know how to validate and parse.""" def __init__(self) -> None: - self._subkey_model_to_name: Dict[Type[BaseModel], str] = {} - self._taken_subkey_names: Set[str] = set() + self._subkey_model_to_name: dict[Type[BaseModel], str] = {} + self._taken_subkey_names: set[str] = set() def clone(self) -> 'ConfigRegistry': clone = ConfigRegistry() @@ -69,14 +70,14 @@ class ConfigRegistry: def __init__(self, context: ValidationContext): super().__init__(context) - self._parsed_config: Optional[Dict[Type[BaseModel], BaseModel]] = None + self._parsed_config: dict[Type[BaseModel], BaseModel] | None = None - def get_result(self) -> Dict[Type[BaseModel], BaseModel]: + def get_result(self) -> dict[Type[BaseModel], BaseModel]: assert self._parsed_config is not None, 'Should not call get_result if we had a validation failure' return self._parsed_config def run(self) -> None: - parsed_config: Dict[Type[BaseModel], BaseModel] = {} + parsed_config: dict[Type[BaseModel], BaseModel] = {} registered_subkey_names = set() for model, subkey_name in registry._subkey_model_to_name.items(): registered_subkey_names.add(subkey_name) diff --git a/osprey_worker/src/osprey/engine/config/config_subkey_handler.py b/osprey_worker/src/osprey/engine/config/config_subkey_handler.py index 4801415..1ca3313 100644 --- a/osprey_worker/src/osprey/engine/config/config_subkey_handler.py +++ b/osprey_worker/src/osprey/engine/config/config_subkey_handler.py @@ -1,5 +1,6 @@ from collections import defaultdict -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Type, TypeVar +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Type, TypeVar from pydantic.main import BaseModel @@ -17,14 +18,14 @@ class ConfigSubkeyHandler: def __init__(self, config_registry: ConfigRegistry, initial_sources: 'ValidatedSources') -> None: self._config_registry = config_registry - self._config_subkey_handlers: Dict[Type[BaseModel], List[Callable[[Any], None]]] = defaultdict(list) + self._config_subkey_handlers: dict[Type[BaseModel], list[Callable[[Any], None]]] = defaultdict(list) # Holds the parsed configs self._known_good_parsed_config = self._parse_new_config(initial_sources) def _validate_subkey_registered(self, model_class: Type[BaseModel]) -> None: assert self._config_registry.has_model(model_class), 'Must register config subkey models before using them!' - def _parse_new_config(self, validated_sources: 'ValidatedSources') -> Dict[Type[BaseModel], BaseModel]: + def _parse_new_config(self, validated_sources: 'ValidatedSources') -> dict[Type[BaseModel], BaseModel]: raw_config = validated_sources.sources.config # First parse and validate all config subkeys diff --git a/osprey_worker/src/osprey/engine/config/tests/test_config.py b/osprey_worker/src/osprey/engine/config/tests/test_config.py index e47b5d4..c5660f1 100644 --- a/osprey_worker/src/osprey/engine/config/tests/test_config.py +++ b/osprey_worker/src/osprey/engine/config/tests/test_config.py @@ -1,6 +1,5 @@ import json import textwrap -from typing import Dict from unittest.mock import MagicMock import pytest @@ -43,7 +42,7 @@ def handler(registry: ConfigRegistry) -> ConfigSubkeyHandler: return ConfigSubkeyHandler(registry, make_validated_sources_with_config({})) -def make_validated_sources_with_config(raw_config: Dict[str, object]) -> ValidatedSources: +def make_validated_sources_with_config(raw_config: dict[str, object]) -> ValidatedSources: main = Source(path=SOURCE_ENTRY_POINT_PATH, contents='', actual_path=None) sources = Sources( sources={SOURCE_ENTRY_POINT_PATH: main}, diff --git a/osprey_worker/src/osprey/engine/config/utils.py b/osprey_worker/src/osprey/engine/config/utils.py index e738def..80d8a4e 100644 --- a/osprey_worker/src/osprey/engine/config/utils.py +++ b/osprey_worker/src/osprey/engine/config/utils.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Type, Union +from typing import Any, Type from osprey.engine.ast.sources import SourcesConfig from pydantic.fields import SHAPE_LIST, SHAPE_SET @@ -11,7 +11,7 @@ def parse_config_with_auto_default( # Since our configs are based on YAML, each config object can be a mapping-like object # or a list-like object. Therefore, when the config is empty # or missing, the default value should match the model's expected shape. - default_config_obj: Union[Dict[str, Any], List[Any]] = {} + default_config_obj: dict[str, Any] | list[Any] = {} if model.__custom_root_type__ and model.__fields__['__root__'].shape in [SHAPE_LIST, SHAPE_SET]: default_config_obj = [] diff --git a/osprey_worker/src/osprey/engine/conftest.py b/osprey_worker/src/osprey/engine/conftest.py index d3a0230..01b5173 100644 --- a/osprey_worker/src/osprey/engine/conftest.py +++ b/osprey_worker/src/osprey/engine/conftest.py @@ -2,22 +2,15 @@ import itertools import json import pathlib import sys -from contextlib import contextmanager +from collections.abc import Callable, Generator, Iterator +from contextlib import AbstractContextManager, contextmanager from datetime import datetime from textwrap import dedent from typing import ( TYPE_CHECKING, Any, - Callable, - ContextManager, - Dict, - Generator, - Iterator, - Optional, - Set, Type, TypeVar, - Union, ) import gevent.pool @@ -52,7 +45,7 @@ def config_setup() -> Generator[Any, None, None]: CONFIG.instance().unconfigure_for_tests() -SourcesDict = Union[Sources, str, Dict[str, str]] +SourcesDict = Sources | str | dict[str, str] CheckOutputFunction = Callable[[str], bool] _WINDOWS_FRIENDLY_SUBSTITUTIONS = { @@ -181,7 +174,7 @@ class RunValidationFunction(Protocol): self, sources_dict: SourcesDict, warning_as_error: bool = ..., - validator_registry: Optional[ValidatorRegistry] = ..., + validator_registry: ValidatorRegistry | None = ..., ) -> ValidatedSources: ... @@ -200,7 +193,7 @@ def run_validation(request: 'FixtureRequest', udf_registry: UDFRegistry) -> RunV entry-point. Automatically de-dents texts, so you can use triple-quoted strings that are nicely formatted. """ - validators: Set[Type[BaseValidator]] = set( + validators: set[Type[BaseValidator]] = set( assert_issubclass(validator, BaseValidator) for validator in itertools.chain.from_iterable( assert_isinstance(n.args[0], list) for n in request.node.iter_markers('use_validators') @@ -216,7 +209,7 @@ def run_validation(request: 'FixtureRequest', udf_registry: UDFRegistry) -> RunV def run_validation( sources_dict: SourcesDict, warning_as_error: bool = False, - validator_registry: Optional[ValidatorRegistry] = None, + validator_registry: ValidatorRegistry | None = None, ) -> ValidatedSources: context = ValidationContext( sources=into_sources(sources_dict), @@ -251,13 +244,13 @@ class ExecuteWithResultFunction(Protocol): def __call__( self, sources_dict: SourcesDict, - data: Optional[Dict[str, object]] = ..., - secret_data: Optional[Dict[str, str]] = ..., + data: dict[str, object] | None = ..., + secret_data: dict[str, str] | None = ..., action_name: str = ..., action_id: int = ..., - udf_helpers: Optional[UDFHelpers] = None, - async_pool: Optional[gevent.pool.Pool] = ..., - action_time: Optional[datetime] = ..., + udf_helpers: UDFHelpers | None = None, + async_pool: gevent.pool.Pool | None = ..., + action_time: datetime | None = ..., ) -> ExecutionResult: ... @@ -265,15 +258,15 @@ class ExecuteFunction(Protocol): def __call__( self, sources_dict: SourcesDict, - data: Optional[Dict[str, object]] = ..., - secret_data: Optional[Dict[str, str]] = ..., + data: dict[str, object] | None = ..., + secret_data: dict[str, str] | None = ..., action_name: str = ..., action_id: int = ..., - udf_helpers: Optional[UDFHelpers] = None, - async_pool: Optional[gevent.pool.Pool] = ..., - action_time: Optional[datetime] = ..., + udf_helpers: UDFHelpers | None = None, + async_pool: gevent.pool.Pool | None = ..., + action_time: datetime | None = ..., allow_errors: bool = ..., - ) -> Dict[str, object]: ... + ) -> dict[str, object]: ... @pytest.fixture() @@ -282,13 +275,13 @@ def execute_with_result(udf_registry: UDFRegistry) -> ExecuteWithResultFunction: def execute_with_result_( sources_dict: SourcesDict, - data: Optional[Dict[str, object]] = None, - secret_data: Optional[Dict[str, str]] = None, + data: dict[str, object] | None = None, + secret_data: dict[str, str] | None = None, action_name: str = 'test', action_id: int = 1, - udf_helpers: Optional[UDFHelpers] = None, - async_pool: Optional[gevent.pool.Pool] = None, - action_time: Optional[datetime] = None, + udf_helpers: UDFHelpers | None = None, + async_pool: gevent.pool.Pool | None = None, + action_time: datetime | None = None, ) -> ExecutionResult: sources = into_sources(sources_dict) @@ -332,15 +325,15 @@ def execute(execute_with_result: ExecuteWithResultFunction) -> ExecuteFunction: def execute_( sources_dict: SourcesDict, - data: Optional[Dict[str, object]] = None, - secret_data: Optional[Dict[str, str]] = None, + data: dict[str, object] | None = None, + secret_data: dict[str, str] | None = None, action_name: str = 'test', action_id: int = 1, - udf_helpers: Optional[UDFHelpers] = None, - async_pool: Optional[gevent.pool.Pool] = None, - action_time: Optional[datetime] = None, + udf_helpers: UDFHelpers | None = None, + async_pool: gevent.pool.Pool | None = None, + action_time: datetime | None = None, allow_errors: bool = False, - ) -> Dict[str, object]: + ) -> dict[str, object]: result = execute_with_result( sources_dict=sources_dict, data=data, @@ -387,7 +380,7 @@ def udf_registry(request: 'FixtureRequest') -> UDFRegistry: return udf_registry -CheckFailureFunction = Callable[[], ContextManager[None]] +CheckFailureFunction = Callable[[], AbstractContextManager[None]] @pytest.fixture() diff --git a/osprey_worker/src/osprey/engine/executor/custom_extracted_features.py b/osprey_worker/src/osprey/engine/executor/custom_extracted_features.py index 7d9c3df..9d2f6ba 100644 --- a/osprey_worker/src/osprey/engine/executor/custom_extracted_features.py +++ b/osprey_worker/src/osprey/engine/executor/custom_extracted_features.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod from dataclasses import dataclass from datetime import datetime -from typing import Any, Dict, Generic, List, TypeVar, Union +from typing import Any, Generic, TypeVar SerializableT = TypeVar( - 'SerializableT', bound=Union[str, int, float, bool, None, List[Any], Dict[str, Any]], covariant=True + 'SerializableT', bound=str | int | float | bool | None | list[Any] | dict[str, Any], covariant=True ) diff --git a/osprey_worker/src/osprey/engine/executor/dependency_chain.py b/osprey_worker/src/osprey/engine/executor/dependency_chain.py index 82ebcd7..6666af8 100644 --- a/osprey_worker/src/osprey/engine/executor/dependency_chain.py +++ b/osprey_worker/src/osprey/engine/executor/dependency_chain.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING from osprey.engine.utils.types import add_slots @@ -18,5 +18,5 @@ class DependencyChain: executor: 'BaseNodeExecutor[ASTNode, object]' """The executor that we are holding dependencies for.""" - dependent_on: Tuple['DependencyChain', ...] + dependent_on: tuple['DependencyChain', ...] """The requisite dependency chains that must be resolved before we can execute the node `executor`.""" diff --git a/osprey_worker/src/osprey/engine/executor/execution_context.py b/osprey_worker/src/osprey/engine/executor/execution_context.py index 35e3c43..56ff614 100644 --- a/osprey_worker/src/osprey/engine/executor/execution_context.py +++ b/osprey_worker/src/osprey/engine/executor/execution_context.py @@ -2,20 +2,13 @@ import json import logging import traceback from collections import defaultdict +from collections.abc import Iterable, Mapping, Sequence from dataclasses import dataclass, field from datetime import datetime from functools import lru_cache from typing import ( TYPE_CHECKING, Any, - DefaultDict, - Dict, - Iterable, - List, - Mapping, - Optional, - Sequence, - Set, Type, TypeAlias, TypeVar, @@ -119,10 +112,10 @@ class ExternalServiceException(Exception): class WhenRulesAuditEntry: """Audit record for a single WhenRules evaluation.""" - rules_evaluated: List[str] - rules_matched: List[str] - rules_failed: List[str] - effects_emitted: List[str] + rules_evaluated: list[str] + rules_matched: list[str] + rules_failed: list[str] + effects_emitted: list[str] effects_failed: int is_degraded: bool @@ -155,19 +148,19 @@ class ExecutionContext: self._input_encoding = action.encoding self._execution_graph = execution_graph self._udf_helpers: UDFHelpers = helpers - self._outputs: Dict[str, Any] = {} - self._pending_executions: Set[DependencyChain] = set() - self._resolved_node_values: Dict[int, NodeResult] = {} - self._visited_executions: Set[DependencyChain] = set() + self._outputs: dict[str, Any] = {} + self._pending_executions: set[DependencyChain] = set() + self._resolved_node_values: dict[int, NodeResult] = {} + self._visited_executions: set[DependencyChain] = set() # a k/v store of effects, by effect type - self._effects: DefaultDict[Type[EffectBase], List[EffectBase]] = defaultdict(list) - self._external_service_accessors_by_getter_id: Dict[int, Any] = {} - self._async_external_service_accessors_by_getter_id: Dict[int, Any] = {} + self._effects: defaultdict[Type[EffectBase], list[EffectBase]] = defaultdict(list) + self._external_service_accessors_by_getter_id: dict[int, Any] = {} + self._async_external_service_accessors_by_getter_id: dict[int, Any] = {} self._dependency_dag = TopologicalSorter() - self._chain_by_id: Dict[int, DependencyChain] = {} + self._chain_by_id: dict[int, DependencyChain] = {} # feature name -> serializable feature - self._custom_extracted_features: Dict[str, Any] = {} - self._rule_audit_entries: List[WhenRulesAuditEntry] = [] + self._custom_extracted_features: dict[str, Any] = {} + self._rule_audit_entries: list[WhenRulesAuditEntry] = [] self.enqueue_source(execution_graph.get_entry_point()) @@ -214,7 +207,7 @@ class ExecutionContext: """Called by the assignment node executor to store an output key/value pair.""" self._outputs[key] = value - def get_outputs(self) -> Dict[str, Any]: + def get_outputs(self) -> dict[str, Any]: """Gets the output of the executor. This should only be called by the main executor, once execution has finished. Under no circumstance should anything else call this function.""" return { @@ -222,7 +215,7 @@ class ExecutionContext: for k, v in self._outputs.items() } - def get_data(self) -> Dict[str, Any]: + def get_data(self) -> dict[str, Any]: """Gets the input-data that the execution context is currently being invoked upon.""" return self._data @@ -230,7 +223,7 @@ class ExecutionContext: """Gets the encoding type of the Osprey action data (e.g. json or proto)""" return self._input_encoding - def get_secret_data(self) -> Dict[str, Any]: + def get_secret_data(self) -> dict[str, Any]: """Gets the secret input-data that the execution context is currently being invoked upon.""" return self._action.secret_data @@ -275,7 +268,7 @@ class ExecutionContext: def add_rule_audit_entry(self, entry: WhenRulesAuditEntry) -> None: self._rule_audit_entries.append(entry) - def get_rule_audit_entries(self) -> List[WhenRulesAuditEntry]: + def get_rule_audit_entries(self) -> list[WhenRulesAuditEntry]: return list(self._rule_audit_entries) def add_custom_extracted_feature( @@ -303,9 +296,9 @@ class ExecutionContext: for custom_extracted_feature in custom_extracted_features: self.add_custom_extracted_feature(custom_extracted_feature, error_on_duplicate_keys) - def get_extracted_features(self) -> Dict[str, Any]: + def get_extracted_features(self) -> dict[str, Any]: """ - Returns a `Dict[str, Any]` of all of the extracted features, including the base extracted features ("outputs") + Returns a `dict[str, Any]` of all of the extracted features, including the base extracted features ("outputs") and any custom extracted features supplied via `add_custom_extracted_feature` or `add_custom_extracted_features`. If any custom extracted features have the same key as a base extracted feature, the custom extracted feature will @@ -399,13 +392,13 @@ class Action: action_id: int action_name: str - data: Dict[str, Any] + data: dict[str, Any] timestamp: datetime - secret_data: Dict[str, Any] = field(default_factory=dict) + secret_data: dict[str, Any] = field(default_factory=dict) encoding: str = 'unknown' @classmethod - def from_dict(cls: Type[_ActionT], d: Dict[str, Any]) -> '_ActionT': + def from_dict(cls: Type[_ActionT], d: dict[str, Any]) -> '_ActionT': return cls( action_id=int(d['action_id']), action_name=d['action_name'], @@ -414,7 +407,7 @@ class Action: timestamp=datetime.fromisoformat(d['timestamp']), ) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: # secret data intentionally left out return { 'action_id': self.action_id, @@ -444,16 +437,16 @@ class NodeErrorInfo: class ExecutionResult: """The result of the execution of an action.""" - extracted_features: Dict[str, Any] + extracted_features: dict[str, Any] action: Action # A k/v store of effects, by effect class type effects: Mapping[Type[EffectBase], Sequence[EffectBase]] error_infos: Sequence[NodeErrorInfo] # leaving it up to the users of `validator_results`, but maybe we want to enforce # some kind of typing when outputing `validator_results` - validator_results: Dict[Any, Any] = field(default_factory=dict) + validator_results: dict[Any, Any] = field(default_factory=dict) sample_rate: int = 100 - trace_id: Optional[str] = None + trace_id: str | None = None rule_audit_entries: Sequence[WhenRulesAuditEntry] = field(default_factory=list) def add_custom_extracted_feature(self, custom_extracted_feature: CustomExtractedFeature[Any]) -> None: diff --git a/osprey_worker/src/osprey/engine/executor/execution_graph.py b/osprey_worker/src/osprey/engine/executor/execution_graph.py index 5299141..fe506fd 100644 --- a/osprey_worker/src/osprey/engine/executor/execution_graph.py +++ b/osprey_worker/src/osprey/engine/executor/execution_graph.py @@ -1,4 +1,7 @@ -from typing import TYPE_CHECKING, Any, Dict, Hashable, Iterator, List, Optional, Sequence, Set, TypeVar +from __future__ import annotations + +from collections.abc import Hashable, Iterator, Sequence +from typing import TYPE_CHECKING, Any, TypeVar from osprey.engine.ast.grammar import Assign, ASTNode, Load, Name, Source, Statement from osprey.engine.utils.periodic_execution_yielder import maybe_periodic_yield @@ -29,10 +32,10 @@ class ExecutionGraph: '_nodes_to_unwrap', ) - _root_node_executor_mapping: Dict[int, DependencyChain] + _root_node_executor_mapping: dict[int, DependencyChain] """This is a mapping of the node to its dependency chain. """ - _assignment_executor_mapping: Dict[str, DependencyChain] + _assignment_executor_mapping: dict[str, DependencyChain] """This is a mapping of an identifier (stored Name), to the dependency chain which would execute it.""" _node_executor_registry: 'NodeExecutorRegistry' @@ -42,14 +45,14 @@ class ExecutionGraph: _validated_sources: 'ValidatedSources' """The validated sources that this execution graph was constructed from.""" - _sorted_dependency_chains: Dict[Source, Sequence[DependencyChain]] + _sorted_dependency_chains: dict[Source, Sequence[DependencyChain]] """A dict of sources to sorted dependency chains.""" - _nodes_to_unwrap: Set[int] + _nodes_to_unwrap: set[int] """ID's for nodes that need to be unwrapped to its inner type when used.""" def __init__( - self, node_executor_registry: 'NodeExecutorRegistry', sources: 'ValidatedSources', nodes_to_unwrap: Set[int] + self, node_executor_registry: 'NodeExecutorRegistry', sources: 'ValidatedSources', nodes_to_unwrap: set[int] ): self._root_node_executor_mapping = {} self._assignment_executor_mapping = {} @@ -109,7 +112,7 @@ class ExecutionGraph: def compile_execution_graph( - validated_sources: 'ValidatedSources', node_executor_registry: Optional['NodeExecutorRegistry'] = None + validated_sources: 'ValidatedSources', node_executor_registry: 'NodeExecutorRegistry' | None = None ) -> ExecutionGraph: """Given a validated sources collection, compiles it into an execution graph that can then be used by the executor.""" @@ -126,14 +129,14 @@ def compile_execution_graph( except KeyError: sorted_sources = [] try: - nodes_to_unwrap: Set[int] = validated_sources.get_validator_result(ValidateStaticTypes).nodes_to_unwrap + nodes_to_unwrap: set[int] = validated_sources.get_validator_result(ValidateStaticTypes).nodes_to_unwrap except KeyError: nodes_to_unwrap = set() instance = ExecutionGraph( node_executor_registry=node_executor_registry, sources=validated_sources, nodes_to_unwrap=nodes_to_unwrap ) - ordered_sources: List[Source] = list(chain_dedupe(iter(sorted_sources), iter(validated_sources.sources))) + ordered_sources: list[Source] = list(chain_dedupe(iter(sorted_sources), iter(validated_sources.sources))) for source in ordered_sources: # noinspection PyProtectedMember @@ -150,7 +153,7 @@ def compile_execution_graph( def chain_dedupe(a: Iterator[T], b: Iterator[T]) -> Iterator[T]: - seen: Set[T] = set() + seen: set[T] = set() for iterator in (a, b): for item in iterator: @@ -165,7 +168,7 @@ def _topologically_sort_dependency_chain_for( execution_graph: ExecutionGraph, source: Source ) -> Sequence[DependencyChain]: sorted_chain = [] - visited: Set[DependencyChain] = set() + visited: set[DependencyChain] = set() def do_topological_sort(chain: DependencyChain) -> None: for dependency in chain.dependent_on: diff --git a/osprey_worker/src/osprey/engine/executor/execution_visualizer.py b/osprey_worker/src/osprey/engine/executor/execution_visualizer.py index 435931d..96ba03b 100644 --- a/osprey_worker/src/osprey/engine/executor/execution_visualizer.py +++ b/osprey_worker/src/osprey/engine/executor/execution_visualizer.py @@ -2,7 +2,7 @@ import copy import enum import pathlib import tempfile -from typing import Any, Dict, Optional, Protocol, Set, Type, Union +from typing import Any, Protocol, Type from graphviz import Digraph from osprey.engine.ast.grammar import ( @@ -36,7 +36,7 @@ class EngineLike(Protocol): own engine without dragging in the sync singleton. """ - def get_known_action_names(self) -> Set[str]: ... + def get_known_action_names(self) -> set[str]: ... def get_config_subkey(self, model_class: Type[ModelT]) -> ModelT: ... @@ -108,8 +108,8 @@ def _merge_label_add_nodes_with_whenrules_nodes(data: GraphData) -> None: except IndexError: continue if node.type == NodeType.LABEL: - new_parents: Set[int] = set() - new_children: Dict[int, Any] = {} + new_parents: set[int] = set() + new_children: dict[int, Any] = {} # Remove old edges and collect the edges of the WhenRules node for child_id in copy.deepcopy(node.children): child_node = data.get_node(child_id) @@ -131,7 +131,7 @@ def _merge_label_add_nodes_with_whenrules_nodes(data: GraphData) -> None: data.create_edge(new_parent_id, node_id) -def _recursively_collect_all_children_ids(data: GraphData, root_node: Node, node_ids: Set[int]) -> None: +def _recursively_collect_all_children_ids(data: GraphData, root_node: Node, node_ids: set[int]) -> None: """ Iterates through the provided node's children and adds all of the IDs to node_ids """ @@ -142,7 +142,7 @@ def _recursively_collect_all_children_ids(data: GraphData, root_node: Node, node _recursively_collect_all_children_ids(data, data.get_node(child_id), node_ids) -def _recursively_collect_all_parent_ids(data: GraphData, root_node: Node, node_ids: Set[int]) -> None: +def _recursively_collect_all_parent_ids(data: GraphData, root_node: Node, node_ids: set[int]) -> None: """ Iterates through the provided node's parents and adds all of the IDs to node_ids """ @@ -155,7 +155,7 @@ def _recursively_collect_all_parent_ids(data: GraphData, root_node: Node, node_i def _create_label_view( data: GraphData, - label_names: Set[str], + label_names: set[str], show_label_upstream: bool, show_label_downstream: bool, ) -> None: @@ -163,8 +163,8 @@ def _create_label_view( Turns the provided GraphData into a label view graph by conforming to the upstream/downstream view requests """ # Grab all nodes matching the requested label names - root_nodes: Set[Node] = set() - safe_node_ids: Set[int] = set() + root_nodes: set[Node] = set() + safe_node_ids: set[int] = set() for node_id in data.get_node_ids(): node = data.get_node(node_id) if node.type == NodeType.LABEL and node.data.get('label_name') in label_names: @@ -189,7 +189,7 @@ def _create_label_view( def _graph_data_post_processing( data: GraphData, graph_view_type: GraphViewType, - label_names: Set[str], + label_names: set[str], show_label_upstream: bool, show_label_downstream: bool, ) -> None: @@ -209,7 +209,7 @@ def _graph_data_post_processing( def process_graph_data( data: GraphData, graph_view_type: GraphViewType, - label_names: Set[str], + label_names: set[str], show_label_upstream: bool, show_label_downstream: bool, ) -> None: @@ -223,13 +223,12 @@ def process_graph_data( def render_graph( execution_graph: ExecutionGraph, # The compiled execution graph to render - action_names: Optional[Set[str]] = None, # Action names to show - label_names: Optional[Set[str]] = None, # Label names to show + action_names: set[str] | None = None, # Action names to show + label_names: set[str] | None = None, # Label names to show show_label_upstream: bool = False, # Upstream for label view show_label_downstream: bool = True, # Downstream for label view - engine: Optional[ - EngineLike - ] = None, # Engine instance to resolve action/label names from; falls back to the sync ENGINE singleton + engine: EngineLike + | None = None, # Engine instance to resolve action/label names from; falls back to the sync ENGINE singleton ) -> 'RenderedDigraph': """ Generate a rules vizualization graph based on the provided parameters. @@ -260,11 +259,11 @@ def render_graph( def _render_graph( - all_action_names: Set[str], # All action names that exist within Osprey - all_label_names: Set[str], # All label names that exist within Osprey Rules + all_action_names: set[str], # All action names that exist within Osprey + all_label_names: set[str], # All label names that exist within Osprey Rules execution_graph: ExecutionGraph, # The compiled execution graph to render - action_names_to_render: Optional[Set[str]] = None, # Action names to show - label_names_to_render: Optional[Set[str]] = None, # Label names to show + action_names_to_render: set[str] | None = None, # Action names to show + label_names_to_render: set[str] | None = None, # Label names to show show_label_upstream: bool = False, # Upstream for label view show_label_downstream: bool = True, # Downstream for label view ) -> 'RenderedDigraph': @@ -327,8 +326,8 @@ def _render_graph( name += ' [Type: ' + node_type.name + '] [Path: ' + path + ']' return name - def get_node_value(node: ASTNode) -> Optional[Any]: - value: Optional[Any] + def get_node_value(node: ASTNode) -> Any | None: + value: Any | None if isinstance(node, Call): path = get_path_from_require_node(node) if path: @@ -351,7 +350,7 @@ def _render_graph( value = None return value - def get_node_type(node: ASTNode, node_type: Type[ASTNode], node_value: Optional[str]) -> NodeType: + def get_node_type(node: ASTNode, node_type: Type[ASTNode], node_value: str | None) -> NodeType: if isinstance(node, Call) and node.func.identifier == 'Require' and node_value and node_value.endswith('.sml'): return NodeType.FILE elif is_rule_node(node): @@ -387,9 +386,9 @@ def _render_graph( span=str(node.span), ) - traversed_paths: Set[str] = set() + traversed_paths: set[str] = set() - def handle_label_node_if_present(node: ASTNode) -> Optional[Node]: + def handle_label_node_if_present(node: ASTNode) -> Node | None: if not isinstance(node, Call) or node.func.identifier not in [label.value for label in LabelType]: return None label_name: str = [i.value.value for i in node.arguments if i.name == 'label'][0] # type: ignore @@ -409,14 +408,14 @@ def _render_graph( if current_node.type == NodeType.FILE: load_path(current_node.data['file_path'], current_node) - referenced_label_nodes: Set[str] = set() + referenced_label_nodes: set[str] = set() def create_node_from_label_name( label_name: str, - entity_name: Optional[str], - label_type: Optional[LabelType] = None, + entity_name: str | None, + label_type: LabelType | None = None, path: str = 'Unknown path', - ) -> Optional[Node]: + ) -> Node | None: if label_name not in referenced_label_nodes: referenced_label_nodes.add(label_name) @@ -475,7 +474,7 @@ def _render_graph( chain = execution_graph.get_dependency_chain(statement) render_dependency_recursively(chain, root_dependency=root_dependency) - def get_path_from_require_node(node: ASTNode) -> Optional[str]: + def get_path_from_require_node(node: ASTNode) -> str | None: if not (isinstance(node, Call) and node.func.identifier == 'Require' and isinstance(node.func.context, Load)): return None encapsulated_string: str @@ -497,9 +496,9 @@ def _render_graph( def render_dependency_recursively( current_dependency: DependencyChain, # A representation of the root node for the current dependency chain, if any. - root_dependency: Union[DependencyChain, Node, None] = None, + root_dependency: DependencyChain | Node | None = None, # Set this to skip the current node - dependent_node: Optional[Node] = None, + dependent_node: Node | None = None, ) -> Node: skip_next_node: bool = False if not dependent_node: @@ -519,7 +518,7 @@ def _render_graph( render_dependency_recursively(dependency, root_dependency=root_dependency, dependent_node=node) if root_dependency and len(current_dependency.dependent_on) == 0: - root_node: Union[ASTNode, Node] + root_node: ASTNode | Node if isinstance(root_dependency, DependencyChain): root_node = create_node_from_ast(root_dependency.executor.node, root_dependency.executor.node_type) associate_edge(root_node.id, node.id, '#FF00FF') @@ -553,7 +552,7 @@ def _render_graph( class RenderedDigraph: - def _render_digraph_from_json_data(self, data: Dict[str, Any]) -> Digraph: + def _render_digraph_from_json_data(self, data: dict[str, Any]) -> Digraph: """ Converts JSON data to a Digraph """ @@ -563,7 +562,7 @@ class RenderedDigraph: dot.attr(margin='0,0') dot.attr(pad='0.5,0.5') - def get_attrs_from_json_node(node: Dict[str, Any]) -> Dict[str, str]: + def get_attrs_from_json_node(node: dict[str, Any]) -> dict[str, str]: attrs = { 'label': node['name'], 'shape': 'box', @@ -608,7 +607,7 @@ class RenderedDigraph: attrs['fontcolor'] = '#23272A' return attrs - def get_edge_attrs(color: str) -> Dict[str, str]: + def get_edge_attrs(color: str) -> dict[str, str]: edge_attrs = { 'color': color, 'fontcolor': '#99AAB5', @@ -626,8 +625,8 @@ class RenderedDigraph: dot.edge(edge['source'], edge['target'], _attributes=get_edge_attrs(edge['color'])) return dot - def __init__(self, data: Dict[str, Any]): - self._digraph: Optional[Digraph] = None + def __init__(self, data: dict[str, Any]): + self._digraph: Digraph | None = None self.data = data def view(self) -> None: diff --git a/osprey_worker/src/osprey/engine/executor/executor.py b/osprey_worker/src/osprey/engine/executor/executor.py index 9a697f7..cc9c113 100644 --- a/osprey_worker/src/osprey/engine/executor/executor.py +++ b/osprey_worker/src/osprey/engine/executor/executor.py @@ -1,5 +1,6 @@ from collections import defaultdict -from typing import Any, Dict, List, Optional, Sequence, Tuple +from collections.abc import Sequence +from typing import Any import gevent import gevent.pool @@ -34,11 +35,11 @@ from .udf_execution_helpers import UDFHelpers logger = get_logger(__name__) -InProgressSingletsType = Dict['gevent.Greenlet[NodeResult]', DependencyChain] +InProgressSingletsType = dict['gevent.Greenlet[NodeResult]', DependencyChain] """ A dictionary mapping in-progress async greenlets to the chain that they are executing. """ -InProgressBatchesType = Dict['gevent.Greenlet[Sequence[NodeResult]]', Sequence[DependencyChain]] +InProgressBatchesType = dict['gevent.Greenlet[Sequence[NodeResult]]', Sequence[DependencyChain]] """ A dictionary mapping in-progress batch async greenlets to the sequence of chains that they are executing. """ @@ -54,7 +55,7 @@ A sequence of finished async batches. def _get_ready_sync_and_async( allow_async: bool, context: ExecutionContext -) -> Tuple[Sequence[DependencyChain], Sequence[DependencyChain]]: +) -> tuple[Sequence[DependencyChain], Sequence[DependencyChain]]: _ready_sync = [] _ready_async = [] # Partition the ready chains into sync and async @@ -66,7 +67,7 @@ def _get_ready_sync_and_async( return _ready_sync, _ready_async -def _is_spammy_exception(e: Optional[Exception]) -> bool: +def _is_spammy_exception(e: Exception | None) -> bool: """ Add any spammy exceptions here to avoid sending them in metrics """ @@ -80,8 +81,8 @@ def _is_spammy_exception(e: Optional[Exception]) -> bool: def _get_metric_tags( - context: ExecutionContext, batchable_udf: Optional[BatchableUDFBase[Any, Any, Any]] = None -) -> List[str]: + context: ExecutionContext, batchable_udf: BatchableUDFBase[Any, Any, Any] | None = None +) -> list[str]: return [ f'action:{context.get_action_name()}', f'encoding:{context.get_data_encoding()}', @@ -102,7 +103,7 @@ def _wrapped_batch_execution( nodes: Sequence[ASTNode], # these are passed in for error tracking ^^ batchable_args: Sequence[Any], context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> Sequence[NodeResult]: """ Executes a batch of batchable UDFs, and returns an ordered list of the results of the execution. @@ -188,9 +189,9 @@ def _wrapped_batch_execution( def _wrapped_execution( chain: DependencyChain, context: ExecutionContext, - error_info_: List[NodeErrorInfo], + error_info_: list[NodeErrorInfo], ) -> NodeResult: - caught_exception: Optional[Exception] = None + caught_exception: Exception | None = None metric_tags = _get_metric_tags(context) if isinstance(chain.executor, CallExecutor): @@ -233,7 +234,7 @@ def _wrapped_execution( def _enqueue_batches( context: ExecutionContext, - error_infos: List[NodeErrorInfo], + error_infos: list[NodeErrorInfo], async_pool: gevent.pool.Pool, in_progress_async_batches: InProgressBatchesType, ready_async: Sequence[DependencyChain], @@ -245,8 +246,8 @@ def _enqueue_batches( Returns the remaining ready async chains that could not be batched together. """ # tuple( batch_type, routing_key ) -> list of tuple( chain, args ) - batch_chains: Dict[Tuple[type, str], List[Tuple[DependencyChain, Any]]] = defaultdict(list) - chains_to_remove: List[DependencyChain] = [] + batch_chains: dict[tuple[type, str], list[tuple[DependencyChain, Any]]] = defaultdict(list) + chains_to_remove: list[DependencyChain] = [] for async_chain in ready_async: if not isinstance(async_chain.executor, CallExecutor): continue @@ -302,9 +303,9 @@ def execute( execution_graph: ExecutionGraph, udf_helpers: UDFHelpers, action: Action, - async_pool: Optional[gevent.pool.Pool], + async_pool: gevent.pool.Pool | None, sample_rate: int = 100, - parent_tracer_span: Optional[TracerSpan] = None, + parent_tracer_span: TracerSpan | None = None, ) -> ExecutionResult: """A 'parallel' executor using gevent greenlets. @@ -322,7 +323,7 @@ def execute( context = ExecutionContext(execution_graph=execution_graph, helpers=udf_helpers, action=action) allow_async = async_pool is not None assert async_pool is None or async_pool.size is None or async_pool.size > 0 - error_infos: List[NodeErrorInfo] = [] + error_infos: list[NodeErrorInfo] = [] in_progress_async_singlets: InProgressSingletsType = {} in_progress_async_batches: InProgressBatchesType = {} diff --git a/osprey_worker/src/osprey/engine/executor/external_service_utils.py b/osprey_worker/src/osprey/engine/executor/external_service_utils.py index fb0918f..96475c3 100644 --- a/osprey_worker/src/osprey/engine/executor/external_service_utils.py +++ b/osprey_worker/src/osprey/engine/executor/external_service_utils.py @@ -1,5 +1,6 @@ +from collections.abc import Sequence from datetime import datetime -from typing import Dict, Generic, Optional, Sequence, Tuple, cast +from typing import Generic, cast from gevent.event import AsyncResult @@ -28,10 +29,10 @@ class ExternalServiceAccessor(Generic[KeyT, ValueT]): def __init__(self, service: ExternalService[KeyT, ValueT]): self._service = service - # Key -> Tuple[ AsyncResult[ValueT], Expiration datetime ] - self._cache: Dict[KeyT, Tuple[AsyncResult[ValueT], Optional[datetime]]] = {} + # Key -> tuple[ AsyncResult[ValueT], Expiration datetime ] + self._cache: dict[KeyT, tuple[AsyncResult[ValueT], datetime | None]] = {} - def _is_past_cache_expiration(self, cache_expiration: Optional[datetime]) -> bool: + def _is_past_cache_expiration(self, cache_expiration: datetime | None) -> bool: """ Helper method to perform a time check on an optional datetime. """ @@ -39,7 +40,7 @@ class ExternalServiceAccessor(Generic[KeyT, ValueT]): return False return datetime.now() > cache_expiration - def _get_cache_expiration_datetime(self) -> Optional[datetime]: + def _get_cache_expiration_datetime(self) -> datetime | None: """ Helper method to generate an optional cache expiration datetime based on the cache TTL. """ @@ -52,7 +53,7 @@ class ExternalServiceAccessor(Generic[KeyT, ValueT]): The new value is then used to update the cache entry for subsequent `get` calls. """ # Provide an explicit type annotation for cache_entry. - cache_entry: Tuple[AsyncResult[ValueT], Optional[datetime]] = ( + cache_entry: tuple[AsyncResult[ValueT], datetime | None] = ( AsyncResult(), self._get_cache_expiration_datetime(), ) diff --git a/osprey_worker/src/osprey/engine/executor/graph_data.py b/osprey_worker/src/osprey/engine/executor/graph_data.py index abfc333..2af3124 100644 --- a/osprey_worker/src/osprey/engine/executor/graph_data.py +++ b/osprey_worker/src/osprey/engine/executor/graph_data.py @@ -1,6 +1,6 @@ import copy from enum import StrEnum -from typing import Any, Dict, List, Optional, Set, Tuple +from typing import Any from typing_extensions import TypedDict @@ -37,18 +37,18 @@ class NodeData(TypedDict, total=False): name: str type: NodeType file_path: str - value: Optional[Any] - num_children: Optional[int] - label_name: Optional[str] - label_type: Optional[LabelType] - entity_name: Optional[str] + value: Any | None + num_children: int | None + label_name: str | None + label_type: LabelType | None + entity_name: str | None GRAPH_VIZ_NODE_TYPES = {NodeType.LABEL, NodeType.RULE} class Node: - def __init__(self, id: int, name: str, type: NodeType, file_path: str, value: Optional[Any]) -> None: + def __init__(self, id: int, name: str, type: NodeType, file_path: str, value: Any | None) -> None: """ Data structure: @@ -68,8 +68,8 @@ class Node: } """ self.id: int = id - self.children: Dict[int, Any] = {} - self.parents: Set[int] = set() + self.children: dict[int, Any] = {} + self.parents: set[int] = set() self.data: NodeData = {'id': id, 'name': name, 'type': type, 'file_path': file_path, 'value': value} self.type: NodeType = type @@ -128,39 +128,39 @@ class GraphData: O(1) insertion and deletion for edges; Allows us to store edge data """ - self._data: Dict[int, Node] = {} + self._data: dict[int, Node] = {} self._auto_increment: int = 1 # Key: Hash of contents, Value: ID of first node found with those contents - self._created_node_id_by_contents: Dict[int, int] = {} - self._created_edges: Set[Tuple[int, int]] = set() + self._created_node_id_by_contents: dict[int, int] = {} + self._created_edges: set[tuple[int, int]] = set() def get_node(self, id: int) -> Node: """ Get a node from the graph by ID """ - node: Optional[Node] = self._data.get(id) + node: Node | None = self._data.get(id) if not node: raise IndexError return node - def get_node_ids(self) -> Set[int]: + def get_node_ids(self) -> set[int]: node_ids = {k for k in self._data} return node_ids - def get_edges(self) -> Set[Tuple[int, int]]: - edges: Set[Tuple[int, int]] = set() + def get_edges(self) -> set[tuple[int, int]]: + edges: set[tuple[int, int]] = set() for node_id in self.get_node_ids(): node = self.get_node(node_id) for child_id in node.children: edges.add((node_id, child_id)) return copy.deepcopy(edges) - def _get_parents_with_data(self, id: int) -> Dict[int, Any]: + def _get_parents_with_data(self, id: int) -> dict[int, Any]: """ Get all parents for the given node (including the edge data) """ - parents: Set[int] = self.get_node(id).parents - parents_with_data: Dict[int, Any] = {} + parents: set[int] = self.get_node(id).parents + parents_with_data: dict[int, Any] = {} for parent in parents: try: parents_with_data[parent] = self.get_node(parent).children[id] @@ -177,9 +177,9 @@ class GraphData: name: str, type: NodeType, file_path: str, - value: Optional[Any], - extra_parameters: Optional[NodeData] = None, - span: Optional[str] = None, + value: Any | None, + extra_parameters: NodeData | None = None, + span: str | None = None, ) -> Node: """ Creates a new node at the given ID. @@ -202,9 +202,9 @@ class GraphData: def _get_contents_hash( self, type: NodeType, - value: Optional[Any], - span: Optional[str] = None, - extra_parameters: Optional[NodeData] = None, + value: Any | None, + span: str | None = None, + extra_parameters: NodeData | None = None, ) -> int: if extra_parameters is None: extra_parameters = {} @@ -221,7 +221,7 @@ class GraphData: else: return hash((type, value, span)) - def create_edge(self, source_id: int, target_id: int, edge_data: Optional[Dict[str, Any]] = None) -> None: + def create_edge(self, source_id: int, target_id: int, edge_data: dict[str, Any] | None = None) -> None: """ Attach the provided source node to the provided target node """ @@ -269,7 +269,7 @@ class GraphData: This method also reattaches the parents of the node to it's children (to compact the graph) """ - def get_average_hex(color_a: Optional[str], color_b: Optional[str]) -> Optional[str]: + def get_average_hex(color_a: str | None, color_b: str | None) -> str | None: """ Gets the average of two HEX colors """ @@ -284,8 +284,8 @@ class GraphData: color_c_decimal = round((color_a_decimal + color_b_decimal) / 2) return '#{0:06X}'.format(color_c_decimal).lstrip('0x').rstrip('L') - parents: Dict[int, Any] = self._get_parents_with_data(id) - children: Dict[int, Any] = copy.deepcopy(self._data[id].children) + parents: dict[int, Any] = self._get_parents_with_data(id) + children: dict[int, Any] = copy.deepcopy(self._data[id].children) for child_id in children: self.delete_edge(id, child_id) for parent_id in parents: @@ -305,7 +305,7 @@ class GraphData: Recursively counts the number of children below this node """ - def get_num_children_recursively(id: int, visited_ids: Set[int]) -> int: + def get_num_children_recursively(id: int, visited_ids: set[int]) -> int: children = 0 if id in visited_ids: return children @@ -317,7 +317,7 @@ class GraphData: return get_num_children_recursively(id, set()) - def get_node_ids_by_num_children(self) -> List[int]: + def get_node_ids_by_num_children(self) -> list[int]: """ Returns a list of node IDs sorted in descending order from most-children to least-children """ @@ -334,8 +334,8 @@ class GraphData: ) ) - def to_dict(self) -> Dict[str, Any]: - output_dict: Dict[str, Any] = {'nodes': [], 'edges': []} + def to_dict(self) -> dict[str, Any]: + output_dict: dict[str, Any] = {'nodes': [], 'edges': []} node_ids = self.get_node_ids_by_num_children() for node_id in node_ids: node = self.get_node(node_id) @@ -354,7 +354,7 @@ class GraphData: self._clean_edges(output_dict['edges'], output_dict['nodes']) return output_dict - def _clean_edges(self, edges: List[Dict[str, Any]], nodes: List[Dict[str, Any]]) -> None: + def _clean_edges(self, edges: list[dict[str, Any]], nodes: list[dict[str, Any]]) -> None: for i in range(len(edges) - 1, -1, -1): edge_data = edges[i] missing_source = True diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/_base_node_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/_base_node_executor.py index 6c62874..5bb7604 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/_base_node_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/_base_node_executor.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, ClassVar, Generic, Sequence, Type, TypeVar +from collections.abc import Sequence +from typing import TYPE_CHECKING, ClassVar, Generic, Type, TypeVar from ddtrace.span import Span from osprey.engine.ast.grammar import ASTNode diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/assign_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/assign_executor.py index 4306574..0601557 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/assign_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/assign_executor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, List +from typing import TYPE_CHECKING, Any from osprey.engine.ast.grammar import Assign, ASTNode @@ -24,5 +24,5 @@ class AssignExecutor(BaseNodeExecutor[Assign, Any]): resolved_not_error = execution_context.resolved(self._node.value, return_none_for_failed_values=False) return resolved_not_error - def get_dependent_nodes(self) -> List[ASTNode]: + def get_dependent_nodes(self) -> list[ASTNode]: return [self._node.value] diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/binary_comparison_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/binary_comparison_executor.py index 75beef6..7e7d315 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/binary_comparison_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/binary_comparison_executor.py @@ -1,5 +1,6 @@ import operator -from typing import TYPE_CHECKING, Callable, List +from collections.abc import Callable +from typing import TYPE_CHECKING from osprey.engine.ast.grammar import ( ASTNode, @@ -64,7 +65,7 @@ class BinaryComparisonExecutor(BaseNodeExecutor[BinaryComparison, bool]): return bool(self.comparator(left, right)) - def get_dependent_nodes(self) -> List[ASTNode]: + def get_dependent_nodes(self) -> list[ASTNode]: return [self._node.left, self._node.right] diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/binary_operation_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/binary_operation_executor.py index 3994c05..30a58a7 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/binary_operation_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/binary_operation_executor.py @@ -1,5 +1,6 @@ import operator -from typing import TYPE_CHECKING, Any, Callable, List +from collections.abc import Callable +from typing import TYPE_CHECKING, Any from osprey.engine.ast.grammar import ( Add, @@ -40,7 +41,7 @@ class BinaryOperationExecutor(BaseNodeExecutor[BinaryOperation, Any]): right = execution_context.resolved(self._node.right) return self.operator(left, right) - def get_dependent_nodes(self) -> List[ASTNode]: + def get_dependent_nodes(self) -> list[ASTNode]: return [self._node.left, self._node.right] diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/boolean_operation_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/boolean_operation_executor.py index bc5a55c..8caa4f5 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/boolean_operation_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/boolean_operation_executor.py @@ -1,4 +1,5 @@ -from typing import TYPE_CHECKING, Callable, Iterator, Sequence +from collections.abc import Callable, Iterator, Sequence +from typing import TYPE_CHECKING from osprey.engine.ast.grammar import And, ASTNode, BooleanOperation, Or diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/call_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/call_executor.py index 09455ed..48f8529 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/call_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/call_executor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, List +from typing import TYPE_CHECKING, Any from osprey.engine.ast.grammar import ASTNode, Call @@ -37,7 +37,7 @@ class CallExecutor(BaseNodeExecutor[Call, Any]): result = self._udf.execute(execution_context, resolved_arguments) return self._udf.check_result_type(result) - def get_dependent_nodes(self) -> List[ASTNode]: + def get_dependent_nodes(self) -> list[ASTNode]: return list(self.dependent_node_dict.values()) @property diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/literals/format_string_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/literals/format_string_executor.py index 5f9636f..3ba516c 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/literals/format_string_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/literals/format_string_executor.py @@ -1,4 +1,5 @@ -from typing import TYPE_CHECKING, Sequence +from collections.abc import Sequence +from typing import TYPE_CHECKING from osprey.engine.ast.grammar import ASTNode, FormatString diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/literals/list_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/literals/list_executor.py index 2a61d39..a6ae581 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/literals/list_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/literals/list_executor.py @@ -1,5 +1,5 @@ -from typing import TYPE_CHECKING, Any, Sequence -from typing import List as ListT +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any from osprey.engine.ast.grammar import ASTNode, List @@ -11,10 +11,10 @@ if TYPE_CHECKING: @NodeExecutorRegistry.register_globally -class ListExecutor(BaseNodeExecutor[List, ListT[Any]]): +class ListExecutor(BaseNodeExecutor[List, list[Any]]): node_type = List - def execute(self, execution_context: 'ExecutionContext') -> ListT[Any]: + def execute(self, execution_context: 'ExecutionContext') -> list[Any]: return [execution_context.resolved(n) for n in self._node.items] def get_dependent_nodes(self) -> Sequence[ASTNode]: diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/literals/number_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/literals/number_executor.py index ada3170..fed49db 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/literals/number_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/literals/number_executor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING from osprey.engine.ast.grammar import Number @@ -10,8 +10,8 @@ if TYPE_CHECKING: @NodeExecutorRegistry.register_globally -class NumberExecutor(BaseNodeExecutor[Number, Union[int, float]]): +class NumberExecutor(BaseNodeExecutor[Number, int | float]): node_type = Number - def execute(self, execution_context: 'ExecutionContext') -> Union[int, float]: + def execute(self, execution_context: 'ExecutionContext') -> int | float: return self._node.value diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/name_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/name_executor.py index 8f7917b..a030d62 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/name_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/name_executor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, List +from typing import TYPE_CHECKING, Any from osprey.engine.ast.grammar import ASTNode, Load, Name @@ -22,5 +22,5 @@ class NameExecutor(BaseNodeExecutor[Name, Any]): def execute(self, execution_context: 'ExecutionContext') -> Any: return execution_context.resolved(self._node) - def get_dependent_nodes(self) -> List[ASTNode]: + def get_dependent_nodes(self) -> list[ASTNode]: return [self._node] diff --git a/osprey_worker/src/osprey/engine/executor/node_executor/unary_operation_executor.py b/osprey_worker/src/osprey/engine/executor/node_executor/unary_operation_executor.py index be079e3..2dd036a 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor/unary_operation_executor.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor/unary_operation_executor.py @@ -1,5 +1,6 @@ import operator -from typing import TYPE_CHECKING, Any, Callable, List, Mapping, Type +from collections.abc import Callable, Mapping +from typing import TYPE_CHECKING, Any, Type from osprey.engine.ast.grammar import ASTNode, Not, UnaryOperation, UnaryOperator, USub @@ -24,7 +25,7 @@ class UnaryOperationExecutor(BaseNodeExecutor[UnaryOperation, Any]): operand = execution_context.resolved(self._node.operand) return self.operator(operand) - def get_dependent_nodes(self) -> List[ASTNode]: + def get_dependent_nodes(self) -> list[ASTNode]: return [self._node.operand] diff --git a/osprey_worker/src/osprey/engine/executor/node_executor_registry.py b/osprey_worker/src/osprey/engine/executor/node_executor_registry.py index 4cb2622..10a8fae 100644 --- a/osprey_worker/src/osprey/engine/executor/node_executor_registry.py +++ b/osprey_worker/src/osprey/engine/executor/node_executor_registry.py @@ -1,4 +1,6 @@ -from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Type +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, ClassVar, Type from osprey.engine.ast.grammar import ASTNode @@ -12,7 +14,7 @@ class NodeExecutorRegistry: """Holds a mapping of ASTNode -> BaseNodeExecutor, which will be used by the execution graph to build the dependency chains.""" - _instance: ClassVar[Optional['NodeExecutorRegistry']] = None + _instance: ClassVar['NodeExecutorRegistry' | None] = None @classmethod def get_instance(cls) -> 'NodeExecutorRegistry': @@ -28,7 +30,7 @@ class NodeExecutorRegistry: return cls.get_instance().register(node_executor) def __init__(self) -> None: - self._registered_executors: Dict[Type[ASTNode], Type['BaseNodeExecutor[Any, Any]']] = {} + self._registered_executors: dict[Type[ASTNode], Type['BaseNodeExecutor[Any, Any]']] = {} def register(self, node_executor: Type['BaseNodeExecutor[Any, Any]']) -> Type['BaseNodeExecutor[Any, Any]']: """Registers a node executor with this node executor registry, throwing an error if an executor has already diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_binary_comparison.py b/osprey_worker/src/osprey/engine/executor/tests/test_binary_comparison.py index 89a90fe..f321ed0 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_binary_comparison.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_binary_comparison.py @@ -24,8 +24,8 @@ def test_equality(execute: ExecuteFunction, statement: str, expected: bool) -> N f""" Foo: ExtractLiteral[str] = "hello" Bar: ExtractLiteral[str] = "world" - Bizz: Optional[str] = None - Buzz: Optional[str] = "some_value" + Bizz: str | None = None + Buzz: str | None = "some_value" Ret: bool = {statement} """ ) @@ -181,8 +181,8 @@ def test_optional_null_check_before_comparison(execute: ExecuteFunction, opt_val """Test that type narrowing works for X != None and X >= 90 pattern.""" data = execute( f""" - OptVal: Optional[int] = {opt_val} - # Type narrowing: after OptVal != None, OptVal is narrowed from Optional[int] to int + OptVal: int | None = {opt_val} + # Type narrowing: after OptVal != None, OptVal is narrowed from int | None to int Ret = OptVal != None and OptVal >= 90 """ ) @@ -194,8 +194,8 @@ def test_optional_null_check_chained_narrowing(execute: ExecuteFunction) -> None """Test chained type narrowing with multiple optional values.""" data = execute( """ - A: Optional[int] = 100 - B: Optional[int] = 50 + A: int | None = 100 + B: int | None = 50 # Both A and B get narrowed after their respective null checks Ret = A != None and B != None and A >= 90 and B >= 40 """ @@ -216,8 +216,8 @@ def test_optional_or_pattern_null_check(execute: ExecuteFunction, opt_val: objec """Test that type narrowing works for X == None or X >= 90 pattern.""" data = execute( f""" - OptVal: Optional[int] = {opt_val} - # Type narrowing: after OptVal == None is false, OptVal is narrowed from Optional[int] to int + OptVal: int | None = {opt_val} + # Type narrowing: after OptVal == None is false, OptVal is narrowed from int | None to int Ret = OptVal == None or OptVal >= 90 """ ) diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_call.py b/osprey_worker/src/osprey/engine/executor/tests/test_call.py index 141064f..f690252 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_call.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_call.py @@ -54,7 +54,7 @@ def test_dynamic_result_coerces_type(udf_registry: UDFRegistry, execute_with_res e_info = result.error_infos[0] assert isinstance(e_info.error, InvalidDynamicReturnType) assert str(e_info.error) == ( - 'Function `Test` with dynamic return type returned `int` but was expected to return `List[str]`.' + 'Function `Test` with dynamic return type returned `int` but was expected to return `list[str]`.' ) diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_custom_extracted_features.py b/osprey_worker/src/osprey/engine/executor/tests/test_custom_extracted_features.py index 37dfe3b..bd34a96 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_custom_extracted_features.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_custom_extracted_features.py @@ -1,7 +1,8 @@ import datetime from collections import defaultdict +from collections.abc import Sequence from dataclasses import dataclass -from typing import Any, List, Self, Sequence, Tuple +from typing import Any, Self from unittest.mock import Mock, patch from osprey.engine.executor.custom_extracted_features import ( @@ -33,7 +34,7 @@ def test_default_custom_extracted_features(): sample_rate_full = SampleRateExtractedFeature(sample_rate=100) sample_rate_full_packed = None - cases: Sequence[Tuple[CustomExtractedFeature, Any]] = [ + cases: Sequence[tuple[CustomExtractedFeature, Any]] = [ (action_id, action_id_packed), (timestamp, timestamp_packed), (error_count, error_count_packed), @@ -45,24 +46,24 @@ def test_default_custom_extracted_features(): @dataclass -class TestEffect(EffectToCustomExtractedFeatureBase[List[str]]): +class TestEffect(EffectToCustomExtractedFeatureBase[list[str]]): value: str @classmethod - def build_custom_extracted_feature_from_list(cls, values: List[Self]) -> CustomExtractedFeature[List[str]]: + def build_custom_extracted_feature_from_list(cls, values: list[Self]) -> CustomExtractedFeature[list[str]]: # isinstance check just helps with typing. it shouldnt be possible for it to fail cuz Self type return TestEffectsExtractedFeature(values=[value for value in values if isinstance(value, TestEffect)]) @dataclass -class TestEffectsExtractedFeature(CustomExtractedFeature[List[str]]): - values: List[TestEffect] +class TestEffectsExtractedFeature(CustomExtractedFeature[list[str]]): + values: list[TestEffect] @classmethod def feature_name(cls) -> str: return 'test_effects' - def get_serializable_feature(self) -> List[str] | None: + def get_serializable_feature(self) -> list[str] | None: return [value.value for value in self.values] diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_executor.py b/osprey_worker/src/osprey/engine/executor/tests/test_executor.py index 143ffd1..dcd8ca1 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_executor.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_executor.py @@ -1,7 +1,8 @@ import abc import json +from collections.abc import Sequence from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Sequence, Type +from typing import Any, Type import gevent import gevent.event @@ -20,13 +21,13 @@ from result import Err, Ok, Result class RecordingArguments(ArgumentsBase): id: str - routing_key: Optional[str] = None + routing_key: str | None = None class RecordingUdf(UDFBase[RecordingArguments, str], metaclass=abc.ABCMeta): @classmethod @abc.abstractmethod - def order_called(cls) -> List[str]: + def order_called(cls) -> list[str]: pass def execute(self, execution_context: ExecutionContext, arguments: RecordingArguments) -> str: @@ -37,10 +38,10 @@ class RecordingUdf(UDFBase[RecordingArguments, str], metaclass=abc.ABCMeta): @pytest.fixture() def recording_udf(udf_registry: UDFRegistry) -> Type[RecordingUdf]: class RecordingUdfImpl(RecordingUdf): - _order_called: List[str] = [] + _order_called: list[str] = [] @classmethod - def order_called(cls) -> List[str]: + def order_called(cls) -> list[str]: return cls._order_called RecordingUdfImpl.__name__ = 'RecordingUdf' @@ -51,7 +52,7 @@ def recording_udf(udf_registry: UDFRegistry) -> Type[RecordingUdf]: class BatchRecordingUdf(BatchableUDFBase[RecordingArguments, str, RecordingArguments], metaclass=abc.ABCMeta): @classmethod @abc.abstractmethod - def order_called(cls) -> List[List[str]]: + def order_called(cls) -> list[list[str]]: pass def execute(self, execution_context: ExecutionContext, arguments: RecordingArguments) -> str: @@ -76,10 +77,10 @@ class BatchRecordingUdf(BatchableUDFBase[RecordingArguments, str, RecordingArgum @pytest.fixture() def batch_recording_udf(udf_registry: UDFRegistry) -> Type[BatchRecordingUdf]: class BatchRecordingUdfImpl(BatchRecordingUdf): - _order_called: List[List[str]] = [] + _order_called: list[list[str]] = [] @classmethod - def order_called(cls) -> List[List[str]]: + def order_called(cls) -> list[list[str]]: return cls._order_called BatchRecordingUdfImpl.__name__ = 'BatchRecordingUdf' @@ -95,12 +96,12 @@ class BlockingArguments(ArgumentsBase): class BlockingUdf(UDFBase[BlockingArguments, str]): @classmethod @abc.abstractmethod - def order_called(cls) -> List[str]: + def order_called(cls) -> list[str]: pass @classmethod @abc.abstractmethod - def blocking(cls) -> Dict['BlockingUdf', 'gevent.Greenlet[object]']: + def blocking(cls) -> dict['BlockingUdf', 'gevent.Greenlet[object]']: pass @classmethod @@ -128,18 +129,18 @@ class BlockingUdf(UDFBase[BlockingArguments, str]): @pytest.fixture() def blocking_udf(udf_registry: UDFRegistry) -> Type[BlockingUdf]: class BlockingUdfImpl(BlockingUdf): - _order_called: List[str] = [] - _blocking: Dict['BlockingUdf', 'gevent.Greenlet[object]'] = {} + _order_called: list[str] = [] + _blocking: dict['BlockingUdf', 'gevent.Greenlet[object]'] = {} # Put this here (not in base) so it's reset for each test. execute_async = True @classmethod - def order_called(cls) -> List[str]: + def order_called(cls) -> list[str]: return cls._order_called @classmethod - def blocking(cls) -> Dict['BlockingUdf', 'gevent.Greenlet[object]']: + def blocking(cls) -> dict['BlockingUdf', 'gevent.Greenlet[object]']: return cls._blocking BlockingUdfImpl.__name__ = 'BlockingUdf' @@ -168,7 +169,7 @@ class BatchFailingUdf(BatchableUDFBase[BatchFailingUdfArgs, int, BatchFailingUdf @classmethod @abc.abstractmethod - def order_called(cls) -> List[List[int]]: + def order_called(cls) -> list[list[int]]: pass def execute(self, execution_context: ExecutionContext, arguments: BatchFailingUdfArgs) -> int: @@ -188,10 +189,10 @@ class BatchFailingUdf(BatchableUDFBase[BatchFailingUdfArgs, int, BatchFailingUdf @pytest.fixture() def batch_failing_udf(udf_registry: UDFRegistry) -> Type[BatchFailingUdf]: class BatchFailingUdfImpl(BatchFailingUdf): - _order_called: List[List[int]] = [] + _order_called: list[list[int]] = [] @classmethod - def order_called(cls) -> List[List[int]]: + def order_called(cls) -> list[list[int]]: return cls._order_called BatchFailingUdfImpl.__name__ = 'BatchFailingUdf' @@ -541,7 +542,7 @@ def test_errors_propagate_through_features_with_batching( # explicitly handle errors (rather than implicitly treating every value as Nullable) def test_errors_can_conditionally_be_consumed_as_none(udf_registry: UDFRegistry, execute: ExecuteFunction) -> None: class HadValueUdfArguments(ArgumentsBase): - value: Optional[object] + value: object | None class HadValueUdf(UDFBase[HadValueUdfArguments, str]): def execute(self, execution_context: ExecutionContext, arguments: HadValueUdfArguments) -> str: diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_graph_data.py b/osprey_worker/src/osprey/engine/executor/tests/test_graph_data.py index 7209c9c..7418a74 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_graph_data.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_graph_data.py @@ -37,7 +37,7 @@ def test_node_deletion() -> None: def test_node_deletion_with_edge_preservation() -> None: - """ # noqa: W605 + r""" # noqa: W605 We are testing that the following graph: 1-----2 @@ -81,7 +81,7 @@ def test_node_deletion_with_edge_preservation() -> None: def test_node_deletion_without_edge_preservation() -> None: - """ # noqa: W605 + r""" # noqa: W605 We are testing that the following graph: 1 2 diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_literals/test_export_fails_on_non_literal.txt b/osprey_worker/src/osprey/engine/executor/tests/test_literals/test_export_fails_on_non_literal.txt index 956b80d..21c7934 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_literals/test_export_fails_on_non_literal.txt +++ b/osprey_worker/src/osprey/engine/executor/tests/test_literals/test_export_fails_on_non_literal.txt @@ -2,4 +2,4 @@ error: expected `Literal` or `FormatString`, got `BinaryOperation` --> main.sml:4:27 | 4 | Foo: ExtractLiteral[int] = IntA + IntB - | ^ `ExtractLiteral` assignment expects an rvalue of type `Union[Literal, FormatString]` \ No newline at end of file + | ^ `ExtractLiteral` assignment expects an rvalue of type `Literal | FormatString` \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_render_graph.py b/osprey_worker/src/osprey/engine/executor/tests/test_render_graph.py index b92c182..57adc06 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_render_graph.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_render_graph.py @@ -1,6 +1,6 @@ import copy import json -from typing import Any, Dict, Set +from typing import Any import pytest from osprey.engine.ast_validator.validation_context import ValidatedSources @@ -149,8 +149,8 @@ def execution_graph(run_validation: RunValidationFunction) -> ExecutionGraph: def get_labels_view_graph( - execution_graph: ExecutionGraph, label_names: Set[str], show_upstream: bool = False, show_downstream: bool = True -) -> Dict[str, Any]: + execution_graph: ExecutionGraph, label_names: set[str], show_upstream: bool = False, show_downstream: bool = True +) -> dict[str, Any]: """ Returns a graph of the specified label_names """ @@ -162,11 +162,11 @@ def get_labels_view_graph( show_label_upstream=show_upstream, show_label_downstream=show_downstream, ) - val: Dict[str, Any] = json.loads(json.dumps(render.data)) + val: dict[str, Any] = json.loads(json.dumps(render.data)) return val -def get_actions_view_graph(execution_graph: ExecutionGraph, action_names: Set[str]) -> Dict[str, Any]: +def get_actions_view_graph(execution_graph: ExecutionGraph, action_names: set[str]) -> dict[str, Any]: """ Returns a graph of the specified action_names """ @@ -176,18 +176,18 @@ def get_actions_view_graph(execution_graph: ExecutionGraph, action_names: Set[st execution_graph=execution_graph, action_names_to_render=action_names, ) - val: Dict[str, Any] = json.loads(json.dumps(render.data)) + val: dict[str, Any] = json.loads(json.dumps(render.data)) return val -def assert_graphs_are_equal(actual_graph: Dict[str, Any], expected_graph: Dict[str, Any]) -> None: +def assert_graphs_are_equal(actual_graph: dict[str, Any], expected_graph: dict[str, Any]) -> None: """ Asserts that the two supplied graphs are equal. Note that actual_graph and expected_graph will have different unique IDs but the same data-- This is expected behavior, hence why this logic is necessary to ensure a fair comparison. """ - def remove_references_to_ids(graph: Dict[str, Any]) -> None: + def remove_references_to_ids(graph: dict[str, Any]) -> None: """ Removes all ID fields and replaces all node IDs inside edges with their actual node data """ diff --git a/osprey_worker/src/osprey/engine/executor/tests/test_udf_execution_helpers.py b/osprey_worker/src/osprey/engine/executor/tests/test_udf_execution_helpers.py index f2b8a4a..95fbf93 100644 --- a/osprey_worker/src/osprey/engine/executor/tests/test_udf_execution_helpers.py +++ b/osprey_worker/src/osprey/engine/executor/tests/test_udf_execution_helpers.py @@ -1,5 +1,3 @@ -from typing import List - import pytest from osprey.engine.conftest import ExecuteFunction from osprey.engine.executor.execution_context import ExecutionContext @@ -13,12 +11,12 @@ from osprey.engine.udf.registry import UDFRegistry class Arguments(ArgumentsBase): # this is checkign that the arguments are hashable message: str = '' - some_list: List[str] = [] + some_list: list[str] = [] class CountingService(ExternalService[Arguments, int]): def __init__(self) -> None: - self.calls: List[Arguments] = [] + self.calls: list[Arguments] = [] def get_from_service(self, key: Arguments) -> int: self.calls.append(key) diff --git a/osprey_worker/src/osprey/engine/executor/topological_sorter.py b/osprey_worker/src/osprey/engine/executor/topological_sorter.py index 93b5a7c..acb16d4 100644 --- a/osprey_worker/src/osprey/engine/executor/topological_sorter.py +++ b/osprey_worker/src/osprey/engine/executor/topological_sorter.py @@ -15,7 +15,8 @@ List of notable changes: so we optimize the prepare() step by skipping the cycle check. """ -from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple +from collections.abc import Iterable, Iterator +from typing import Any _NODE_OUT = -1 _NODE_DONE = -2 @@ -35,7 +36,7 @@ class _NodeInfo: # List of successor nodes. The list can contain duplicated elements as # long as they're all reflected in the successor's npredecessors attribute). - self.successors: List[Any] = [] + self.successors: list[Any] = [] class CycleError(ValueError): @@ -55,9 +56,9 @@ class CycleError(ValueError): class TopologicalSorter: """Provides functionality to topologically sort a graph of hashable nodes""" - def __init__(self, graph: Optional[Dict[Any, Iterable[Any]]] = None): - self._node2info: Dict[Any, _NodeInfo] = {} - self._ready_nodes: List[Any] = [] + def __init__(self, graph: dict[Any, Iterable[Any]] | None = None): + self._node2info: dict[Any, _NodeInfo] = {} + self._ready_nodes: list[Any] = [] self._npassedout = 0 self._nfinished = 0 self._needs_prepare = True @@ -117,7 +118,7 @@ class TopologicalSorter: self._ready_nodes = [i.node for i in self._node2info.values() if i.npredecessors == 0] self._needs_prepare = False - def get_ready(self) -> Tuple[Any, ...]: + def get_ready(self) -> tuple[Any, ...]: """Return a tuple of all the nodes that are ready. Initially it returns all nodes with no predecessors; once those are marked diff --git a/osprey_worker/src/osprey/engine/executor/udf_execution_helpers.py b/osprey_worker/src/osprey/engine/executor/udf_execution_helpers.py index 13f52ba..4230d50 100644 --- a/osprey_worker/src/osprey/engine/executor/udf_execution_helpers.py +++ b/osprey_worker/src/osprey/engine/executor/udf_execution_helpers.py @@ -1,7 +1,8 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Dict, Generic, Hashable, Type, TypeVar, cast +from collections.abc import Hashable +from typing import TYPE_CHECKING, Any, Generic, Type, TypeVar, cast from osprey.engine.executor.external_service_utils_base import ExternalService @@ -38,7 +39,7 @@ class UDFHelpers: """Holds a set of helpers necessary for UDFs to execute, such as an accessor for an external service.""" def __init__(self) -> None: - self._helpers: Dict[Type[HasHelperInternal[Any]], object] = {} + self._helpers: dict[Type[HasHelperInternal[Any]], object] = {} def set_udf_helper(self, udf_class: Type[HasHelperInternal[HelperT]], helper: HelperT) -> 'UDFHelpers': self._helpers[udf_class] = helper diff --git a/osprey_worker/src/osprey/engine/language_types/effects.py b/osprey_worker/src/osprey/engine/language_types/effects.py index 3adb728..55eee40 100644 --- a/osprey_worker/src/osprey/engine/language_types/effects.py +++ b/osprey_worker/src/osprey/engine/language_types/effects.py @@ -1,6 +1,7 @@ from abc import abstractmethod +from collections.abc import Iterable from dataclasses import dataclass, field -from typing import Generic, Iterable, List, Self +from typing import Generic, Self from osprey.engine.executor.custom_extracted_features import ( CustomExtractedFeature, @@ -16,10 +17,10 @@ class EffectBase: Effects are outcomes of `WhenRules` blocks, and are appended to the `ExecutionResult.effects`. They can also be automatically serialized into a custom extracted feature (`ExecutionResult.extracted_features`) - if they implement the `ListToCustomExtractedFeature[SerializableT]` protocol, i.e. implement a class method with spec: + if they implement the `listToCustomExtractedFeature[SerializableT]` protocol, i.e. implement a class method with spec: ```python @classmethod - def build_custom_extracted_feature_from_list(cls, values: List[Self]) -> CustomExtractedFeature[SerializableT]: + def build_custom_extracted_feature_from_list(cls, values: list[Self]) -> CustomExtractedFeature[SerializableT]: ... ``` @@ -30,7 +31,7 @@ class EffectBase: - Used in :class:`osprey_engine.packages.osprey_stdlib.udfs.labels.LabelAdd` and :class:`osprey_engine.packages.osprey_stdlib.udfs.labels.LabelRemove` """ - rules: List[RuleT] = field(default_factory=list) + rules: list[RuleT] = field(default_factory=list) """ The rules that caused this effect to be emitted. These are appended automatically during WhenRules execution. @@ -53,7 +54,7 @@ class EffectToCustomExtractedFeatureBase(EffectBase, Generic[SerializableT]): @classmethod @abstractmethod - def build_custom_extracted_feature_from_list(cls, values: List[Self]) -> CustomExtractedFeature[SerializableT]: + def build_custom_extracted_feature_from_list(cls, values: list[Self]) -> CustomExtractedFeature[SerializableT]: """ This method should return a custom extracted feature from a list of its own type. It will be called by the executor to build the custom extracted feature to represent the effect diff --git a/osprey_worker/src/osprey/engine/language_types/entities.py b/osprey_worker/src/osprey/engine/language_types/entities.py index 0af07dd..0900e20 100644 --- a/osprey_worker/src/osprey/engine/language_types/entities.py +++ b/osprey_worker/src/osprey/engine/language_types/entities.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, Tuple, Type, TypeVar, Union +from typing import Any, Type, TypeVar import typing_inspect from osprey.engine.language_types.osprey_invariant_generic import OspreyInvariantGeneric @@ -22,7 +22,7 @@ class EntityT(OspreyInvariantGeneric[_T], PostExecutionConvertible[_T]): if t not in (str, int): raise TypeError(f'Can only have `str` or `int` entities, got `{t.__name__}`') - def __class_getitem__(cls, args: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]: + def __class_getitem__(cls, args: Type[Any] | tuple[Type[Any], ...]) -> Type[Any]: ret_cls = super().__class_getitem__(args) # Because the super method returned we know we have reasonably shaped args diff --git a/osprey_worker/src/osprey/engine/language_types/experiments.py b/osprey_worker/src/osprey/engine/language_types/experiments.py index 6413ac4..9f06258 100644 --- a/osprey_worker/src/osprey/engine/language_types/experiments.py +++ b/osprey_worker/src/osprey/engine/language_types/experiments.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, List +from typing import Any from osprey.engine.utils.types import add_slots @@ -23,16 +23,16 @@ NOT_IN_EXPERIMENT_BUCKET_INDEX = -1 # bucket index value for entities not in th @add_slots @dataclass(frozen=True) -class ExperimentT(PostExecutionConvertible[List[str]]): +class ExperimentT(PostExecutionConvertible[list[str]]): name: str entity: EntityT[Any] - buckets: List[str] - bucket_sizes: List[float] + buckets: list[str] + bucket_sizes: list[float] resolved_bucket: str version: int revision: int - def to_post_execution_value(self) -> List[str]: + def to_post_execution_value(self) -> list[str]: return [ self.name, self.entity.id, diff --git a/osprey_worker/src/osprey/engine/language_types/labels.py b/osprey_worker/src/osprey/engine/language_types/labels.py index a6617d4..3db6a07 100644 --- a/osprey_worker/src/osprey/engine/language_types/labels.py +++ b/osprey_worker/src/osprey/engine/language_types/labels.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import timedelta -from typing import Any, List, Optional, Self, cast +from typing import Any, Self, cast from osprey.engine.executor.custom_extracted_features import CustomExtractedFeature from osprey.engine.language_types.effects import EffectToCustomExtractedFeatureBase @@ -16,7 +16,7 @@ from .rules import RuleT, add_slots @add_slots @dataclass -class LabelEffect(EffectToCustomExtractedFeatureBase[List[str]]): +class LabelEffect(EffectToCustomExtractedFeatureBase[list[str]]): """Stores a label effect of a WhenRules(...) invocation, which stores the label mutations that should occur once a given action has finished classification.""" @@ -29,13 +29,13 @@ class LabelEffect(EffectToCustomExtractedFeatureBase[List[str]]): name: str """The name of the label to apply.""" - expires_after: Optional[timedelta] = None + expires_after: timedelta | None = None """If set, the label effect has a timed expiration, which means that the reason will expire after this time.""" - delay_action_by: Optional[timedelta] = None + delay_action_by: timedelta | None = None """Osprey can be configured to respond to this duration downstream to delay when a label is applied and/or causes an effect""" - dependent_rule: Optional[RuleT] = None + dependent_rule: RuleT | None = None """If set, the effect will only be applied if the dependent rule evaluates to true.""" suppressed: bool = False @@ -45,14 +45,14 @@ class LabelEffect(EffectToCustomExtractedFeatureBase[List[str]]): return ENTITY_LABEL_MUTATION_DIMENSION_VALUE(self.entity.type, self.name, self.status) @classmethod - def build_custom_extracted_feature_from_list(cls, values: List[Self]) -> CustomExtractedFeature[List[str]]: - return LabelEffectsExtractedFeature(effects=cast(List[LabelEffect], values)) + def build_custom_extracted_feature_from_list(cls, values: list[Self]) -> CustomExtractedFeature[list[str]]: + return LabelEffectsExtractedFeature(effects=cast(list[LabelEffect], values)) @add_slots @dataclass -class LabelEffectsExtractedFeature(CustomExtractedFeature[List[str]]): - effects: List[LabelEffect] +class LabelEffectsExtractedFeature(CustomExtractedFeature[list[str]]): + effects: list[LabelEffect] @classmethod def feature_name(cls) -> str: @@ -62,5 +62,5 @@ class LabelEffectsExtractedFeature(CustomExtractedFeature[List[str]]): else ENTITY_LABEL_MUTATION_DIMENSION_NAME ) - def get_serializable_feature(self) -> List[str] | None: + def get_serializable_feature(self) -> list[str] | None: return [effect.to_str() for effect in self.effects] diff --git a/osprey_worker/src/osprey/engine/language_types/osprey_invariant_generic.py b/osprey_worker/src/osprey/engine/language_types/osprey_invariant_generic.py index bd64681..f8aa69a 100644 --- a/osprey_worker/src/osprey/engine/language_types/osprey_invariant_generic.py +++ b/osprey_worker/src/osprey/engine/language_types/osprey_invariant_generic.py @@ -1,4 +1,4 @@ -from typing import Any, Generic, Tuple, TypeVar, Union +from typing import Any, Generic, TypeVar _T = TypeVar('_T') @@ -12,10 +12,10 @@ class OspreyInvariantGeneric(Generic[_T]): """ # Enforce that any TypeVar used in this class actually is invariant. - def __class_getitem__(cls, args: Union[type, Tuple[type, ...]]) -> type: + def __class_getitem__(cls, args: type | tuple[type, ...]) -> type: # Mypy is super unhappy with all this runtime stuff, so lots of `Any`s and ignores generic_alias: Any = super().__class_getitem__(args) # type: ignore # Missing from Generic stub - params: Tuple[Any, ...] = generic_alias.__parameters__ + params: tuple[Any, ...] = generic_alias.__parameters__ if len(params) > 0: if len(params) != 1: raise TypeError(f'Expected one or zero parameters, got ({params})') diff --git a/osprey_worker/src/osprey/engine/language_types/post_execution_convertible.py b/osprey_worker/src/osprey/engine/language_types/post_execution_convertible.py index 285cffb..21d19ca 100644 --- a/osprey_worker/src/osprey/engine/language_types/post_execution_convertible.py +++ b/osprey_worker/src/osprey/engine/language_types/post_execution_convertible.py @@ -1,5 +1,5 @@ import abc -from typing import Generic, Optional, Type, TypeVar +from typing import Generic, Type, TypeVar import typing_inspect @@ -19,7 +19,7 @@ class PostExecutionConvertible(abc.ABC, Generic[_T]): # These are static methods so that the implementations can access the generic type. With a classmethod we'd just # get `PostExecutionConvertible`, but with the static method we'd get (say) `PostExecutionConvertible[str]`. @staticmethod - def maybe_post_execution_type(t: type) -> Optional[type]: + def maybe_post_execution_type(t: type) -> type | None: origin = typing_inspect.get_origin(t) if origin is None: origin = t diff --git a/osprey_worker/src/osprey/engine/language_types/rules.py b/osprey_worker/src/osprey/engine/language_types/rules.py index e1a8e79..dbfc667 100644 --- a/osprey_worker/src/osprey/engine/language_types/rules.py +++ b/osprey_worker/src/osprey/engine/language_types/rules.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Dict from osprey.engine.utils.types import add_slots @@ -12,7 +11,7 @@ class RuleT(PostExecutionConvertible[bool]): name: str value: bool description: str - features: Dict[str, str] + features: dict[str, str] def to_post_execution_value(self) -> bool: return self.value diff --git a/osprey_worker/src/osprey/engine/language_types/tests/test_osprey_invariant_generic.py b/osprey_worker/src/osprey/engine/language_types/tests/test_osprey_invariant_generic.py index a4d2b3c..20ed007 100644 --- a/osprey_worker/src/osprey/engine/language_types/tests/test_osprey_invariant_generic.py +++ b/osprey_worker/src/osprey/engine/language_types/tests/test_osprey_invariant_generic.py @@ -1,4 +1,5 @@ -from typing import Any, Mapping, Sequence, TypeVar +from collections.abc import Mapping, Sequence +from typing import Any, TypeVar import pytest from osprey.engine.language_types.osprey_invariant_generic import OspreyInvariantGeneric diff --git a/osprey_worker/src/osprey/engine/language_types/time_delta.py b/osprey_worker/src/osprey/engine/language_types/time_delta.py index 7bf7b85..dc56cff 100644 --- a/osprey_worker/src/osprey/engine/language_types/time_delta.py +++ b/osprey_worker/src/osprey/engine/language_types/time_delta.py @@ -1,6 +1,5 @@ import datetime from dataclasses import dataclass -from typing import Optional from osprey.engine.utils.types import add_slots @@ -17,7 +16,7 @@ class TimeDeltaT(PostExecutionConvertible[float]): return self.timedelta.total_seconds() @classmethod - def inner_from_optional(cls, maybe_time_delta: 'Optional[TimeDeltaT]') -> Optional[datetime.timedelta]: + def inner_from_optional(cls, maybe_time_delta: 'TimeDeltaT | None') -> datetime.timedelta | None: if maybe_time_delta is None: return None diff --git a/osprey_worker/src/osprey/engine/language_types/verdicts.py b/osprey_worker/src/osprey/engine/language_types/verdicts.py index 433fe36..ee4b74c 100644 --- a/osprey_worker/src/osprey/engine/language_types/verdicts.py +++ b/osprey_worker/src/osprey/engine/language_types/verdicts.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import List, Self, cast +from typing import Self, cast from osprey.engine.executor.custom_extracted_features import CustomExtractedFeature from osprey.engine.language_types.effects import EffectToCustomExtractedFeatureBase @@ -10,7 +10,7 @@ from .rules import add_slots @add_slots @dataclass -class VerdictEffect(EffectToCustomExtractedFeatureBase[List[str]]): +class VerdictEffect(EffectToCustomExtractedFeatureBase[list[str]]): """Contains information about verdicts emitted during execution that will be sent back to synchronous callers of Osprey if the action was processed synchronously""" @@ -21,14 +21,14 @@ class VerdictEffect(EffectToCustomExtractedFeatureBase[List[str]]): return self.verdict @classmethod - def build_custom_extracted_feature_from_list(cls, values: List[Self]) -> CustomExtractedFeature[List[str]]: - return VerdictEffectsExtractedFeature(effects=cast(List[VerdictEffect], values)) + def build_custom_extracted_feature_from_list(cls, values: list[Self]) -> CustomExtractedFeature[list[str]]: + return VerdictEffectsExtractedFeature(effects=cast(list[VerdictEffect], values)) @add_slots @dataclass -class VerdictEffectsExtractedFeature(CustomExtractedFeature[List[str]]): - effects: List[VerdictEffect] +class VerdictEffectsExtractedFeature(CustomExtractedFeature[list[str]]): + effects: list[VerdictEffect] @classmethod def feature_name(cls) -> str: @@ -36,5 +36,5 @@ class VerdictEffectsExtractedFeature(CustomExtractedFeature[List[str]]): VERDICT_DIMENSION_NAME.lstrip('__') if VERDICT_DIMENSION_NAME.startswith('__') else VERDICT_DIMENSION_NAME ) - def get_serializable_feature(self) -> List[str] | None: + def get_serializable_feature(self) -> list[str] | None: return [effect.to_str() for effect in self.effects] diff --git a/osprey_worker/src/osprey/engine/query_language/ast_druid_translator.py b/osprey_worker/src/osprey/engine/query_language/ast_druid_translator.py index 0bddbe9..c5f4228 100644 --- a/osprey_worker/src/osprey/engine/query_language/ast_druid_translator.py +++ b/osprey_worker/src/osprey/engine/query_language/ast_druid_translator.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from typing import Any from osprey.engine.ast import grammar from osprey.engine.ast_validator.validation_context import ValidatedSources @@ -28,10 +28,10 @@ class DruidQueryTransformer: assert isinstance(assign_node, grammar.Assign) self._root = assign_node.value - def transform(self) -> Dict[str, Any]: + def transform(self) -> dict[str, Any]: return {'filter': self._transform(self._root)} - def _transform(self, node: grammar.ASTNode) -> Dict[str, Any]: + def _transform(self, node: grammar.ASTNode) -> dict[str, Any]: method = 'transform_' + node.__class__.__name__ transformer = getattr(self, method, None) @@ -42,14 +42,14 @@ class DruidQueryTransformer: assert isinstance(ret, dict) return ret - def transform_BooleanOperation(self, node: grammar.BooleanOperation) -> Dict[str, Any]: + def transform_BooleanOperation(self, node: grammar.BooleanOperation) -> dict[str, Any]: assert isinstance(node.operand, grammar.And) or isinstance(node.operand, grammar.Or) filter_type = 'and' if isinstance(node.operand, grammar.And) else 'or' values = [self._transform(v) for v in node.values] return {'type': filter_type, 'fields': values} - def transform_BinaryComparison(self, node: grammar.BinaryComparison) -> Dict[str, Any]: + def transform_BinaryComparison(self, node: grammar.BinaryComparison) -> dict[str, Any]: if isinstance(node.left, grammar.Name) and isinstance(node.right, grammar.Name): column_comparison = { 'type': 'columnComparison', @@ -92,13 +92,13 @@ class DruidQueryTransformer: ], } - def transform_UnaryOperation(self, node: grammar.UnaryOperation) -> Dict[str, Any]: + def transform_UnaryOperation(self, node: grammar.UnaryOperation) -> dict[str, Any]: if isinstance(node.operator, grammar.Not): return {'type': 'not', 'field': self._transform(node.operand)} else: raise DruidQueryTransformException(node, 'Unknown Unary Operator') - def transform_Call(self, node: grammar.Call) -> Dict[str, Any]: + def transform_Call(self, node: grammar.Call) -> dict[str, Any]: udf, _ = self._udf_node_mapping[id(node)] if not isinstance(udf, QueryUdfBase): @@ -107,7 +107,7 @@ class DruidQueryTransformer: return udf.to_druid_query() -def get_in_query_by_value_type(node: grammar.BinaryComparison, dimension: str, comparison_value: Any) -> Dict[str, Any]: +def get_in_query_by_value_type(node: grammar.BinaryComparison, dimension: str, comparison_value: Any) -> dict[str, Any]: if isinstance(comparison_value, str): return { 'type': 'search', @@ -120,7 +120,7 @@ def get_in_query_by_value_type(node: grammar.BinaryComparison, dimension: str, c raise DruidQueryTransformException(node, 'Invalid "in" comparison value type, must be string or list') -def get_druid_bound_query_props(node: grammar.BinaryComparison, comparison_value: Any) -> Dict[str, Any]: +def get_druid_bound_query_props(node: grammar.BinaryComparison, comparison_value: Any) -> dict[str, Any]: """Get the correct query properties for the various type of `bound` filters""" if isinstance(node.comparator, grammar.LessThan): diff --git a/osprey_worker/src/osprey/engine/query_language/tests/conftest.py b/osprey_worker/src/osprey/engine/query_language/tests/conftest.py index e5c75a5..4f537a9 100644 --- a/osprey_worker/src/osprey/engine/query_language/tests/conftest.py +++ b/osprey_worker/src/osprey/engine/query_language/tests/conftest.py @@ -1,4 +1,4 @@ -from typing import Sequence, Tuple, Union +from collections.abc import Sequence import pytest from osprey.engine.ast_validator.validation_context import ValidatedSources @@ -16,12 +16,12 @@ from typing_extensions import Protocol class MakeRulesSourcesFunction(Protocol): - def __call__(self, names: Sequence[Union[str, Tuple[str, str]]]) -> ValidatedSources: ... + def __call__(self, names: Sequence[str | tuple[str, str]]) -> ValidatedSources: ... @pytest.fixture() def make_rules_sources(run_validation: RunValidationFunction) -> MakeRulesSourcesFunction: - def _make_rules_sources(names: Sequence[Union[str, Tuple[str, str]]]) -> ValidatedSources: + def _make_rules_sources(names: Sequence[str | tuple[str, str]]) -> ValidatedSources: source_lines = [] for name_and_value in names: if isinstance(name_and_value, tuple): diff --git a/osprey_worker/src/osprey/engine/query_language/tests/test_did_mutate_label.py b/osprey_worker/src/osprey/engine/query_language/tests/test_did_mutate_label.py index 374ec2a..653e69e 100644 --- a/osprey_worker/src/osprey/engine/query_language/tests/test_did_mutate_label.py +++ b/osprey_worker/src/osprey/engine/query_language/tests/test_did_mutate_label.py @@ -1,5 +1,6 @@ import json -from typing import Any, Callable, Dict, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -9,13 +10,13 @@ from osprey.engine.query_language.udfs.did_mutate_label import DidAddLabel, DidR from osprey.engine.stdlib import get_config_registry from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames, get_config_registry().get_validator()]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(DidAddLabel, DidRemoveLabel)), ] -def source_with_config(source: str) -> Dict[str, str]: +def source_with_config(source: str) -> dict[str, str]: return {'main.sml': source, 'config.yaml': json.dumps({'labels': {'my_label': {'valid_for': ['MyEntity']}}})} diff --git a/osprey_worker/src/osprey/engine/query_language/tests/test_parse_query_to_validated_ast.py b/osprey_worker/src/osprey/engine/query_language/tests/test_parse_query_to_validated_ast.py index 2f2bba3..f4beab8 100644 --- a/osprey_worker/src/osprey/engine/query_language/tests/test_parse_query_to_validated_ast.py +++ b/osprey_worker/src/osprey/engine/query_language/tests/test_parse_query_to_validated_ast.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.imports_must_not_have_cycles import ImportsMustNotHaveCycles @@ -15,7 +16,7 @@ from osprey.engine.query_language.tests.conftest import MakeRulesSourcesFunction # The validators and UDFs that the rules source validation should use, *not* the query source validation. # We need to include the specific validators that parse_query_to_validated_ast expects. -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_standard_rules_validators(), pytest.mark.use_validators( [ @@ -85,7 +86,7 @@ def test_static_types_are_converted_post_execution( Foo = Entity(type="Name", id="some name") Bar = Entity(type="User", id=123) ARule = Rule(when_all=[True], description="") - AnOptional: Optional[bool] = True + AnOptional: bool | None = True """ ) parse_query_to_validated_ast('Foo in "hello"', sources) diff --git a/osprey_worker/src/osprey/engine/query_language/tests/test_regex_match.py b/osprey_worker/src/osprey/engine/query_language/tests/test_regex_match.py index 19791c7..2bbb2b1 100644 --- a/osprey_worker/src/osprey/engine/query_language/tests/test_regex_match.py +++ b/osprey_worker/src/osprey/engine/query_language/tests/test_regex_match.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -10,7 +11,7 @@ from osprey.engine.conftest import CheckFailureFunction, RunValidationFunction from osprey.engine.query_language.udfs.regex_match import RegexMatch from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, ValidateDynamicCallsHaveAnnotatedRValue, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(RegexMatch)), ] diff --git a/osprey_worker/src/osprey/engine/query_language/udfs/did_declare_verdict.py b/osprey_worker/src/osprey/engine/query_language/udfs/did_declare_verdict.py index d740a9f..3e78265 100644 --- a/osprey_worker/src/osprey/engine/query_language/udfs/did_declare_verdict.py +++ b/osprey_worker/src/osprey/engine/query_language/udfs/did_declare_verdict.py @@ -1,5 +1,3 @@ -from typing import Dict - from osprey.engine import shared_constants from osprey.engine.ast_validator.validation_context import ValidationContext from osprey.engine.query_language.udfs.registry import register @@ -25,7 +23,7 @@ class DidDeclareVerdict(QueryUdfBase[Arguments, bool]): super().__init__(validation_context, arguments) self.verdict = arguments.verdict.value - def to_druid_query(self) -> Dict[str, object]: + def to_druid_query(self) -> dict[str, object]: return { 'type': 'arrayContainsElement', 'column': shared_constants.VERDICT_DIMENSION_NAME, diff --git a/osprey_worker/src/osprey/engine/query_language/udfs/did_mutate_label.py b/osprey_worker/src/osprey/engine/query_language/udfs/did_mutate_label.py index 245e6ed..bd507c6 100644 --- a/osprey_worker/src/osprey/engine/query_language/udfs/did_mutate_label.py +++ b/osprey_worker/src/osprey/engine/query_language/udfs/did_mutate_label.py @@ -1,5 +1,3 @@ -from typing import Dict - from osprey.engine import shared_constants from osprey.engine.ast_validator.validation_context import ValidationContext from osprey.engine.language_types.labels import LabelStatus @@ -33,7 +31,7 @@ class DidAddLabel(DidMutateLabel): `DidAddLabel(entity_type='User',label_name='user_hell_ban')` """ - def to_druid_query(self) -> Dict[str, object]: + def to_druid_query(self) -> dict[str, object]: return { 'type': 'like', 'dimension': shared_constants.ENTITY_LABEL_MUTATION_DIMENSION_NAME, @@ -58,7 +56,7 @@ class DidRemoveLabel(DidMutateLabel): `DidRemoveLabel(entity_type='User',label_name='user_hell_ban')` """ - def to_druid_query(self) -> Dict[str, object]: + def to_druid_query(self) -> dict[str, object]: return { 'type': 'like', 'dimension': shared_constants.ENTITY_LABEL_MUTATION_DIMENSION_NAME, diff --git a/osprey_worker/src/osprey/engine/query_language/udfs/regex_match.py b/osprey_worker/src/osprey/engine/query_language/udfs/regex_match.py index d56b0cd..c0ca5b2 100644 --- a/osprey_worker/src/osprey/engine/query_language/udfs/regex_match.py +++ b/osprey_worker/src/osprey/engine/query_language/udfs/regex_match.py @@ -1,5 +1,4 @@ import re -from typing import Dict from osprey.engine.ast import grammar from osprey.engine.ast_validator.validation_context import ValidationContext @@ -39,5 +38,5 @@ class RegexMatch(QueryUdfBase[Arguments, bool]): message='expected variable', span=item_node.span, hint='argument `target` must be a variable' ) - def to_druid_query(self) -> Dict[str, object]: + def to_druid_query(self) -> dict[str, object]: return {'type': 'regex', 'dimension': self.item, 'pattern': self.regex} diff --git a/osprey_worker/src/osprey/engine/stdlib/_registry.py b/osprey_worker/src/osprey/engine/stdlib/_registry.py index 56b6bdf..6c2435e 100644 --- a/osprey_worker/src/osprey/engine/stdlib/_registry.py +++ b/osprey_worker/src/osprey/engine/stdlib/_registry.py @@ -1,4 +1,5 @@ -from typing import Callable, Type +from collections.abc import Callable +from typing import Type from osprey.engine.config.config_registry import ConfigRegistry from osprey.engine.config.config_subkey_handler import ModelT diff --git a/osprey_worker/src/osprey/engine/stdlib/configs/analytics_config.py b/osprey_worker/src/osprey/engine/stdlib/configs/analytics_config.py index f963c35..45a3a38 100644 --- a/osprey_worker/src/osprey/engine/stdlib/configs/analytics_config.py +++ b/osprey_worker/src/osprey/engine/stdlib/configs/analytics_config.py @@ -1,5 +1,3 @@ -from typing import Dict, Set - from pydantic import BaseModel from .._registry import register_config_subkey @@ -21,6 +19,6 @@ class AnalyticsConfig(BaseModel): Currently validation is done in osprey_ast_validator because we need access to `labels` config. """ - filtered_labels: Set[str] = set() - monitored_labels: Set[str] = set() - monitored_counters: Dict[str, CounterInfo] = dict() + filtered_labels: set[str] = set() + monitored_labels: set[str] = set() + monitored_counters: dict[str, CounterInfo] = dict() diff --git a/osprey_worker/src/osprey/engine/stdlib/configs/feature_flags_config.py b/osprey_worker/src/osprey/engine/stdlib/configs/feature_flags_config.py index b74ba28..0d685c4 100644 --- a/osprey_worker/src/osprey/engine/stdlib/configs/feature_flags_config.py +++ b/osprey_worker/src/osprey/engine/stdlib/configs/feature_flags_config.py @@ -1,5 +1,4 @@ from random import random -from typing import Dict from pydantic import BaseModel, validator @@ -21,7 +20,7 @@ class PercentageFlagInfo(BaseModel): @register_config_subkey(FEATURE_FLAGS_CONFIG_SUBKEY) class FeatureFlagsConfig(BaseModel): - percentage_flags: Dict[str, PercentageFlagInfo] = {} + percentage_flags: dict[str, PercentageFlagInfo] = {} def is_percentage_enabled(self, flag: str) -> bool: if flag not in self.percentage_flags: diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/domain_chopper.py b/osprey_worker/src/osprey/engine/stdlib/udfs/domain_chopper.py index 76fc8b7..b3b2a68 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/domain_chopper.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/domain_chopper.py @@ -1,4 +1,4 @@ -from typing import List, cast +from typing import cast from osprey.engine.executor.execution_context import ExpectedUdfException from tld import get_tld @@ -8,11 +8,11 @@ from .categories import UdfCategories class DomainChopperArguments(ArgumentsBase): - urls: List[str] + urls: list[str] fld: ConstExpr[bool] = ConstExpr.for_default('fld', False) -class DomainChopper(UDFBase[DomainChopperArguments, List[str]]): +class DomainChopper(UDFBase[DomainChopperArguments, list[str]]): """Parses an list of valid URLs or Domains and returns a requested formatting of the Domains or URLs within, chopping the rest.""" @@ -40,7 +40,7 @@ class DomainChopper(UDFBase[DomainChopperArguments, List[str]]): # return fld for given domain return normalized_domain - def execute(self, execution_context: ExecutionContext, arguments: DomainChopperArguments) -> List[str]: + def execute(self, execution_context: ExecutionContext, arguments: DomainChopperArguments) -> list[str]: normalized_result = [] # for list of domains parse out and return the fld + tld only diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/experiments.py b/osprey_worker/src/osprey/engine/stdlib/udfs/experiments.py index 14f4ab5..7ed06cd 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/experiments.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/experiments.py @@ -3,7 +3,7 @@ from __future__ import annotations from decimal import Decimal from enum import Enum from math import floor -from typing import Any, Dict, List, Optional, Tuple, Type, cast +from typing import Any, Type, cast import mmh3 # type: ignore from osprey.engine.ast import grammar @@ -25,8 +25,8 @@ HASH_SEED = 42 class ExperimentArguments(ArgumentsBase): entity: EntityT[Any] - buckets: ConstExpr[List[str]] - bucket_sizes: ConstExpr[List[float]] + buckets: ConstExpr[list[str]] + bucket_sizes: ConstExpr[list[float]] version: ConstExpr[int] revision: ConstExpr[int] @@ -135,7 +135,7 @@ class Experiment(UDFBase[ExperimentArguments, ExperimentT]): self._register_experiment(validation_context=validation_context, experiment_call_node=call_node) def _register_experiment(self, validation_context: ValidationContext, experiment_call_node: grammar.Call) -> None: - cur_experiment_nodes: Dict[str, grammar.Call] = validation_context.get_validator_input(ValidateExperiments, {}) + cur_experiment_nodes: dict[str, grammar.Call] = validation_context.get_validator_input(ValidateExperiments, {}) if not cur_experiment_nodes: validation_context.set_validator_input(ValidateExperiments, cur_experiment_nodes) cur_experiment_nodes.update({self._feature_name: experiment_call_node}) @@ -214,10 +214,10 @@ class Experiment(UDFBase[ExperimentArguments, ExperimentT]): class ExperimentWhenArguments(ArgumentsBase): experiment: ExperimentT - extra_arguments: Dict[str, List[bool]] + extra_arguments: dict[str, list[bool]] -class ExperimentWhen(UDFBase[ExperimentWhenArguments, List[bool]]): +class ExperimentWhen(UDFBase[ExperimentWhenArguments, list[bool]]): """ Takes in an experiment and returns the List of bools for the specific bucket """ @@ -265,12 +265,12 @@ class ExperimentWhen(UDFBase[ExperimentWhenArguments, List[bool]]): additional_spans=[experiment_buckets.span], ) - def _get_experiments(self, validation_context: 'ValidationContext') -> Dict[str, grammar.Call]: + def _get_experiments(self, validation_context: 'ValidationContext') -> dict[str, grammar.Call]: return validation_context.get_validator_input(ValidateExperiments, dict()) def _get_valid_experiment( self, validation_context: 'ValidationContext', arguments: ExperimentWhenArguments - ) -> Tuple[str, Optional[grammar.Call]]: + ) -> tuple[str, grammar.Call | None]: experiment_arg = arguments.get_argument_ast('experiment') assert isinstance(experiment_arg, grammar.Name), 'this should be a Name' @@ -292,7 +292,7 @@ class ExperimentWhen(UDFBase[ExperimentWhenArguments, List[bool]]): assert isinstance(experiment_buckets, grammar.List), 'buckets should be a List node' return experiment_buckets - def execute(self, execution_context: ExecutionContext, arguments: ExperimentWhenArguments) -> List[bool]: + def execute(self, execution_context: ExecutionContext, arguments: ExperimentWhenArguments) -> list[bool]: resolved_bucket = arguments.experiment.resolved_bucket bucket = CONTROL_BUCKET if resolved_bucket is NOT_IN_EXPERIMENT_BUCKET else resolved_bucket # validation that the bucket_name is a valid key in extra_arguments should already be done diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/import_.py b/osprey_worker/src/osprey/engine/stdlib/udfs/import_.py index ebf9920..9b53ac2 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/import_.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/import_.py @@ -1,4 +1,3 @@ -import typing from collections import defaultdict from osprey.engine.ast import ast_utils, grammar, printer @@ -7,7 +6,7 @@ from ._prelude import ArgumentsBase, ConstExpr, ExecutionContext, Source, UDFBas class Arguments(ArgumentsBase): - rules: ConstExpr[typing.List[str]] + rules: ConstExpr[list[str]] """A list of rule files to Include. Each string in this list must be a relative path to a *.sml file, and the list must be sorted lexicographically. @@ -24,10 +23,10 @@ class Import(UDFBase[Arguments, None]): super().__init__(validation_context, arguments) rules = arguments.rules assert isinstance(rules.literal, grammar.List) - self.sources_and_spans: typing.List[typing.Tuple[Source, grammar.Span]] = [] + self.sources_and_spans: list[tuple[Source, grammar.Span]] = [] - import_source_names: typing.List[str] = [] - import_spans_by_name: typing.DefaultDict[str, typing.List[grammar.Span]] = defaultdict(list) + import_source_names: list[str] = [] + import_spans_by_name: defaultdict[str, list[grammar.Span]] = defaultdict(list) for node in rules.literal.items: assert isinstance(node, grammar.String) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/json_utils.py b/osprey_worker/src/osprey/engine/stdlib/udfs/json_utils.py index 384eb0c..d5f2ee3 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/json_utils.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/json_utils.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, TypeVar +from typing import Any, TypeVar from jsonpath_rw import JSONPath, parse from osprey.engine.executor.execution_context import ExpectedUdfException @@ -45,7 +45,7 @@ _T = TypeVar('_T') def get_from_data( expr: JSONPath, - data: Dict[str, object], + data: dict[str, object], required: bool, coerce_type: bool, rvalue_type_checker: RValueTypeChecker, diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/labels.py b/osprey_worker/src/osprey/engine/stdlib/udfs/labels.py index 96a8ae9..daaa70f 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/labels.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/labels.py @@ -1,7 +1,8 @@ +from collections.abc import Sequence from dataclasses import dataclass from datetime import datetime, timezone from enum import Enum, auto -from typing import Any, Optional, Sequence +from typing import Any from osprey.engine.executor.udf_execution_helpers import HasHelperInternal from osprey.engine.language_types.effects import ( @@ -42,11 +43,11 @@ class LabelArguments(ArgumentsBase): # from verdicts, which were created to be an output (whereas labels were created # to simply store state, thus making label webhooks a leaky abstraction) # NOTE(@elijaharita): this is being re-added because removing it breaks backwards compatibility. - delay_action_by: Optional[TimeDeltaT] = None + delay_action_by: TimeDeltaT | None = None """Optional: Delays a label action by a specified `TimeDeltaT` time if Osprey is configured to.""" - apply_if: Optional[RuleT] = None + apply_if: RuleT | None = None """Optional: Conditions that must be met for the label mutation to succeed.""" - expires_after: Optional[TimeDeltaT] = None + expires_after: TimeDeltaT | None = None """Optional: Automatically expire the mutation after a specified `TimeDeltaT` time.""" @@ -91,7 +92,7 @@ class _ManualType(Enum): EITHER = auto() @classmethod - def get(cls, manual: Optional[bool]) -> '_ManualType': + def get(cls, manual: bool | None) -> '_ManualType': if manual is True: return _ManualType.YES if manual is False: @@ -125,11 +126,11 @@ class HasLabelArguments(ArgumentsBase): """An Entity to check for a label on.""" label: ConstExpr[str] """A label name to check the state of.""" - manual: Optional[bool] = None + manual: bool | None = None """Optional: If `True`, only check if the label was manually added by an operator.""" status: ConstExpr[str] = ConstExpr.for_default('status', _SimpleStatus.ADDED.value) """Optional: A specific status to check for. Default is 'added'.""" - min_label_age: Optional[TimeDeltaT] = None + min_label_age: TimeDeltaT | None = None """Optional: Checks to see if the label was added after a period of time""" error_on_empty: bool = False """Optional: If True, raise EmptyEntityError when the entity has no labels at all. @@ -148,10 +149,10 @@ class HasLabelArguments(ArgumentsBase): class BatchableHasLabelArguments: entity: EntityT[Any] label: str - manual: Optional[bool] + manual: bool | None status: str - min_label_age: Optional[TimeDeltaT] - desired_status: Optional[_SimpleStatus] + min_label_age: TimeDeltaT | None + desired_status: _SimpleStatus | None error_on_empty: bool @@ -166,7 +167,7 @@ class HasLabel( super().__init__(validation_context, arguments) status_name = arguments.status.value try: - self.desired_status: Optional[_SimpleStatus] = _SimpleStatus(status_name) + self.desired_status: _SimpleStatus | None = _SimpleStatus(status_name) except ValueError: self.desired_status = None diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/list_length.py b/osprey_worker/src/osprey/engine/stdlib/udfs/list_length.py index ca1bb3c..d7fe653 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/list_length.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/list_length.py @@ -1,11 +1,11 @@ -from typing import Any, List +from typing import Any from ._prelude import ArgumentsBase, ExecutionContext, UDFBase from .categories import UdfCategories class Arguments(ArgumentsBase): - list: List[Any] + list: list[Any] class ListLength(UDFBase[Arguments, int]): diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/list_read.py b/osprey_worker/src/osprey/engine/stdlib/udfs/list_read.py index 5f72b72..a78c2a5 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/list_read.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/list_read.py @@ -1,4 +1,6 @@ -from typing import Any, List +from __future__ import annotations + +from typing import Any from osprey.engine.executor.execution_context import ExpectedUdfException @@ -7,7 +9,7 @@ from .categories import UdfCategories class Arguments(ArgumentsBase): - list: List[Any] = [] + list: list[Any] index: int = 0 diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/list_sort.py b/osprey_worker/src/osprey/engine/stdlib/udfs/list_sort.py index 7ac88f6..660b462 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/list_sort.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/list_sort.py @@ -1,18 +1,18 @@ -from typing import Any, List +from typing import Any from ._prelude import ArgumentsBase, ExecutionContext, UDFBase from .categories import UdfCategories class Arguments(ArgumentsBase): - list: List[Any] + list: list[Any] reverse: bool = False -class ListSort(UDFBase[Arguments, List[Any]]): +class ListSort(UDFBase[Arguments, list[Any]]): """Returns a sorted list.""" category = UdfCategories.ENGINE - def execute(self, execution_context: ExecutionContext, arguments: Arguments) -> List[Any]: + def execute(self, execution_context: ExecutionContext, arguments: Arguments) -> list[Any]: return sorted(arguments.list, reverse=arguments.reverse) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/regex_match.py b/osprey_worker/src/osprey/engine/stdlib/udfs/regex_match.py index 7d63f28..14bc41d 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/regex_match.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/regex_match.py @@ -1,5 +1,4 @@ import re -from typing import List from ._prelude import ArgumentsBase, ConstExpr, ExecutionContext, UDFBase, ValidationContext from .categories import UdfCategories @@ -41,7 +40,7 @@ class RegexMatch(RegexUDFBase, UDFBase[RegexMatchArguments, bool]): class RegexMatchMapArguments(RegexArgumentsBase): - target: List[str] + target: list[str] """A target string to evaluate the regex pattern on.""" mode: ConstExpr[str] = ConstExpr.for_default('mode', 'any') diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/resolve_optional.py b/osprey_worker/src/osprey/engine/stdlib/udfs/resolve_optional.py index 8ea4a9b..906bcb5 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/resolve_optional.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/resolve_optional.py @@ -1,4 +1,4 @@ -from typing import Optional, TypeVar +from typing import TypeVar from osprey.engine.executor.execution_context import ExpectedUdfException from osprey.engine.language_types.osprey_invariant_generic import OspreyInvariantGeneric @@ -9,12 +9,12 @@ _T = TypeVar('_T') class Arguments(OspreyInvariantGeneric[_T], ArgumentsBase): - optional_value: Optional[_T] + optional_value: _T | None """ The Optional value to unwrap. """ - default_value: Optional[_T] = None + default_value: _T | None = None """ The default value to return if the Optional value is missing. `should_report_error` is ignored if there is a `default_value` present. diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/rules.py b/osprey_worker/src/osprey/engine/stdlib/udfs/rules.py index 93f750d..c0d2c72 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/rules.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/rules.py @@ -1,5 +1,5 @@ import re -from typing import List, Optional, cast +from typing import cast from osprey.engine.ast import grammar from osprey.engine.ast_validator.validation_utils import add_must_assign_to_variable_error @@ -18,14 +18,14 @@ _HAS_FORMAT_STRING_RE = re.compile(r'\{([^\d\W]\w*)\}') class RuleArguments(ArgumentsBase): # TODO - Should we require that this is a list literal? If so, should we require it be non-empty? - when_all: List[bool] + when_all: list[bool] description: str class Rule(UDFBase[RuleArguments, RuleT]): """Defines a named rule with conditions. Evaluates to true when all conditions in when_all are met.""" - name: Optional[str] = None + name: str | None = None category = UdfCategories.ENGINE def __init__(self, validation_context: ValidationContext, arguments: RuleArguments): @@ -115,9 +115,9 @@ class Rule(UDFBase[RuleArguments, RuleT]): class WhenRulesArguments(ArgumentsBase): # TODO - Should we require this be non-empty? - rules_any: List[RuleT] + rules_any: list[RuleT] # TODO - Should we require this be non-empty? - then: List[EffectBase] + then: list[EffectBase] class WhenRules(UDFBase[WhenRulesArguments, None]): @@ -150,7 +150,7 @@ class WhenRules(UDFBase[WhenRulesArguments, None]): # `ListExecutor`, in order to peek inside, and grab each non-failed item within the list. rules_any_value = [] rules_any_failed = 0 - failed_rule_names: List[str] = [] + failed_rule_names: list[str] = [] assert isinstance(rules_any_node, grammar.List), 'BUG: `rules_any node is not a List!' for item in rules_any_node.items: resolved = execution_context.resolved(item, return_none_for_failed_values=True) @@ -188,10 +188,10 @@ class WhenRules(UDFBase[WhenRulesArguments, None]): passing_rules = [rule for rule in arguments.rules_any if rule.value] passing_names = [rule.name for rule in passing_rules] assert hasattr(self, '_failed_rule_names'), 'BUG: resolve_arguments() must be called before execute()' - failed_rule_names: List[str] = self._failed_rule_names + failed_rule_names: list[str] = self._failed_rule_names then_failed: int = self._then_failed - effects_emitted: List[str] = [] + effects_emitted: list[str] = [] if passing_rules: effects_emitted = [type(o).__name__ for o in arguments.then if isinstance(o, EffectBase)] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/string.py b/osprey_worker/src/osprey/engine/stdlib/udfs/string.py index 2e133a1..8c6eafb 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/string.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/string.py @@ -3,8 +3,9 @@ from __future__ import annotations import re import string import unicodedata +from collections.abc import Iterator from itertools import chain -from typing import Dict, Iterator, List, Literal, Optional, Set, cast +from typing import Literal, Set, cast from urllib.parse import ParseResult, urlparse, urlunparse from osprey.engine.stdlib.udfs._prelude import ( @@ -78,7 +79,7 @@ class StringEndsWith(UDFBase[StringEndsWithArgument, bool]): class StringStripArguments(StringArguments): - chars: Optional[str] = None + chars: str | None = None class StringStrip(UDFBase[StringStripArguments, str]): @@ -123,7 +124,7 @@ class StringReplace(UDFBase[StringReplaceArguments, str]): class StringJoinArguments(StringArguments): - iterable: List[str] + iterable: list[str] class StringJoin(UDFBase[StringJoinArguments, str]): @@ -136,16 +137,16 @@ class StringJoin(UDFBase[StringJoinArguments, str]): class StringSplitArguments(StringArguments): - sep: Optional[str] = None + sep: str | None = None maxsplit: int = -1 -class StringSplit(UDFBase[StringSplitArguments, List[str]]): +class StringSplit(UDFBase[StringSplitArguments, list[str]]): """Splits the string by a delimiter into a list of strings.""" category = UdfCategories.STRING - def execute(self, execution_context: ExecutionContext, arguments: StringSplitArguments) -> List[str]: + def execute(self, execution_context: ExecutionContext, arguments: StringSplitArguments) -> list[str]: return arguments.s.split(arguments.sep, arguments.maxsplit) @@ -218,7 +219,7 @@ class StringCleaningArguments(StringArguments): remove_punctuation: bool = False -TranslationT = Dict[int, Optional[int]] +TranslationT = dict[int, int | None] _SPACE_PATTERN: re.Pattern[str] = re.compile(r'\s+') @@ -412,7 +413,7 @@ class StringClean(UDFBase[StringCleaningArguments, str]): return s -def _safe_urlparse(url: str) -> Optional[ParseResult]: +def _safe_urlparse(url: str) -> ParseResult | None: """Safely parse a URL, returning None for malformed URLs (e.g., invalid IPv6).""" try: return urlparse(url) @@ -421,7 +422,7 @@ def _safe_urlparse(url: str) -> Optional[ParseResult]: return None -class StringExtractDomains(UDFBase[StringArguments, List[str]]): +class StringExtractDomains(UDFBase[StringArguments, list[str]]): """ Used to extract a list of potential URL domains from a string of tokens. Returns a list of candidate domains encountered in the input string. Should be used in conjunction with @@ -430,10 +431,10 @@ class StringExtractDomains(UDFBase[StringArguments, List[str]]): category = UdfCategories.STRING - def execute(self, execution_context: ExecutionContext, arguments: StringArguments) -> List[str]: + def execute(self, execution_context: ExecutionContext, arguments: StringArguments) -> list[str]: # split the message into individual tokens as based on a modified URL regex from messages_common. # should capture space based links and markdown based links without duplication. - potential_urls: Iterator[Optional[ParseResult]] = ( + potential_urls: Iterator[ParseResult | None] = ( _safe_urlparse(token) for token in re.findall(r'(https?:\/\/[^\/\s][^\s\)>]+)', arguments.s) ) @@ -455,7 +456,7 @@ class StringExtractDomains(UDFBase[StringArguments, List[str]]): return list(valid_domains) -class StringExtractURLs(UDFBase[StringArguments, List[str]]): +class StringExtractURLs(UDFBase[StringArguments, list[str]]): """ Used to extract a list of potential URLs from a string of tokens. Returns a list of candidate URLs encountered in the input string. Should be used in conjunction with @@ -464,10 +465,10 @@ class StringExtractURLs(UDFBase[StringArguments, List[str]]): category = UdfCategories.STRING - def execute(self, execution_context: ExecutionContext, arguments: StringArguments) -> List[str]: + def execute(self, execution_context: ExecutionContext, arguments: StringArguments) -> list[str]: # split the message into individual tokens as based on a modified URL regex from messages_common. # should capture space based links and markdown based links without duplication. - potential_urls: Iterator[Optional[ParseResult]] = ( + potential_urls: Iterator[ParseResult | None] = ( _safe_urlparse(token) for token in re.findall(r'(https?:\/\/[^\/\s][^\s\)>]+)', arguments.s) ) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_chopper.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_chopper.py index 9d69a72..0cccaa2 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_chopper.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_chopper.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -6,7 +7,7 @@ from osprey.engine.conftest import ExecuteFunction from osprey.engine.stdlib.udfs.domain_chopper import DomainChopper from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(DomainChopper)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_tld.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_tld.py index 2e03695..2a38a6c 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_tld.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_domain_tld.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -6,7 +7,7 @@ from osprey.engine.conftest import ExecuteFunction from osprey.engine.stdlib.udfs.domain_tld import DomainTld from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(DomainTld)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_domain.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_domain.py index f2afe04..e74a7eb 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_domain.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_domain.py @@ -1,5 +1,3 @@ -from typing import Dict, Optional - import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs from osprey.engine.conftest import ExecuteFunction @@ -59,7 +57,7 @@ def test_accepts_json_data_email_empty(execute: ExecuteFunction) -> None: ], ) def test_invalid_email_addresses( - execute: ExecuteFunction, data: Dict[str, object], expected_result: Optional[str] + execute: ExecuteFunction, data: dict[str, object], expected_result: str | None ) -> None: result = execute(sources, data=data) @@ -79,7 +77,7 @@ def test_invalid_email_addresses( ], ) def test_invalid_email_subdomain_addresses( - execute: ExecuteFunction, data: Dict[str, object], expected_result: Optional[str] + execute: ExecuteFunction, data: dict[str, object], expected_result: str | None ) -> None: result = execute(sources, data=data) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_local_part.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_local_part.py index 2246fff..dcc3768 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_local_part.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_email_local_part.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List, Optional +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -6,7 +7,7 @@ from osprey.engine.conftest import ExecuteFunction from osprey.engine.stdlib.udfs.email_local_part import EmailLocalPart from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(EmailLocalPart)), ] @@ -23,6 +24,6 @@ pytestmark: List[Callable[[Any], Any]] = [ ('tEsT@eXaMpLe.org', 'tEsT'), ], ) -def test_email_local_part(execute: ExecuteFunction, email: str, expected_result: Optional[str]) -> None: +def test_email_local_part(execute: ExecuteFunction, email: str, expected_result: str | None) -> None: result = execute(f'UserEmailLocalPart = EmailLocalPart(email="{email}")') assert result == {'UserEmailLocalPart': expected_result} diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_entity.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_entity.py index 103a4be..fc66ee5 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_entity.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_entity.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -14,7 +15,7 @@ from osprey.engine.stdlib.udfs.entity import Entity, EntityJson from osprey.engine.stdlib.udfs.import_ import Import from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(EmailDomain, Entity, EntityJson, Import)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_experiments.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_experiments.py index c1ce689..2925d05 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_experiments.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_experiments.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List, Tuple +from collections.abc import Callable +from typing import Any from unittest import mock import pytest @@ -7,11 +8,16 @@ from osprey.engine.ast_validator.validators.validate_call_kwargs import Validate from osprey.engine.conftest import CheckFailureFunction, ExecuteFunction, RunValidationFunction from osprey.engine.language_types.experiments import NOT_IN_EXPERIMENT_BUCKET, NOT_IN_EXPERIMENT_BUCKET_INDEX from osprey.engine.stdlib.udfs.entity import Entity -from osprey.engine.stdlib.udfs.experiments import CONTROL_BUCKET, EXPERIMENT_GRANULARITY, Experiment, ExperimentWhen +from osprey.engine.stdlib.udfs.experiments import ( + CONTROL_BUCKET, + EXPERIMENT_GRANULARITY, + Experiment, + ExperimentWhen, +) from osprey.engine.stdlib.udfs.rules import Rule from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_udf_registry(UDFRegistry.with_udfs(Entity, Rule, Experiment, ExperimentWhen)), pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), ] @@ -30,7 +36,7 @@ def test_hash_mod_should_mod(experiment_name: str, entity_id: str) -> None: 'hash_keys', [(('E1', 'ID1'), ('E1', 'ID1'), ('E1', 'ID1'))], ) -def test_consistent_hash_mod(hash_keys: List[Tuple[str, str]]) -> None: +def test_consistent_hash_mod(hash_keys: list[tuple[str, str]]) -> None: hash_mod_values = [] for experiment_name, entity_id in hash_keys: hash_mod_values.append(Experiment.hash_mod(experiment_name, entity_id)) @@ -147,8 +153,8 @@ def test_consistent_bucketing_with_rollout(execute: ExecuteFunction) -> None: def test_experiment_bucket_size_too_large( run_validation: RunValidationFunction, check_failure: CheckFailureFunction, - buckets: List[str], - bucket_sizes: List[float], + buckets: list[str], + bucket_sizes: list[float], ) -> None: with check_failure(): run_validation( @@ -270,8 +276,8 @@ def test_experiment_revision_error(run_validation: RunValidationFunction, check_ def test_experiment_resolution( hash_mod_mock: mock.MagicMock, execute: ExecuteFunction, - buckets: List[str], - bucket_sizes: List[float], + buckets: list[str], + bucket_sizes: list[float], mock_hash_value: int, expected_bucket: str, expected_bucket_index: int, diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_external_service_utils.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_external_service_utils.py index e7915eb..6818d32 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_external_service_utils.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_external_service_utils.py @@ -1,5 +1,3 @@ -from typing import List, Optional - import gevent import pytest from gevent.event import Event @@ -8,9 +6,7 @@ from osprey.engine.executor.external_service_utils import ExternalService, Exter class CountingService(ExternalService[str, int]): def __init__(self) -> None: - from typing import List - - self.calls: List[str] = [] + self.calls: list[str] = [] def get_from_service(self, key: str) -> int: self.calls.append(key) @@ -20,7 +16,7 @@ class CountingService(ExternalService[str, int]): class BlockingService(CountingService): def __init__(self) -> None: super().__init__() - self.blocking_events: List[Event] = [] + self.blocking_events: list[Event] = [] def get_from_service(self, key: str) -> int: event = Event() @@ -35,23 +31,23 @@ class FailingService(ExternalService[str, int]): """Always raises on the first call for a key.""" def __init__(self) -> None: - self.calls: List[str] = [] + self.calls: list[str] = [] def get_from_service(self, key: str) -> int: self.calls.append(key) raise RuntimeError(f'timeout for {key}') -class CountErrorOnceFailingService(ExternalService[str, Optional[int]]): +class CountErrorOnceFailingService(ExternalService[str, int | None]): """Always raises, but opts in to count_error_once.""" def __init__(self) -> None: - self.calls: List[str] = [] + self.calls: list[str] = [] def count_error_once(self) -> bool: return True - def get_from_service(self, key: str) -> Optional[int]: + def get_from_service(self, key: str) -> int | None: self.calls.append(key) raise RuntimeError(f'timeout for {key}') @@ -153,14 +149,14 @@ def test_count_error_once_concurrent_waiters() -> None: """With count_error_once, concurrent waiters get None while the initiating greenlet gets the exception.""" - class BlockingThenFailService(ExternalService[str, Optional[int]]): + class BlockingThenFailService(ExternalService[str, int | None]): def __init__(self) -> None: self.event = Event() def count_error_once(self) -> bool: return True - def get_from_service(self, key: str) -> Optional[int]: + def get_from_service(self, key: str) -> int | None: self.event.wait() raise RuntimeError('timeout') diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_extract_cookie.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_extract_cookie.py index e5e5959..c4ebad9 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_extract_cookie.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_extract_cookie.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -7,7 +8,7 @@ from osprey.engine.stdlib.udfs.extract_cookie import ExtractCookie from osprey.engine.stdlib.udfs.json_data import JsonData from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(JsonData, ExtractCookie)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_get_action_name.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_get_action_name.py index 82be558..e4a2bfa 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_get_action_name.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_get_action_name.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -6,7 +7,7 @@ from osprey.engine.conftest import ExecuteFunction from osprey.engine.stdlib.udfs.get_action_name import GetActionName from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(GetActionName)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_import.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_import.py index f8a50c9..851e2f3 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_import.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_import.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.imports_must_not_have_cycles import ImportsMustNotHaveCycles @@ -11,7 +12,7 @@ from osprey.engine.conftest import CheckFailureFunction, ExecuteFunction, RunVal from osprey.engine.stdlib.udfs.import_ import Import from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators( [ValidateCallKwargs, ImportsMustNotHaveCycles, ValidateDynamicCallsHaveAnnotatedRValue, UniqueStoredNames] ), diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_ip_network.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_ip_network.py index 0d2cb21..2857ac3 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_ip_network.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_ip_network.py @@ -1,5 +1,6 @@ +from collections.abc import Callable from ipaddress import AddressValueError -from typing import Any, Callable, List +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -8,7 +9,7 @@ from osprey.engine.stdlib.udfs.ip_network import IpNetwork from osprey.engine.stdlib.udfs.json_data import JsonData from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(JsonData, IpNetwork)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_json_data.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_json_data.py index cc9032f..c8f3529 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_json_data.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_json_data.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -15,7 +16,7 @@ from osprey.engine.conftest import ( from osprey.engine.stdlib.udfs.json_data import JsonData from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, ValidateDynamicCallsHaveAnnotatedRValue, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(JsonData)), ] @@ -49,11 +50,11 @@ def test_execute_value_not_present(execute: ExecuteFunction, execute_with_result assert '$.foo' in error_message assert result.extracted_features['Foo'] is None - result = execute_with_result("Foo: Optional[str] = JsonData(path='$.foo', required=True)", data={}) + result = execute_with_result("Foo: str | None = JsonData(path='$.foo', required=True)", data={}) assert not result.error_infos assert result.extracted_features['Foo'] is None - result = execute_with_result("Foo: Optional[str] = JsonData(path='$.foo', required=False)", data={}) + result = execute_with_result("Foo: str | None = JsonData(path='$.foo', required=False)", data={}) assert not result.error_infos assert result.extracted_features['Foo'] is None @@ -69,7 +70,7 @@ def test_execute_coerce_type(execute: ExecuteFunction) -> None: """ Foo: int = JsonData(path='$.foo', coerce_type=True) Bar: int = JsonData(path='$.bar', coerce_type=True, required=False) - Foo2: Optional[int] = JsonData(path='$.foo', coerce_type=True, required=False) + Foo2: int | None = JsonData(path='$.foo', coerce_type=True, required=False) """, data={'foo': '123', 'bar': None}, ) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_labels.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_labels.py index bb10501..01e84fe 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_labels.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_labels.py @@ -1,6 +1,7 @@ import json +from collections.abc import Callable, Sequence from datetime import datetime, timedelta, timezone -from typing import Any, Callable, Dict, List, Optional, Sequence, Set +from typing import Any import gevent import pytest @@ -38,7 +39,7 @@ from osprey.worker.lib.osprey_shared.labels import ( from osprey.worker.lib.storage.labels import LabelsProvider from result import Result -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators( [ ValidateLabels, @@ -55,7 +56,7 @@ pytestmark: List[Callable[[Any], Any]] = [ class StaticLabelProvider(LabelsProvider): - def __init__(self, entity_labels: Dict[EntityT[Any], EntityLabels]) -> None: + def __init__(self, entity_labels: dict[EntityT[Any], EntityLabels]) -> None: self._entity_labels = entity_labels def get_from_service(self, key: EntityT[Any]) -> EntityLabels: @@ -65,16 +66,16 @@ class StaticLabelProvider(LabelsProvider): return [Result.Ok(self.get_from_service(key)) for key in keys] def apply_entity_mutation( - self, entity_key: EntityT[Any], mutations: List[EntityLabelMutation] + self, entity_key: EntityT[Any], mutations: list[EntityLabelMutation] ) -> EntityLabelMutationsResult: return self.apply_entity_label_mutations(entity_key, mutations) class BlockingLabelProvider(StaticLabelProvider): - def __init__(self, entity_labels: Dict[EntityT[Any], EntityLabels]) -> None: + def __init__(self, entity_labels: dict[EntityT[Any], EntityLabels]) -> None: super().__init__(entity_labels) - self.blocking_events: List[Event] = [] - self.calls: List[EntityT[Any]] = [] + self.blocking_events: list[Event] = [] + self.calls: list[EntityT[Any]] = [] def get_from_service(self, key: EntityT[Any]) -> EntityLabels: event = Event() @@ -86,7 +87,7 @@ class BlockingLabelProvider(StaticLabelProvider): return super().get_from_service(key) -def source_with_labels_config(source: str, labels: Set[str]) -> Dict[str, str]: +def source_with_labels_config(source: str, labels: set[str]) -> dict[str, str]: config = json.dumps({'labels': {label: {} for label in labels}}) return {'main.sml': source, 'config.yaml': config} @@ -177,8 +178,8 @@ def source_with_labels_config(source: str, labels: Set[str]) -> Dict[str, str]: def test_get_labels_retrieves_data( execute: ExecuteFunction, checking_status: str, - manual: Optional[bool], - actual_status: Optional[LabelStatus], + manual: bool | None, + actual_status: LabelStatus | None, reasons: LabelReasons, result: bool, ) -> None: @@ -228,8 +229,8 @@ def test_get_labels_retrieves_data( def test_get_labels_retrieves_data_added_after( execute: ExecuteFunction, checking_status: str, - manual: Optional[bool], - actual_status: Optional[LabelStatus], + manual: bool | None, + actual_status: LabelStatus | None, reasons: LabelReasons, min_label_age: timedelta, result: bool, @@ -510,7 +511,7 @@ def test_label_effects_are_exported_to_extracted_features_multi_rule_add_and_rem execute_with_result: ExecuteWithResultFunction, entity_type: str, label_name: str, - entity_label_mutation: List[str], + entity_label_mutation: list[str], ) -> None: result = execute_with_result( { @@ -556,7 +557,7 @@ def test_label_effects_are_exported_to_extracted_features_multi_add( execute_with_result: ExecuteWithResultFunction, entity_type: str, label_name: str, - entity_label_mutation: List[str], + entity_label_mutation: list[str], ) -> None: result = execute_with_result( { diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_length.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_length.py index 0dc3872..e1b6f00 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_length.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_length.py @@ -1,4 +1,4 @@ -from typing import Any, List, Optional +from typing import Any import pytest from osprey.engine.conftest import ExecuteFunction @@ -9,7 +9,7 @@ pytestmark = [pytest.mark.use_udf_registry(UDFRegistry.with_udfs(ListLength))] @pytest.mark.parametrize('input,expected_length', [(['hello', 'world'], 2), ([1, 2, 3, 4], 4), ([], 0), ([None], 1)]) -def test_list_length(execute: ExecuteFunction, input: Optional[List[Any]], expected_length: int) -> None: +def test_list_length(execute: ExecuteFunction, input: list[Any] | None, expected_length: int) -> None: data = execute( f""" Result = ListLength(list={str(input)}) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_read.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_read.py index 576288b..cce388d 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_read.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_read.py @@ -1,4 +1,4 @@ -from typing import Any, List, Optional +from typing import Any import pytest from osprey.engine.conftest import ExecuteFunction @@ -18,7 +18,7 @@ pytestmark = [pytest.mark.use_udf_registry(UDFRegistry.with_udfs(ListRead))] (['118', '2', '5', '30'], '2', 1), ], ) -def test_list_read(execute: ExecuteFunction, input: Optional[List[Any]], expected_str: str, index: int) -> None: +def test_list_read(execute: ExecuteFunction, input: list[Any] | None, expected_str: str, index: int) -> None: data = execute( f""" Result = ListRead(list={input}, index={index}) @@ -34,7 +34,7 @@ def test_list_read(execute: ExecuteFunction, input: Optional[List[Any]], expecte ([], 3), ], ) -def test_list_read_failures(execute: ExecuteFunction, input_fail: Optional[List[Any]], index_fail: int) -> None: +def test_list_read_failures(execute: ExecuteFunction, input_fail: list[Any] | None, index_fail: int) -> None: data = execute( f""" Result = ListRead(list={input_fail}, index={index_fail}) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_sort.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_sort.py index 0d8cba3..edcaf20 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_sort.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_list_sort.py @@ -1,4 +1,4 @@ -from typing import Any, List, Optional +from typing import Any import pytest from osprey.engine.conftest import ExecuteFunction @@ -12,7 +12,7 @@ pytestmark = [pytest.mark.use_udf_registry(UDFRegistry.with_udfs(ListSort))] 'input,expected_sorted_list', [(['world', 'hello'], ['hello', 'world']), ([1, 3, 4, 2], [1, 2, 3, 4]), ([], []), ([None], [None])], ) -def test_list_length(execute: ExecuteFunction, input: Optional[List[Any]], expected_sorted_list: List[Any]) -> None: +def test_list_length(execute: ExecuteFunction, input: list[Any] | None, expected_sorted_list: list[Any]) -> None: data = execute( f""" Result = ListSort(list={input}) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_mx_lookup.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_mx_lookup.py index 8ae0d0c..a5fa66c 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_mx_lookup.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_mx_lookup.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any from unittest.mock import MagicMock, patch import pytest @@ -7,13 +8,13 @@ from osprey.engine.conftest import ExecuteFunction from osprey.engine.stdlib.udfs.mx_lookup import MXLookup from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(MXLookup)), ] -def fake_resolve(domain: str, record_type: str, raise_on_no_answer: bool) -> List[Any]: +def fake_resolve(domain: str, record_type: str, raise_on_no_answer: bool) -> list[Any]: if record_type == 'MX': return [MagicMock()] if record_type == 'A': diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_phone_country.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_phone_country.py index b8b6f4e..12f6978 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_phone_country.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_phone_country.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.validate_call_kwargs import ValidateCallKwargs @@ -6,7 +7,7 @@ from osprey.engine.conftest import ExecuteFunction from osprey.engine.stdlib.udfs.phone_country import PhoneCountry from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(PhoneCountry)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_bool.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_bool.py index 0df8a0f..d1eb76a 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_bool.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_bool.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -7,7 +8,7 @@ from osprey.engine.conftest import CheckFailureFunction, ExecuteFunction, RunVal from osprey.engine.stdlib.udfs.random_bool import RandomBool from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(RandomBool)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_int.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_int.py index 81c37b4..501d9ca 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_int.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_random_int.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -7,7 +8,7 @@ from osprey.engine.conftest import CheckFailureFunction, ExecuteFunction, RunVal from osprey.engine.stdlib.udfs.random_int import RandomInt from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(RandomInt)), ] diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_regex_match.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_regex_match.py index f62474b..abd5ffb 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_regex_match.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_regex_match.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List, Optional +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -7,7 +8,7 @@ from osprey.engine.conftest import CheckFailureFunction, ExecuteFunction, RunVal from osprey.engine.stdlib.udfs.regex_match import RegexMatch, RegexMatchMap from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(RegexMatch, RegexMatchMap)), ] @@ -90,7 +91,7 @@ def test_regex_map_all_and_any(execute: ExecuteFunction, pattern: str, target: s ), ) def test_can_be_case_insensitive( - execute: ExecuteFunction, pattern: str, target: str, case_insensitive: Optional[bool], should_match: bool + execute: ExecuteFunction, pattern: str, target: str, case_insensitive: bool | None, should_match: bool ) -> None: extra_args = '' if case_insensitive is not None: diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_require.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_require.py index ff94bd0..a2b0da4 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_require.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_require.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, Dict, List, Optional +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -11,7 +12,7 @@ from osprey.engine.stdlib.udfs.json_data import JsonData from osprey.engine.stdlib.udfs.require import Require from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, ValidateDynamicCallsHaveAnnotatedRValue, UniqueStoredNames]), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(JsonData, Require)), ] @@ -47,7 +48,7 @@ sources = { ), ], ) -def test_require(execute: ExecuteFunction, data: Dict[str, object], expected_result: Dict[str, Optional[str]]) -> None: +def test_require(execute: ExecuteFunction, data: dict[str, object], expected_result: dict[str, str | None]) -> None: result = execute(sources, data=data, allow_errors=True) assert result == expected_result @@ -77,7 +78,7 @@ sources_require_if = { ), ], ) -def test_require_if(execute: ExecuteFunction, data: Dict[str, object], expected_result: Dict[str, object]) -> None: +def test_require_if(execute: ExecuteFunction, data: dict[str, object], expected_result: dict[str, object]) -> None: result = execute(sources_require_if, data=data, allow_errors=True) assert result == expected_result diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_resolve_optional.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_resolve_optional.py index e789020..37f3cc6 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_resolve_optional.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_resolve_optional.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.imports_must_not_have_cycles import ImportsMustNotHaveCycles @@ -14,7 +15,7 @@ from osprey.engine.stdlib.udfs.json_data import JsonData from osprey.engine.stdlib.udfs.resolve_optional import ResolveOptional from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_udf_registry(UDFRegistry.with_udfs(JsonData, ResolveOptional)), pytest.mark.use_validators( [ @@ -33,7 +34,7 @@ pytestmark: List[Callable[[Any], Any]] = [ def test_resolve_optional_unwraps_value(execute: ExecuteFunction) -> None: data = execute( """ - Foo: Optional[str] = JsonData(path='$.foo') + Foo: str | None = JsonData(path='$.foo') FooUnwrapped: str = ResolveOptional(optional_value=Foo) """, data={'foo': 'test'}, @@ -46,7 +47,7 @@ def test_resolve_optional_errors_on_none(execute: ExecuteFunction) -> None: with pytest.raises(ValueError): execute( """ - Foo: Optional[str] = None + Foo: str | None = None FooUnwrapped: str = ResolveOptional(optional_value=Foo, should_report_error=True) """ ) @@ -54,7 +55,7 @@ def test_resolve_optional_errors_on_none(execute: ExecuteFunction) -> None: # should_report_error=False by default so execution should not raise an exception execute( """ - Foo: Optional[str] = None + Foo: str | None = None FooUnwrapped: str = ResolveOptional(optional_value=Foo) """ ) @@ -63,7 +64,7 @@ def test_resolve_optional_errors_on_none(execute: ExecuteFunction) -> None: def test_resolve_optional_default_value_on_none(execute: ExecuteFunction) -> None: data = execute( """ - Foo: Optional[str] = None + Foo: str | None = None FooUnwrapped: str = ResolveOptional(optional_value=Foo, default_value='test') """ ) @@ -77,9 +78,9 @@ def test_resolve_optional_invalid_default_value_type( with check_failure(): run_validation( """ - Foo: Optional[str] = None + Foo: str | None = None FooUnwrapped: str = ResolveOptional(optional_value=Foo, default_value=1) - Bar: Optional[int] = 1 + Bar: int | None = 1 BarUnwrapper: int = ResolveOptional(optional_value=Bar, default_value='test') """ ) @@ -91,7 +92,7 @@ def test_resolve_optional_invalid_optional_value_type( with check_failure(): run_validation( """ - Foo: Optional[int] = 1 + Foo: int | None = 1 FooUnwrapped: str = ResolveOptional(optional_value=Foo) """ ) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_rules.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_rules.py index 64b686a..af7bbaf 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_rules.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_rules.py @@ -1,7 +1,8 @@ import dataclasses import json +from collections.abc import Callable, Mapping, Sequence from datetime import datetime, timedelta -from typing import Any, Callable, Dict, List, Mapping, Sequence +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -37,7 +38,7 @@ class FailingString(UDFBase[ArgumentsBase, str]): raise ValueError('intentional failure') -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_udf_registry( UDFRegistry.with_udfs(Entity, Rule, WhenRules, LabelAdd, LabelRemove, TimeDelta, FailingUdf, FailingString) ), @@ -484,10 +485,10 @@ def _sort_entity_mutations( return {entity: sorted(mutations, key=sort_key) for entity, mutations in effects.items()} -def _to_simple_dict(label_effects: Mapping[EntityT[Any], Sequence[EntityLabelMutation]]) -> Dict[object, object]: +def _to_simple_dict(label_effects: Mapping[EntityT[Any], Sequence[EntityLabelMutation]]) -> dict[object, object]: """Converts effects to bare dicts, so py.test can display them better in failure output!""" - def entity_mutation_to_dict(mutation: EntityLabelMutation) -> Dict[str, Any]: + def entity_mutation_to_dict(mutation: EntityLabelMutation) -> dict[str, Any]: # Convert EntityLabelMutation to a comparable dict expires_at_timestamp = mutation.expires_at.timestamp() if mutation.expires_at is not None else None diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_secret_data.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_secret_data.py index c2287d8..5b0b551 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_secret_data.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_secret_data.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, Dict, List, Optional +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.conftest import CheckFailureFunction, ExecuteFunction, RunValidationFunction @@ -7,7 +8,7 @@ from osprey.engine.stdlib.udfs.string import StringClean, StringLength from osprey.engine.udf.registry import UDFRegistry from typing_extensions import TypedDict -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_standard_rules_validators(), pytest.mark.use_udf_registry(UDFRegistry.with_udfs(JsonData, StringClean, StringLength)), ] @@ -23,8 +24,8 @@ is_secret_mark = pytest.mark.parametrize( class DataT(TypedDict): - data: Optional[Dict[str, object]] - secret_data: Optional[Dict[str, str]] + data: dict[str, object] | None + secret_data: dict[str, str] | None @pytest.mark.use_standard_rules_validators() diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_strings.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_strings.py index c8345bc..1cffdcc 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_strings.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_strings.py @@ -1,6 +1,7 @@ import string +from collections.abc import Callable, Iterable from dataclasses import dataclass -from typing import Any, Callable, Dict, Iterable, List, Optional, Union, cast +from typing import Any, cast import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -25,7 +26,7 @@ from osprey.engine.stdlib.udfs.string import ( ) from osprey.engine.udf.registry import UDFRegistry -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_udf_registry( UDFRegistry.with_udfs( @@ -99,7 +100,7 @@ def test_string_slice_validation( @pytest.mark.parametrize('sep,maxsplit', [(None, -1), (None, 2), ('o', -1), ('o', 2)]) -def test_string_split(execute: ExecuteFunction, sep: Optional[str], maxsplit: int) -> None: +def test_string_split(execute: ExecuteFunction, sep: str | None, maxsplit: int) -> None: sep_arg = '' if sep is None else f', sep="{sep}"' maxsplit_arg = '' if maxsplit == -1 else f', maxsplit={maxsplit}' @@ -150,7 +151,7 @@ def test_string_strip( UDF: str, func: Callable[..., str], input: str, - chars: Optional[str], + chars: str | None, ) -> None: chars_arg = '' if chars is None else f', chars="{chars}"' data = execute( @@ -210,7 +211,7 @@ def test_string_to_upper(execute: ExecuteFunction) -> None: @dataclass class Scenario: s: str - expects: Union[str, Iterable[str]] = ('text',) + expects: str | Iterable[str] = ('text',) not_expects: Iterable[str] = ('|',) @@ -304,14 +305,14 @@ def test_string_normalization(s: Scenario, execute: ExecuteFunction) -> None: ('check this out https://[bad::ipv6 click here', []), # malformed IPv6 in text ], ) -def test_extract_domains(execute: ExecuteFunction, text: str, expected_result: List[str]) -> None: - data: Dict[str, Any] = execute( +def test_extract_domains(execute: ExecuteFunction, text: str, expected_result: list[str]) -> None: + data: dict[str, Any] = execute( f""" Result = StringExtractDomains(s="{text}") """ ) - result: List[str] = data['Result'] + result: list[str] = data['Result'] assert len(expected_result) == len(result) assert set(expected_result) == set(result) @@ -353,13 +354,13 @@ def test_extract_domains(execute: ExecuteFunction, text: str, expected_result: L ('check this out https://[bad::ipv6 click here', []), # malformed IPv6 in text ], ) -def test_extract_urls(execute: ExecuteFunction, text: str, expected_result: List[str]) -> None: - data: Dict[str, Any] = execute( +def test_extract_urls(execute: ExecuteFunction, text: str, expected_result: list[str]) -> None: + data: dict[str, Any] = execute( f""" Result = StringExtractURLs(s="{text}") """ ) - result: List[str] = data['Result'] + result: list[str] = data['Result'] assert len(expected_result) == len(result) assert set(expected_result) == set(result) diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_time_bucket.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_time_bucket.py index 4d06a51..30a1343 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_time_bucket.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_time_bucket.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.unique_stored_names import UniqueStoredNames @@ -9,7 +10,7 @@ from osprey.engine.stdlib.udfs.time_delta import TimeDelta from osprey.engine.udf.registry import UDFRegistry from osprey.worker.lib.snowflake import Snowflake -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators([ValidateCallKwargs, UniqueStoredNames]), pytest.mark.use_udf_registry( UDFRegistry.with_udfs(GetTimedeltaBucket, GetSnowflakeBucket, GetTimestampBucket, TimeDelta), diff --git a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_verdicts.py b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_verdicts.py index 5304eac..a6ea3a4 100644 --- a/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_verdicts.py +++ b/osprey_worker/src/osprey/engine/stdlib/udfs/tests/test_verdicts.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List +from collections.abc import Callable +from typing import Any import pytest from osprey.engine.ast_validator.validators.feature_name_to_entity_type_mapping import ( @@ -14,7 +15,7 @@ from osprey.engine.udf.registry import UDFRegistry # Moved here because WhenRules is not included in the MVP yet -pytestmark: List[Callable[[Any], Any]] = [ +pytestmark: list[Callable[[Any], Any]] = [ pytest.mark.use_validators( [ FeatureNameToEntityTypeMapping, diff --git a/osprey_worker/src/osprey/engine/udf/arguments.py b/osprey_worker/src/osprey/engine/udf/arguments.py index 5def7d5..0499f4f 100644 --- a/osprey_worker/src/osprey/engine/udf/arguments.py +++ b/osprey_worker/src/osprey/engine/udf/arguments.py @@ -1,9 +1,10 @@ import ast import inspect import textwrap +from collections.abc import Iterator, Sequence from contextlib import contextmanager from functools import lru_cache -from typing import Any, Dict, Generic, Iterator, List, Optional, Sequence, Type, TypeVar, Union, cast, get_type_hints +from typing import Any, Generic, Type, TypeVar, cast, get_type_hints import typing_inspect from osprey.engine.ast import grammar @@ -16,7 +17,7 @@ DefaultT = TypeVar('DefaultT', None, bool, int, float, str) _dummy_span = grammar.Span(source=grammar.Source(path='', contents=''), start_line=1, start_pos=0) # If an Arguments class has this attribute as a dict then extra arguments (otherwise unspecified on the arguments class) -# will be collected in it. The arguments will be typechecked against the value type, e.g. extra_args: Dict[str, int] +# will be collected in it. The arguments will be typechecked against the value type, e.g. extra_args: dict[str, int] # would require all extra arguments to be ints EXTRA_ARGS_ATTR = 'extra_arguments' @@ -54,14 +55,16 @@ class ConstExpr(Generic[T]): return cast(Type[T], origin or type_class) @staticmethod - def get_item_type_class(cls: 'Type[ConstExpr[T]]') -> Type[Union[str, float, int, bool, None]]: + def get_item_type_class(cls: 'Type[ConstExpr[T]]') -> Type[str | float | int | bool | None]: type_class = ConstExpr.get_type_class(cls) assert type_class is list list_ty = typing_inspect.get_args(cls)[0] item_ty = typing_inspect.get_args(list_ty)[0] + if not item_ty: + item_ty = type(item_ty) assert item_ty in (str, float, int, bool, type(None)) # Mypy isn't smart enough to downcast with the above assert. - return cast(Type[Union[str, float, int, bool, None]], item_ty) + return cast(Type[str | float | int | bool | None], item_ty) @staticmethod def get_item_literal_node_type(cls: 'Type[ConstExpr[T]]') -> Type[grammar.Literal]: @@ -96,7 +99,7 @@ class ConstExpr(Generic[T]): ) return ret # type: ignore - def raise_for(self, exception: Exception, message: Optional[str] = None) -> None: + def raise_for(self, exception: Exception, message: str | None = None) -> None: """ Raises an exception on behalf of an argument. Use this if you wish to implement more bespoke error handling than that provided by `attribute_errors`. @@ -104,7 +107,7 @@ class ConstExpr(Generic[T]): raise ConstExprArgumentException(const_expr=self, wrapped_exception=exception, message_override=message) @contextmanager - def attribute_errors(self, message: Optional[str] = None) -> Iterator[None]: + def attribute_errors(self, message: str | None = None) -> Iterator[None]: """ A context manager wraps something that might throw during the compilation/validation phase, allowing the error to point to the specific argument, with a specific exception. @@ -132,9 +135,7 @@ class ConstExprArgumentException(Exception): NOTE: This is not thrown when the type does not match, but simply when the value is invalid, e.g. a JSON string is expected, but it cannot be parsed.""" - def __init__( - self, const_expr: ConstExpr[Any], wrapped_exception: Exception, message_override: Optional[str] = None - ): + def __init__(self, const_expr: ConstExpr[Any], wrapped_exception: Exception, message_override: str | None = None): self.const_expr = const_expr self.wrapped_exception = wrapped_exception self.message_override = message_override @@ -149,7 +150,7 @@ _LITERAL_TO_RUNTIME_TYPE_TRANSLATIONS = { grammar.None_: type(None), } -_RUNTIME_TO_LITERAL_TYPE_TRANSLATIONS: Dict[Any, Type[grammar.Literal]] = {} +_RUNTIME_TO_LITERAL_TYPE_TRANSLATIONS: dict[Any, Type[grammar.Literal]] = {} for k, v in _LITERAL_TO_RUNTIME_TYPE_TRANSLATIONS.items(): if isinstance(v, tuple): for it in v: @@ -165,8 +166,8 @@ T_arguments = TypeVar('T_arguments', bound='ArgumentsBase') class ArgumentSpec(BaseModel): name: str type: str - default: Optional[str] - doc: Optional[str] + default: str | None + doc: str | None def declaration(self) -> str: if self.default is None: @@ -176,7 +177,7 @@ class ArgumentSpec(BaseModel): return f'{self.name}: {self.type}{default}' - def param_docstring(self) -> Optional[str]: + def param_docstring(self) -> str | None: if not self.doc: return None # Clean it up a bit @@ -199,7 +200,7 @@ class ArgumentsBase: def __init__( self, call_node: grammar.Call, - arguments: Dict[str, Any], + arguments: dict[str, Any], resolved: bool = False, ): self._call_node = call_node @@ -234,7 +235,7 @@ class ArgumentsBase: def get_argument_ast(self, key: str) -> grammar.Expression: return self._arguments_ast[key] - def get_extra_arguments_ast(self) -> Dict[str, grammar.Expression]: + def get_extra_arguments_ast(self) -> dict[str, grammar.Expression]: """returns a dict of keys that are unexpected kwargs and their expressions""" keys = set(self._arguments_ast.keys() - self.items().keys()) return {k: v for k, v in self._arguments_ast.items() if k in keys} @@ -242,7 +243,7 @@ class ArgumentsBase: def has_argument_ast(self, key: str) -> bool: return key in self._arguments_ast - def update_with_resolved(self: T_arguments, resolved: Dict[str, Any]) -> T_arguments: + def update_with_resolved(self: T_arguments, resolved: dict[str, Any]) -> T_arguments: assert not self._resolved return self.__class__(call_node=self._call_node, arguments={**self._arguments, **resolved}, resolved=True) @@ -265,8 +266,8 @@ class ArgumentsBase: @classmethod @lru_cache(1) - def items(cls) -> Dict[str, type]: - fields: Dict[str, type] = {} + def items(cls) -> dict[str, type]: + fields: dict[str, type] = {} for klass in cls._traverse_mro(): for field, value in get_type_hints(klass).items(): @@ -275,7 +276,7 @@ class ArgumentsBase: return fields @classmethod - def get_generic_param(cls) -> Optional[type]: + def get_generic_param(cls) -> type | None: """Returns the `TypeVar` used if this class is generic, otherwise `None`. If it *is* generic, asserts that it inherits from `OspreyInvariantGeneric`. @@ -283,12 +284,12 @@ class ArgumentsBase: return get_osprey_generic_param(cls, kind='arguments') @classmethod - def get_generic_item_names(cls, func_name: str) -> List[str]: + def get_generic_item_names(cls, func_name: str) -> list[str]: """ Get the list of generic argument names. Asserts that we only have one type variable. For each generic item, also asserts that it only has one type - parameter (so Optional[T] is okay, but Dict[T, T] is not). + parameter (so T | None is okay, but dict[T, T] is not). """ generic_args = [] for arg_name, arg_type in cls.items().items(): @@ -352,7 +353,7 @@ class ArgumentsBase: # If this value is set on the class, then that's the default. return hasattr(cls, name) - def get_dependent_node_dict(self) -> Dict[str, grammar.ASTNode]: + def get_dependent_node_dict(self) -> dict[str, grammar.ASTNode]: assert not self._resolved items = self.items() @@ -371,8 +372,8 @@ class ArgumentsBase: seen_specs = set() items = cls.items() - def add_argument(name: str, doc: Optional[str]) -> None: - default: Optional[str] + def add_argument(name: str, doc: str | None) -> None: + default: str | None if hasattr(cls, name): default_value = getattr(cls, name) if isinstance(default_value, ConstExpr): @@ -399,16 +400,16 @@ class ArgumentsBase: klass_ast = parsed.body[0] assert isinstance(klass_ast, ast.ClassDef) - previous_variable: Optional[str] = None + previous_variable: str | None = None for statement in klass_ast.body: - current_variable: Optional[str] + current_variable: str | None if isinstance(statement, ast.AnnAssign) and isinstance(statement.target, ast.Name): current_variable = statement.target.id else: current_variable = None if previous_variable is not None and previous_variable not in seen_specs and previous_variable in items: - doc: Optional[str] + doc: str | None if isinstance(statement, ast.Expr) and isinstance(statement.value, ast.Str): assert isinstance(statement.value.s, str) doc = inspect.cleandoc(statement.value.s) @@ -447,7 +448,7 @@ def type_invariant(node: grammar.ASTNode, expected: Type[LiteralT]) -> LiteralT: return node -def literal_value(literal: grammar.Literal) -> Union[str, int, float, bool, None]: +def literal_value(literal: grammar.Literal) -> str | int | float | bool | None: if isinstance(literal, (grammar.String, grammar.Number, grammar.Boolean)): return literal.value diff --git a/osprey_worker/src/osprey/engine/udf/base.py b/osprey_worker/src/osprey/engine/udf/base.py index 4a235b9..bdea688 100644 --- a/osprey_worker/src/osprey/engine/udf/base.py +++ b/osprey_worker/src/osprey/engine/udf/base.py @@ -1,7 +1,8 @@ import inspect import textwrap from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, ClassVar, Dict, Generic, Optional, Sequence, Tuple, Type, TypeVar, cast +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, ClassVar, Generic, Type, TypeVar, cast import typing_inspect from osprey.engine.executor.execution_context import ExecutionContext @@ -25,10 +26,10 @@ NoneType = type(None) class MethodSpec(BaseModel): name: str - doc: Optional[str] + doc: str | None argument_specs: Sequence[ArgumentSpec] return_type: str - category: Optional[str] + category: str | None def stub(self) -> str: arg_declarations = ', '.join(arg.declaration() for arg in self.argument_specs) @@ -69,7 +70,7 @@ class UDFBase(Generic[Arguments, RValue], ABC): generic functions: - **With a *generic* arguments class.** In this case, the arguments class must have at least one item (eg one kwarg) that is generic, and that item's type must be just the TypeVar or a simple wrapper around - the TypeVar that has one parameter (i.e. Optional[T] and List[T] are okay, but not Dict[T, T]). We infer the + the TypeVar that has one parameter (i.e. T | None and list[T] are okay, but not dict[T, T]). We infer the value of the TypeVar to determine the return type of the function statically (more on returns below). - **With a *non-generic* arguments class.** In this case, we have no way to statically determine the return type, so we treat it as a dynamic return type. The function must be assigned to a type-annotated variable, @@ -77,7 +78,7 @@ class UDFBase(Generic[Arguments, RValue], ABC): In either case, all generic functions must have a generic return type (otherwise why is it generic?). Both the UDF classes and Arguments classes must inherit from `OspreyInvariantGeneric`, not the plain `typing.Generic`, - though the return type may inherit from `typing.Generic` (eg `Optional[T]`) or even just be a plain `TypeVar` + though the return type may inherit from `typing.Generic` (eg `T | None`) or even just be a plain `TypeVar` (eg `T`). These restrictions are verified by a combination of getters on `UDFBase` and `ArgumentsBase` and extra @@ -89,12 +90,12 @@ class UDFBase(Generic[Arguments, RValue], ABC): the `execute_async` field in `BaseNodeExecutor`. """ - category: ClassVar[Optional[str]] = None + category: ClassVar[str | None] = None """If present, a string name for what category this UDF falls into. Can be used for, say, grouping UDFs in documentation.""" def __init__(self, validation_context: 'ValidationContext', arguments: Arguments): - self._rvalue_type_checker: Optional[RValueTypeChecker] = None + self._rvalue_type_checker: RValueTypeChecker | None = None def resolve_arguments(self, execution_context: ExecutionContext, call_executor: 'CallExecutor') -> Arguments: """Resolves the arguments once all dependent nodes have completed execution. The return value of this function @@ -115,7 +116,7 @@ class UDFBase(Generic[Arguments, RValue], ABC): raise NotImplementedError @classmethod - def _get_udf_base_args(cls) -> Tuple[type, ...]: + def _get_udf_base_args(cls) -> tuple[type, ...]: for base in cls.__mro__: for generic_base in typing_inspect.get_generic_bases(base): if typing_inspect.get_origin(generic_base) in (UDFBase, BatchableUDFBase, QueryUdfBase): @@ -155,8 +156,8 @@ class UDFBase(Generic[Arguments, RValue], ABC): """Get the concrete return type, using the given resolved type to fill in the generic return. If the UDF returns a `TypeVar` (eg `T`) then this will just return the given resolved type. If the UDF - returns a generic type (eg `List[Optional[T]]`) then this will return that type with the given type inserted - into if (eg `List[Optional[str]]` if `resolved_generic_type` were `str`). + returns a generic type (eg `list[T | None]`) then this will return that type with the given type inserted + into if (eg `list[str | None] if `resolved_generic_type` were `str`). Asserts that the UDF is generic. """ @@ -168,10 +169,10 @@ class UDFBase(Generic[Arguments, RValue], ABC): # The return type is just the bare typevar, so return the resolved typevar return resolved_typevar_type else: - # If the type var is nested within another type (e.g. List[T]), then we perform typevar substitution + # If the type var is nested within another type (e.g. list[T]), then we perform typevar substitution return cls.get_rvalue_type()[resolved_typevar_type] # type: ignore # Runtime typing - def get_resolved_rvalue_type(self, resolved_typevar_type: Optional[type]) -> type: + def get_resolved_rvalue_type(self, resolved_typevar_type: type | None) -> type: if self.has_dynamic_result(): assert resolved_typevar_type is None, 'Should not have resolved generic type with dynamic result' assert self._rvalue_type_checker is not None, ( @@ -257,7 +258,7 @@ class QueryUdfBase(Generic[Arguments, RValue], UDFBase[Arguments, RValue]): raise NotImplementedError @abstractmethod - def to_druid_query(self) -> Dict[str, object]: + def to_druid_query(self) -> dict[str, object]: raise NotImplementedError diff --git a/osprey_worker/src/osprey/engine/udf/registry.py b/osprey_worker/src/osprey/engine/udf/registry.py index 541d127..bdb6cbd 100644 --- a/osprey_worker/src/osprey/engine/udf/registry.py +++ b/osprey_worker/src/osprey/engine/udf/registry.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Iterator, Optional, Type +from collections.abc import Iterator +from typing import Any, Type import typing_inspect from osprey.engine.udf.arguments import EXTRA_ARGS_ATTR @@ -10,7 +11,7 @@ from .type_helpers import UnsupportedTypeError, get_osprey_generic_param, is_typ class UDFRegistry: def __init__(self) -> None: - self._functions: Dict[str, Type[UDFBase[Any, Any]]] = {} + self._functions: dict[str, Type[UDFBase[Any, Any]]] = {} @classmethod def with_udfs(cls, *funcs: Type[UDFBase[Any, Any]]) -> 'UDFRegistry': @@ -77,7 +78,7 @@ class UDFRegistry: return self - def get(self, function_name: str) -> Optional[Type[UDFBase[Any, Any]]]: + def get(self, function_name: str) -> Type[UDFBase[Any, Any]] | None: return self._functions.get(function_name) diff --git a/osprey_worker/src/osprey/engine/udf/rvalue_type_checker.py b/osprey_worker/src/osprey/engine/udf/rvalue_type_checker.py index 5e3d8e2..75e5caa 100644 --- a/osprey_worker/src/osprey/engine/udf/rvalue_type_checker.py +++ b/osprey_worker/src/osprey/engine/udf/rvalue_type_checker.py @@ -1,5 +1,8 @@ +import operator from abc import ABC, abstractmethod -from typing import Callable, ClassVar, Dict, List, Optional, Sequence, Tuple, Type, TypeVar, Union +from collections.abc import Callable, Sequence +from functools import reduce +from typing import ClassVar, Type, TypeVar from osprey.engine.ast.grammar import Annotation, Annotations, AnnotationWithVariants, Assign, Span from osprey.engine.language_types.entities import EntityT @@ -27,7 +30,7 @@ class RValueTypeChecker(ABC): raise TypeError(f'Cannot coerce `{obj!r}` to {to_display_str(self.to_typing_type())}') -_AnnotationMaybeWithVariantT = Union[Annotation, AnnotationWithVariants] +_AnnotationMaybeWithVariantT = Annotation | AnnotationWithVariants TypeConstructorT = Callable[[_AnnotationMaybeWithVariantT, str], RValueTypeChecker] @@ -52,8 +55,8 @@ class TypeRegistry: """Holds information about generic and non-generic types that can be checked at runtime.""" def __init__(self) -> None: - self._non_generic_types: Dict[str, RValueTypeChecker] = {} - self._generic_types: Dict[str, Type[GenericTypeChecker]] = {} + self._non_generic_types: dict[str, RValueTypeChecker] = {} + self._generic_types: dict[str, Type[GenericTypeChecker]] = {} def register_non_generic(self, name: str, type_checker: RValueTypeChecker) -> None: self._non_generic_types[name] = type_checker @@ -62,13 +65,13 @@ class TypeRegistry: self._generic_types[type_checker.name()] = type_checker return type_checker - def get_non_generic(self, node: Annotation) -> Optional[RValueTypeChecker]: + def get_non_generic(self, node: Annotation) -> RValueTypeChecker | None: return self._non_generic_types.get(node.identifier) - def get_generic(self, node: AnnotationWithVariants) -> Optional[Type[GenericTypeChecker]]: + def get_generic(self, node: AnnotationWithVariants) -> Type[GenericTypeChecker] | None: return self._generic_types.get(node.identifier) - def generic_names(self) -> List[str]: + def generic_names(self) -> list[str]: return list(self._generic_types.keys()) @@ -136,7 +139,7 @@ class UnionTypeChecker(GenericTypeChecker): hint=hint, ) - seen_types: Dict[str, Span] = {} + seen_types: dict[str, Span] = {} inner_types = [] for variant in node.variants: # Check if the variant was already seen for this Union. @@ -153,11 +156,11 @@ class UnionTypeChecker(GenericTypeChecker): return UnionTypeChecker(tuple(inner_types)) - def __init__(self, inner_types: Tuple[RValueTypeChecker, ...]): + def __init__(self, inner_types: tuple[RValueTypeChecker, ...]): assert len(inner_types) > 1, f'Tried to create union with {len(inner_types)} inner types: {inner_types}' self.inner_types = inner_types - def _find_working_inner_type(self, obj: object) -> Optional[RValueTypeChecker]: + def _find_working_inner_type(self, obj: object) -> RValueTypeChecker | None: for inner_type in self.inner_types: if inner_type.check(obj): return inner_type @@ -184,7 +187,7 @@ class UnionTypeChecker(GenericTypeChecker): def to_typing_type(self) -> type: # Mypy doesn't like runtime types like this # noinspection PyTypeChecker - return Union[tuple(inner.to_typing_type() for inner in self.inner_types)] # type: ignore + return reduce(operator.or_, (inner.to_typing_type() for inner in self.inner_types)) # type: ignore @REGISTRY.register_generic @@ -195,20 +198,28 @@ class OptionalTypeChecker(UnionTypeChecker): @classmethod def parse(cls, node: AnnotationWithVariants, type_constructor: TypeConstructorT) -> 'OptionalTypeChecker': - if len(node.variants) != 1: + if len(node.variants) < 1 or len(node.variants) > 2: raise AnnotationConversionError( - message='`Optional` must have exactly one argument', + message='`Optional` must have one or two arguments', span=node.span, hint=f'got {len(node.variants)} arguments', ) + if len(node.variants) > 1 and node.variants[-1].identifier != 'None': + args = ' and '.join([x.identifier for x in node.variants]) + raise AnnotationConversionError( + message="`Optional` can't have arguments of different types or duplicate types", + span=node.span, + hint=f'got {args} arguments', + ) + variant = node.variants[0] inner_type = type_constructor(variant, 'expected simple type in `Optional`') return OptionalTypeChecker((inner_type, InstanceTypeChecker(type(None)))) class BaseWrapperTypeChecker(GenericTypeChecker): - wrapped_type: ClassVar[Optional[Annotations]] = None + wrapped_type: ClassVar[Annotations | None] = None @classmethod def name(cls) -> str: @@ -231,7 +242,7 @@ class BaseWrapperTypeChecker(GenericTypeChecker): inner_type = type_constructor(variant, f'expected simple type in `{cls.name()}`') return cls((inner_type,)) - def __init__(self, inner_types: Tuple[RValueTypeChecker, ...]): + def __init__(self, inner_types: tuple[RValueTypeChecker, ...]): assert len(inner_types) == 1, ( f'Tried to create `{self.name()}` with {len(inner_types)} inner types: {inner_types}' ) @@ -302,7 +313,7 @@ class ListTypeChecker(GenericTypeChecker): def to_typing_type(self) -> type: # noinspection PyTypeChecker - return List[self.item_checker.to_typing_type()] # type: ignore # Doesn't like runtime types like this + return list[self.item_checker.to_typing_type()] # type: ignore # Doesn't like runtime types like this @REGISTRY.register_generic @@ -356,7 +367,7 @@ def _get_default_error_message() -> str: def _convert_simple_annotation_to_typechecker( - node: _AnnotationMaybeWithVariantT, error_message: Optional[str] = None + node: _AnnotationMaybeWithVariantT, error_message: str | None = None ) -> RValueTypeChecker: assert not isinstance(node, AnnotationWithVariants), 'expected simple annotation' checker = REGISTRY.get_non_generic(node) diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_arguments.py b/osprey_worker/src/osprey/engine/udf/tests/test_arguments.py index 319a959..877da29 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_arguments.py +++ b/osprey_worker/src/osprey/engine/udf/tests/test_arguments.py @@ -1,5 +1,3 @@ -from typing import Optional, Union - from osprey.engine.udf.arguments import ArgumentsBase, ConstExpr StrConstExpr = ConstExpr[str] # This being inside the below function is causing mypy to crash @@ -19,8 +17,8 @@ def test_arguments_items() -> None: def test_arguments_can_be_none() -> None: class Arguments(ArgumentsBase): - optional: Optional[str] - union: Union[str, int, None] + optional: str | None + union: str | int | None none: None obj: object string: str diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_const_expr.py b/osprey_worker/src/osprey/engine/udf/tests/test_const_expr.py index 4ccbf1c..f61aeeb 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_const_expr.py +++ b/osprey_worker/src/osprey/engine/udf/tests/test_const_expr.py @@ -1,4 +1,4 @@ -from typing import List, Type, TypeVar +from typing import Type, TypeVar import pytest from osprey.engine.ast import grammar @@ -32,17 +32,17 @@ def test_scalar_const_expr(ty: Type[_T], lit: Type[grammar.Literal]) -> None: @pytest.mark.parametrize( 'ty, lit, inner_ty, inner_lit_ty', [ - (List[str], grammar.List, str, grammar.String), - (List[int], grammar.List, int, grammar.Number), - (List[float], grammar.List, float, grammar.Number), - (List[bool], grammar.List, bool, grammar.Boolean), - (List[None], grammar.List, type(None), grammar.None_), + (list[str], grammar.List, str, grammar.String), + (list[int], grammar.List, int, grammar.Number), + (list[float], grammar.List, float, grammar.Number), + (list[bool], grammar.List, bool, grammar.Boolean), + (list[None], grammar.List, type(None), grammar.None_), ], ) def test_list_const_expr( - ty: Type[List[_T]], lit: Type[grammar.Literal], inner_ty: Type[_T], inner_lit_ty: Type[grammar.Literal] + ty: Type[list[_T]], lit: Type[grammar.Literal], inner_ty: Type[_T], inner_lit_ty: Type[grammar.Literal] ) -> None: - ConstExprT: Type[ConstExpr[List[_T]]] = ConstExpr[ty] # type: ignore # Can't use runtime variable in a generic + ConstExprT: Type[ConstExpr[list[_T]]] = ConstExpr[ty] # type: ignore # Can't use runtime variable in a generic assert ConstExpr.get_type_class(ConstExprT) is list assert ConstExpr.get_literal_node_type(ConstExprT) is lit diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_rvalue_type_checker.py b/osprey_worker/src/osprey/engine/udf/tests/test_rvalue_type_checker.py index ec3292c..8aa032a 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_rvalue_type_checker.py +++ b/osprey_worker/src/osprey/engine/udf/tests/test_rvalue_type_checker.py @@ -1,4 +1,5 @@ -from typing import List, Sequence, Tuple, Type +from collections.abc import Sequence +from typing import Type import pytest from osprey.engine.ast.grammar import Annotation, AnnotationWithVariants, Span @@ -110,8 +111,8 @@ def test_conversion_of_complex_annotation( ('Union', ('str',), '`Union` of one item'), ('List', ('str', 'int'), 'unexpected additional'), ('Unknown', ('str', 'int'), 'can only check dynamic return values of'), - ('Optional', (), '`Optional` must have exactly one argument'), - ('Optional', ('str', 'int'), '`Optional` must have exactly one argument'), + ('Optional', (), '`Optional` must have one or two arguments'), + ('Optional', ('str', 'int'), "`Optional` can't have arguments of different types"), ('Optional', ('List',), 'expected simple type in `Optional`'), ('Entity', (), '`Entity` must have exactly one argument'), ('Entity', ('str', 'int'), '`Entity` must have exactly one argument'), @@ -179,7 +180,7 @@ def test_coerce_simple(span: Span, identifier: str, value: object, result: Resul if result.is_ok(): assert checker.coerce(value) == result.unwrap() else: - expected_exceptions: Tuple[Type[Exception], ...] = (ValueError, TypeError) + expected_exceptions: tuple[Type[Exception], ...] = (ValueError, TypeError) with pytest.raises(expected_exceptions) as e: checker.coerce(value) @@ -211,7 +212,7 @@ def test_coerce_simple(span: Span, identifier: str, value: object, result: Resul def test_coerce_complex( span: Span, outer_identifier: str, - inner_identifiers: List[str], + inner_identifiers: list[str], value: object, result: Result[object, str], ) -> None: @@ -225,7 +226,7 @@ def test_coerce_complex( if result.is_ok(): assert checker.coerce(value) == result.unwrap() else: - expected_exceptions: Tuple[Type[Exception], ...] = (ValueError, TypeError) + expected_exceptions: tuple[Type[Exception], ...] = (ValueError, TypeError) with pytest.raises(expected_exceptions) as e: checker.coerce(value) diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_type_evaluator.py b/osprey_worker/src/osprey/engine/udf/tests/test_type_evaluator.py index 7ab6481..b574332 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_type_evaluator.py +++ b/osprey_worker/src/osprey/engine/udf/tests/test_type_evaluator.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, List, Optional, Tuple, TypeVar, Union +from collections.abc import Callable +from typing import Any, TypeVar import pytest from osprey.engine.language_types.entities import EntityT @@ -47,54 +48,54 @@ class Generic2(OspreyInvariantGeneric[_T]): (C, A, True), (C, B, True), # Union types - (int, Optional[int], True), - (None, Optional[int], True), - (Optional[int], int, False), - (Union[int, float], Union[int, float, str], True), - (Union[int, float], Union[int, str], False), - (Union[int, float], int, False), - (int, Union[int, bool], True), - (bool, Union[int, bool], True), - (A, Union[A, B], True), - (C, Union[A, C], True), + (int, int | None, True), + (None, int | None, True), + (int | None, int, False), + (int | float, int | float | str, True), + (int | float, int | str, False), + (int | float, int, False), + (int, int | bool, True), + (bool, int | bool, True), + (A, A | B, True), + (C, A | C, True), # List types (guh!) - (List[int], List[int], True), - (List[float], List[int], False), - (List[float], List[Union[int, float]], True), - (List[float], str, False), - (str, List[float], False), + (list[int], list[int], True), + (list[float], list[int], False), + (list[float], list[int | float], True), + (list[float], str, False), + (str, list[float], False), # Any types (int, Any, True), - (Optional[int], Any, True), - (Union[int, str], Any, True), + (int | None, Any, True), + (int | str, Any, True), (A, Any, True), - (List[int], Any, True), - (List[Any], Any, True), - (List[int], List[Any], True), - (int, List[Any], False), + (list[int], Any, True), + (list[Any], Any, True), + (list[int], list[Any], True), + (int, list[Any], False), (Any, int, True), - (Any, Optional[int], True), - (Any, Union[int, str], True), + (Any, int | None, True), + (Any, int | str, True), (Any, A, True), - (Any, List[int], True), - (Any, List[Any], True), - (List[Any], List[int], True), - (List[Any], int, False), + (Any, list[int], True), + (Any, list[Any], True), + (list[Any], list[int], True), + (list[Any], int, False), (Any, Any, True), # ConstExpr (str, ConstExpr[str], True), (int, ConstExpr[str], False), - (List[str], ConstExpr[List[str]], True), + (list[str], ConstExpr[list[str]], True), (ConstExpr[str], str, True), (ConstExpr[str], int, False), - (ConstExpr[List[str]], List[str], True), + (ConstExpr[list[str]], list[str], True), # Allowed generics (Generic1[str], Generic1[str], True), (Generic1[A], Generic1[A], True), (Generic1[str], Generic1[int], False), (Generic1[B], Generic1[A], True), (Generic1[A], Generic2[A], False), - (Optional[A], Optional[A], True), + (A | None, A | None, True), ], ids=lambda arg: arg if isinstance(arg, bool) else to_display_str(arg, include_quotes=False), # type: ignore ) @@ -113,10 +114,10 @@ def test_is_compatible_type_supported_types(type_t: type, accepted_type_t: type, @pytest.mark.parametrize( 'type_t', [ - Tuple[str, ...], - Union[List[str], str], + tuple[str, ...], + list[str] | str, Callable[[int], int], - List, + list, ConstExpr, EntityT, EntityT[_T], # type: ignore[valid-type] diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_type_helpers.py b/osprey_worker/src/osprey/engine/udf/tests/test_type_helpers.py index 5ca25a0..325fefb 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_type_helpers.py +++ b/osprey_worker/src/osprey/engine/udf/tests/test_type_helpers.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, TypeVar, Union +from typing import Any, TypeVar import pytest from osprey.engine.language_types.entities import EntityT @@ -12,10 +12,10 @@ from osprey.engine.udf.type_helpers import UnsupportedTypeError, get_typevar_sub (str, '`str`'), (None, '`None`'), (type(None), '`None`'), - (Optional[str], '`Optional[str]`'), - (Union[str, None], '`Optional[str]`'), - (Union[str, int], '`Union[str, int]`'), - (List[Any], '`List[Any]`'), + (str | None, '`str | None`'), + (str | None, '`str | None`'), + (str | int, '`str | int`'), + (list[Any], '`list[Any]`'), (ConstExpr[str], '`ConstExpr[str]`'), (EntityT, '`Entity`'), ], @@ -32,11 +32,11 @@ _T2 = TypeVar('_T2') 'generic_type, resolved_type, expected_typevar_type', [ (_T, str, str), - (_T, List[str], List[str]), - (Optional[_T], Optional[int], int), - (List[_T], List[bool], bool), # type: ignore[valid-type] - (Optional[_T], Optional[Any], Any), - (Optional[_T], Optional[str], str), + (_T, list[str], list[str]), + (_T | None, int | None, int), + (list[_T], list[bool], bool), # type: ignore[valid-type] + (_T | None, Any | None, Any), + (_T | None, str | None, str), ], ) def test_get_typevar_substitution(generic_type: type, resolved_type: type, expected_typevar_type: type) -> None: @@ -46,15 +46,15 @@ def test_get_typevar_substitution(generic_type: type, resolved_type: type, expec @pytest.mark.parametrize( 'generic_type, resolved_type', [ - (_T, Optional[_T]), - (Optional[_T], Optional[_T]), - (Optional[_T], List[str]), - (List[_T], str), # type: ignore[valid-type] - (Dict[str, _T], Dict[int, str]), # type: ignore[valid-type] - (Dict[_T, _T], Dict[str, int]), # type: ignore[valid-type] - (Dict[_T, List[_T]], Dict[str, Optional[str]]), # type: ignore[valid-type] - (Dict[_T, _T2], Dict[str, int]), # type: ignore[valid-type] - (Dict[_T, int], Dict[str, int]), # type: ignore[valid-type] + (_T, _T | None), + (_T | None, _T | None), + (_T | None, list[str]), + (list[_T], str), # type: ignore[valid-type] + (dict[str, _T], dict[int, str]), # type: ignore[valid-type] + (dict[_T, _T], dict[str, int]), # type: ignore[valid-type] + (dict[_T, list[_T]], dict[str, str | None]), # type: ignore[valid-type] + (dict[_T, _T2], dict[str, int]), # type: ignore[valid-type] + (dict[_T, int], dict[str, int]), # type: ignore[valid-type] ], ) def test_get_typevar_substitution_fails(generic_type: type, resolved_type: type) -> None: diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry.py b/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry.py index 29fd691..482bfe2 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry.py +++ b/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry.py @@ -1,4 +1,5 @@ -from typing import Any, Generic, List, Optional, Sequence, Tuple, Type, TypeVar, cast +from collections.abc import Sequence +from typing import Any, Generic, Type, TypeVar, cast import pytest from osprey.engine.conftest import CheckOutputFunction @@ -84,14 +85,14 @@ def _get_invalid_types() -> Sequence[Type[UDFBase[Any, Any]]]: # Complex types class ComplexParamArguments(ArgumentsBase): # This is a type you can't write in the rules language - p: Tuple[str, ...] + p: tuple[str, ...] class ComplexParamUdf(UDFBase[ComplexParamArguments, str]): def execute(self, execution_context: ExecutionContext, arguments: ArgumentsBase) -> str: return '' - class ComplexReturnUdf(UDFBase[ArgumentsBase, Tuple[str, ...]]): - def execute(self, execution_context: ExecutionContext, arguments: ArgumentsBase) -> Tuple[str, ...]: + class ComplexReturnUdf(UDFBase[ArgumentsBase, tuple[str, ...]]): + def execute(self, execution_context: ExecutionContext, arguments: ArgumentsBase) -> tuple[str, ...]: return tuple() # Generics @@ -181,8 +182,8 @@ def test_valid_generic_functions() -> None: ) -> A: pass - class ReturnsTypeVarIndirectlyUdf(OspreyInvariantGeneric[A], UDFBase[ArgumentsBase, Optional[A]]): - def execute(self, execution_context: ExecutionContext, arguments: ArgumentsBase) -> Optional[A]: + class ReturnsTypeVarIndirectlyUdf(OspreyInvariantGeneric[A], UDFBase[ArgumentsBase, A | None]): + def execute(self, execution_context: ExecutionContext, arguments: ArgumentsBase) -> A | None: pass class ArgumentsUseTypeVarsDirectlyArgs(OspreyInvariantGeneric[A], ArgumentsBase): @@ -195,7 +196,7 @@ def test_valid_generic_functions() -> None: pass class ArgumentsUseTypeVarsOptionalArgs(OspreyInvariantGeneric[A], ArgumentsBase): - foo: Optional[A] + foo: A | None class ArgumentsUseTypeVarsOptionalUdf(OspreyInvariantGeneric[A], UDFBase[ArgumentsUseTypeVarsOptionalArgs[A], A]): def execute( # type: ignore[empty-body] @@ -204,7 +205,7 @@ def test_valid_generic_functions() -> None: pass class ArgumentsUseTypeVarsListArgs(OspreyInvariantGeneric[A], ArgumentsBase): - foo: List[A] + foo: list[A] class ArgumentsUseTypeVarsListUdf(OspreyInvariantGeneric[A], UDFBase[ArgumentsUseTypeVarsListArgs[A], A]): def execute( # type: ignore[empty-body] diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexParamUdf].txt b/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexParamUdf].txt index 4d05dd0..a0c4492 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexParamUdf].txt +++ b/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexParamUdf].txt @@ -1 +1 @@ -cannot get type candidates for `Tuple[str, ...]`, is an unknown generic \ No newline at end of file +cannot get type candidates for `tuple[str, ...]`, is an unknown generic \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexReturnUdf].txt b/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexReturnUdf].txt index 4d05dd0..a0c4492 100644 --- a/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexReturnUdf].txt +++ b/osprey_worker/src/osprey/engine/udf/tests/test_udf_registry/test_cannot_register_invalid_types[ComplexReturnUdf].txt @@ -1 +1 @@ -cannot get type candidates for `Tuple[str, ...]`, is an unknown generic \ No newline at end of file +cannot get type candidates for `tuple[str, ...]`, is an unknown generic \ No newline at end of file diff --git a/osprey_worker/src/osprey/engine/udf/type_evaluator.py b/osprey_worker/src/osprey/engine/udf/type_evaluator.py index ce72bff..96d51d3 100644 --- a/osprey_worker/src/osprey/engine/udf/type_evaluator.py +++ b/osprey_worker/src/osprey/engine/udf/type_evaluator.py @@ -1,6 +1,7 @@ -import typing +import types +from collections.abc import Sequence from dataclasses import dataclass -from typing import Any, List, Optional, Sequence, TypeVar +from typing import Any, TypeVar from osprey.engine.language_types.osprey_invariant_generic import OspreyInvariantGeneric from osprey.engine.language_types.post_execution_convertible import PostExecutionConvertible @@ -23,13 +24,13 @@ from .type_helpers import UnsupportedTypeError, get_normalized_origin, get_singl @add_slots @dataclass class CompatibleTypeInfo: - unwrapped_to_type: Optional[type] + unwrapped_to_type: type | None """If non-None, the given type had to be unwrapped (to this type) in order to be considered compatible.""" def is_compatible_type( type_t: type, accepted_by_t: type, allow_unwrap: bool = True -) -> Result[Optional[CompatibleTypeInfo], UnsupportedTypeError]: +) -> Result[CompatibleTypeInfo | None, UnsupportedTypeError]: """Determines whether the given `type_t` is compatible with `accepted_by_t`. This assumes that the given type relationship is *covaraint*, aka type_t is allowed to be a subtype of @@ -111,16 +112,14 @@ def _is_parameterized_generic(t: type) -> bool: if not is_generic_type(t): return False + # With native typing support, builtin generics are now types.GenericAlias. + if isinstance(t, types.GenericAlias): + return len(t.__args__) > 0 + # Ensure we're working with the base/origin of the generic class. Otherwise things like `Foo[str]` will show as # having no parameters. t = get_normalized_origin(t) or t - # From python 3.9, get_parameters will return an empty tuple for non-indexed built-in generics - # https://github.com/ilevkivskyi/typing_inspect/pull/94 - # Hack: Built-in generics are defined a special class typing._SpecialGenericAlias with an _nparams attribute - if isinstance(t, typing._SpecialGenericAlias): # type: ignore - return t._nparams > 0 - # If this has any parameters return len(get_parameters(t)) > 0 @@ -137,11 +136,11 @@ def _is_simple_type(t: type) -> bool: def _is_single_arg_invariant_generic(t: type) -> bool: - origin = get_normalized_origin(t) + origin = get_normalized_origin(t) or t return ( # NOTE: Treating lists as invariant is the only safe way to handle lists that might be mutated. If we assume # no mutation then we could do a `is_compatible_type` check on the list item types. - origin == List or (isinstance(origin, type) and issubclass(origin, OspreyInvariantGeneric)) + origin is list or (isinstance(origin, type) and issubclass(origin, OspreyInvariantGeneric)) ) @@ -159,6 +158,7 @@ def _get_type_candidates(type_t: type) -> Sequence[type]: f' arg {to_display_str(arg)} is not a simple type' ) + arg = get_normalized_origin(arg) or arg type_t_candidates.append(_coerce_none_type(arg)) return type_t_candidates diff --git a/osprey_worker/src/osprey/engine/udf/type_helpers.py b/osprey_worker/src/osprey/engine/udf/type_helpers.py index 7487f81..3a88a3c 100644 --- a/osprey_worker/src/osprey/engine/udf/type_helpers.py +++ b/osprey_worker/src/osprey/engine/udf/type_helpers.py @@ -1,9 +1,12 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, TypeVar, Union, overload +import operator +from functools import reduce +from types import UnionType +from typing import TYPE_CHECKING, Any, Type, TypeVar, Union, overload +from typing import get_origin as get_origin_not_normalized from osprey.engine.ast.grammar import Span from osprey.engine.language_types.osprey_invariant_generic import OspreyInvariantGeneric from typing_inspect import get_args, get_parameters, is_generic_type, is_union_type -from typing_inspect import get_origin as get_origin_not_normalized if TYPE_CHECKING: from osprey.engine.ast_validator.validation_context import ValidationContext @@ -39,7 +42,7 @@ def is_typevar(t: type) -> bool: return isinstance(t, type_var_type) -def get_osprey_generic_param(t: type, kind: str) -> Optional[type]: +def get_osprey_generic_param(t: type, kind: str) -> type | None: """ If the type is generic, asserts that it inherits from `OspreyInvariantGeneric` and returns the `TypeVar` in the generic. If not generic, returns `None`. The `kind` is used for better error messages. @@ -65,13 +68,13 @@ def get_osprey_generic_param(t: type, kind: str) -> Optional[type]: return generic_param -def to_display_str(t: Optional[type], include_quotes: bool = True) -> str: +def to_display_str(t: type | None, include_quotes: bool = True) -> str: """Given a type, returns a string suitable for pretty printing it, eg in an error message. By defaults includes quotes around the message, but those can be turned off with the include_quotes option. """ - def _to_display_str(inner_t: Optional[type]) -> str: + def _to_display_str(inner_t: type | None) -> str: if inner_t is None or inner_t is type(None): # noqa: E721 return 'None' elif isinstance(inner_t, type) or is_typevar(t): @@ -84,9 +87,19 @@ def to_display_str(t: Optional[type], include_quotes: bool = True) -> str: args_without_none = [arg for arg in args if arg is not type(None)] # noqa: E721 if is_union_type(inner_t) and len(args) == 2 and type(None) in args and len(args_without_none) == 1: (optional_arg,) = args_without_none - return f'Optional[{_to_display_str(optional_arg)}]' + return f'{_to_display_str(optional_arg)} | None' - args_str = ', '.join(_to_display_str(arg) for arg in args) + # Also for Optionals + if is_union_type(inner_t) and len(args) == 2 and not origin_name: + args = [_to_display_str(arg) for arg in args_without_none] + return f'{args[0]} | {args[1]}' + + # For Union types that aren't Optionals + if is_union_type(inner_t) and len(args) >= 2 and origin_name: + args_str = reduce(operator.or_, args_without_none) + return f'{args_str}' + + args_str = ','.join(_to_display_str(arg) for arg in args) return f'{origin_name}[{args_str}]' else: return repr(inner_t).replace('typing.', '') @@ -98,18 +111,18 @@ def to_display_str(t: Optional[type], include_quotes: bool = True) -> str: return display_str -_ORIGIN_TO_NORMALIZED_ORIGIN: Dict[Optional[type], type] = { - list: List, +_ORIGIN_TO_NORMALIZED_ORIGIN: dict[type | None, type] = { + list: list, } -def get_normalized_origin(t: type) -> Optional[type]: - """Like typing_inspect.get_origin, but normalizes special types, eg `list` -> `List`.""" +def get_normalized_origin(t: type) -> type | None: + """Like typing_inspect.get_origin, but normalizes special types, eg `list` -> `list`.""" origin_not_normalized = get_origin_not_normalized(t) return _ORIGIN_TO_NORMALIZED_ORIGIN.get(origin_not_normalized, origin_not_normalized) -def get_origin_name(t: type) -> Optional[str]: +def get_origin_name(t: type) -> str | None: """Gets the name of the generic origin class, since the origin isn't always actually a `type`.""" origin = get_normalized_origin(t) origin_name = getattr(origin, '__name__', None) or getattr(origin, '_name', None) @@ -119,7 +132,7 @@ def get_origin_name(t: type) -> Optional[str]: def is_list(type_t: type) -> bool: """Returns whether or not the given type is a list.""" - return get_normalized_origin(type_t) == List + return get_normalized_origin(type_t) is list def get_list_item_type(t: type) -> type: @@ -155,7 +168,7 @@ def validate_kwarg_node_type( message_ending: str, expected_type: Type[_T], expected_str: str, -) -> Optional[_T]: ... +) -> _T | None: ... # See https://gitlab.com/pycqa/flake8/issues/423 @@ -166,7 +179,7 @@ def validate_kwarg_node_type( # noqa: F811 arguments: 'ArgumentsBase', kwarg: str, message_ending: str, - expected_type: Tuple[type, ...], + expected_type: tuple[type, ...], expected_str: str, ) -> object: ... @@ -178,7 +191,7 @@ def validate_kwarg_node_type( # noqa: F811 arguments: 'ArgumentsBase', kwarg: str, message_ending: str, - expected_type: Union[Type[_T], Tuple[type, ...]], + expected_type: Type[_T] | tuple[type, ...], expected_str: str, ) -> object: kwarg_ast = arguments.get_argument_ast(kwarg) @@ -197,8 +210,47 @@ def validate_kwarg_node_type( # noqa: F811 AnyType: type = Any # type: ignore # Mypy thinks Any is an object. -def _get_args_excluding_nonetype(t: type) -> List[type]: - return [arg for arg in get_args(t) if arg is not type(None)] # noqa: E721 +def _get_args_excluding_nonetype(t: type) -> list[type]: + args = [arg for arg in get_args(t) if arg is not type(None)] # noqa: E721 + + if len(args) == 0: + args = [t] + + return args + + +def _check_origin(generic_type: type, resolved_type: type) -> bool: + generic_args = get_args(generic_type) + resolved_args = get_args(resolved_type) + + generic_origin = get_normalized_origin(generic_type) + resolved_origin = get_normalized_origin(resolved_type) + + if len(generic_args) == len(resolved_args): + # This ensures that Optional args always have + # the same second argument: None. + if generic_origin != resolved_origin and generic_args[-1] is not resolved_args[-1]: + return False + else: + # If resolved type is None, then the generic_type might be + # an Optional. + if generic_origin != resolved_origin and not resolved_type and generic_args[-1] is not None: + return False + + # If resolved type is not None and the generic_type isn't + # an Optional. + if generic_origin != resolved_origin and resolved_type and generic_args[-1] is not type(None): + return False + + # When an Optional argument is supplied, it'll have one annotation, + # and that annotation's origin would likely be None. + # Other valid annotations would have Union as their origin, and anything else + # wouldn't be valid. + # Hack: the list in here is a hack for parameterized list generics. + if generic_origin != resolved_origin and resolved_args and resolved_origin in (Union, UnionType, None, list): + return False + + return True def get_typevar_substitution( @@ -236,7 +288,7 @@ def get_typevar_substitution( f'generic type {generic_type} must have exactly one typevar nested at most one level deep' ) - if get_normalized_origin(generic_type) != get_normalized_origin(resolved_type): + if not _check_origin(generic_type, resolved_type): raise UnsupportedTypeError( f'generic type {generic_type} and concrete type {resolved_type} have different origins' ) diff --git a/osprey_worker/src/osprey/engine/utils/get_closest_string_within_threshold.py b/osprey_worker/src/osprey/engine/utils/get_closest_string_within_threshold.py index b295d5b..521ca30 100644 --- a/osprey_worker/src/osprey/engine/utils/get_closest_string_within_threshold.py +++ b/osprey_worker/src/osprey/engine/utils/get_closest_string_within_threshold.py @@ -1,12 +1,12 @@ import functools -from typing import Iterable, Optional +from collections.abc import Iterable from rapidfuzz.distance import Levenshtein def get_closest_string_within_threshold( string: str, candidate_strings: Iterable[str], distance_threshold: int = 3 -) -> Optional[str]: +) -> str | None: """Given a string, return the string that is the closest (in terms of case-insensitive levenshtein edit distance) from the given candidate strings.""" if len(string) <= distance_threshold or not candidate_strings: diff --git a/osprey_worker/src/osprey/engine/utils/graph.py b/osprey_worker/src/osprey/engine/utils/graph.py index 9cbbc91..6a6d4e1 100644 --- a/osprey_worker/src/osprey/engine/utils/graph.py +++ b/osprey_worker/src/osprey/engine/utils/graph.py @@ -1,12 +1,13 @@ from collections import defaultdict, deque -from typing import DefaultDict, Deque, Dict, Generic, Hashable, Iterator, List, Sequence, Set, TypeVar +from collections.abc import Hashable, Iterator, Sequence +from typing import Generic, TypeVar T = TypeVar('T', bound=Hashable) class Graph(Generic[T]): def __init__(self) -> None: - self._graph: DefaultDict[T, Set[T]] = defaultdict(set) + self._graph: defaultdict[T, set[T]] = defaultdict(set) def add_node(self, node: T) -> bool: return self._graph[node] is not None @@ -28,13 +29,13 @@ class Graph(Generic[T]): """Returns a flat sorted array of the graph in topological order. Throws a CyclicDependencyError if the graph is not a DAG.""" # A path set - for O(1) lookups of nodes within the path. - path: Set[T] = set() + path: set[T] = set() # A path list - to allow us to preserve path ordering for error reporting. - sorted_path: List[T] = [] + sorted_path: list[T] = [] # A set of node we've visited - to assure this sort is O(N + E) where N = Nodes, E = Edges - visited: Set[T] = set() + visited: set[T] = set() # The output of sorted nodes. - sorted_nodes: List[T] = [] + sorted_nodes: list[T] = [] def visit(node: T) -> None: # Node has already been visited, so we don't need to do anything. @@ -59,10 +60,10 @@ class Graph(Generic[T]): return sorted_nodes - def bfs(self, start: T, end: T) -> List[T]: - prev_ptrs: Dict[T, T] = {} + def bfs(self, start: T, end: T) -> list[T]: + prev_ptrs: dict[T, T] = {} - to_visit: Deque[T] = deque() + to_visit: deque[T] = deque() to_visit.append(start) while to_visit: @@ -73,7 +74,7 @@ class Graph(Generic[T]): prev_ptrs[neighbor] = node to_visit.append(neighbor) - def construct_path() -> List[T]: + def construct_path() -> list[T]: path_reversed = [] curr_node = end while curr_node != start: diff --git a/osprey_worker/src/osprey/engine/utils/osprey_unary_executor.py b/osprey_worker/src/osprey/engine/utils/osprey_unary_executor.py index 439d8fd..0387535 100644 --- a/osprey_worker/src/osprey/engine/utils/osprey_unary_executor.py +++ b/osprey_worker/src/osprey/engine/utils/osprey_unary_executor.py @@ -1,4 +1,5 @@ -from typing import Mapping, Type, Union +from collections.abc import Mapping +from typing import Type from osprey.engine.ast.grammar import Number, UnaryOperation, UnaryOperator, USub from osprey.engine.executor.node_executor.unary_operation_executor import _UNARY_OPERATORS @@ -18,18 +19,16 @@ class OspreyUnaryExecutor: self._node = node self._executed_value = self._execute_unary_operation() - def get_execution_value(self) -> Union[int, float]: + def get_execution_value(self) -> int | float: return self._executed_value def get_modified_node(self) -> UnaryOperation: return self._node - def _execute_unary_operation(self) -> Union[int, float]: + def _execute_unary_operation(self) -> int | float: if self._validate_unary_operation(): assert isinstance(self._node.operand, self._valid_unary_ops_to_type[self._node.operator.__class__]) - executed_value: Union[int, float] = _UNARY_OPERATORS[self._node.operator.__class__]( - self._node.operand.value - ) + executed_value: int | float = _UNARY_OPERATORS[self._node.operator.__class__](self._node.operand.value) self._node.operand.value = executed_value return executed_value else: diff --git a/osprey_worker/src/osprey/engine/utils/periodic_execution_yielder.py b/osprey_worker/src/osprey/engine/utils/periodic_execution_yielder.py index 9502add..af23222 100644 --- a/osprey_worker/src/osprey/engine/utils/periodic_execution_yielder.py +++ b/osprey_worker/src/osprey/engine/utils/periodic_execution_yielder.py @@ -1,7 +1,8 @@ import threading import time +from collections.abc import Iterator from contextlib import contextmanager -from typing import Any, Iterator +from typing import Any class PeriodicExecutionYielder: diff --git a/osprey_worker/src/osprey/engine/utils/tests/test_get_closest_string_within_threshold.py b/osprey_worker/src/osprey/engine/utils/tests/test_get_closest_string_within_threshold.py index d85c65d..5469812 100644 --- a/osprey_worker/src/osprey/engine/utils/tests/test_get_closest_string_within_threshold.py +++ b/osprey_worker/src/osprey/engine/utils/tests/test_get_closest_string_within_threshold.py @@ -1,5 +1,3 @@ -from typing import List, Optional - import pytest from osprey.engine.utils.get_closest_string_within_threshold import get_closest_string_within_threshold @@ -17,5 +15,5 @@ from osprey.engine.utils.get_closest_string_within_threshold import get_closest_ ('Foo', ['GuildId', 'Food'], None), ], ) -def test_get_closest_string_within_threshold(string: str, candidates: List[str], expected: Optional[str]) -> None: +def test_get_closest_string_within_threshold(string: str, candidates: list[str], expected: str | None) -> None: assert get_closest_string_within_threshold(string, candidate_strings=candidates) == expected diff --git a/osprey_worker/src/osprey/engine/utils/tests/test_osprey_unary_executor.py b/osprey_worker/src/osprey/engine/utils/tests/test_osprey_unary_executor.py index 1bff7f7..5d83d49 100644 --- a/osprey_worker/src/osprey/engine/utils/tests/test_osprey_unary_executor.py +++ b/osprey_worker/src/osprey/engine/utils/tests/test_osprey_unary_executor.py @@ -1,5 +1,3 @@ -from typing import Union - import pytest from osprey.engine.ast.grammar import Boolean, Number, Span, UnaryOperation, USub from osprey.engine.ast.sources import Sources @@ -20,7 +18,7 @@ def span(sources: Sources) -> Span: 'value, expected_value', [(-1, 1), (2, -2), (3.1, -3.1)], ) -def test_execution_golden_path(span: Span, value: Union[int, float], expected_value: Union[int, float]) -> None: +def test_execution_golden_path(span: Span, value: int | float, expected_value: int | float) -> None: node = UnaryOperation(span=span, operand=Number(value=value, span=span), operator=USub(span=span)) osprey_unary_executor = OspreyUnaryExecutor(node) assert osprey_unary_executor.get_execution_value() == expected_value @@ -33,7 +31,7 @@ def test_execution_golden_path(span: Span, value: Union[int, float], expected_va 'value, expected_value', [(True, -1), (False, 0)], ) -def test_execution_fails_validation(span: Span, value: bool, expected_value: Union[int, float]) -> None: +def test_execution_fails_validation(span: Span, value: bool, expected_value: int | float) -> None: node = UnaryOperation(span=span, operand=Boolean(value=value, span=span), operator=USub(span=span)) with pytest.raises(Exception): OspreyUnaryExecutor(node).get_execution_value() == expected_value diff --git a/osprey_worker/src/osprey/engine/utils/types.py b/osprey_worker/src/osprey/engine/utils/types.py index 9a1cb1e..6a6944d 100644 --- a/osprey_worker/src/osprey/engine/utils/types.py +++ b/osprey_worker/src/osprey/engine/utils/types.py @@ -1,7 +1,8 @@ import dataclasses import weakref +from collections.abc import Callable, Sequence from functools import wraps -from typing import Callable, Dict, Optional, Sequence, Type, TypeVar +from typing import Type, TypeVar from typing_extensions import Protocol @@ -20,7 +21,7 @@ def _weakref_inherited(cls: type) -> bool: return False -def _add_state_functions(cls_dict: Dict[str, object], field_names: Sequence[str]) -> None: +def _add_state_functions(cls_dict: dict[str, object], field_names: Sequence[str]) -> None: # Taken from: # https://github.com/python-attrs/attrs/blob/33b61316f8fd97d78374818e5ecc21068cf69ae3/src/attr/_make.py#L660-L689 @@ -87,14 +88,14 @@ ReturnT = TypeVar('ReturnT', covariant=True) # An estimation of what a readonly `@property` looks like. Can be extended to support the rest of the methods that # descriptors/properties have as necessary. class Property(Protocol[SelfT, ReturnT]): - def __get__(self, obj: SelfT, type: Optional[Type[SelfT]] = None) -> ReturnT: ... + def __get__(self, obj: SelfT, type: Type[SelfT] | None = None) -> ReturnT: ... def cached_property(func: Callable[[SelfT], ReturnT]) -> Property[SelfT, ReturnT]: """Caches a property's value based on the instance.""" # Like a WeakKeyDictionary, but keyed on instance ID instead of the instance itself (in case the instance # isn't hashable). - value_cache: Dict[int, ReturnT] = {} + value_cache: dict[int, ReturnT] = {} @wraps(func) def cached_caller(self: SelfT) -> ReturnT: diff --git a/osprey_worker/src/osprey/worker/_stdlibplugin/execution_result_store_chooser.py b/osprey_worker/src/osprey/worker/_stdlibplugin/execution_result_store_chooser.py index 21035f7..c8d5b0b 100644 --- a/osprey_worker/src/osprey/worker/_stdlibplugin/execution_result_store_chooser.py +++ b/osprey_worker/src/osprey/worker/_stdlibplugin/execution_result_store_chooser.py @@ -1,5 +1,3 @@ -from typing import Optional - from osprey.worker.adaptor.plugin_manager import bootstrap_execution_result_store from osprey.worker.lib.singletons import CONFIG from osprey.worker.lib.storage import ExecutionResultStorageBackendType @@ -14,7 +12,7 @@ from osprey.worker.lib.storage.stored_execution_result import ( def get_rules_execution_result_storage_backend( backend_type: ExecutionResultStorageBackendType, -) -> Optional[ExecutionResultStore]: +) -> ExecutionResultStore | None: """Based on the `backend_type` constructs a configured execution result store that can be used to store execution results. For more details, see `ExecutionResultStore`.""" diff --git a/osprey_worker/src/osprey/worker/_stdlibplugin/sink_register.py b/osprey_worker/src/osprey/worker/_stdlibplugin/sink_register.py index 20a790a..9d494ac 100644 --- a/osprey_worker/src/osprey/worker/_stdlibplugin/sink_register.py +++ b/osprey_worker/src/osprey/worker/_stdlibplugin/sink_register.py @@ -1,4 +1,4 @@ -from typing import List, Sequence +from collections.abc import Sequence from kafka import KafkaProducer from osprey.worker._stdlibplugin.execution_result_store_chooser import get_rules_execution_result_storage_backend @@ -12,7 +12,7 @@ from osprey.worker.sinks.sink.stored_execution_result_output_sink import StoredE @hookimpl_osprey def register_output_sinks(config: Config) -> Sequence[BaseOutputSink]: - sinks: List[BaseOutputSink] = [] + sinks: list[BaseOutputSink] = [] if config.get_bool('OSPREY_STDOUT_OUTPUT_SINK', False): sinks.append(StdoutOutputSink()) if config.get_bool('OSPREY_KAFKA_OUTPUT_SINK', False): diff --git a/osprey_worker/src/osprey/worker/_stdlibplugin/storage_register.py b/osprey_worker/src/osprey/worker/_stdlibplugin/storage_register.py index b860efb..1bab199 100644 --- a/osprey_worker/src/osprey/worker/_stdlibplugin/storage_register.py +++ b/osprey_worker/src/osprey/worker/_stdlibplugin/storage_register.py @@ -1,5 +1,3 @@ -from typing import Optional - from osprey.worker._stdlibplugin.execution_result_store_chooser import get_rules_execution_result_storage_backend from osprey.worker.adaptor.plugin_manager import hookimpl_osprey from osprey.worker.lib.config import Config @@ -8,10 +6,11 @@ from osprey.worker.lib.storage.stored_execution_result import ExecutionResultSto @hookimpl_osprey(trylast=True) -def register_execution_result_store(config: Config) -> Optional[ExecutionResultStore]: +def register_execution_result_store(config: Config) -> ExecutionResultStore | None: storage_backend_type = ExecutionResultStorageBackendType( config.get_str('OSPREY_EXECUTION_RESULT_STORAGE_BACKEND', 'none').lower() ) + storage_backend = get_rules_execution_result_storage_backend(backend_type=storage_backend_type) return storage_backend diff --git a/osprey_worker/src/osprey/worker/_stdlibplugin/udf_register.py b/osprey_worker/src/osprey/worker/_stdlibplugin/udf_register.py index 2d85007..342a5e4 100644 --- a/osprey_worker/src/osprey/worker/_stdlibplugin/udf_register.py +++ b/osprey_worker/src/osprey/worker/_stdlibplugin/udf_register.py @@ -1,4 +1,5 @@ -from typing import Any, Sequence, Type +from collections.abc import Sequence +from typing import Any, Type from osprey.engine.stdlib.udfs.count_regex_matches import CountRegexMatches from osprey.engine.stdlib.udfs.domain_chopper import DomainChopper diff --git a/osprey_worker/src/osprey/worker/_stdlibplugin/validator_regsiter.py b/osprey_worker/src/osprey/worker/_stdlibplugin/validator_regsiter.py index 611b99f..6989c1c 100644 --- a/osprey_worker/src/osprey/worker/_stdlibplugin/validator_regsiter.py +++ b/osprey_worker/src/osprey/worker/_stdlibplugin/validator_regsiter.py @@ -1,4 +1,5 @@ -from typing import Sequence, Type +from collections.abc import Sequence +from typing import Type from osprey.engine.ast_validator.base_validator import BaseValidator from osprey.engine.ast_validator.validators.feature_name_to_entity_type_mapping import FeatureNameToEntityTypeMapping diff --git a/osprey_worker/src/osprey/worker/adaptor/hookspecs/osprey_hooks.py b/osprey_worker/src/osprey/worker/adaptor/hookspecs/osprey_hooks.py index 27c58a5..ec127f7 100644 --- a/osprey_worker/src/osprey/worker/adaptor/hookspecs/osprey_hooks.py +++ b/osprey_worker/src/osprey/worker/adaptor/hookspecs/osprey_hooks.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Sequence, Type +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, Type import pluggy from osprey.engine.ast_validator.base_validator import BaseValidator diff --git a/osprey_worker/src/osprey/worker/adaptor/plugin_manager.py b/osprey_worker/src/osprey/worker/adaptor/plugin_manager.py index 243fa9d..8bb30a9 100644 --- a/osprey_worker/src/osprey/worker/adaptor/plugin_manager.py +++ b/osprey_worker/src/osprey/worker/adaptor/plugin_manager.py @@ -1,7 +1,7 @@ from __future__ import annotations from functools import lru_cache -from typing import TYPE_CHECKING, Any, List, Type, TypeVar +from typing import TYPE_CHECKING, Any, Type, TypeVar import pluggy from osprey.engine.ast_validator import ValidatorRegistry @@ -37,7 +37,7 @@ def load_all_osprey_plugins(): T = TypeVar('T') -def flatten(seq: List[List[T]]) -> List[T]: +def flatten(seq: list[list[T]]) -> list[T]: return sum(seq, []) @@ -49,7 +49,7 @@ def bootstrap_udfs() -> tuple[UDFRegistry, UDFHelpers]: load_all_osprey_plugins() udf_helpers = UDFHelpers() - udfs: List[Type[UDFBase[Any, Any]]] = flatten(plugin_manager.hook.register_udfs()) + udfs: list[Type[UDFBase[Any, Any]]] = flatten(plugin_manager.hook.register_udfs()) for udf in udfs: if issubclass(udf, HasHelper): diff --git a/osprey_worker/src/osprey/worker/cli/sinks.py b/osprey_worker/src/osprey/worker/cli/sinks.py index ee20c90..25b6d31 100644 --- a/osprey_worker/src/osprey/worker/cli/sinks.py +++ b/osprey_worker/src/osprey/worker/cli/sinks.py @@ -19,7 +19,7 @@ gevent_config.track_greenlet_tree = False import multiprocessing import os from concurrent.futures import ProcessPoolExecutor -from typing import Optional, Set, TextIO, cast +from typing import TextIO, cast import click import gevent @@ -295,9 +295,7 @@ def run_bulk_label_sink(pooled: bool) -> None: @click.pass_context @click.argument('task_id', type=int) @click.option('--include-ids-from-file', type=click.File('r')) -def rollback_bulk_label_effects( - ctx: click.Context, task_id: int, include_ids_from_file: Optional[TextIO] = None -) -> None: +def rollback_bulk_label_effects(ctx: click.Context, task_id: int, include_ids_from_file: TextIO | None = None) -> None: # TODO: Clean up this copy pasta. config = init_config() postgres.init_from_config('osprey_db') @@ -325,7 +323,7 @@ def rollback_bulk_label_effects( click.echo(f'Task with id {task_id} is not in final status, status is {task.task_status!r}.') ctx.abort() - include_ids: Optional[Set[str]] = None + include_ids: set[str] | None = None if include_ids_from_file is not None: include_ids = {line.strip() for line in include_ids_from_file} include_ids.discard('') diff --git a/osprey_worker/src/osprey/worker/conftest.py b/osprey_worker/src/osprey/worker/conftest.py index 7c9f2a2..449141f 100644 --- a/osprey_worker/src/osprey/worker/conftest.py +++ b/osprey_worker/src/osprey/worker/conftest.py @@ -1,4 +1,5 @@ -from typing import Any, Generator +from collections.abc import Generator +from typing import Any import pytest from osprey.worker.lib.config import Config diff --git a/osprey_worker/src/osprey/worker/lib/acls/acls.py b/osprey_worker/src/osprey/worker/lib/acls/acls.py index a552c7c..6cb3ca0 100644 --- a/osprey_worker/src/osprey/worker/lib/acls/acls.py +++ b/osprey_worker/src/osprey/worker/lib/acls/acls.py @@ -1,7 +1,7 @@ import json import logging from pathlib import Path -from typing import Any, Dict, List +from typing import Any from osprey.worker.ui_api.osprey.lib.abilities import Ability from pydantic import BaseModel @@ -15,8 +15,8 @@ DEV_ACL_ASSIGNMENTS_FILE = DIR / 'dev_acl_assignments.json' class ACL(BaseModel): - _acls: Dict[str, List[Ability[Any, Any]]] = {} - _ability_groups: Dict[str, List[Ability[Any, Any]]] = {} + _acls: dict[str, list[Ability[Any, Any]]] = {} + _ability_groups: dict[str, list[Ability[Any, Any]]] = {} @classmethod def _load(cls) -> None: @@ -47,14 +47,14 @@ class ACL(BaseModel): cls._acls[acl_name] = abilities @classmethod - def get_one(cls, name: str) -> List[Ability[Any, Any]]: + def get_one(cls, name: str) -> list[Ability[Any, Any]]: abilities = cls._acls.get(name) if abilities is None: logger.warning(f'ACL `{name}` not found.') return abilities if abilities else [] @classmethod - def get_roles(cls) -> List[str]: + def get_roles(cls) -> list[str]: return list(cls._acls.keys()) diff --git a/osprey_worker/src/osprey/worker/lib/action_proto_deserializer.py b/osprey_worker/src/osprey/worker/lib/action_proto_deserializer.py index 99dde7e..aee136c 100644 --- a/osprey_worker/src/osprey/worker/lib/action_proto_deserializer.py +++ b/osprey_worker/src/osprey/worker/lib/action_proto_deserializer.py @@ -1,11 +1,11 @@ import abc from dataclasses import dataclass -from typing import Any, Dict +from typing import Any @dataclass class ActionProtoDeserializeResult: - data: Dict[str, Any] + data: dict[str, Any] action_id: int action_name: str diff --git a/osprey_worker/src/osprey/worker/lib/backoff/__init__.py b/osprey_worker/src/osprey/worker/lib/backoff/__init__.py index 657eb90..2180c41 100644 --- a/osprey_worker/src/osprey/worker/lib/backoff/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/backoff/__init__.py @@ -1,7 +1,6 @@ from __future__ import absolute_import import random -from typing import Optional class Backoff(object): @@ -9,7 +8,7 @@ class Backoff(object): A class that manages an exponential backoff. """ - def __init__(self, min_delay: float = 0.5, max_delay: Optional[float] = None, jitter: bool = True): + def __init__(self, min_delay: float = 0.5, max_delay: float | None = None, jitter: bool = True): self._min = min_delay if max_delay is None: max_delay = min_delay * 10 diff --git a/osprey_worker/src/osprey/worker/lib/bulk_label.py b/osprey_worker/src/osprey/worker/lib/bulk_label.py index 877f598..be35656 100644 --- a/osprey_worker/src/osprey/worker/lib/bulk_label.py +++ b/osprey_worker/src/osprey/worker/lib/bulk_label.py @@ -1,5 +1,5 @@ +from collections.abc import Collection from enum import Enum -from typing import Collection class TaskStatus(Enum): diff --git a/osprey_worker/src/osprey/worker/lib/cli.py b/osprey_worker/src/osprey/worker/lib/cli.py index 83c7981..d230fa3 100644 --- a/osprey_worker/src/osprey/worker/lib/cli.py +++ b/osprey_worker/src/osprey/worker/lib/cli.py @@ -12,7 +12,7 @@ patch_all() # please ensure this occurs before *any* other imports ! import datetime # noqa: E402 import os # noqa: E402 -from typing import Any, Optional, Set # noqa: E402 +from typing import Any # noqa: E402 import click # noqa: E402 from osprey.worker.lib.osprey_logging import configure_logging # noqa: E402 @@ -185,7 +185,7 @@ def shell(auto_import: str) -> None: code.InteractiveConsole(namespace).interact() -def get_lines_from_file_as_set(file_path: str) -> Set[str]: +def get_lines_from_file_as_set(file_path: str) -> set[str]: """ Collects all lines from a file in an unordered set. This collection does not include empty lines. @@ -229,8 +229,8 @@ def apply_label( entity_id: str, label_name: str, label_status: LabelStatus, - reason: Optional[str], - description: Optional[str], + reason: str | None, + description: str | None, expire_instantly: bool, ) -> None: """Manually apply a label to an entity. @@ -292,8 +292,8 @@ def bulk_apply_label( entity_ids_file_path: str, label_name: str, label_status: LabelStatus, - reason: Optional[str], - description: Optional[str], + reason: str | None, + description: str | None, expire_instantly: bool, ) -> None: """Manually apply a label to all entity IDs in the provided file at the file path. diff --git a/osprey_worker/src/osprey/worker/lib/config/__init__.py b/osprey_worker/src/osprey/worker/lib/config/__init__.py index b8ffc7e..71cb959 100644 --- a/osprey_worker/src/osprey/worker/lib/config/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/config/__init__.py @@ -1,22 +1,23 @@ import json import os -from typing import Any, Callable, Dict, List, Optional, Tuple +from collections.abc import Callable +from typing import Any from osprey.worker.lib.config.callbacks import tracing_callback -ConfigT = Dict[str, Any] +ConfigT = dict[str, Any] ConfigurationCallback = Callable[['Config'], None] -DEFAULT_CONFIGURATION_CALLBACKS: Tuple[ConfigurationCallback] = (tracing_callback,) +DEFAULT_CONFIGURATION_CALLBACKS: tuple[ConfigurationCallback] = (tracing_callback,) class Config: """Provides configuration for the rest of the osprey library.""" - def __init__(self, underlying_config_dict: Optional[ConfigT] = None): - self._pending_configuration_callbacks: List[ConfigurationCallback] = list(DEFAULT_CONFIGURATION_CALLBACKS) - self._underlying_config_dict: Optional[ConfigT] = None + def __init__(self, underlying_config_dict: ConfigT | None = None): + self._pending_configuration_callbacks: list[ConfigurationCallback] = list(DEFAULT_CONFIGURATION_CALLBACKS) + self._underlying_config_dict: ConfigT | None = None if underlying_config_dict is not None: self.configure(underlying_config_dict) @@ -66,7 +67,7 @@ class Config: except KeyError: return default - def get_optional_str(self, key: str) -> Optional[str]: + def get_optional_str(self, key: str) -> str | None: """Like `expect_str`, but returns None if the key does not exist. Will still throw a type error if the value was present and not a string.""" try: @@ -180,9 +181,9 @@ class Config: except KeyError: return default - def expect_str_list(self, key: str) -> List[str]: - """Gets a List[str] value from the dictionary in a type-safe way, throwing a `TypeError` if the value is not a - List[str], and a `KeyError` if the key does not exist.""" + def expect_str_list(self, key: str) -> list[str]: + """Gets a list[str] value from the dictionary in a type-safe way, throwing a `TypeError` if the value is not a + list[str], and a `KeyError` if the key does not exist.""" value = self._config_dict[key] if not isinstance(value, list): raise TypeError(f'Type of config[{key!r}] is not a list, but a {type(value)}') @@ -193,9 +194,9 @@ class Config: return value - def get_str_list(self, key: str, default: List[str]) -> List[str]: + def get_str_list(self, key: str, default: list[str]) -> list[str]: """Like `get_str`, returning a default value if the key does not exist. - Will still throw a type error, if the value was not a List[str].""" + Will still throw a type error, if the value was not a list[str].""" try: return self.expect_str_list(key) except KeyError: @@ -223,8 +224,8 @@ class Config: def config_from_env( - env: Optional[Dict[str, str]] = None, key_filter: Optional[Callable[[str], bool]] = None -) -> Dict[str, Any]: + env: dict[str, str] | None = None, key_filter: Callable[[str], bool] | None = None +) -> dict[str, Any]: """Creates a config dictionary from the process environment. Tries to parse json-like values as JSON, meaning, if you had a config value that looks like a JSON object (starts with `{`, `[` or `"`), it will try to be interpreted as JSON, and fail loudly if it can't. @@ -234,7 +235,7 @@ def config_from_env( An optional `key_filter` can be provided, that will take the key, and return True if the key should be used in the config, or false if it shouldn't. For example, you can make the key filter be: `{'foo', 'bar'}.__contains__`. """ - env_: Dict[str, str] = env if env is not None else os.environ.copy() + env_: dict[str, str] = env if env is not None else os.environ.copy() config = {} diff --git a/osprey_worker/src/osprey/worker/lib/data_exporters/models.py b/osprey_worker/src/osprey/worker/lib/data_exporters/models.py index 5ab5bb3..3fb3fa4 100644 --- a/osprey_worker/src/osprey/worker/lib/data_exporters/models.py +++ b/osprey_worker/src/osprey/worker/lib/data_exporters/models.py @@ -1,5 +1,3 @@ -from typing import List - from osprey.worker.lib.data_exporters.constants import DATA_EVENT, EXPERIMENT_METADATA_UPDATE_EVENT from pydantic import BaseModel @@ -8,8 +6,8 @@ class ospreyExperimentMetadataUpdate(BaseModel): name: str = DATA_EVENT event_type: str = EXPERIMENT_METADATA_UPDATE_EVENT experiment: str - buckets: List[str] - bucket_sizes_v2: List[float] + buckets: list[str] + bucket_sizes_v2: list[float] experiment_version: int experiment_revision: int rules_hash: str diff --git a/osprey_worker/src/osprey/worker/lib/data_exporters/test/test_validation_result_exporter.py b/osprey_worker/src/osprey/worker/lib/data_exporters/test/test_validation_result_exporter.py index 478a2af..ff67a73 100644 --- a/osprey_worker/src/osprey/worker/lib/data_exporters/test/test_validation_result_exporter.py +++ b/osprey_worker/src/osprey/worker/lib/data_exporters/test/test_validation_result_exporter.py @@ -1,5 +1,5 @@ import json -from typing import Any, Dict, List +from typing import Any from unittest.mock import MagicMock import pytest @@ -21,7 +21,7 @@ def experiment_validation_result_exporter() -> ExperimentValidationResultExporte return ExperimentValidationResultExporter(PubSubPublisher('test_project', 'test_topic')) -def create_experiments() -> List[ExperimentT]: +def create_experiments() -> list[ExperimentT]: user_entity = EntityT(type='User', id='4321') guild_entity = EntityT(type='Guild', id='1234') return [ @@ -55,7 +55,7 @@ def create_experiments() -> List[ExperimentT]: ] -def get_validate_experiments_result(experiments: List[ExperimentT]) -> ValidateExperimentsResult: +def get_validate_experiments_result(experiments: list[ExperimentT]) -> ValidateExperimentsResult: experiment_validation_results = { e.name: ExperimentValidationResult( name=e.name, @@ -81,7 +81,7 @@ def get_validated_sources() -> ValidatedSources: ) -def assert_experiment_metadata_event(experiment: str, experiment_payload: Dict[str, Any]) -> None: +def assert_experiment_metadata_event(experiment: str, experiment_payload: dict[str, Any]) -> None: if experiment == 'Experiment1': assert experiment_payload['experiment'] == 'Experiment1' assert experiment_payload['buckets'] == ['a', 'b', 'c'] diff --git a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/__init__.py b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/__init__.py index 6def97a..a26ae74 100644 --- a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/__init__.py @@ -1,6 +1,7 @@ import functools import sys -from typing import Any, Callable, Dict, Optional, TypeVar, Union +from collections.abc import Callable +from typing import Any, TypeVar import ddtrace from ddtrace.span import Span @@ -39,10 +40,10 @@ def after_flask_request(response): def trace( name: str, - service: Optional[str] = None, - resource: Optional[str] = None, - span_type: Optional[str] = None, - tags: Optional[Dict[Union[str, bytes], str]] = None, + service: str | None = None, + resource: str | None = None, + span_type: str | None = None, + tags: dict[str | bytes, str] | None = None, ) -> Span: span = ddtrace.tracer.trace(name, service, resource, span_type) or _noop_span() if tags: @@ -58,7 +59,7 @@ def current_span() -> Span: return ddtrace.tracer.current_span() or _noop_span() -def pin_override(cluster: Any, service: Optional[str], tags: Optional[Dict[str, str]] = None) -> None: +def pin_override(cluster: Any, service: str | None, tags: dict[str, str] | None = None) -> None: ddtrace.Pin.override(cluster, service, tags=tags) diff --git a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/instrumentation/flask/middleware.py b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/instrumentation/flask/middleware.py index 972aadc..1dffa86 100644 --- a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/instrumentation/flask/middleware.py +++ b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/instrumentation/flask/middleware.py @@ -2,7 +2,8 @@ # In order to fix status_code bug import re import sys -from typing import Any, Callable, Dict, List, Optional, Union +from collections.abc import Callable +from typing import Any import flask.templating from ddtrace import Span, Tracer @@ -73,13 +74,13 @@ class TraceMiddleware: timing_signals = { 'got_request_exception': self._request_exception, } - self._receivers: List[Callable[[Any, Any], None]] = [] + self._receivers: list[Callable[[Any, Any], None]] = [] if self.use_signals and _signals_exist(timing_signals): self._connect(timing_signals) _patch_render(tracer) - def _connect(self, signal_to_handler: Dict[str, Callable[[Any, Any], None]]) -> bool: + def _connect(self, signal_to_handler: dict[str, Callable[[Any, Any], None]]) -> bool: connected = True for name, handler in signal_to_handler.items(): s = getattr(signals, name, None) @@ -109,7 +110,7 @@ class TraceMiddleware: log.debug('flask: error tracing response', exc_info=True) return response - def _teardown_request(self, exception: Optional[Exception]) -> None: + def _teardown_request(self, exception: Exception | None) -> None: """Runs at the end of a request. If there's an unhandled exception, it will be passed in. """ @@ -141,9 +142,9 @@ class TraceMiddleware: baggage_manager.store_baggage_items(span, baggage, False) local_baggage = {} - dd_service: Optional[str] = request.environ.get('DD_SERVICE') - role: Optional[str] = request.environ.get('role') - service: Optional[str] = self.app._service or dd_service or role + dd_service: str | None = request.environ.get('DD_SERVICE') + role: str | None = request.environ.get('role') + service: str | None = self.app._service or dd_service or role if span.name: local_baggage[SpanAttributes.OPERATION] = span.name @@ -210,7 +211,7 @@ class TraceMiddleware: if not (span and span.sampled): return - code: Union[str, int] = response.status_code if response else '' + code: str | int = response.status_code if response else '' # Sometimes the status code is a good old which makes ddtrace barf unless # we manually coerce, since it tries to be smart and sets the tag to the string value of the enum, but this # makes the trace agent drop the heckin trace. @@ -227,11 +228,11 @@ class TraceMiddleware: if span and exception: _set_error_on_span(span, exception) - def _finish_span(self, span: Span, exception: Optional[Exception] = None) -> None: + def _finish_span(self, span: Span, exception: Exception | None = None) -> None: if not span or not span.sampled: return - code: Union[int, str] = span.get_tag(http.STATUS_CODE) or 0 + code: int | str = span.get_tag(http.STATUS_CODE) or 0 try: code = int(code) except Exception: @@ -303,7 +304,7 @@ def _patch_render(tracer: Tracer) -> None: flask.templating._render = _traced_render # type: ignore[attr-defined] -def _signals_exist(names: Dict[str, Callable[[Any, Any], None]]) -> bool: +def _signals_exist(names: dict[str, Callable[[Any, Any], None]]) -> bool: """Return true if all of the given signals exist in this version of flask.""" return all(getattr(signals, n, False) for n in names) diff --git a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/internal/baggage.py b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/internal/baggage.py index a11b5e4..980a3d1 100644 --- a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/internal/baggage.py +++ b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/internal/baggage.py @@ -1,11 +1,9 @@ -from typing import Dict, List, Optional, Union - from ddtrace.filters import TraceFilter from ddtrace.span import Span from ..constants import BaggagePrefix -Baggage = Dict[str, str] +Baggage = dict[str, str] DEFAULT_BAGGAGE_PREFIX = 'baggage.' @@ -120,12 +118,12 @@ class _BaggageFilter(TraceFilter): def __init__(self, baggage_prefix: str = DEFAULT_BAGGAGE_PREFIX): self._baggage_prefix = baggage_prefix - def process_trace(self, trace: List[Span]) -> Optional[List[Span]]: + def process_trace(self, trace: list[Span]) -> list[Span] | None: # Export the baggage to Datadog under the non-prefixed key for span in trace: # We need a new dictionary because you can't safely mutate a dict # while iterating over it - tags: Dict[Union[str, bytes], str] = {} + tags: dict[str | bytes, str] = {} for k, v in span.get_tags().items(): if isinstance(k, bytes): diff --git a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/propagation/baggage.py b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/propagation/baggage.py index 678c6ea..cffad14 100644 --- a/osprey_worker/src/osprey/worker/lib/ddtrace_utils/propagation/baggage.py +++ b/osprey_worker/src/osprey/worker/lib/ddtrace_utils/propagation/baggage.py @@ -1,5 +1,4 @@ from re import compile, split, sub -from typing import Dict, List from urllib.parse import quote_plus, unquote_plus from osprey.worker.lib.ddtrace_utils.constants import BaggagePrefix @@ -33,7 +32,7 @@ class HTTPBaggagePropagator(object): if not baggage_header.lower().startswith('x-'): self._possible_headers.append(f'x-{baggage_header}') - def inject(self, baggage: Baggage, headers: Dict[str, str]) -> None: + def inject(self, baggage: Baggage, headers: dict[str, str]) -> None: # Extract any existing baggage first so it's not overwridden existing_baggage = self.extract(headers) existing_baggage.update(baggage) @@ -50,7 +49,7 @@ class HTTPBaggagePropagator(object): headers[self._baggage_header] = ','.join([f'{quote_plus(k)}={quote_plus(v)}' for k, v in baggage.items()]) - def extract(self, headers: Dict[str, str]) -> Baggage: + def extract(self, headers: dict[str, str]) -> Baggage: normalized_headers = {name.lower(): v for name, v in headers.items()} header = _extract_header_value(normalized_headers, self._possible_headers) entries = split(_DELIMITER_PATTERN, header) @@ -71,7 +70,7 @@ class HTTPBaggagePropagator(object): return baggage -def _extract_header_value(headers: Dict[str, str], possible_headers: List[str]) -> str: +def _extract_header_value(headers: dict[str, str], possible_headers: list[str]) -> str: for header in possible_headers: try: return headers[header] diff --git a/osprey_worker/src/osprey/worker/lib/discovery/directory.py b/osprey_worker/src/osprey/worker/lib/discovery/directory.py index b27b8a2..b6140e1 100644 --- a/osprey_worker/src/osprey/worker/lib/discovery/directory.py +++ b/osprey_worker/src/osprey/worker/lib/discovery/directory.py @@ -1,7 +1,8 @@ from __future__ import annotations import os -from typing import TYPE_CHECKING, Any, ClassVar, Dict, Iterable, List, Optional, Tuple +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any, ClassVar from osprey.worker.lib.discovery.service import Service from osprey.worker.lib.discovery.service_watcher import ServiceWatcher @@ -10,11 +11,11 @@ from osprey.worker.lib.etcd import EtcdClient if TYPE_CHECKING: from .service_watcher import SelectorFunctionType - _InstancesKeyType = Tuple[Tuple[Any, ...], Tuple[Tuple[str, Any], ...]] + _InstancesKeyType = tuple[tuple[Any, ...], tuple[tuple[str, Any], ...]] class Directory: - _instances: ClassVar[Dict[_InstancesKeyType, 'Directory']] = {} + _instances: ClassVar[dict[_InstancesKeyType, 'Directory']] = {} @classmethod def instance(cls, *args, **kwargs) -> Directory: @@ -24,12 +25,12 @@ class Directory: cls._instances[key] = cls(*args, **kwargs) return cls._instances[key] - def __init__(self, base_key: str = '/discovery', etcd_client: Optional[EtcdClient] = None, *args, **kwargs): + def __init__(self, base_key: str = '/discovery', etcd_client: EtcdClient | None = None, *args, **kwargs): # (...) -> None self.base_key = base_key self.etcd_client = etcd_client or EtcdClient(*args, **kwargs) - self._watchers: Dict[str, ServiceWatcher] = {} + self._watchers: dict[str, ServiceWatcher] = {} def __repr__(self) -> str: return f'<{self.__class__.__name__}: {self.base_key}>' @@ -51,11 +52,11 @@ class Directory: rv.add(os.path.basename(node.key)) return rv - def select(self, name: str, selector: Optional[SelectorFunctionType] = None) -> Service: + def select(self, name: str, selector: SelectorFunctionType | None = None) -> Service: """Selects an instance of a service based on a selector.""" return self.get_watcher(name).select(selector) - def select_all(self, name: str, selector: Optional[SelectorFunctionType] = None) -> List[Service]: + def select_all(self, name: str, selector: SelectorFunctionType | None = None) -> list[Service]: """Selects all instances of a service based on a selector.""" return self.get_watcher(name).select_all(selector) @@ -73,7 +74,7 @@ class Directory: """Returns a path for a given service.""" return self._key_for(service.name, service.id) - def _key_for(self, service_name: str, service_id: Optional[str] = None) -> str: + def _key_for(self, service_name: str, service_id: str | None = None) -> str: """Returns a path for a service.""" key = f'{self.base_key}/{service_name}/instances' if service_id is not None: diff --git a/osprey_worker/src/osprey/worker/lib/discovery/service.py b/osprey_worker/src/osprey/worker/lib/discovery/service.py index deb7ada..1bdef67 100644 --- a/osprey_worker/src/osprey/worker/lib/discovery/service.py +++ b/osprey_worker/src/osprey/worker/lib/discovery/service.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, Dict, Optional, Tuple +from typing import Any import simplejson as json @@ -11,17 +11,17 @@ class Service: name: str, port: int, address: str = 'localhost', - metadata: Optional[Dict[str, Any]] = None, - ports: Optional[Dict[str, int]] = None, - ip: Optional[str] = None, - id_override: Optional[str] = None, + metadata: dict[str, Any] | None = None, + ports: dict[str, int] | None = None, + ip: str | None = None, + id_override: str | None = None, draining: bool = False, ): # type (...) -> None self.name = name self.address = address self.port = port - self.ports: Dict[str, int] = ports or {} + self.ports: dict[str, int] = ports or {} self.metadata = metadata or {} self.ip = ip self.id_override = id_override @@ -53,7 +53,7 @@ class Service: return f'{self.address}:{self.port}' @property - def connection_key(self) -> Tuple[str, Optional[str]]: + def connection_key(self) -> tuple[str, str | None]: """A key for distinguishing this service based on the host it's connecting to. It contains both hostname and IP in order to prevent confusion if another host picked up the same IP as an old host. diff --git a/osprey_worker/src/osprey/worker/lib/discovery/service_watcher.py b/osprey_worker/src/osprey/worker/lib/discovery/service_watcher.py index 921cf0e..20ebe20 100644 --- a/osprey_worker/src/osprey/worker/lib/discovery/service_watcher.py +++ b/osprey_worker/src/osprey/worker/lib/discovery/service_watcher.py @@ -1,11 +1,12 @@ from __future__ import annotations -import collections import logging import weakref +from collections import deque +from collections.abc import Callable from random import choice, randint, uniform from time import time -from typing import TYPE_CHECKING, Callable, Deque, Dict, List, Optional +from typing import TYPE_CHECKING import gevent from gevent.lock import RLock @@ -33,11 +34,11 @@ ListenerFn = Callable[[Literal['UP', 'DOWN'], Service], None] class ServiceWrapper: service: Service - visible_at: Optional[float] + visible_at: float | None __slots__ = ('service', 'visible_at') - def __init__(self, service: Service, visible_at: Optional[float]) -> None: + def __init__(self, service: Service, visible_at: float | None) -> None: self.service = service self.visible_at = visible_at @@ -71,11 +72,11 @@ class ServiceWatcher: self._lock = RLock() - self._instances: Dict[str, ServiceWrapper] = {} - self._rotation: Deque[str] = collections.deque() + self._instances: dict[str, ServiceWrapper] = {} + self._rotation: deque[str] = deque() self._listeners: weakref.WeakSet[ListenerFn] = weakref.WeakSet() - self._watcher_greenlet: Optional[gevent.Greenlet] = None + self._watcher_greenlet: gevent.Greenlet | None = None def __repr__(self) -> str: return f'<{self.__class__.__name__}: {self.key}>' @@ -86,7 +87,7 @@ class ServiceWatcher: def select( self, - selector: Optional[SelectorFunctionType] = None, + selector: SelectorFunctionType | None = None, tolerate_draining: bool = False, ) -> Service: """Selects an instance of a service based on a selector.""" @@ -122,10 +123,10 @@ class ServiceWatcher: def select_all( self, - selector: Optional[SelectorFunctionType] = None, + selector: SelectorFunctionType | None = None, include_not_yet_visible: bool = False, tolerate_draining: bool = False, - ) -> List[Service]: + ) -> list[Service]: """Selects all instances of a service based on a selector.""" self.ensure_watching() diff --git a/osprey_worker/src/osprey/worker/lib/encryption/base.py b/osprey_worker/src/osprey/worker/lib/encryption/base.py index 360fb9c..c83d5d5 100644 --- a/osprey_worker/src/osprey/worker/lib/encryption/base.py +++ b/osprey_worker/src/osprey/worker/lib/encryption/base.py @@ -1,6 +1,5 @@ import logging from dataclasses import dataclass -from typing import Optional import tink from tink import aead @@ -9,7 +8,7 @@ from tink.integration import gcpkms @dataclass class EncryptionBase: - kek_uri: Optional[str] = None + kek_uri: str | None = None gcp_credential_path: str = '' is_setup: bool = False diff --git a/osprey_worker/src/osprey/worker/lib/encryption/envelope.py b/osprey_worker/src/osprey/worker/lib/encryption/envelope.py index 3d27ae3..3afcf7e 100644 --- a/osprey_worker/src/osprey/worker/lib/encryption/envelope.py +++ b/osprey_worker/src/osprey/worker/lib/encryption/envelope.py @@ -1,6 +1,5 @@ import logging from base64 import b64decode, b64encode -from typing import Optional, Union import tink from osprey.worker.lib.encryption.base import EncryptionBase @@ -12,7 +11,7 @@ from tink.proto import tink_pb2 class Envelope(EncryptionBase): associated_data: bytes = b'' dek_template: tink_pb2.KeyTemplate = aead.aead_key_templates.AES256_GCM - keyset_b64: Optional[str] = None # Optional for local env based aead encryption + keyset_b64: str | None = None # Optional for local env based aead encryption def __post_init__(self): super().__post_init__() @@ -35,7 +34,7 @@ class Envelope(EncryptionBase): self.is_setup = False logging.exception('Error initializing Encryption Envelope client: %s', e) - def encrypt(self, plaintext: Union[str, bytes], base64: bool = True) -> bytes: + def encrypt(self, plaintext: str | bytes, base64: bool = True) -> bytes: """ plaintext: the message to encrypt base64: base64 encode the encrypted output (useful for json encoding) diff --git a/osprey_worker/src/osprey/worker/lib/etcd/__init__.py b/osprey_worker/src/osprey/worker/lib/etcd/__init__.py index 6d5fc8e..7204e0c 100644 --- a/osprey_worker/src/osprey/worker/lib/etcd/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/etcd/__init__.py @@ -7,8 +7,9 @@ import logging import os import random import socket +from collections.abc import Callable from email.message import Message -from typing import Any, Callable, Dict, List, Optional +from typing import Any import gevent import six @@ -252,9 +253,7 @@ class EtcdClient(object): def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, ', '.join(self.peers)) - def create( - self, key: str, value: Optional[str] = None, ttl: Optional[int] = None, sequential=False, directory=False - ): + def create(self, key: str, value: str | None = None, ttl: int | None = None, sequential=False, directory=False): """Create a node with all possible options. >>> client = EtcdClient() @@ -273,7 +272,7 @@ class EtcdClient(object): :type directory: bool :rtype: EtcdEvent """ - params: Dict[str, Any] = {} + params: dict[str, Any] = {} if ttl is not None: params['ttl'] = ttl if value is not None: @@ -325,10 +324,10 @@ class EtcdClient(object): self, key: str, value='', - ttl: Optional[int] = None, - prev_exist: Optional[str] = None, - prev_value: Optional[str] = None, - prev_index: Optional[int] = None, + ttl: int | None = None, + prev_exist: str | None = None, + prev_value: str | None = None, + prev_index: int | None = None, directory=False, ): """Set the value of a node. @@ -349,7 +348,7 @@ class EtcdClient(object): :type directory: bool :rtype: EtcdEvent """ - params: Dict[str, Any] = {} + params: dict[str, Any] = {} if prev_exist is not None: params['prevExist'] = prev_exist if ttl: @@ -387,8 +386,8 @@ class EtcdClient(object): def delete( self, key: str, - prev_value: Optional[str] = None, - prev_index: Optional[int] = None, + prev_value: str | None = None, + prev_index: int | None = None, directory=True, recursive=True, ): @@ -408,7 +407,7 @@ class EtcdClient(object): :type recursive: bool :rtype: EtcdEvent """ - params: Dict[str, Any] = {} + params: dict[str, Any] = {} if prev_value is not None: params['prevValue'] = prev_value if prev_index is not None: @@ -529,9 +528,9 @@ class HTTPHandler(six.moves.urllib.request.HTTPHandler): def walk_etcd_tree( start_path: str, - matcher_fn: Optional[Callable[[EtcdNode], bool]] = None, - action_fn: Optional[Callable[[EtcdNode], Any]] = None, - max_depth: Optional[int] = None, + matcher_fn: Callable[[EtcdNode], bool] | None = None, + action_fn: Callable[[EtcdNode], Any] | None = None, + max_depth: int | None = None, _current_depth=0, ): """ @@ -548,7 +547,7 @@ def walk_etcd_tree( List of results from action_fn for all matching nodes """ etcd_client = EtcdClient() - results: List[Any] = [] + results: list[Any] = [] if max_depth is not None and _current_depth > max_depth: return results diff --git a/osprey_worker/src/osprey/worker/lib/etcd/dict.py b/osprey_worker/src/osprey/worker/lib/etcd/dict.py index e20938c..d716767 100644 --- a/osprey_worker/src/osprey/worker/lib/etcd/dict.py +++ b/osprey_worker/src/osprey/worker/lib/etcd/dict.py @@ -1,34 +1,29 @@ from __future__ import absolute_import import json +from collections.abc import Callable, Mapping, MutableMapping from multiprocessing import RLock -from typing import Callable, Dict, List, Mapping, MutableMapping, Optional, TypeVar +from typing import TypeVar import gevent from osprey.worker.lib import etcd -# Apparently we can't easily add pip requirements for transitive dependencies of confy... -# Use the magic MYPY variable to get around this: https://mypy.readthedocs.io/en/stable/common_issues.html#import-cycles -MYPY = False -if MYPY: - from typing import Callable, Dict, List, Optional - K = TypeVar('K') V = TypeVar('V') class ReadOnlyEtcdDict(Mapping[K, V]): - def __init__(self, etcd_key: str, etcd_client: Optional[etcd.EtcdClient] = None, lazy=True, serializer=json): + def __init__(self, etcd_key: str, etcd_client: etcd.EtcdClient | None = None, lazy=True, serializer=json): self._client = etcd_client or etcd.EtcdClient() self._etcd_key = etcd_key self._lazy = lazy self._loaded = False self._watcher = None - self._watcher_greenlet: Optional[gevent.Greenlet] = None + self._watcher_greenlet: gevent.Greenlet | None = None self._serializer = serializer - self._internal_dict: Dict[str, str] = {} + self._internal_dict: dict[str, str] = {} self._load_lock = RLock() - self._watchers: List[Callable[[Dict[str, str]], None]] = [] + self._watchers: list[Callable[[dict[str, str]], None]] = [] if not lazy: self._load() @@ -104,7 +99,7 @@ class ReadOnlyEtcdDict(Mapping[K, V]): for watcher in self._watchers: watcher(self._dict) - def add_watcher(self, watcher: Callable[[Dict[str, str]], None]): + def add_watcher(self, watcher: Callable[[dict[str, str]], None]): self._watchers.append(watcher) def __len__(self): @@ -142,7 +137,7 @@ class EtcdDict(ReadOnlyEtcdDict[K, V], MutableMapping[K, V]): def clear(self): self._cas_atomic_update(lambda _: {}) - def replace_with(self, new_dict: Dict[str, str]): + def replace_with(self, new_dict: dict[str, str]): assert isinstance(new_dict, dict) self._cas_atomic_update(lambda _: new_dict) diff --git a/osprey_worker/src/osprey/worker/lib/etcd/set.py b/osprey_worker/src/osprey/worker/lib/etcd/set.py index 3fdc8da..182da0c 100644 --- a/osprey_worker/src/osprey/worker/lib/etcd/set.py +++ b/osprey_worker/src/osprey/worker/lib/etcd/set.py @@ -1,14 +1,15 @@ from __future__ import absolute_import import json -from typing import AbstractSet, Any, MutableSet +from collections.abc import MutableSet, Set +from typing import Any import gevent from gevent.lock import RLock from osprey.worker.lib import etcd -class ReadOnlyEtcdSet(AbstractSet[Any]): +class ReadOnlyEtcdSet(Set[Any]): def __init__( self, etcd_key, etcd_client=None, lazy=True, item_encode_hook=None, item_decode_hook=None, serializer=json ): diff --git a/osprey_worker/src/osprey/worker/lib/etcd/tree.py b/osprey_worker/src/osprey/worker/lib/etcd/tree.py index 51942ad..3bb126e 100644 --- a/osprey_worker/src/osprey/worker/lib/etcd/tree.py +++ b/osprey_worker/src/osprey/worker/lib/etcd/tree.py @@ -2,13 +2,13 @@ from __future__ import print_function import os from collections import defaultdict +from collections.abc import Callable, Mapping from multiprocessing import RLock -from typing import Callable, Dict, List, Mapping, Optional import gevent from osprey.worker.lib import etcd -TWatcherCallback = Callable[[str, Optional[str]], None] +TWatcherCallback = Callable[[str, str | None], None] class ReadOnlyEtcdTree(Mapping[str, str]): @@ -33,7 +33,7 @@ class ReadOnlyEtcdTree(Mapping[str, str]): self._watcher = None self._watcher_greenlet = None - self._dict: Dict[str, str] = {} + self._dict: dict[str, str] = {} """ The dict holds the values, keys are the full absolute node path (i.e. starting with /example_path/...). @@ -43,7 +43,7 @@ class ReadOnlyEtcdTree(Mapping[str, str]): operations, just simple set/get/delete by path. So we're using a dict to simplify. """ - self._node_watchers: Dict[str, List[TWatcherCallback]] = defaultdict(list) + self._node_watchers: dict[str, list[TWatcherCallback]] = defaultdict(list) """ Watchers for a specific node path e.g. /foo/bar/baz. The node path is the fully qualified path, i.e. self._root_path is the prefix. diff --git a/osprey_worker/src/osprey/worker/lib/instruments/__init__.py b/osprey_worker/src/osprey/worker/lib/instruments/__init__.py index 85f09ef..72ee076 100644 --- a/osprey_worker/src/osprey/worker/lib/instruments/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/instruments/__init__.py @@ -3,8 +3,10 @@ from __future__ import absolute_import, annotations, print_function import contextlib import os import re +from collections.abc import Sequence +from re import Pattern from types import TracebackType -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Pattern, Sequence, Type, Union +from typing import TYPE_CHECKING, Any, Type from datadog.dogstatsd.base import DogStatsd @@ -19,8 +21,8 @@ if TYPE_CHECKING: def percentile( - unsorted_list: Sequence[SupportsRichComparisonT], requested_percentile: Union[int, float] -) -> Optional[SupportsRichComparisonT]: + unsorted_list: Sequence[SupportsRichComparisonT], requested_percentile: int | float +) -> SupportsRichComparisonT | None: """Return the value at a percentile Given an unsorted list as input, this returns the value at the requested @@ -33,7 +35,7 @@ def percentile( return percentile_sorted(sorted_list, requested_percentile) -def percentile_sorted(sorted_list: Sequence[T], requested_percentile: Union[int, float]) -> Optional[T]: +def percentile_sorted(sorted_list: Sequence[T], requested_percentile: int | float) -> T | None: """Return the value at a percentile Given a sorted list, return the value at the requested percentile. If your @@ -56,7 +58,7 @@ class _DogStatsd(DogStatsd): host: str = 'localhost', port: int = 8125, max_buffer_size: int = 50, - constant_tags: Optional[List[str]] = None, + constant_tags: list[str] | None = None, use_ms: bool = False, ): # If not None, this will override host/port @@ -105,9 +107,9 @@ class _DogStatsd(DogStatsd): metric: str, metric_type: str, value: float, - tags: Optional[Union[Dict[str, str], List[str]]], - sample_rate: Optional[float], - timestamp: Optional[int] = None, + tags: dict[str, str] | list[str] | None, + sample_rate: float | None, + timestamp: int | None = None, ) -> None: if self.debug: return @@ -123,8 +125,8 @@ class _DogStatsd(DogStatsd): self, metric: str, value: float = 1, - tags: Optional[Union[Dict[str, str], List[str]]] = None, - sample_rate: Optional[float] = None, + tags: dict[str, str] | list[str] | None = None, + sample_rate: float | None = None, ) -> None: """ Update a gauge value. @@ -140,8 +142,8 @@ class _DogStatsd(DogStatsd): self, metric: str, value: float = 1, - tags: Optional[Union[Dict[str, str], List[str]]] = None, - sample_rate: Optional[float] = None, + tags: dict[str, str] | list[str] | None = None, + sample_rate: float | None = None, ) -> None: """ Increment a metric by the given amount. @@ -156,8 +158,8 @@ class _DogStatsd(DogStatsd): self, metric: str, value: float, - tags: Optional[Union[Dict[str, str], List[str]]] = None, - sample_rate: Optional[float] = None, + tags: dict[str, str] | list[str] | None = None, + sample_rate: float | None = None, ) -> None: """ Distributions are a metric type that aggregate values sent from multiple hosts @@ -174,8 +176,8 @@ class _DogStatsd(DogStatsd): self, metric: str, value: float, - tags: Optional[Union[Dict[str, str], List[str]]] = None, - sample_rate: Optional[float] = None, + tags: dict[str, str] | list[str] | None = None, + sample_rate: float | None = None, ) -> None: super().timing(metric, value, self._transform_tags(tags), sample_rate) @@ -183,13 +185,13 @@ class _DogStatsd(DogStatsd): self, title: str, message: str, - alert_type: Optional[str] = None, + alert_type: str | None = None, aggregation_key: Any = None, source_type_name: Any = None, date_happened: Any = None, priority: Any = None, - tags: Optional[List[str]] = None, - hostname: Optional[str] = None, + tags: list[str] | None = None, + hostname: str | None = None, ) -> None: """ Log an event that can be overlayed over Data Dog's graphs @@ -207,7 +209,7 @@ class _DogStatsd(DogStatsd): ) @staticmethod - def _transform_tags(tags: Optional[Union[Dict[str, str], List[str]]] = None) -> Optional[List[str]]: + def _transform_tags(tags: dict[str, str] | list[str] | None = None) -> list[str] | None: if tags is None: return None if isinstance(tags, dict): @@ -237,7 +239,7 @@ class concurrency(contextlib.ContextDecorator): NOTE: If this is used on a recursive function, the metrics will likely be garbage """ - def __init__(self, metric_name: str, metric_tags: Optional[List[str]] = None): + def __init__(self, metric_name: str, metric_tags: list[str] | None = None): self.metric_name = metric_name self.metric_tags = metric_tags self._count = 0 @@ -250,7 +252,7 @@ class concurrency(contextlib.ContextDecorator): self._emit_metric() def __exit__( - self, type: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType] + self, type: Type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None ) -> None: self._count -= 1 self._emit_metric() diff --git a/osprey_worker/src/osprey/worker/lib/instruments/tests/test_metrics.py b/osprey_worker/src/osprey/worker/lib/instruments/tests/test_metrics.py index 61f5198..343089b 100644 --- a/osprey_worker/src/osprey/worker/lib/instruments/tests/test_metrics.py +++ b/osprey_worker/src/osprey/worker/lib/instruments/tests/test_metrics.py @@ -1,5 +1,3 @@ -from typing import Dict, List, Union - import pytest from osprey.worker.lib.instruments import metrics from pytest_mock import MockFixture @@ -12,7 +10,7 @@ from pytest_mock import MockFixture pytest.param({'test_tag_1': 'test_value_1', 'test_tag_2': 'test_value_2'}, id='dict'), ), ) -def test_report_accepts_dict_or_list_tags(tags: Union[Dict[str, str], List[str]], mocker: MockFixture) -> None: +def test_report_accepts_dict_or_list_tags(tags: dict[str, str] | list[str], mocker: MockFixture) -> None: mock = mocker.patch('datadog.dogstatsd.base.DogStatsd._report', autospec=True) metrics._report('test.metric', 'c', 1, tags, 1) diff --git a/osprey_worker/src/osprey/worker/lib/instruments/types.py b/osprey_worker/src/osprey/worker/lib/instruments/types.py index 8f6d301..6f36ef7 100644 --- a/osprey_worker/src/osprey/worker/lib/instruments/types.py +++ b/osprey_worker/src/osprey/worker/lib/instruments/types.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, TypeVar, Union +from typing import Any, TypeVar from typing_extensions import Protocol, TypeAlias @@ -18,5 +18,5 @@ class SupportsDunderGT(Protocol): def __gt__(self, __other: Any) -> bool: ... -SupportsRichComparison: TypeAlias = Union[SupportsDunderLT, SupportsDunderGT] +SupportsRichComparison: TypeAlias = SupportsDunderLT | SupportsDunderGT SupportsRichComparisonT = TypeVar('SupportsRichComparisonT', bound=SupportsRichComparison) diff --git a/osprey_worker/src/osprey/worker/lib/osprey_engine.py b/osprey_worker/src/osprey/worker/lib/osprey_engine.py index 624a059..2e6318d 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_engine.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_engine.py @@ -1,8 +1,9 @@ import logging +from collections.abc import Callable from dataclasses import dataclass from pathlib import Path from time import time -from typing import Callable, Dict, Generic, List, Optional, Set, Tuple, Type, TypeVar +from typing import Generic, Type, TypeVar import gevent import gevent.pool @@ -57,7 +58,7 @@ _ModelT = TypeVar('_ModelT', bound=BaseModel) @dataclass class _ConfigSubkeyHandler(Generic[_ModelT]): model_class: Type[_ModelT] - callbacks: List[Callable[[_ModelT], None]] + callbacks: list[Callable[[_ModelT], None]] @dataclass @@ -160,7 +161,7 @@ class OspreyEngine: def config(self) -> SourcesConfig: return self._execution_graph.validated_sources.sources.config - def get_known_feature_locations(self) -> List[FeatureLocation]: + def get_known_feature_locations(self) -> list[FeatureLocation]: """Gets the known feature locations from the rules engine.""" def _should_extract(span: Span) -> bool: @@ -183,7 +184,7 @@ class OspreyEngine: if _should_extract(span) ] - def get_known_action_names(self) -> Set[str]: + def get_known_action_names(self) -> set[str]: """Gets known action names by looking at the sources for files in the `actions/` directory. It is assumed, that .sml files in that directory map to a given action name. @@ -199,7 +200,7 @@ class OspreyEngine: Path(source.path).stem for source in self.execution_graph.validated_sources.sources.glob('actions/*.sml') } - def get_rule_to_info_mapping(self) -> Dict[str, str]: + def get_rule_to_info_mapping(self) -> dict[str, str]: """Returns a mapping from 'rule name' -> 'rule description' for each feature that is a rule declaration.""" return self._execution_graph.validated_sources.get_validator_result(RuleNameToDescriptionMapping) @@ -208,7 +209,7 @@ class OspreyEngine: udf_helpers: UDFHelpers, action: Action, sample_rate: int = 100, - parent_tracer_span: Optional[TracerSpan] = None, + parent_tracer_span: TracerSpan | None = None, ) -> ExecutionResult: """Given input action, execute it against the execution engine and return the result.""" return execute( @@ -234,11 +235,11 @@ class OspreyEngine: """ return self._config_subkey_handler.get_config_subkey(model_class) - def get_feature_name_to_entity_type_mapping(self) -> Dict[str, str]: + def get_feature_name_to_entity_type_mapping(self) -> dict[str, str]: """Returns a mapping from 'feature name' -> 'entity type' for each feature that holds an entity.""" return self._execution_graph.validated_sources.get_validator_result(FeatureNameToEntityTypeMapping) - def get_post_execution_feature_name_to_value_type_mapping(self) -> Dict[str, type]: + def get_post_execution_feature_name_to_value_type_mapping(self) -> dict[str, type]: """Returns a mapping from 'feature name' -> 'value type' for each feature.""" post_execution_name_to_type_and_span = ValidateStaticTypes.to_post_execution_types( self._execution_graph.validated_sources.get_validator_result(ValidateStaticTypes) @@ -252,8 +253,8 @@ class OspreyEngine: def get_sources_provider( - rules_path: Optional[Path] = None, - input_stream_ready_signaler: Optional[InputStreamReadySignaler] = None, + rules_path: Path | None = None, + input_stream_ready_signaler: InputStreamReadySignaler | None = None, ) -> BaseSourcesProvider: """Creates the osprey engine sources provider. If a path is provided, will use a `StaticSourcesProvider` which will load sources from the given location on disk. Otherwise, will use the `EtcdSourcesProvider` to dynamically @@ -306,8 +307,8 @@ def extract_source_snippet(span: Span) -> str: def bootstrap_engine_with_helpers( - sources_provider: Optional[BaseSourcesProvider] = None, -) -> Tuple[OspreyEngine, UDFHelpers]: + sources_provider: BaseSourcesProvider | None = None, +) -> tuple[OspreyEngine, UDFHelpers]: # Avoid circular imports from osprey.worker.adaptor.plugin_manager import ( bootstrap_ast_validators, @@ -339,5 +340,5 @@ def bootstrap_engine_with_helpers( ) -def bootstrap_engine(sources_provider: Optional[BaseSourcesProvider] = None) -> OspreyEngine: +def bootstrap_engine(sources_provider: BaseSourcesProvider | None = None) -> OspreyEngine: return bootstrap_engine_with_helpers(sources_provider)[0] diff --git a/osprey_worker/src/osprey/worker/lib/osprey_logging/__init__.py b/osprey_worker/src/osprey/worker/lib/osprey_logging/__init__.py index 32fe215..2aaab4a 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_logging/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_logging/__init__.py @@ -7,7 +7,7 @@ import os import sys import types from logging.handlers import SysLogHandler -from typing import Dict, List, Optional, Tuple, Union, cast +from typing import cast import pythonjsonlogger.jsonlogger import pytz @@ -142,7 +142,7 @@ class PrettyLogFormatter(logging.Formatter): class JsonLogFormatter(pythonjsonlogger.jsonlogger.JsonFormatter): # type: ignore - def __init__(self, *args, rename_fields: Optional[Dict[str, str]] = None, **kwargs): + def __init__(self, *args, rename_fields: dict[str, str] | None = None, **kwargs): """Support renaming fields in python-json-logger<2.0.1 and python_json_logger>=2.0.1 In the latter version, `rename_fields` is supported in the superclass's constructor parameters. In @@ -160,7 +160,7 @@ class JsonLogFormatter(pythonjsonlogger.jsonlogger.JsonFormatter): # type: igno self._include_datadog = environ_bool('OSPREY_DD_LOGGING', True) - def formatTime(self, record: logging.LogRecord, datefmt: Optional[str] = None) -> str: + def formatTime(self, record: logging.LogRecord, datefmt: str | None = None) -> str: # https://stackoverflow.com/questions/6290739/python-logging-use-milliseconds-in-time-format dt = datetime.datetime.fromtimestamp(record.created, tz=datetime.timezone.utc) if datefmt: @@ -170,7 +170,7 @@ class JsonLogFormatter(pythonjsonlogger.jsonlogger.JsonFormatter): # type: igno s = '%s.%03d' % (t, record.msecs) return s - def add_fields(self, log_record: Dict, record: logging.LogRecord, message_dict: Dict) -> None: # type: ignore + def add_fields(self, log_record: dict, record: logging.LogRecord, message_dict: dict) -> None: # type: ignore # backport rename_fields from v2.0.1+ of python-json-logger into py2-compatible versions of JsonFormatter. for field in self._required_fields: if field in self.rename_fields: @@ -212,18 +212,18 @@ def _remove_handlers_except(name: str, logger: logging.Logger) -> None: logger.removeHandler(handler) -def get_route_metadata_logging_tags() -> List[Tuple[str, Optional[str]]]: +def get_route_metadata_logging_tags() -> list[tuple[str, str | None]]: """Fetches route metadata from the Flask global context so it can be added as log tags. Returns an empty array if no metadata exists. Else, returns a list of tuples of tag name and tag value. """ if not has_request_context() or not hasattr(flask_global, DATADOG_ROUTE_METADATA_ATTR): return [] - return cast(List[Tuple[str, Optional[str]]], flask_global.get(DATADOG_ROUTE_METADATA_ATTR).items()) + return cast(list[tuple[str, str | None]], flask_global.get(DATADOG_ROUTE_METADATA_ATTR).items()) def configure_logging( - package: Union[types.ModuleType, str] = 'osprey.worker.lib.osprey_logging', + package: types.ModuleType | str = 'osprey.worker.lib.osprey_logging', handler_name: str = 'pretty_stderr', ) -> None: """Apply a global logging configuration YAML within the given package. If handler name is given as an argument, or diff --git a/osprey_worker/src/osprey/worker/lib/osprey_logging/request_metadata.py b/osprey_worker/src/osprey/worker/lib/osprey_logging/request_metadata.py index 4899a5c..7b267a2 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_logging/request_metadata.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_logging/request_metadata.py @@ -1,4 +1,4 @@ -from typing import Any, Optional +from typing import Any from flask import has_request_context, request from osprey.worker.lib.osprey_logging.util import METADATA_FINALIZER_KEY, METADATA_KEY, USER_ID_KEY @@ -15,7 +15,7 @@ def set_user(user): set_user_id(user.id) -def get(key: str) -> Optional[Any]: +def get(key: str) -> Any | None: """ Get a key from the request metadata. diff --git a/osprey_worker/src/osprey/worker/lib/osprey_shared/abilities.py b/osprey_worker/src/osprey/worker/lib/osprey_shared/abilities.py index c354b99..f75425b 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_shared/abilities.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_shared/abilities.py @@ -1,5 +1,6 @@ +from collections.abc import Mapping, Sequence from dataclasses import dataclass, field -from typing import Any, List, Mapping, Optional, Sequence, Set +from typing import Any from urllib.parse import urlencode import requests @@ -11,23 +12,23 @@ from requests.models import ChunkedEncodingError class CreateTemporaryAbilityTokenRequest(BaseModel): - abilities: List[Mapping[str, Any]] + abilities: list[Mapping[str, Any]] class BulkCreateTemporaryAbilityTokenRequest(BaseModel): - create_temporary_ability_token_requests: List[CreateTemporaryAbilityTokenRequest] + create_temporary_ability_token_requests: list[CreateTemporaryAbilityTokenRequest] creation_origin: str class BulkCreateTemporaryAbilityTokenResponse(BaseModel): - ability_tokens: List[str] + ability_tokens: list[str] @dataclass(frozen=True) class EntityUrlOptions: """Additional options that can be passed to customize the generated links.""" - entity_feature_filters: Set[str] = field(default_factory=set) + entity_feature_filters: set[str] = field(default_factory=set) """Applies a feature filter to the entity view, which will filter down events that only match the provided entity id for the fields specified. This is applied as a logical OR, if there are more than one values present in the set. Meaning, if you specify `UserId` and `TargetUserId`, it will filter down the event stream where the entity @@ -40,11 +41,11 @@ def bulk_create_entity_ability_links( osprey_ui_endpoint: str, osprey_ui_api_endpoint: str, creation_origin: str, - entities: List[EntityT[str]], + entities: list[EntityT[str]], raise_on_error: bool = False, entity_url_options: EntityUrlOptions = EntityUrlOptions(), -) -> Optional[Sequence[str]]: - abilities_list: List[List[Mapping[str, Any]]] = [ +) -> Sequence[str] | None: + abilities_list: list[list[Mapping[str, Any]]] = [ [ {'name': 'CAN_VIEW_LABELS_FOR_ENTITY', 'allow_all': True}, {'name': 'CAN_VIEW_EVENTS_BY_ENTITY', 'allow_specific': [{'type': entity.type, 'id': entity.id}]}, @@ -92,7 +93,7 @@ def bulk_create_entity_ability_links( def bulk_create_temporary_ability_token( - endpoint: str, signer: Signer, creation_origin: str, abilities_list: List[List[Mapping[str, Any]]] + endpoint: str, signer: Signer, creation_origin: str, abilities_list: list[list[Mapping[str, Any]]] ) -> BulkCreateTemporaryAbilityTokenResponse: request = BulkCreateTemporaryAbilityTokenRequest( creation_origin=creation_origin, @@ -110,7 +111,7 @@ def bulk_create_temporary_ability_token( def create_temporary_ability_token( - endpoint: str, signer: Signer, creation_origin: str, abilities: List[Mapping[str, Any]] + endpoint: str, signer: Signer, creation_origin: str, abilities: list[Mapping[str, Any]] ) -> str: request = BulkCreateTemporaryAbilityTokenRequest( creation_origin=creation_origin, diff --git a/osprey_worker/src/osprey/worker/lib/osprey_shared/counters.py b/osprey_worker/src/osprey/worker/lib/osprey_shared/counters.py index 1ec83f1..8d68338 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_shared/counters.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_shared/counters.py @@ -1,6 +1,5 @@ from datetime import timedelta from enum import Enum -from typing import List import requests from osprey.worker.lib.utils.flask_signing import Signer @@ -44,7 +43,7 @@ class BulkReadCounterRequest(BaseModel): Used to request many counters at once """ - read_counter_requests: List[ReadCounterRequest] + read_counter_requests: list[ReadCounterRequest] class BulkReadCounterResponse(BaseModel): @@ -52,7 +51,7 @@ class BulkReadCounterResponse(BaseModel): Each index in the list is the response associated with the request at the index in `BulkReadCounterRequest` """ - read_counter_responses: List[ReadCounterResponse] + read_counter_responses: list[ReadCounterResponse] def read_counter(endpoint: str, signer: Signer, key: str, window: timedelta, count_service: CountService) -> int: @@ -69,12 +68,12 @@ def read_counter(endpoint: str, signer: Signer, key: str, window: timedelta, cou def bulk_read_counters( endpoint: str, signer: Signer, - read_counter_requests: List[ReadCounterRequest], + read_counter_requests: list[ReadCounterRequest], timeout: int = BULK_READ_COUNTER_TIMEOUT, -) -> List[ReadCounterResponse]: +) -> list[ReadCounterResponse]: """ returns a list of `ReadCounterResponse` associated index-by-index - with `read_counter_requests: List[ReadCounterRequest]` + with `read_counter_requests: list[ReadCounterRequest]` """ bulk_read_counter_request = BulkReadCounterRequest(read_counter_requests=read_counter_requests) data = bulk_read_counter_request.json().encode() diff --git a/osprey_worker/src/osprey/worker/lib/osprey_shared/labels.py b/osprey_worker/src/osprey/worker/lib/osprey_shared/labels.py index 381d383..b2ddcfa 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_shared/labels.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_shared/labels.py @@ -3,7 +3,7 @@ from collections import UserDict from dataclasses import dataclass, field, replace from datetime import datetime, timedelta, timezone from enum import Enum, IntEnum -from typing import Any, Dict, Self +from typing import Any, Self from osprey.worker.lib.osprey_shared.logging import get_logger from osprey.worker.lib.utils.request_utils import SessionWithRetries @@ -373,7 +373,7 @@ class LabelState: class EntityLabels: """this class represents a given entity's current labels & label states""" - labels: Dict[str, LabelState] = field(default_factory=dict) + labels: dict[str, LabelState] = field(default_factory=dict) """a mapping of label names to their current states'""" def serialize(self) -> dict[str, Any]: diff --git a/osprey_worker/src/osprey/worker/lib/osprey_shared/logging.py b/osprey_worker/src/osprey/worker/lib/osprey_shared/logging.py index d77293e..fa97fbb 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_shared/logging.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_shared/logging.py @@ -1,7 +1,6 @@ import logging from datetime import datetime, timedelta from random import SystemRandom -from typing import Optional class RollingCounter: @@ -84,14 +83,14 @@ class DynamicLogSampler(logging.Filter): else: self._process_log_record(record) - def _process_log_record(self, record: Optional[logging.LogRecord] = None): + def _process_log_record(self, record: logging.LogRecord | None = None): self.rolling_log_counter.increment() self.num_increments_since_log_recalculation += 1 # Only recalculate once per num_increments_per_recalculation log msgs to prevent excessive recalculation if self.num_increments_since_log_recalculation >= self.num_increments_per_recalculation: self._recalculate_probability() - def _process_error_record(self, record: Optional[logging.LogRecord] = None): + def _process_error_record(self, record: logging.LogRecord | None = None): self.rolling_error_counter.increment() self.num_increments_since_error_recalculation += 1 # Only recalculate once per num_increments_since_error_recalculation errors to prevent excessive recalculation @@ -116,7 +115,7 @@ class DynamicLogSampler(logging.Filter): else: self.error_probability = 1.0 - def _should_log(self, record: Optional[logging.LogRecord] = None) -> bool: + def _should_log(self, record: logging.LogRecord | None = None) -> bool: if record is not None and record.levelno >= logging.ERROR: if self.error_probability <= 0: return False @@ -138,7 +137,7 @@ DEFAULT_DYNAMIC_LOG_SAMPLER = DynamicLogSampler(target_max_logs_per_minute=30, t def get_logger( - name: Optional[str] = None, dynamic_log_sampler: Optional[DynamicLogSampler] = DEFAULT_DYNAMIC_LOG_SAMPLER + name: str | None = None, dynamic_log_sampler: DynamicLogSampler | None = DEFAULT_DYNAMIC_LOG_SAMPLER ) -> logging.Logger: """ Gets a dynamically sampled logger with a shared log rate limit across all loggers diff --git a/osprey_worker/src/osprey/worker/lib/osprey_typing.py b/osprey_worker/src/osprey/worker/lib/osprey_typing.py index 0d34f29..c5aeeb1 100644 --- a/osprey_worker/src/osprey/worker/lib/osprey_typing.py +++ b/osprey_worker/src/osprey/worker/lib/osprey_typing.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import AbstractSet, Any, Tuple, TypeVar, Union +from collections.abc import Set +from typing import Any, TypeVar from typing_extensions import Protocol, TypeAlias @@ -11,7 +12,7 @@ VT_co = TypeVar('VT_co', covariant=True) class SupportsItems(Protocol[KT_co, VT_co]): - def items(self) -> AbstractSet[Tuple[KT_co, VT_co]]: + def items(self) -> Set[tuple[KT_co, VT_co]]: pass @@ -39,5 +40,5 @@ class SupportsAllComparisons( ): ... -SupportsRichComparison: TypeAlias = Union[SupportsDunderLT[Any], SupportsDunderGT[Any]] +SupportsRichComparison: TypeAlias = SupportsDunderLT[Any] | SupportsDunderGT[Any] SupportsRichComparisonT = TypeVar('SupportsRichComparisonT', bound=SupportsRichComparison) diff --git a/osprey_worker/src/osprey/worker/lib/patcher.py b/osprey_worker/src/osprey/worker/lib/patcher.py index a40aa9c..acc11ca 100644 --- a/osprey_worker/src/osprey/worker/lib/patcher.py +++ b/osprey_worker/src/osprey/worker/lib/patcher.py @@ -12,14 +12,14 @@ patch_all() """ # Importing non-std modules here may break patching -from typing import Any, Dict, Optional +from typing import Any def patch_all( patch_gevent: bool = True, patch_grpc: bool = True, patch_ddtrace: bool = True, - ddtrace_args: Optional[Dict[str, Any]] = None, + ddtrace_args: dict[str, Any] | None = None, ) -> None: if patch_gevent: # gevent must be patched first https://github.com/DataDog/dd-trace-py/issues/3595 diff --git a/osprey_worker/src/osprey/worker/lib/profiling/feature.py b/osprey_worker/src/osprey/worker/lib/profiling/feature.py index ff2207c..2fdd638 100644 --- a/osprey_worker/src/osprey/worker/lib/profiling/feature.py +++ b/osprey_worker/src/osprey/worker/lib/profiling/feature.py @@ -1,20 +1,19 @@ from contextvars import ContextVar from enum import StrEnum -from typing import List, Optional class Feature(StrEnum): pass -_features_var: ContextVar[Optional[List[Feature]]] = ContextVar('features', default=None) +_features_var: ContextVar[list[Feature] | None] = ContextVar('features', default=None) -def current_features() -> List[Feature]: +def current_features() -> list[Feature]: """Return the current features""" return _features_var.get() or [] -def set_current_features(features: List[Feature]) -> None: +def set_current_features(features: list[Feature]) -> None: """Set the current features for the duration of the current context""" _features_var.set(features) diff --git a/osprey_worker/src/osprey/worker/lib/profiling/pyroscope_reporter.py b/osprey_worker/src/osprey/worker/lib/profiling/pyroscope_reporter.py index d18d1ed..4733a53 100644 --- a/osprey_worker/src/osprey/worker/lib/profiling/pyroscope_reporter.py +++ b/osprey_worker/src/osprey/worker/lib/profiling/pyroscope_reporter.py @@ -8,7 +8,6 @@ import time import types from collections import defaultdict from dataclasses import dataclass -from typing import DefaultDict, Dict, Optional, Tuple, Union import gevent import greenlet @@ -20,11 +19,11 @@ logger = logging.getLogger(__name__) @dataclass(frozen=True) class StackFrame: - module: Optional[str] + module: str | None """Module name""" - name: Optional[str] + name: str | None """Function name""" - line: Optional[int] + line: int | None """Line number""" def __str__(self) -> str: @@ -34,7 +33,7 @@ class StackFrame: @dataclass(frozen=True) class StackTrace: - frames: Tuple[StackFrame, ...] + frames: tuple[StackFrame, ...] """Tuple of stack frames""" def __str__(self) -> str: @@ -43,7 +42,7 @@ class StackTrace: @staticmethod def from_frametype(frame: types.FrameType) -> StackTrace: frames = [] - f: Optional[types.FrameType] = frame + f: types.FrameType | None = frame while f is not None: name = f.f_code.co_name module = f.f_globals.get('__name__', None) @@ -60,29 +59,29 @@ class StackTrace: # Valid report types for Pyroscope # From: https://github.com/grafana/pyroscope/blob/main/pkg/ingester/pyroscope/ingest_adapter.go#L201 -ReportType = Union[ - Literal['cpu'], - Literal['wall'], - Literal['inuse_objects'], - Literal['inuse_space'], - Literal['alloc_objects'], - Literal['alloc_space'], - Literal['goroutines'], - Literal['mutex_count'], - Literal['mutex_wait'], - Literal['mutex_duration'], - Literal['block_count'], - Literal['block_duration'], - Literal['itimer'], - Literal['alloc_in_new_tlab_objects'], - Literal['alloc_in_new_tlab_bytes'], - Literal['alloc_outside_tlab_objects'], - Literal['alloc_outside_tlab_bytes'], - Literal['lock_count'], - Literal['lock_duration'], - Literal['live'], - Literal['exceptions'], -] +ReportType = ( + Literal['cpu'] + | Literal['wall'] + | Literal['inuse_objects'] + | Literal['inuse_space'] + | Literal['alloc_objects'] + | Literal['alloc_space'] + | Literal['goroutines'] + | Literal['mutex_count'] + | Literal['mutex_wait'] + | Literal['mutex_duration'] + | Literal['block_count'] + | Literal['block_duration'] + | Literal['itimer'] + | Literal['alloc_in_new_tlab_objects'] + | Literal['alloc_in_new_tlab_bytes'] + | Literal['alloc_outside_tlab_objects'] + | Literal['alloc_outside_tlab_bytes'] + | Literal['lock_count'] + | Literal['lock_duration'] + | Literal['live'] + | Literal['exceptions'] +) class Reporter(object): @@ -111,15 +110,15 @@ class Reporter(object): self.pyroscope_url = os.getenv('PYROSCOPE_URL', f'http://{self.pyroscope_host}:{self.pyroscope_port}/ingest') self._started = time.time() - self._stack_counts_by_key: DefaultDict[Tuple[Optional[str], Optional[str]], DefaultDict[StackTrace, int]] = ( + self._stack_counts_by_key: defaultdict[tuple[str | None, str | None], defaultdict[StackTrace, int]] = ( defaultdict(lambda: defaultdict(int)) ) - self._report_greenlet: Optional[gevent.Greenlet] = None + self._report_greenlet: gevent.Greenlet | None = None - def add_tags(self, tags: Dict[str, str]) -> None: + def add_tags(self, tags: dict[str, str]) -> None: self.tags.update(tags) - def name(self, feature: Optional[str] = None, endpoint: Optional[str] = None) -> str: + def name(self, feature: str | None = None, endpoint: str | None = None) -> str: """Generates the application name string for Pyroscope, optionally including a feature tag.""" application_name = os.getenv('DD_SERVICE', 'osprey-api') all_tags = self.tags.copy() @@ -130,12 +129,12 @@ class Reporter(object): tags_str = ','.join(f'{k}={v}' for k, v in all_tags.items() if v is not None) return f'{application_name}.{self.report_type}{{{tags_str}}}' - def record(self, stack_trace: StackTrace, feature: Optional[str] = None, endpoint: Optional[str] = None) -> None: + def record(self, stack_trace: StackTrace, feature: str | None = None, endpoint: str | None = None) -> None: """Records a stack trace occurrence, optionally associated with a feature and endpoint.""" self._stack_counts_by_key[(feature, endpoint)][stack_trace] += 1 def record_with_value( - self, stack_trace: StackTrace, value: int, feature: Optional[str] = None, endpoint: Optional[str] = None + self, stack_trace: StackTrace, value: int, feature: str | None = None, endpoint: str | None = None ) -> None: """Records a stack trace occurrence with a specific value, optionally associated with a feature and endpoint.""" self._stack_counts_by_key[(feature, endpoint)][stack_trace] += value @@ -172,7 +171,7 @@ class Reporter(object): name = self.name(feature=feature, endpoint=endpoint) # https://grafana.com/docs/pyroscope/latest/reference-server-api/ - params: Dict[str, str] = { + params: dict[str, str] = { 'name': name, 'from': str(from_), 'until': str(until), diff --git a/osprey_worker/src/osprey/worker/lib/profiling/sampler.py b/osprey_worker/src/osprey/worker/lib/profiling/sampler.py index 8241829..233666b 100644 --- a/osprey_worker/src/osprey/worker/lib/profiling/sampler.py +++ b/osprey_worker/src/osprey/worker/lib/profiling/sampler.py @@ -4,14 +4,13 @@ import atexit import logging import signal import types -from typing import Optional from flask import request from .feature import current_features from .pyroscope_reporter import Reporter, StackTrace -sampler: Optional[Sampler] = None +sampler: Sampler | None = None logger = logging.getLogger(__name__) @@ -40,7 +39,7 @@ class Sampler(object): self._reporter.start() atexit.register(self.stop) - def _get_current_feature(self) -> Optional[str]: + def _get_current_feature(self) -> str | None: """Get the current features from tiering library.""" features = current_features() if not features: @@ -49,14 +48,14 @@ class Sampler(object): # TODO: decide how to handle multiple features return features[0].value - def _get_current_endpoint(self) -> Optional[str]: + def _get_current_endpoint(self) -> str | None: """Get the current endpoint from the request.""" try: return request.endpoint except Exception: return None - def _sample(self, _signum: int, frame: Optional[types.FrameType]) -> None: + def _sample(self, _signum: int, frame: types.FrameType | None) -> None: if frame: feature = self._get_current_feature() endpoint = self._get_current_endpoint() diff --git a/osprey_worker/src/osprey/worker/lib/publisher.py b/osprey_worker/src/osprey/worker/lib/publisher.py index cce08e9..cb7a3ed 100644 --- a/osprey_worker/src/osprey/worker/lib/publisher.py +++ b/osprey_worker/src/osprey/worker/lib/publisher.py @@ -1,5 +1,5 @@ import abc -from typing import Dict, Optional, TypeVar +from typing import TypeVar from google.cloud import pubsub_v1 from osprey.worker.lib.instruments import metrics @@ -15,7 +15,7 @@ class BasePublisher(abc.ABC): """ @abc.abstractmethod - def publish(self, data: _PydanticModelT, attributes: Optional[Dict[str, str]] = None) -> None: + def publish(self, data: _PydanticModelT, attributes: dict[str, str] | None = None) -> None: raise NotImplementedError @abc.abstractmethod @@ -24,7 +24,7 @@ class BasePublisher(abc.ABC): class StdoutPublisher(BasePublisher): - def publish(self, data: _PydanticModelT, attributes: Optional[Dict[str, str]] = None) -> None: + def publish(self, data: _PydanticModelT, attributes: dict[str, str] | None = None) -> None: print(data) def stop(self) -> None: @@ -32,7 +32,7 @@ class StdoutPublisher(BasePublisher): class NullPublisher(BasePublisher): - def publish(self, data: _PydanticModelT, attributes: Optional[Dict[str, str]] = None) -> None: + def publish(self, data: _PydanticModelT, attributes: dict[str, str] | None = None) -> None: return def stop(self) -> None: @@ -71,7 +71,7 @@ class PubSubPublisher(BasePublisher): """ return data.json(exclude_none=True).encode() - def publish(self, data: _PydanticModelT, attributes: Optional[Dict[str, str]] = None) -> None: + def publish(self, data: _PydanticModelT, attributes: dict[str, str] | None = None) -> None: if attributes is None: attributes = {} @@ -98,7 +98,7 @@ class StrPubSubPublisher(PubSubPublisher): def prepare_data(self, data: str) -> bytes: # type: ignore[override] return data.encode() - def publish(self, data: str, attributes: Optional[Dict[str, str]] = None) -> None: # type: ignore[override] + def publish(self, data: str, attributes: dict[str, str] | None = None) -> None: # type: ignore[override] if attributes is None: attributes = {} diff --git a/osprey_worker/src/osprey/worker/lib/pubsub/publisher_client.py b/osprey_worker/src/osprey/worker/lib/pubsub/publisher_client.py index 981485f..ecf7cc9 100644 --- a/osprey_worker/src/osprey/worker/lib/pubsub/publisher_client.py +++ b/osprey_worker/src/osprey/worker/lib/pubsub/publisher_client.py @@ -1,7 +1,6 @@ import abc from concurrent import futures from threading import Lock -from typing import Set, Union from google.cloud import pubsub_v1 from osprey.worker.lib.instruments import metrics @@ -22,7 +21,7 @@ class BasePubsubPublisherClient(abc.ABC): class BatchPubsubPublisherClient(BasePubsubPublisherClient): _futures_buffer_lock: Lock = Lock() - _futures_buffer: Set[pubsub_v1.publisher.futures.Future] = set() + _futures_buffer: set[pubsub_v1.publisher.futures.Future] = set() _publisher: pubsub_v1.PublisherClient def __init__(self, batch_settings: pubsub_v1.types.BatchSettings): @@ -37,7 +36,7 @@ class BatchPubsubPublisherClient(BasePubsubPublisherClient): with self._futures_buffer_lock: self._futures_buffer.remove(future) - def publish(self, topic: str, data: bytes, **attributes: Union[bytes, str]) -> None: + def publish(self, topic: str, data: bytes, **attributes: bytes | str) -> None: if len(self._futures_buffer) >= self._max_future_buffer_size: # https://github.com/googleapis/google-cloud-python/issues/6201 ???? futures.wait(self._futures_buffer, return_when=futures.ALL_COMPLETED) diff --git a/osprey_worker/src/osprey/worker/lib/pubsub/tasks/types.py b/osprey_worker/src/osprey/worker/lib/pubsub/tasks/types.py index 8dcc281..8cd53d0 100644 --- a/osprey_worker/src/osprey/worker/lib/pubsub/tasks/types.py +++ b/osprey_worker/src/osprey/worker/lib/pubsub/tasks/types.py @@ -1,20 +1,20 @@ -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any from typing_extensions import NotRequired, TypedDict class PubSubTaskMessageData(TypedDict): task_name: str - old_task_name: NotRequired[Optional[str]] - task_args: Union[List, Tuple] # type: ignore[type-arg] - task_kwargs: Dict[str, Any] + old_task_name: NotRequired[str | None] + task_args: list | tuple # type: ignore[type-arg] + task_kwargs: dict[str, Any] # The unix timestamps (millis) at which the message was created, even # before publishing to pubsub. - created_at_ms: Optional[int] + created_at_ms: int | None # Optionally, one can specify a delay in milliseconds relative to created_at_ms. If set, # this will make the subscriber worker keep delaying doing the task until delay_ms have passed since created_at_ms. # Note that we cannot guarantee an upper-bound of how long we will wait to do the task, only a lower bound # -- namely, delay_ms. That is, actual_task_execution_time >= created_at_ms + delay_ms, but in terms of # actual_task_execution_time <= created_at_ms + delay_ms + x, we cannot guarantee a maximum x. - delay_ms: Optional[int] + delay_ms: int | None diff --git a/osprey_worker/src/osprey/worker/lib/singleton.py b/osprey_worker/src/osprey/worker/lib/singleton.py index 696906d..fbfcb91 100644 --- a/osprey_worker/src/osprey/worker/lib/singleton.py +++ b/osprey_worker/src/osprey/worker/lib/singleton.py @@ -1,5 +1,6 @@ +from collections.abc import Callable, Iterator from contextlib import contextmanager -from typing import Callable, Generic, Iterator, Optional, TypeVar +from typing import Generic, TypeVar T = TypeVar('T') @@ -21,7 +22,7 @@ class Singleton(Generic[T]): def __init__(self, factory: Callable[[], T]): self._factory = factory - self._instance: Optional[T] = None + self._instance: T | None = None def instance(self) -> T: """Gets or lazily creates the singleton object by invoking the factory function.""" diff --git a/osprey_worker/src/osprey/worker/lib/sources_config/__init__.py b/osprey_worker/src/osprey/worker/lib/sources_config/__init__.py index 2936820..035db68 100644 --- a/osprey_worker/src/osprey/worker/lib/sources_config/__init__.py +++ b/osprey_worker/src/osprey/worker/lib/sources_config/__init__.py @@ -1,4 +1,5 @@ -from typing import Callable, Type +from collections.abc import Callable +from typing import Type from osprey.engine.config.config_registry import ConfigRegistry from osprey.engine.config.config_subkey_handler import ModelT diff --git a/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/acl_config.py b/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/acl_config.py index 86cb562..3ae7d0e 100644 --- a/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/acl_config.py +++ b/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/acl_config.py @@ -1,7 +1,8 @@ from __future__ import annotations import json -from typing import Any, Iterable, List, Mapping +from collections.abc import Iterable, Mapping +from typing import Any from osprey.worker.lib.acls.acls import ACL, DEV_ACL_ASSIGNMENTS_FILE from osprey.worker.lib.instruments import metrics @@ -15,8 +16,8 @@ OKTA_GROUP_PREFIX = 'App-Osprey-' class UsersConfig(BaseModel): - roles: List[str] = [] - abilities: List[Ability[Any, Any]] = [] + roles: list[str] = [] + abilities: list[Ability[Any, Any]] = [] @register_config_subkey('acl') @@ -27,7 +28,7 @@ class AclConfig(BaseModel): Validates that the config is valid on being loaded """ - roles: Mapping[str, List[Ability[Any, Any]]] = {} + roles: Mapping[str, list[Ability[Any, Any]]] = {} users: Mapping[str, UsersConfig] = {} @validator('users', pre=False) @@ -44,7 +45,7 @@ class AclConfig(BaseModel): raise ValueError(f'`{role}` is not defined in the `roles` acl config') return users - def get_abilities_for_unregistered_user(self, user_email: str) -> List[Ability[BaseModel, Any]]: + def get_abilities_for_unregistered_user(self, user_email: str) -> list[Ability[BaseModel, Any]]: user_abilities = TemporaryAbilityToken.get_abilities(user_email) if user_abilities: metrics.increment('osprey.get_abilities_for_unregistered_user', tags=['success:true']) @@ -53,7 +54,7 @@ class AclConfig(BaseModel): metrics.increment('osprey.get_abilities_for_unregistered_user', tags=['success:false']) return [] - def get_abilities_for_dev_user(self, user_email: str) -> List[Ability[BaseModel, Any]]: + def get_abilities_for_dev_user(self, user_email: str) -> list[Ability[BaseModel, Any]]: try: # assign local dev user acls from a file with open(DEV_ACL_ASSIGNMENTS_FILE) as acl_assignments_file: @@ -67,7 +68,7 @@ class AclConfig(BaseModel): # otherwise, enforce super user by default if file not found return [ability for ability in ACL.get_one('SUPER_USER')] - def get_abilities_for_user(self, user_email: str) -> List[Ability[BaseModel, Any]]: + def get_abilities_for_user(self, user_email: str) -> list[Ability[BaseModel, Any]]: # For local dev, read ACLs from a file if CONFIG.instance().debug: return self.get_abilities_for_dev_user(user_email) @@ -82,7 +83,7 @@ class AclConfig(BaseModel): def _get_role_name_from_okta_group(self, okta_role: str) -> str: _trim = len(OKTA_GROUP_PREFIX) - okta_role_parts: List[str] = [] + okta_role_parts: list[str] = [] for role_part in okta_role[_trim:].split('-'): okta_role_parts.append(role_part.upper()) @@ -94,7 +95,7 @@ class AclConfig(BaseModel): return role_name - def get_abilities_for_okta_groups(self, okta_roles: Iterable[str]) -> List[Ability[BaseModel, Any]]: + def get_abilities_for_okta_groups(self, okta_roles: Iterable[str]) -> list[Ability[BaseModel, Any]]: okta_roles = ( self._get_role_name_from_okta_group(role) for role in okta_roles diff --git a/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/action_config.py b/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/action_config.py index d6e1dfa..ee634d7 100644 --- a/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/action_config.py +++ b/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/action_config.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional +from typing import Any from osprey.worker.lib.sources_config import register_config_subkey from pydantic import BaseModel, Field, root_validator @@ -10,11 +10,11 @@ class ActionConfig(BaseModel): @register_config_subkey('actions') class ActionConfigs(BaseModel): - actions: Dict[str, ActionConfig] + actions: dict[str, ActionConfig] @root_validator(pre=True) - def root_validator(cls, values: Any) -> Dict[str, Any]: + def root_validator(cls, values: Any) -> dict[str, Any]: return {'actions': values} - def get_action_config(self, action_name: str) -> Optional[ActionConfig]: + def get_action_config(self, action_name: str) -> ActionConfig | None: return self.actions.get(action_name) diff --git a/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/ui_config.py b/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/ui_config.py index 31166ab..15cc5e4 100644 --- a/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/ui_config.py +++ b/osprey_worker/src/osprey/worker/lib/sources_config/subkeys/ui_config.py @@ -1,12 +1,10 @@ -from typing import Dict, List - from osprey.worker.lib.sources_config import register_config_subkey from pydantic import BaseModel class FeatureSummaryConfig(BaseModel): - actions: List[str] = [] - features: List[str] = [] + actions: list[str] = [] + features: list[str] = [] @register_config_subkey('ui_config') @@ -14,5 +12,5 @@ class UIConfig(BaseModel): class Config: arbitrary_types_allowed = True - default_summary_features: List[FeatureSummaryConfig] = [] - external_links: Dict[str, str] = {} + default_summary_features: list[FeatureSummaryConfig] = [] + external_links: dict[str, str] = {} diff --git a/osprey_worker/src/osprey/worker/lib/sources_provider.py b/osprey_worker/src/osprey/worker/lib/sources_provider.py index 4d13c34..a3ac927 100644 --- a/osprey_worker/src/osprey/worker/lib/sources_provider.py +++ b/osprey_worker/src/osprey/worker/lib/sources_provider.py @@ -1,5 +1,4 @@ import logging -from typing import Dict, Optional from osprey.engine.ast.sources import Sources from osprey.worker.lib.etcd import EtcdClient @@ -26,23 +25,23 @@ class EtcdSourcesProvider(BaseSourcesProvider): def __init__( self, etcd_key: str, - etcd_client: Optional[EtcdClient] = None, - input_stream_ready_signaler: Optional[InputStreamReadySignaler] = None, + etcd_client: EtcdClient | None = None, + input_stream_ready_signaler: InputStreamReadySignaler | None = None, ): self._sources_dict: ReadOnlyEtcdDict[str, str] = ReadOnlyEtcdDict(etcd_key=etcd_key, etcd_client=etcd_client) self._current_sources = Sources.from_dict(self._sources_dict.copy()) - self._sources_watcher_callback: Optional[SourcesWatcherCallback] = None + self._sources_watcher_callback: SourcesWatcherCallback | None = None self._input_stream_ready_signaler = input_stream_ready_signaler # The consumer (engine) compiles this initial snapshot at construction, so # seed the applied-hash to it — a later re-delivery of the same value is a # genuine no-op and should be skipped. See _notify_watcher for why dedup # keys off the *applied* hash rather than the last *received* one. - self._applied_sources_hash: Optional[str] = self._current_sources.hash() + self._applied_sources_hash: str | None = self._current_sources.hash() self._sources_dict.add_watcher(self._notify_watcher) self._sources_dict.watch() - def _notify_watcher(self, sources_dict: Dict[str, str]) -> None: + def _notify_watcher(self, sources_dict: dict[str, str]) -> None: new_sources = Sources.from_dict(sources_dict) # Etcd watcher reconnects and session refreshes re-deliver the current diff --git a/osprey_worker/src/osprey/worker/lib/sources_publisher.py b/osprey_worker/src/osprey/worker/lib/sources_publisher.py index 6f7adfe..e99cb6f 100644 --- a/osprey_worker/src/osprey/worker/lib/sources_publisher.py +++ b/osprey_worker/src/osprey/worker/lib/sources_publisher.py @@ -1,7 +1,6 @@ import abc import logging from datetime import datetime -from typing import Dict, Optional, Set from google.cloud import bigquery from osprey.engine.ast.grammar import Assign, Call @@ -34,7 +33,7 @@ class BaseSourcesPublisher(abc.ABC): class EtcdSourcesPublisher(BaseSourcesPublisher): """Publishes the sources to be consumed by the EtcdSourcesProvider""" - def __init__(self, etcd_key: str, etcd_client: Optional[EtcdClient] = None): + def __init__(self, etcd_key: str, etcd_client: EtcdClient | None = None): self._etcd_dict: EtcdDict[str, str] = EtcdDict(etcd_key=etcd_key, etcd_client=etcd_client) def publish_sources(self, sources: ValidatedSources) -> None: @@ -85,7 +84,7 @@ def validate_and_push( return True -def _dependency_chain_to_str_set(dependency_chain: DependencyChain) -> Set[str]: +def _dependency_chain_to_str_set(dependency_chain: DependencyChain) -> set[str]: if dependency_chain.executor.node_type == Assign: output = set([dependency_chain.executor.node.target.identifier]) # type: ignore elif dependency_chain.executor.node_type == Call: @@ -125,12 +124,12 @@ def upload_dependencies_mapping( execution_graph = compile_execution_graph(validated_sources) - dependencies: Dict[str, Set[str]] = {} + dependencies: dict[str, set[str]] = {} for var_name, dependency_chain in execution_graph._assignment_executor_mapping.items(): dependencies[var_name] = _dependency_chain_to_str_set(dependency_chain) # compute reversed dependencies (what relies on this variable) - reversed_dependencies: Dict[str, Set[str]] = {} + reversed_dependencies: dict[str, set[str]] = {} for key, val in dependencies.items(): for v in val: if v not in reversed_dependencies: diff --git a/osprey_worker/src/osprey/worker/lib/storage/access_audit_log.py b/osprey_worker/src/osprey/worker/lib/storage/access_audit_log.py index e65fc43..9fce9a2 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/access_audit_log.py +++ b/osprey_worker/src/osprey/worker/lib/storage/access_audit_log.py @@ -1,5 +1,4 @@ import dataclasses -from typing import Optional from osprey.engine.utils.types import add_slots @@ -13,7 +12,7 @@ class AccessAuditLog: """ id: int # snowflake - requester_email: Optional[str] + requester_email: str | None request_method: str request_path: str request_headers: str diff --git a/osprey_worker/src/osprey/worker/lib/storage/bigquery.py b/osprey_worker/src/osprey/worker/lib/storage/bigquery.py index 3fd9b76..f628a16 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/bigquery.py +++ b/osprey_worker/src/osprey/worker/lib/storage/bigquery.py @@ -1,5 +1,6 @@ import time -from typing import Any, Dict, List, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from uuid import uuid4 from google.cloud import bigquery @@ -8,9 +9,9 @@ from google.cloud.bigquery.job import QueryJob, QueryJobConfig, QueryPriority from google.cloud.bigquery.table import RowIterator from osprey.worker.lib.ddtrace_utils import current_span, trace_wrap -AbstractQueryParameterT = Union[bigquery.ScalarQueryParameter, bigquery.ArrayQueryParameter] +AbstractQueryParameterT = bigquery.ScalarQueryParameter | bigquery.ArrayQueryParameter QueryParamsT = Sequence[AbstractQueryParameterT] -QueryExecutorRetT = List[Dict[str, Any]] +QueryExecutorRetT = list[dict[str, Any]] TIMEOUT_MS = 60 * 1000 TIMEOUT_WAIT_INCREMENT_S = 1 @@ -38,7 +39,7 @@ def execute_query( query: str, timeout_ms: int, query_parameters: QueryParamsT = (), - job_name_prefix: Optional[str] = None, + job_name_prefix: str | None = None, ) -> QueryExecutorRetT: """ Runs a query with the provided client diff --git a/osprey_worker/src/osprey/worker/lib/storage/bigtable.py b/osprey_worker/src/osprey/worker/lib/storage/bigtable.py index f19e567..a514391 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/bigtable.py +++ b/osprey_worker/src/osprey/worker/lib/storage/bigtable.py @@ -4,7 +4,6 @@ # import pytest import logging from abc import ABC, abstractmethod -from typing import Dict from google.cloud.bigtable import Client from google.cloud.bigtable.instance import Instance @@ -14,7 +13,7 @@ from osprey.worker.lib.ddtrace_utils import pin_override from osprey.worker.lib.singletons import CONFIG from osprey.worker.lib.utils.bigtable import fix_bigtable_client_if_using_emulator -OSPREY_TABLES_TO_COLUMN_FAMILIES: Dict[str, Dict[str, None]] = { +OSPREY_TABLES_TO_COLUMN_FAMILIES: dict[str, dict[str, None]] = { 'stored_execution_result': {'execution_result': None}, 'audit_log': {'audit_log': None}, } diff --git a/osprey_worker/src/osprey/worker/lib/storage/bulk_action_files.py b/osprey_worker/src/osprey/worker/lib/storage/bulk_action_files.py index be9444a..ef3086f 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/bulk_action_files.py +++ b/osprey_worker/src/osprey/worker/lib/storage/bulk_action_files.py @@ -2,7 +2,7 @@ import csv import os import tempfile from itertools import islice -from typing import Any, Dict, Generator, Optional, Protocol +from typing import Any, Generator, Protocol from google.cloud import storage from osprey.worker.lib.singletons import CONFIG @@ -18,8 +18,8 @@ class BulkActionFileManager(Protocol): pass def get_bulk_action_file_stream( - self, object_name: str, start_row: int = 0, num_rows: Optional[int] = None - ) -> Generator[Dict[str, Any], None, None]: + self, object_name: str, start_row: int = 0, num_rows: int | None = None + ) -> Generator[dict[str, Any], None, None]: pass def upload_file(self, object_name: str, file_stream: FileStorage) -> None: @@ -31,8 +31,8 @@ class NoopBulkActionFileManager(BulkActionFileManager): return f'http://localhost:5004/bulk_action/upload/{object_name}' def get_bulk_action_file_stream( - self, object_name: str, start_row: int = 0, num_rows: Optional[int] = None - ) -> Generator[Dict[str, Any], None, None]: + self, object_name: str, start_row: int = 0, num_rows: int | None = None + ) -> Generator[dict[str, Any], None, None]: yield {} def upload_file(self, object_name: str, file_stream: FileStorage) -> None: @@ -47,8 +47,8 @@ class LocalBulkActionFileManager(BulkActionFileManager): return f'http://localhost:5004/bulk_action/upload/{object_name}' def get_bulk_action_file_stream( - self, object_name: str, start_row: int = 0, num_rows: Optional[int] = None - ) -> Generator[Dict[str, Any], None, None]: + self, object_name: str, start_row: int = 0, num_rows: int | None = None + ) -> Generator[dict[str, Any], None, None]: with open(os.path.join(self.local_dir, object_name), 'r') as f: reader = islice(csv.DictReader(f), start_row, start_row + num_rows if num_rows is not None else None) for row in reader: @@ -77,8 +77,8 @@ class GCSBulkActionFileManager(BulkActionFileManager): return f'{base_url}/api/bulk_action/upload/{object_name}' def get_bulk_action_file_stream( - self, object_name: str, start_row: int = 0, num_rows: Optional[int] = None - ) -> Generator[Dict[str, Any], None, None]: + self, object_name: str, start_row: int = 0, num_rows: int | None = None + ) -> Generator[dict[str, Any], None, None]: blob = self._client.get_bucket(self.bucket_name).get_blob(object_name) if blob is None: @@ -95,7 +95,7 @@ class GCSBulkActionFileManager(BulkActionFileManager): upload_bulk_action_file_to_gcs(self.bucket_name, self._client, object_name, file_stream) -def get_bulk_action_file_manager(environment: Optional[str] = None) -> BulkActionFileManager: +def get_bulk_action_file_manager(environment: str | None = None) -> BulkActionFileManager: if environment is None: environment = os.getenv('ENVIRONMENT', 'development') diff --git a/osprey_worker/src/osprey/worker/lib/storage/bulk_action_task.py b/osprey_worker/src/osprey/worker/lib/storage/bulk_action_task.py index e0d17e6..bb6d272 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/bulk_action_task.py +++ b/osprey_worker/src/osprey/worker/lib/storage/bulk_action_task.py @@ -1,9 +1,9 @@ -from __future__ import absolute_import +from __future__ import absolute_import, annotations import logging from datetime import datetime, timezone from enum import StrEnum -from typing import Any, Dict, List, Optional +from typing import Any from sqlalchemy import ARRAY, BigInteger, Column, DateTime, Enum, Integer, Text @@ -44,7 +44,7 @@ class BulkActionJob(Model): total_rows: int = Column(Integer, nullable=False) processed_rows: int = Column(Integer, nullable=False) # sqlalchemy 1.4 mypy plugin doesn't read nullable= when inferring Mapped[T]. - error: Optional[str] = Column(Text, nullable=True) # type: ignore[misc] + error: str | None = Column(Text, nullable=True) # type: ignore[misc] action_workflow_name: str = Column(Text, nullable=False) entity_type: str = Column(Text, nullable=False) created_at: datetime = Column(DateTime(timezone=True), nullable=False) @@ -103,22 +103,22 @@ class BulkActionJob(Model): return job @classmethod - def get_one(cls, job_id: int) -> Optional['BulkActionJob']: + def get_one(cls, job_id: int) -> 'BulkActionJob' | None: with scoped_session() as session: return session.query(cls).filter(cls.id == job_id).first() @classmethod - def get_all(cls) -> List['BulkActionJob']: + def get_all(cls) -> list['BulkActionJob']: with scoped_session() as session: return session.query(cls).all() @classmethod - def get_all_jobs_by_status(cls, status: BulkActionJobStatus) -> List['BulkActionJob']: + def get_all_jobs_by_status(cls, status: BulkActionJobStatus) -> list['BulkActionJob']: with scoped_session() as session: return session.query(cls).filter(cls.status == status).all() @classmethod - def get_next_file_process_job(cls) -> Optional['BulkActionJob']: + def get_next_file_process_job(cls) -> 'BulkActionJob' | None: with scoped_session() as session: return ( session.query(cls).filter(cls.status == BulkActionJobStatus.UPLOADED).order_by(cls.created_at).first() @@ -143,11 +143,11 @@ class BulkActionJob(Model): session.merge(self) - def get_all_tasks(self) -> List['BulkActionTask']: + def get_all_tasks(self) -> list['BulkActionTask']: with scoped_session() as session: return session.query(BulkActionTask).filter(BulkActionTask.job_id == self.id).all() - def serialize(self) -> Dict[str, Any]: + def serialize(self) -> dict[str, Any]: return { 'id': str(self.id), 'status': self.status, @@ -181,25 +181,25 @@ class BulkActionTask(Model): row_offset: int = Column(Integer, nullable=False) row_count: int = Column(Integer, nullable=False) # sqlalchemy 1.4 mypy plugin doesn't read nullable= when inferring Mapped[T]. - error: Optional[str] = Column(Text, nullable=True) # type: ignore[misc] + error: str | None = Column(Text, nullable=True) # type: ignore[misc] attempts: int = Column(Integer, nullable=False) failed_row_offsets = Column(ARRAY(Integer), nullable=False) created_at: datetime = Column(DateTime(timezone=True), nullable=False) # sqlalchemy 1.4 mypy plugin doesn't read nullable= when inferring Mapped[T]. - completed_at: Optional[datetime] = Column(DateTime(timezone=True), nullable=True) # type: ignore[misc] + completed_at: datetime | None = Column(DateTime(timezone=True), nullable=True) # type: ignore[misc] @classmethod - def get_one(cls, task_id: int) -> Optional['BulkActionTask']: + def get_one(cls, task_id: int) -> 'BulkActionTask' | None: with scoped_session() as session: return session.query(cls).filter(cls.id == task_id).first() @classmethod - def get_all_by_job_id_for_status(cls, job_id: int, status: BulkActionTaskStatus) -> List['BulkActionTask']: + def get_all_by_job_id_for_status(cls, job_id: int, status: BulkActionTaskStatus) -> list['BulkActionTask']: with scoped_session() as session: return session.query(cls).filter(cls.job_id == job_id, cls.status == status).all() @classmethod - def get_next_pending_task(cls, job_id: int) -> Optional['BulkActionTask']: + def get_next_pending_task(cls, job_id: int) -> 'BulkActionTask' | None: with scoped_session() as session: return ( session.query(cls) diff --git a/osprey_worker/src/osprey/worker/lib/storage/bulk_label_task.py b/osprey_worker/src/osprey/worker/lib/storage/bulk_label_task.py index 906d5f2..0a6415e 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/bulk_label_task.py +++ b/osprey_worker/src/osprey/worker/lib/storage/bulk_label_task.py @@ -1,10 +1,11 @@ -from __future__ import absolute_import +from __future__ import absolute_import, annotations import logging import time +from collections.abc import Iterator from datetime import datetime from random import random -from typing import Any, Dict, Iterator, List, Optional +from typing import Any from osprey.worker.lib.osprey_shared.labels import LabelStatus from osprey.worker.lib.storage.types import Enum @@ -57,14 +58,14 @@ class BulkLabelTask(Model): @classmethod def enqueue( cls, - query: Dict[str, Any], + query: dict[str, Any], dimension: str, initiated_by: str, label_name: str, label_reason: str, label_status: LabelStatus, - label_expiry: Optional[datetime], - excluded_entities: List[str], + label_expiry: datetime | None, + excluded_entities: list[str], expected_total_entities_to_label: int, no_limit: bool, ) -> 'BulkLabelTask': @@ -89,13 +90,13 @@ class BulkLabelTask(Model): return task @classmethod - def get_one(cls, task_id: int) -> Optional['BulkLabelTask']: + def get_one(cls, task_id: int) -> 'BulkLabelTask' | None: with scoped_session() as session: - task: Optional[BulkLabelTask] = session.query(BulkLabelTask).get(task_id) + task: BulkLabelTask | None = session.query(BulkLabelTask).get(task_id) return task @classmethod - def get_last_n(cls, last_n: int) -> List['BulkLabelTask']: + def get_last_n(cls, last_n: int) -> list['BulkLabelTask']: table = cls.__table__ query = table.select().limit(last_n).order_by(table.c.id.desc()) with scoped_session() as session: @@ -182,7 +183,7 @@ class BulkLabelTask(Model): self.claim_until = func.now() + func.cast(func.concat(claim_until_seconds, ' SECONDS'), INTERVAL) @classmethod - def claim(cls) -> Optional['BulkLabelTask']: + def claim(cls) -> 'BulkLabelTask' | None: """Claim one task to process.""" table = cls.__table__ @@ -254,7 +255,7 @@ class BulkLabelTask(Model): assert isinstance(row, BulkLabelTask) return row - def release(self, status: TaskStatus, result: Optional[str] = None) -> None: + def release(self, status: TaskStatus, result: str | None = None) -> None: with scoped_session(commit=True) as session: session.add(self) self.task_status = status diff --git a/osprey_worker/src/osprey/worker/lib/storage/labels.py b/osprey_worker/src/osprey/worker/lib/storage/labels.py index d60e400..435f41a 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/labels.py +++ b/osprey_worker/src/osprey/worker/lib/storage/labels.py @@ -1,9 +1,10 @@ import copy from abc import ABC, abstractmethod from collections import defaultdict +from collections.abc import Sequence from contextlib import contextmanager from datetime import timedelta -from typing import Any, Generator, Optional, Sequence +from typing import Any, Generator from osprey.engine.executor.external_service_utils import ExternalService from osprey.engine.language_types.entities import EntityT @@ -270,7 +271,7 @@ class LabelsProvider(ExternalService[EntityT[Any], EntityLabels]): logger.error(f'Could not read-modify-write labels for entity {entity.__repr__()}:', e) raise e - def cache_ttl(self) -> Optional[timedelta]: + def cache_ttl(self) -> timedelta | None: return timedelta(minutes=1) def get_from_service(self, key: EntityT[Any]) -> EntityLabels: diff --git a/osprey_worker/src/osprey/worker/lib/storage/local_label_provider.py b/osprey_worker/src/osprey/worker/lib/storage/local_label_provider.py index da6460c..9106e09 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/local_label_provider.py +++ b/osprey_worker/src/osprey/worker/lib/storage/local_label_provider.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, List, Sequence +from collections.abc import Sequence +from typing import Any from osprey.engine.language_types.entities import EntityT from osprey.worker.lib.osprey_shared.labels import EntityLabelMutation, EntityLabelMutationsResult, EntityLabels @@ -8,13 +9,13 @@ from result import Result class LocalLabelProvider(LabelsProvider): def __init__(self): - self._labels: Dict[str, EntityLabels] = {} + self._labels: dict[str, EntityLabels] = {} def batch_get_from_service(self, keys: Sequence[EntityT[Any]]) -> Sequence[Result[EntityLabels, Exception]]: raise NotImplementedError() def apply_entity_mutation( - self, entity_key: EntityT[Any], mutations: List[EntityLabelMutation] + self, entity_key: EntityT[Any], mutations: list[EntityLabelMutation] ) -> EntityLabelMutationsResult: raise NotImplementedError() diff --git a/osprey_worker/src/osprey/worker/lib/storage/pg_stored_execution.py b/osprey_worker/src/osprey/worker/lib/storage/pg_stored_execution.py index fbbc53c..4ce1fc2 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/pg_stored_execution.py +++ b/osprey_worker/src/osprey/worker/lib/storage/pg_stored_execution.py @@ -1,4 +1,6 @@ -from typing import Any, Dict, List, Optional +from __future__ import annotations + +from typing import Any from sqlalchemy import BigInteger, Column from sqlalchemy.dialects.postgresql import JSONB @@ -20,7 +22,7 @@ class PgStoredExecutionResult(Model): def insert( cls, id: int, - payload: Dict[str, Any], + payload: dict[str, Any], ) -> None: """ Adds a single `execution_result` to the database @@ -30,23 +32,23 @@ class PgStoredExecutionResult(Model): session.add(execution_result) @classmethod - def select_one(cls, id: int) -> Optional['PgStoredExecutionResult']: + def select_one(cls, id: int) -> 'PgStoredExecutionResult' | None: """ Gets stored execution result with id if it exists """ with scoped_session() as session: - execution_result: Optional['PgStoredExecutionResult'] = ( + execution_result: 'PgStoredExecutionResult' | None = ( session.query(PgStoredExecutionResult).filter(PgStoredExecutionResult.id == id).one_or_none() ) return execution_result @classmethod - def select_many(cls, ids: List[int]) -> List['PgStoredExecutionResult']: + def select_many(cls, ids: list[int]) -> list['PgStoredExecutionResult']: """ Gets list of stored execution results with given ids """ with scoped_session() as session: - execution_results: List['PgStoredExecutionResult'] = ( + execution_results: list['PgStoredExecutionResult'] = ( session.query(PgStoredExecutionResult).filter(PgStoredExecutionResult.id.in_(ids)).all() ) return execution_results diff --git a/osprey_worker/src/osprey/worker/lib/storage/postgres.py b/osprey_worker/src/osprey/worker/lib/storage/postgres.py index b402c15..b0f6704 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/postgres.py +++ b/osprey_worker/src/osprey/worker/lib/storage/postgres.py @@ -3,8 +3,9 @@ import sqlalchemy psycogreen.gevent.patch_psycopg() # noqa: E402 +from collections.abc import Iterator # noqa: E402 from contextlib import contextmanager # noqa: E402 -from typing import TYPE_CHECKING, Dict, Iterator, Optional # noqa: E402 +from typing import TYPE_CHECKING # noqa: E402 from flask import Flask, has_request_context # noqa: E402 from osprey.worker.lib.config import Config # noqa: E402 @@ -23,8 +24,8 @@ if TYPE_CHECKING: else: SessionMaker = sessionmaker -sessions: Dict[str, SessionMaker] = {} -session_registries: Dict[str, ThreadLocalRegistry] = {} +sessions: dict[str, SessionMaker] = {} +session_registries: dict[str, ThreadLocalRegistry] = {} def _get_or_init_session(database: str) -> SessionMaker: @@ -66,7 +67,7 @@ def init_from_config(database: str) -> None: def init_app(app: Flask) -> None: @app.teardown_request - def cleanup_session(_exception: Optional[BaseException]) -> None: + def cleanup_session(_exception: BaseException | None) -> None: for session_registry in session_registries.values(): if session_registry.has(): session_registry().close() diff --git a/osprey_worker/src/osprey/worker/lib/storage/queries.py b/osprey_worker/src/osprey/worker/lib/storage/queries.py index 488e8f7..93ed6fe 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/queries.py +++ b/osprey_worker/src/osprey/worker/lib/storage/queries.py @@ -1,5 +1,5 @@ import enum -from typing import Any, Dict, List, Optional +from typing import Any from osprey.worker.lib.snowflake import Snowflake, generate_snowflake from sqlalchemy import ARRAY, BigInteger, Column, Text, select @@ -50,7 +50,7 @@ class Query(Model): return session.query(cls).filter(cls.id == query_id).limit(1).first() @classmethod - def get_all(cls, before: Optional[int] = None, limit: int = 100) -> List['Query']: + def get_all(cls, before: int | None = None, limit: int = 100) -> list['Query']: table = cls.__table__ query = table.select().limit(limit).order_by(table.c.id.desc()) @@ -61,7 +61,7 @@ class Query(Model): return [cls(**result) for result in session.execute(query)] @classmethod - def get_all_for_user(cls, user_email: str, before: Optional[int] = None, limit: int = 100) -> List['Query']: + def get_all_for_user(cls, user_email: str, before: int | None = None, limit: int = 100) -> list['Query']: table = cls.__table__ query = table.select().where(table.c.executed_by == user_email).limit(limit).order_by(table.c.id.desc()) @@ -72,7 +72,7 @@ class Query(Model): return session.query(cls).from_statement(query).all() @classmethod - def get_all_user_emails(cls) -> List[str]: + def get_all_user_emails(cls) -> list[str]: table = cls.__table__ with scoped_session() as session: @@ -80,7 +80,7 @@ class Query(Model): return [user_email[0] for user_email in emails] @classmethod - def get_all_for_saved_query(cls, query_id: int, limit: int = 10) -> List['Query']: + def get_all_for_saved_query(cls, query_id: int, limit: int = 10) -> list['Query']: table = cls.__table__ queries_cte = select([table]).where(table.c.id == query_id).cte(recursive=True, name='queries_cte') @@ -99,7 +99,7 @@ class Query(Model): self.id = generate_snowflake().to_int() session.add(self) - def serialize(self) -> Dict[str, Any]: + def serialize(self) -> dict[str, Any]: assert self.sort_order is not None assert self.id is not None return { @@ -144,7 +144,7 @@ class SavedQuery(Model): return session.query(cls).filter(cls.query_id == query_id).limit(1).first() @classmethod - def get_all(cls, before: Optional[int] = None, limit: int = 100) -> Any: + def get_all(cls, before: int | None = None, limit: int = 100) -> Any: table = cls.__table__ query = table.select().limit(limit).order_by(table.c.id.desc()) @@ -155,7 +155,7 @@ class SavedQuery(Model): return session.query(SavedQuery).options(selectinload(SavedQuery.query)).from_statement(query).all() @classmethod - def get_all_for_user(cls, user_email: str, before: Optional[int] = None, limit: int = 100) -> List['Query']: + def get_all_for_user(cls, user_email: str, before: int | None = None, limit: int = 100) -> list['Query']: table = cls.__table__ query = table.select().where(table.c.saved_by == user_email).limit(limit).order_by(table.c.id.desc()) @@ -166,7 +166,7 @@ class SavedQuery(Model): return session.query(cls).from_statement(query).all() @classmethod - def get_all_user_emails(cls) -> List[str]: + def get_all_user_emails(cls) -> list[str]: table = cls.__table__ with scoped_session() as session: @@ -199,7 +199,7 @@ class SavedQuery(Model): with scoped_session(commit=True) as session: session.delete(self) - def serialize(self) -> Dict[str, Any]: + def serialize(self) -> dict[str, Any]: assert self.id is not None return { 'id': str(self.id), diff --git a/osprey_worker/src/osprey/worker/lib/storage/stored_execution_result.py b/osprey_worker/src/osprey/worker/lib/storage/stored_execution_result.py index b1bc25a..bb82c87 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/stored_execution_result.py +++ b/osprey_worker/src/osprey/worker/lib/storage/stored_execution_result.py @@ -3,9 +3,10 @@ from __future__ import annotations import gzip import json from abc import ABC, abstractmethod +from collections.abc import Sequence from datetime import datetime from io import BytesIO -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, cast +from typing import TYPE_CHECKING, Any, cast import gevent import google.cloud.storage as storage @@ -39,12 +40,12 @@ class ExecutionResultStore(ABC): """Abstract base class for execution result storage backends.""" @abstractmethod - def select_one(self, action_id: int) -> Optional[Dict[str, Any]]: + def select_one(self, action_id: int) -> dict[str, Any] | None: """Retrieve a single execution result by action ID.""" pass @abstractmethod - def select_many(self, action_ids: List[int]) -> List[Dict[str, Any]]: + def select_many(self, action_ids: list[int]) -> list[dict[str, Any]]: """Retrieve multiple execution results by action IDs.""" pass @@ -73,10 +74,10 @@ class StoredExecutionResult(BaseModel): # NOTE: These fields must match the database column names exactly. id: int - extracted_features: Dict[str, Any] + extracted_features: dict[str, Any] error_traces: Sequence[ErrorTrace] timestamp: datetime - action_data: Optional[Dict[str, Any]] = None + action_data: dict[str, Any] | None = None @classmethod def persist_from_execution_result( @@ -96,8 +97,8 @@ class StoredExecutionResult(BaseModel): cls, event_record_id: int, storage_backend: ExecutionResultStore, - data_censor_abilities: Sequence[Optional[DataCensorAbility[Any, Any]]] = (), - ) -> Optional['StoredExecutionResult']: + data_censor_abilities: Sequence[DataCensorAbility[Any, Any] | None] = (), + ) -> 'StoredExecutionResult' | None: """Get execution result from the provided storage backend.""" result = storage_backend.select_one(event_record_id) if result: @@ -107,10 +108,10 @@ class StoredExecutionResult(BaseModel): @classmethod def get_many( cls, - action_ids: List[int], + action_ids: list[int], storage_backend: ExecutionResultStore, - data_censor_abilities: Sequence[Optional[DataCensorAbility[Any, Any]]] = (), - ) -> List['StoredExecutionResult']: + data_censor_abilities: Sequence[DataCensorAbility[Any, Any] | None] = (), + ) -> list['StoredExecutionResult']: """Get execution results from the provided storage backend.""" results = storage_backend.select_many(action_ids) @@ -122,7 +123,7 @@ class StoredExecutionResult(BaseModel): @classmethod def parse_from_query_result( - cls, result: Dict[str, Any], data_censor_abilities: Sequence[Optional[DataCensorAbility[Any, Any]]] + cls, result: dict[str, Any], data_censor_abilities: Sequence[DataCensorAbility[Any, Any] | None] ) -> 'StoredExecutionResult': # Apply the data censors from osprey.worker.ui_api.osprey.lib.abilities import ( @@ -132,15 +133,15 @@ class StoredExecutionResult(BaseModel): ) def _censor_data( - data: Dict[str, Any], + data: dict[str, Any], field: str, - data_censor_abilities: List[DataCensorAbility[Any, Any]], + data_censor_abilities: list[DataCensorAbility[Any, Any]], action_name: str, - ) -> Optional[Dict[str, Any]]: + ) -> dict[str, Any] | None: data_at_field = data.get(field) if not data_at_field: return None - data_copy: Dict[str, Any] = json.loads(data_at_field) + data_copy: dict[str, Any] = json.loads(data_at_field) if not data_censor_abilities: return DataCensorAbility.censor_all_leafs(data_copy) for censor in data_censor_abilities: @@ -148,16 +149,16 @@ class StoredExecutionResult(BaseModel): assert isinstance(data_copy, dict) return data_copy - action_name: Optional[str] = None - extracted_features: Optional[Any] = result.get('extracted_features') + action_name: str | None = None + extracted_features: Any | None = result.get('extracted_features') if extracted_features: action_name = json.loads(extracted_features).get('ActionName') assert action_name is not None, f'Action name could not be parsed from query result: {str(result)}' - action_data_censors: List[DataCensorAbility[Any, Any]] = [ + action_data_censors: list[DataCensorAbility[Any, Any]] = [ censor for censor in data_censor_abilities if censor and isinstance(censor, CanViewActionData) ] - feature_data_censors: List[DataCensorAbility[Any, Any]] = [ + feature_data_censors: list[DataCensorAbility[Any, Any]] = [ censor for censor in data_censor_abilities if censor and isinstance(censor, CanViewFeatureData) ] censored_action_data = _censor_data(result, 'action_data', action_data_censors, action_name) @@ -183,7 +184,7 @@ class StoredExecutionResult(BaseModel): class StoredExecutionResultBigTable(ExecutionResultStore): retry_policy = retry.Retry(initial=1.0, maximum=2.0, multiplier=1.25, deadline=120.0) - def select_one(self, action_id: int) -> Optional[Dict[str, Any]]: + def select_one(self, action_id: int) -> dict[str, Any] | None: row = osprey_bigtable.table('stored_execution_result').read_row( StoredExecutionResultBigTable._encode_action_id(action_id), row_filters.CellsColumnLimitFilter(1) ) @@ -194,7 +195,7 @@ class StoredExecutionResultBigTable(ExecutionResultStore): # TODO: Add `select_*_minimal` methods - def select_many(self, action_ids: List[int]) -> List[Dict[str, Any]]: + def select_many(self, action_ids: list[int]) -> list[dict[str, Any]]: if not action_ids: return [] @@ -208,7 +209,7 @@ class StoredExecutionResultBigTable(ExecutionResultStore): retry=self.retry_policy, ) - results: List[Dict[str, Any]] = [] + results: list[dict[str, Any]] = [] for row in rows: if not row: continue @@ -246,7 +247,7 @@ class StoredExecutionResultBigTable(ExecutionResultStore): return int(snowflake) @staticmethod - def _execution_result_dict_from_row(row: Row) -> Dict[str, Any]: + def _execution_result_dict_from_row(row: Row) -> dict[str, Any]: # row.cells doesn't have the right type information setup (at least in this version of bt), so its ignored here. extracted_features = row.cells['execution_result'][b'extracted_features'][0].value.decode('utf-8') # type: ignore[attr-defined] error_traces = row.cells['execution_result'][b'error_traces'][0].value.decode('utf-8') # type: ignore[attr-defined] @@ -290,7 +291,7 @@ class StoredExecutionResultGCS(ExecutionResultStore): self._bucket_name = config.get_str('OSPREY_GCS_EXECUTION_RESULTS_BUCKET', 'osprey-execution-results-stg') return self._bucket_name - def select_one(self, action_id: int) -> Optional[Dict[str, Any]]: + def select_one(self, action_id: int) -> dict[str, Any] | None: try: with metrics.timed('gcs_stored_execution_result.get_one'): object_name = StoredExecutionResultGCS._encode_action_id(action_id) @@ -311,7 +312,7 @@ class StoredExecutionResultGCS(ExecutionResultStore): logger.error(f'Failed to retrieve execution result from GCS for action_id {action_id}: {e}') return None - def select_many(self, action_ids: List[int]) -> List[Dict[str, Any]]: + def select_many(self, action_ids: list[int]) -> list[dict[str, Any]]: results = [ result for result in gevent.pool.Pool(GCS_CONCURRENCY_LIMIT).imap(self.select_one, action_ids) @@ -359,7 +360,7 @@ class StoredExecutionResultGCS(ExecutionResultStore): return f'{key_prefix}:{action_id_snowflake}.json' @staticmethod - def _execution_result_dict_from_gcs_data(data: Dict[str, Any]) -> Dict[str, Any]: + def _execution_result_dict_from_gcs_data(data: dict[str, Any]) -> dict[str, Any]: execution_result_dict = { 'id': data['id'], 'extracted_features': data['extracted_features'], @@ -380,7 +381,7 @@ class StoredExecutionResultMinIO(ExecutionResultStore): self._minio_client = Minio(endpoint, access_key=access_key, secret_key=secret_key, secure=secure) self._bucket_name = bucket_name - def select_one(self, action_id: int) -> Optional[Dict[str, Any]]: + def select_one(self, action_id: int) -> dict[str, Any] | None: try: with metrics.timed('minio_stored_execution_result.get_one'): object_name = StoredExecutionResultMinIO._encode_action_id(action_id) @@ -407,7 +408,7 @@ class StoredExecutionResultMinIO(ExecutionResultStore): logger.error(f'Failed to retrieve execution result from MinIO for action_id {action_id}: {e}') return None - def select_many(self, action_ids: List[int]) -> List[Dict[str, Any]]: + def select_many(self, action_ids: list[int]) -> list[dict[str, Any]]: results = [ result for result in gevent.pool.Pool(MINIO_CONCURRENCY_LIMIT).imap(self.select_one, action_ids) @@ -456,7 +457,7 @@ class StoredExecutionResultMinIO(ExecutionResultStore): return f'{key_prefix}:{action_id_snowflake}.json' @staticmethod - def _execution_result_dict_from_minio_data(data: Dict[str, Any]) -> Dict[str, Any]: + def _execution_result_dict_from_minio_data(data: dict[str, Any]) -> dict[str, Any]: execution_result_dict = { 'id': data['id'], 'extracted_features': data['extracted_features'], @@ -476,7 +477,7 @@ class StoredExecutionResultPostgres(ExecutionResultStore): def __init__(self) -> None: postgres.init_from_config('osprey_db') - def select_one(self, action_id: int) -> Optional[Dict[str, Any]]: + def select_one(self, action_id: int) -> dict[str, Any] | None: try: with metrics.timed('pg_stored_execution_result.get_one'): result = PgStoredExecutionResult.select_one(action_id) @@ -485,20 +486,20 @@ class StoredExecutionResultPostgres(ExecutionResultStore): 'pg_stored_execution_result.select_one.not_found', tags=[f'action_id:{action_id}'] ) return None - payload = cast(Dict[str, Any], result.payload) + payload = cast(dict[str, Any], result.payload) return StoredExecutionResultPostgres._execution_result_dict_from_pg_data(payload) except Exception as e: logger.error(f'Failed to retrieve execution result from PG for action_id {action_id}: {e}') return None - def select_many(self, action_ids: List[int]) -> List[Dict[str, Any]]: + def select_many(self, action_ids: list[int]) -> list[dict[str, Any]]: try: with metrics.timed('pg_stored_execution_result.get_many'): results = PgStoredExecutionResult.select_many(action_ids) return [ StoredExecutionResultPostgres._execution_result_dict_from_pg_data( - cast(Dict[str, Any], result.payload) + cast(dict[str, Any], result.payload) ) for result in results ] @@ -516,7 +517,7 @@ class StoredExecutionResultPostgres(ExecutionResultStore): ) -> None: try: with metrics.timed('pg_stored_execution_result.insert'): - payload: Dict[str, Any] = { + payload: dict[str, Any] = { 'id': action_id, 'extracted_features': extracted_features_json, 'error_traces': error_traces_json, @@ -528,7 +529,7 @@ class StoredExecutionResultPostgres(ExecutionResultStore): logger.error(f'Failed to insert execution result into PG for action_id {action_id}: {e}') @staticmethod - def _execution_result_dict_from_pg_data(data: Dict[str, Any]) -> Dict[str, Any]: + def _execution_result_dict_from_pg_data(data: dict[str, Any]) -> dict[str, Any]: execution_result_dict = { 'id': data['id'], 'extracted_features': data['extracted_features'], @@ -555,16 +556,16 @@ class ExecutionResultStorageService: StoredExecutionResult.persist_from_execution_result(execution_result, self._storage_backend) def get_one_with_action_data( - self, event_record_id: int, data_censor_abilities: Sequence[Optional[DataCensorAbility[Any, Any]]] = () - ) -> Optional[StoredExecutionResult]: + self, event_record_id: int, data_censor_abilities: Sequence[DataCensorAbility[Any, Any] | None] = () + ) -> StoredExecutionResult | None: """Get execution result from the configured storage backend.""" return StoredExecutionResult.get_one_with_action_data( event_record_id, self._storage_backend, data_censor_abilities ) def get_many( - self, action_ids: List[int], data_censor_abilities: Sequence[Optional[DataCensorAbility[Any, Any]]] = () - ) -> List[StoredExecutionResult]: + self, action_ids: list[int], data_censor_abilities: Sequence[DataCensorAbility[Any, Any] | None] = () + ) -> list[StoredExecutionResult]: """Get execution results from the configured storage backend.""" return StoredExecutionResult.get_many(action_ids, self._storage_backend, data_censor_abilities) diff --git a/osprey_worker/src/osprey/worker/lib/storage/temporary_ability_token.py b/osprey_worker/src/osprey/worker/lib/storage/temporary_ability_token.py index 8a475ca..e3ab04b 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/temporary_ability_token.py +++ b/osprey_worker/src/osprey/worker/lib/storage/temporary_ability_token.py @@ -1,9 +1,11 @@ +from __future__ import annotations + import base64 import json import os from datetime import datetime, timedelta from enum import Enum -from typing import Any, List, Optional +from typing import Any import pytz from osprey.worker.ui_api.osprey.lib.abilities import Ability @@ -43,7 +45,7 @@ class TemporaryAbilityToken(Model): created_at = Column(DateTime(timezone=True), nullable=False) @classmethod - def create(cls, abilities: List[Ability[Any, Any]], creation_origin: str) -> 'TemporaryAbilityToken': + def create(cls, abilities: list[Ability[Any, Any]], creation_origin: str) -> 'TemporaryAbilityToken': """ Adds a single `ability_token` to the database """ @@ -63,8 +65,8 @@ class TemporaryAbilityToken(Model): return ability_token @classmethod - def _get_ability_token_for_update(cls, token: str, session: Session) -> Optional['TemporaryAbilityToken']: - ability_token: Optional['TemporaryAbilityToken'] = ( + def _get_ability_token_for_update(cls, token: str, session: Session) -> 'TemporaryAbilityToken' | None: + ability_token: 'TemporaryAbilityToken' | None = ( session.query(TemporaryAbilityToken) .with_for_update() # This prevents double consumption by locking the row until the session is over .filter(TemporaryAbilityToken.token == token) @@ -100,17 +102,17 @@ class TemporaryAbilityToken(Model): return ConsumptionResult.SUCCESS @classmethod - def get_abilities(cls, email: str) -> List[Ability[Any, Any]]: + def get_abilities(cls, email: str) -> list[Ability[Any, Any]]: """ Gets all the temporary abilities associated with `email` that haven't expired yet """ with scoped_session() as session: - access_tokens: List['TemporaryAbilityToken'] = ( + access_tokens: list['TemporaryAbilityToken'] = ( session.query(TemporaryAbilityToken) # type: ignore # query is untyped .filter(TemporaryAbilityToken.consumed_by_email == email) .filter(TemporaryAbilityToken.abilities_expire_at > datetime.now(tz=pytz.utc)) ) return [ability for ability_token in access_tokens for ability in ability_token.abilities()] - def abilities(self) -> List[Ability[Any, Any]]: + def abilities(self) -> list[Ability[Any, Any]]: return [Ability.validate(ability_json) for ability_json in self.abilities_json] # type: ignore # mypy doesn't like the list comprehension diff --git a/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_action_task.py b/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_action_task.py index 63ff003..7685fe2 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_action_task.py +++ b/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_action_task.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator from unittest.mock import patch import pytest diff --git a/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_label_task.py b/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_label_task.py index 3770cf9..e20c064 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_label_task.py +++ b/osprey_worker/src/osprey/worker/lib/storage/tests/test_bulk_label_task.py @@ -1,7 +1,7 @@ from __future__ import absolute_import +from collections.abc import Iterator from datetime import datetime, timedelta -from typing import Iterator import pytest from osprey.worker.lib.bulk_label import TaskStatus diff --git a/osprey_worker/src/osprey/worker/lib/storage/tests/test_queries.py b/osprey_worker/src/osprey/worker/lib/storage/tests/test_queries.py index 0dccff2..51fc446 100644 --- a/osprey_worker/src/osprey/worker/lib/storage/tests/test_queries.py +++ b/osprey_worker/src/osprey/worker/lib/storage/tests/test_queries.py @@ -1,7 +1,7 @@ from __future__ import absolute_import +from collections.abc import Iterator from random import choice -from typing import Iterator, Optional import pytest from faker import Faker @@ -20,9 +20,7 @@ def sqlalchemy_session() -> Iterator[Session]: yield session -def _create_query( - executed_by: Optional[str] = None, parent_id: Optional[int] = None, insert: Optional[bool] = False -) -> Query: +def _create_query(executed_by: str | None = None, parent_id: int | None = None, insert: bool | None = False) -> Query: query = Query() query.parent_id = parent_id query.executed_by = executed_by if executed_by else fake.email() @@ -37,7 +35,7 @@ def _create_query( return query -def _create_saved_query(query: Query, saved_by: Optional[str] = None) -> SavedQuery: +def _create_saved_query(query: Query, saved_by: str | None = None) -> SavedQuery: saved_query = SavedQuery() saved_query.query_id = query.id saved_query.name = fake.pystr() diff --git a/osprey_worker/src/osprey/worker/lib/tests/test_utils.py b/osprey_worker/src/osprey/worker/lib/tests/test_utils.py index 55bb653..1839efc 100644 --- a/osprey_worker/src/osprey/worker/lib/tests/test_utils.py +++ b/osprey_worker/src/osprey/worker/lib/tests/test_utils.py @@ -1,6 +1,7 @@ import os import textwrap -from typing import TYPE_CHECKING, Callable, Iterator +from collections.abc import Callable, Iterator +from typing import TYPE_CHECKING import pytest from flask import Flask diff --git a/osprey_worker/src/osprey/worker/lib/utils/click_utils.py b/osprey_worker/src/osprey/worker/lib/utils/click_utils.py index 977df04..d5e48a1 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/click_utils.py +++ b/osprey_worker/src/osprey/worker/lib/utils/click_utils.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Dict, Generic, Optional, Type, TypeVar, Union +from typing import Generic, Type, TypeVar import click from click import Context, Parameter @@ -22,7 +22,7 @@ class EnumChoice(click.Choice, Generic[T]): ``` """ - choice_map: Dict[str, T] + choice_map: dict[str, T] enum: Type[T] def __init__(self, enum: Type[T]): @@ -30,7 +30,7 @@ class EnumChoice(click.Choice, Generic[T]): self.enum = enum super().__init__(choices=list(self.choice_map.keys())) - def convert(self, value: Union[str, T], param: Optional[Parameter], ctx: Optional[Context]) -> Optional[T]: + def convert(self, value: str | T, param: Parameter | None, ctx: Context | None) -> T | None: # This is to support when click is given a default that is a variant. If we have a value that is our variant, # we can just return it without trying to coerce. if isinstance(value, self.enum): diff --git a/osprey_worker/src/osprey/worker/lib/utils/dates.py b/osprey_worker/src/osprey/worker/lib/utils/dates.py index d4af75b..b518b0c 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/dates.py +++ b/osprey_worker/src/osprey/worker/lib/utils/dates.py @@ -1,6 +1,5 @@ import time from datetime import datetime -from typing import Union import pytz from dateutil import parser @@ -21,7 +20,7 @@ class SnowflakeParseError(ValueError): pass -def snowflake_to_datetime(snowflake: Union[str, int]) -> datetime: +def snowflake_to_datetime(snowflake: str | int) -> datetime: """Extract the timestamp from a Snowflake and return a UTC datetime.""" time_portion = int(snowflake) >> 22 if time_portion == 0: diff --git a/osprey_worker/src/osprey/worker/lib/utils/flask_signing.py b/osprey_worker/src/osprey/worker/lib/utils/flask_signing.py index de1f7a3..467160a 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/flask_signing.py +++ b/osprey_worker/src/osprey/worker/lib/utils/flask_signing.py @@ -3,7 +3,8 @@ import binascii import functools import hashlib import json -from typing import Any, Callable, Dict, List, Optional, TypeVar, Union +from collections.abc import Callable +from typing import Any, TypeVar from urllib.parse import urlparse from Crypto.Hash import SHA256 @@ -26,11 +27,11 @@ class Signer: self._key_id = _get_key_id(key) self._dss_sig_scheme = _dss_sig_scheme(key) - def sign(self, message: bytes) -> Dict[str, Union[str, bytes]]: + def sign(self, message: bytes) -> dict[str, str | bytes]: signature = base64.b64encode(self._dss_sig_scheme.sign(SHA256.new(data=message))) return {self._key_id_header: self._key_id, self._signature_header: signature} - def sign_url(self, url: str, normalize: bool = True) -> Dict[str, Union[str, bytes]]: + def sign_url(self, url: str, normalize: bool = True) -> dict[str, str | bytes]: """ `normalize` will normalize the URL to look like Flask's Request.full_path. When calling `verify_request_path`, `use_full_path` should be `True` if `normalize` is also `True` when signing. @@ -57,10 +58,10 @@ def _get_key_id(key: ECC.EccKey) -> str: class PublicKeyGetterFunction(Protocol): - def __call__(self, key_id: str) -> Optional[ECC.EccKey]: ... + def __call__(self, key_id: str) -> ECC.EccKey | None: ... -# Would be great to be able to actually assert that this thing can take a `request_data: Dict[str, object]`, +# Would be great to be able to actually assert that this thing can take a `request_data: dict[str, object]`, # but mypy isn't great at modifying function types. WithRequestDataFunction = Callable[..., Any] FuncT = TypeVar('FuncT', bound=Callable[..., Any]) @@ -70,7 +71,7 @@ def verify_request_data( public_key_getter: PublicKeyGetterFunction, key_id_header: str, key_signature_header: str, - allowed_methods: Optional[List[str]] = None, + allowed_methods: list[str] | None = None, ) -> Callable[[WithRequestDataFunction], Callable[..., Any]]: """ Wraps a view, verifying the request.data against a key signature using the same method as github, @@ -109,7 +110,7 @@ def verify_request_path( key_id_header: str, key_signature_header: str, use_full_path: bool = True, - allowed_methods: Optional[List[str]] = None, + allowed_methods: list[str] | None = None, ) -> Callable[[FuncT], FuncT]: """ Wraps a view, verifying the path and querystring parameters against a key signature. This is similar to diff --git a/osprey_worker/src/osprey/worker/lib/utils/flask_utils.py b/osprey_worker/src/osprey/worker/lib/utils/flask_utils.py index 05bfb7d..45908eb 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/flask_utils.py +++ b/osprey_worker/src/osprey/worker/lib/utils/flask_utils.py @@ -1,5 +1,6 @@ import dataclasses -from typing import TYPE_CHECKING, Any, Callable, Mapping, Optional, cast +from collections.abc import Callable, Mapping +from typing import TYPE_CHECKING, Any, cast import simplejson from flask import Flask @@ -48,7 +49,7 @@ class OspreyFlask(Flask): return super().make_response(rv) - def _json_encode_response(self, rv: Mapping[str, object], encoder: Optional[Callable[[], Any]] = None) -> Any: + def _json_encode_response(self, rv: Mapping[str, object], encoder: Callable[[], Any] | None = None) -> Any: return self.response_class( simplejson.dumps( rv, diff --git a/osprey_worker/src/osprey/worker/lib/utils/generic_events.py b/osprey_worker/src/osprey/worker/lib/utils/generic_events.py index a7354ce..a5c1990 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/generic_events.py +++ b/osprey_worker/src/osprey/worker/lib/utils/generic_events.py @@ -1,5 +1,5 @@ import json -from typing import Any, Dict, Optional +from typing import Any from google.cloud import pubsub_v1 @@ -7,10 +7,10 @@ DEFAULT_PUBLISHER_CLIENT = pubsub_v1.PublisherClient() def publish_generic_event( - event: Dict[str, Any], + event: dict[str, Any], env: str, topic: str = 'projects/osprey-data-{}/topics/generic-events', - client: Optional[pubsub_v1.PublisherClient] = None, + client: pubsub_v1.PublisherClient | None = None, ) -> pubsub_v1.publisher.futures.Future: client = client or DEFAULT_PUBLISHER_CLIENT env_to_project_mapping = {'staging': 'stg', 'production': 'prd'} diff --git a/osprey_worker/src/osprey/worker/lib/utils/grpc_client_pool.py b/osprey_worker/src/osprey/worker/lib/utils/grpc_client_pool.py index da49b6c..c093940 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/grpc_client_pool.py +++ b/osprey_worker/src/osprey/worker/lib/utils/grpc_client_pool.py @@ -1,5 +1,6 @@ import itertools -from typing import Callable, Generic, TypeVar +from collections.abc import Callable +from typing import Generic, TypeVar T = TypeVar('T') diff --git a/osprey_worker/src/osprey/worker/lib/utils/request_utils.py b/osprey_worker/src/osprey/worker/lib/utils/request_utils.py index ebe7cbd..949b24e 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/request_utils.py +++ b/osprey_worker/src/osprey/worker/lib/utils/request_utils.py @@ -3,7 +3,8 @@ from __future__ import annotations import logging import random import time -from typing import Callable, Optional, Tuple, Type +from collections.abc import Callable +from typing import Type import requests from requests.exceptions import ConnectionError, ReadTimeout @@ -15,7 +16,7 @@ logger = logging.getLogger(__name__) class SessionWithRetries: def __init__( self, - exceptions: Tuple[Type[Exception], ...] = (ConnectionError, ReadTimeout), + exceptions: tuple[Type[Exception], ...] = (ConnectionError, ReadTimeout), min_delay: float = 0.1, max_delay: float = 2, jitter: bool = True, @@ -23,7 +24,7 @@ class SessionWithRetries: version: str = 'unknown', environment: str = 'unknown', raise_for_status: bool = False, - predicate: Optional[Callable[[Exception], bool]] = None, + predicate: Callable[[Exception], bool] | None = None, pool_connections: int = requests.adapters.DEFAULT_POOLSIZE, pool_maxsize: int = requests.adapters.DEFAULT_POOLSIZE, connection_retries: int = requests.adapters.DEFAULT_RETRIES, diff --git a/osprey_worker/src/osprey/worker/lib/utils/trace.py b/osprey_worker/src/osprey/worker/lib/utils/trace.py index 12655ef..bfa6692 100644 --- a/osprey_worker/src/osprey/worker/lib/utils/trace.py +++ b/osprey_worker/src/osprey/worker/lib/utils/trace.py @@ -1,13 +1,13 @@ import gc +from collections.abc import Sequence from dataclasses import dataclass, field from time import time -from typing import Dict, List, Optional, Sequence from osprey.worker.lib.instruments import metrics from typing_extensions import Literal PhaseType = Literal['start', 'stop'] -InfoType = Dict[str, int] +InfoType = dict[str, int] # these names reflect those collected by ddtrace _STAT_PREFIX = 'runtime.python.gc' @@ -24,8 +24,8 @@ class GCMetrics: This is probably very expensive and should only run on select nodes at a time. """ - last_gc_start_ms: Optional[int] = None # TODO: confirm that statd requires integers - tags: List[str] = field(default_factory=list) + last_gc_start_ms: int | None = None # TODO: confirm that statd requires integers + tags: list[str] = field(default_factory=list) def configure(self, service_name: str = '', extra_tags: Sequence[str] = ()) -> None: self.tags.extend(extra_tags) diff --git a/osprey_worker/src/osprey/worker/sinks/sink/base_sink.py b/osprey_worker/src/osprey/worker/sinks/sink/base_sink.py index bcfeb82..35da61f 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/base_sink.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/base_sink.py @@ -1,7 +1,8 @@ import abc import logging +from collections.abc import Callable from concurrent.futures import ProcessPoolExecutor -from typing import Any, Callable, Dict, List, Optional +from typing import Any import gevent @@ -31,7 +32,7 @@ class PooledSink(BaseSink): def __init__(self, factory: Callable[[], BaseSink], num_workers: int): self._num_workers = num_workers self._factory = factory - self._children_sinks: List[BaseSink] = [] # set, never append + self._children_sinks: list[BaseSink] = [] # set, never append def run(self) -> None: self._children_sinks = [self._factory() for _ in range(self._num_workers)] @@ -57,12 +58,12 @@ class ProcessPoolSink(BaseSink): self, factory: Callable[..., BaseSink], num_workers: int, - args: Optional[Dict[str, Any]] = None, + args: dict[str, Any] | None = None, ): self._num_workers = num_workers self._factory = factory self._args = args if args is not None else {} - self._executor: Optional[ProcessPoolExecutor] = None + self._executor: ProcessPoolExecutor | None = None def run(self) -> None: """Run the sink workers in a process pool.""" @@ -80,7 +81,7 @@ class ProcessPoolSink(BaseSink): self._executor = None @staticmethod - def _run_sink(factory: Callable[..., BaseSink], args: Dict[str, Any]) -> None: + def _run_sink(factory: Callable[..., BaseSink], args: dict[str, Any]) -> None: try: sink = factory(**args) # Instantiate the sink within the worker sink.run() diff --git a/osprey_worker/src/osprey/worker/sinks/sink/bulk_label_sink.py b/osprey_worker/src/osprey/worker/sinks/sink/bulk_label_sink.py index a90386f..fcd2e16 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/bulk_label_sink.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/bulk_label_sink.py @@ -1,6 +1,7 @@ import time +from collections.abc import Iterable from datetime import datetime, timedelta -from typing import Any, Iterable, List, Optional, Set +from typing import Any import sentry_sdk from osprey.engine.language_types.entities import EntityT @@ -110,7 +111,7 @@ class BulkLabelSink(BaseSink): tags.append(f'prev_status:{task.task_status}') metrics.increment('handled_message', tags=tags) - def _build_top_n_queries(self, task: BulkLabelTask) -> List[TopNDruidQuery]: + def _build_top_n_queries(self, task: BulkLabelTask) -> list[TopNDruidQuery]: """ Returns a list of `TopNDruidQuery`s. These are separated based on smaller time intervals if the task is set to `no_limit`, @@ -120,7 +121,7 @@ class BulkLabelSink(BaseSink): assert isinstance(task.query, dict) query = task.query.copy() query['dimension'] = task.dimension - queries: List[TopNDruidQuery] = [] + queries: list[TopNDruidQuery] = [] query['limit'] = BULK_LABEL_DEFAULT_LIMIT claim_until_seconds = DEFAULT_BULK_LABEL_COLLECTING_HEARTBEAT @@ -155,7 +156,7 @@ class BulkLabelSink(BaseSink): return queries - def _collect_entity_ids(self, task: BulkLabelTask) -> Set[str]: + def _collect_entity_ids(self, task: BulkLabelTask) -> set[str]: def _execute_top_n_query_and_get_result(query: TopNDruidQuery) -> Any: try: query_data: TopNPoPResponse = query.execute( @@ -171,7 +172,7 @@ class BulkLabelSink(BaseSink): return query_data['result'] # Fall back to parsing logic if direct access fails - current_raw_data: List[PeriodData] = query_data.current_period + current_raw_data: list[PeriodData] = query_data.current_period if not current_raw_data: return dict() current_period = PeriodData.parse_obj(current_raw_data[0]).dict(exclude={'timestamp'}) @@ -221,7 +222,7 @@ class BulkLabelSink(BaseSink): assert task.excluded_entities is not None queries = self._build_top_n_queries(task) total_num_queries = len(queries) - entity_ids: Set[str] = set() + entity_ids: set[str] = set() excluded_ids = set(task.excluded_entities) query_timeout = ( DEFAULT_BULK_LABEL_DRUID_QUERY_TIMEOUT if not task.no_limit else NO_LIMIT_BULK_LABEL_DRUID_QUERY_TIMEOUT @@ -264,7 +265,7 @@ class BulkLabelSink(BaseSink): def _process_task(self, task: BulkLabelTask) -> None: logger.info(f'[task_id:{task.id}] Starting bulk label task') - entity_ids: Set[str] = self._collect_entity_ids(task) + entity_ids: set[str] = self._collect_entity_ids(task) # https://docs.sqlalchemy.org/en/14/orm/extensions/mypy.html#introspection-of-columns-based-on-typeengine assert task.expected_total_entities_to_label is not None assert task.excluded_entities is not None @@ -387,7 +388,7 @@ class BulkLabelSink(BaseSink): analytics_publisher: BasePublisher, webhooks_publisher: BasePublisher, task: BulkLabelTask, - include_ids: Optional[Set[str]] = None, + include_ids: set[str] | None = None, ) -> None: assert isinstance(task.query, dict) assert isinstance(task.label_reason, str) @@ -409,7 +410,7 @@ class BulkLabelSink(BaseSink): print('[~] Re-running druid TopN Query') res: TopNPoPResponse = TopNDruidQuery(**task.query).execute(calculate_previous_period=False) - current_raw_data: List[PeriodData] = res.current_period + current_raw_data: list[PeriodData] = res.current_period current_period = PeriodData.parse_obj(current_raw_data[0]).dict(exclude={'timestamp'}) results = current_period.get('result', []) print(f'[!] Found {len(results)} entities to attempt rollback on.') diff --git a/osprey_worker/src/osprey/worker/sinks/sink/input_stream.py b/osprey_worker/src/osprey/worker/sinks/sink/input_stream.py index 55255c1..340e797 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/input_stream.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/input_stream.py @@ -2,8 +2,9 @@ import abc import inspect import json from collections import deque +from collections.abc import Iterator, Sequence from datetime import datetime, timezone -from typing import TYPE_CHECKING, Generic, Iterator, List, Optional, Sequence, Type, TypeVar, Union, cast +from typing import TYPE_CHECKING, Generic, Type, TypeVar, cast import gevent import msgpack @@ -50,7 +51,7 @@ class BaseInputStream(abc.ABC, Generic[_T]): def __init__(self) -> None: super().__init__() - self._iterator: Optional[Iterator[_T]] = None + self._iterator: Iterator[_T] | None = None self._iterator_lock = RLock() @abc.abstractmethod @@ -93,20 +94,18 @@ class StaticInputStream(BaseInputStream[_T]): class StaticMessagesInputStream( - BaseInputStream[Union[NoopAckingContext[Action], PullPubSubMessageContext[List[_PydanticModelT]]]] + BaseInputStream[NoopAckingContext[Action] | PullPubSubMessageContext[list[_PydanticModelT]]] ): """An input stream that will return a static list of contexts, until exhausted. This should only be used in tests to mock a stream of message contexts. """ - def __init__( - self, contexts: Sequence[Union[NoopAckingContext[Action], PullPubSubMessageContext[List[_PydanticModelT]]]] - ): + def __init__(self, contexts: Sequence[NoopAckingContext[Action] | PullPubSubMessageContext[list[_PydanticModelT]]]): super().__init__() self._contexts = list(contexts) - def _gen(self) -> Iterator[Union[NoopAckingContext[Action], PullPubSubMessageContext[List[_PydanticModelT]]]]: + def _gen(self) -> Iterator[NoopAckingContext[Action] | PullPubSubMessageContext[list[_PydanticModelT]]]: return iter(self._contexts) @@ -127,7 +126,7 @@ class BasePubSubInputStream(BaseInputStream[_T]): self.subscription_path = subscription_path self.max_messages = max_messages - def _pull(self, max_messages: Optional[int] = None) -> 'PullResponse': + def _pull(self, max_messages: int | None = None) -> 'PullResponse': max_messages_to_pull = max_messages if max_messages is not None else self.max_messages with metrics.timed('pubsub_consumer.poll_time', tags=[f'subscription_path:{self.subscription_path}']): return self.subscriber.pull( @@ -262,7 +261,7 @@ class SynchronousPubSubMultiProtoInputStream(BasePubSubInputStream[PullPubSubMes self, subscriber: SubscriberClient, subscription_path: str, - proto_message_classes: List[Type[ProtoMessage]], + proto_message_classes: list[Type[ProtoMessage]], max_messages: int = 250, ): super().__init__(subscriber, subscription_path, max_messages) @@ -320,7 +319,7 @@ class RawPubSubInputStream(BasePubSubInputStream[PullPubSubMessageContext[Pubsub ) -class PubSubBulkInputStream(BasePubSubInputStream[PullPubSubMessageContext[List[_PydanticModelT]]]): +class PubSubBulkInputStream(BasePubSubInputStream[PullPubSubMessageContext[list[_PydanticModelT]]]): def __init__( self, subscriber: SubscriberClient, subscription_path: str, model: Type[_PydanticModelT], bulk_size: int ): @@ -328,7 +327,7 @@ class PubSubBulkInputStream(BasePubSubInputStream[PullPubSubMessageContext[List[ self._model = model self._bulk_size = bulk_size - def _gen(self) -> Iterator[PullPubSubMessageContext[List[_PydanticModelT]]]: + def _gen(self) -> Iterator[PullPubSubMessageContext[list[_PydanticModelT]]]: with self.subscriber as subscriber: while True: try: @@ -337,8 +336,8 @@ class PubSubBulkInputStream(BasePubSubInputStream[PullPubSubMessageContext[List[ logger.debug(f'No messages received for subscription {self.subscription_path}') continue - messages: List[_PydanticModelT] = [] - ack_ids: List[str] = [] + messages: list[_PydanticModelT] = [] + ack_ids: list[str] = [] for received_message in response.received_messages: message = received_message.message @@ -367,7 +366,7 @@ _ModelT = TypeVar('_ModelT', bound=Model, covariant=True) class _ClaimableModel(Protocol[_ModelT]): @classmethod - def claim(cls) -> Optional[_ModelT]: ... + def claim(cls) -> _ModelT | None: ... class PostgresInputStream(BaseInputStream[_ModelT]): @@ -397,7 +396,7 @@ class PostgresInputStream(BaseInputStream[_ModelT]): before_sleep=_before_sleep, before=_log_before_attempt, ) - def claim_with_retry() -> Optional[_ModelT]: + def claim_with_retry() -> _ModelT | None: with metrics.timed('claim_postgres_row', tags=self._tags): return self._model.claim() diff --git a/osprey_worker/src/osprey/worker/sinks/sink/osprey_coordinator_input_stream.py b/osprey_worker/src/osprey/worker/sinks/sink/osprey_coordinator_input_stream.py index 5aab4d1..0b737f1 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/osprey_coordinator_input_stream.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/osprey_coordinator_input_stream.py @@ -1,8 +1,9 @@ import json import random import time +from collections.abc import Iterator from queue import SimpleQueue as Queue -from typing import Any, Dict, Iterator, Optional, Tuple +from typing import Any import grpc import pytz @@ -43,7 +44,7 @@ class GrpcConnectionDiscoveryPool: self._service_name = service_name directory = Directory.instance(secure=False) - self._grpc_channels: Dict[Service, Tuple[grpc.Channel, Service]] = { + self._grpc_channels: dict[Service, tuple[grpc.Channel, Service]] = { service: (GrpcConnectionDiscoveryPool._create_insecure_channel(service), service) for service in directory.select_all(self._service_name) } @@ -67,7 +68,7 @@ class GrpcConnectionDiscoveryPool: if self._grpc_channels.get(service): del self._grpc_channels[service] - def get_connection(self) -> Tuple[grpc.Channel, Service]: + def get_connection(self) -> tuple[grpc.Channel, Service]: """ Gets a GRPC connection to a service. @@ -107,7 +108,7 @@ class OspreyCoordinatorBiDirectionalStream(BaseInputStream[OspreyCoordinatorActi # but leaving the old connection open. self._incoming_stream = osprey_coordinator_stub.OspreyBidirectionalStream(streaming_iterator, timeout=None) self._tags = [f'coordinator_connection_address:{service.connection_address}'] - self._connect_time: Optional[float] = None + self._connect_time: float | None = None def _send(self, request: Request) -> None: self._outgoing_request_queue.put(request) @@ -118,7 +119,7 @@ class OspreyCoordinatorBiDirectionalStream(BaseInputStream[OspreyCoordinatorActi # so we just enqueue it here as a quick hack self._outgoing_request_queue.put(OspreyCoordinatorBiDirectionalStream._STOP_STREAMING_SIGNAL) # type: ignore - def send_graceful_disconnect(self, ack_id: int, ack: bool = True, verdicts: Optional[Verdicts] = None) -> None: + def send_graceful_disconnect(self, ack_id: int, ack: bool = True, verdicts: Verdicts | None = None) -> None: ack_or_nack = ( AckOrNack(ack_id=ack_id, ack=Ack(verdicts=verdicts if verdicts else None)) if ack @@ -129,7 +130,7 @@ class OspreyCoordinatorBiDirectionalStream(BaseInputStream[OspreyCoordinatorActi self._outgoing_request_queue.put(Request(disconnect=Disconnect(ack_or_nack=ack_or_nack))) self._enqueue_stop_stream_signal() - def send_ack_or_nack(self, ack_id: int, ack: bool = True, verdicts: Optional[Verdicts] = None) -> None: + def send_ack_or_nack(self, ack_id: int, ack: bool = True, verdicts: Verdicts | None = None) -> None: ack_or_nack = ( AckOrNack(ack_id=ack_id, ack=Ack(verdicts=verdicts if verdicts else None)) if ack @@ -190,7 +191,7 @@ class OspreyCoordinatorInputStream(BaseInputStream[BaseAckingContext[OspreyEngin def __init__( self, client_id: str, - input_stream_ready_signaler: Optional[InputStreamReadySignaler] = None, + input_stream_ready_signaler: InputStreamReadySignaler | None = None, coordinator_service_name: str = 'osprey_coordinator', ) -> None: super().__init__() @@ -200,7 +201,7 @@ class OspreyCoordinatorInputStream(BaseInputStream[BaseAckingContext[OspreyEngin self._channel_pool = GrpcConnectionDiscoveryPool(coordinator_service_name) self._client_id = client_id self._input_stream_ready_signaler = input_stream_ready_signaler - self._current_execution_result: Optional[ExecutionResult] = None + self._current_execution_result: ExecutionResult | None = None def stop(self) -> None: if self._soft_shutdown_signal_received: @@ -213,11 +214,11 @@ class OspreyCoordinatorInputStream(BaseInputStream[BaseAckingContext[OspreyEngin def _create_osprey_engine_action( self, osprey_coordinator_action: OspreyCoordinatorAction - ) -> Optional[OspreyEngineAction]: + ) -> OspreyEngineAction | None: try: tags = [f'action_name:{osprey_coordinator_action.action_name}'] - secret_data: Dict[str, Any] = {} + secret_data: dict[str, Any] = {} which_of_action_data = osprey_coordinator_action.WhichOneof('action_data') if which_of_action_data == 'json_action_data': info_log_osprey_action( diff --git a/osprey_worker/src/osprey/worker/sinks/sink/output_sink.py b/osprey_worker/src/osprey/worker/sinks/sink/output_sink.py index bddc0ed..bdc97c7 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/output_sink.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/output_sink.py @@ -1,7 +1,8 @@ import abc from collections import defaultdict +from collections.abc import Callable, Mapping, Sequence from datetime import datetime -from typing import Any, Callable, DefaultDict, Dict, Mapping, Optional, Sequence +from typing import Any import gevent import sentry_sdk @@ -90,7 +91,7 @@ class MultiOutputSink(BaseOutputSink): return push_with_retry def push(self, result: ExecutionResult) -> None: - errors: Dict[BaseOutputSink, BaseException] = {} + errors: dict[BaseOutputSink, BaseException] = {} for sink in self._sinks: if sink.will_do_work(result): @@ -122,7 +123,7 @@ class MultiOutputSink(BaseOutputSink): class StdoutOutputSink(BaseOutputSink): """An output sink that prints to standard out!""" - def __init__(self, log_sampler: Optional[DynamicLogSampler] = None): + def __init__(self, log_sampler: DynamicLogSampler | None = None): self.logger = get_logger('StdoutOutputSink', log_sampler) def will_do_work(self, result: ExecutionResult) -> bool: @@ -135,9 +136,7 @@ class StdoutOutputSink(BaseOutputSink): pass -def _create_entity_mutation( - label_effect: LabelEffect, rule: RuleT, expires_at: Optional[datetime] -) -> EntityLabelMutation: +def _create_entity_mutation(label_effect: LabelEffect, rule: RuleT, expires_at: datetime | None) -> EntityLabelMutation: return EntityLabelMutation( label_name=label_effect.name, reason_name=rule.name, @@ -149,7 +148,7 @@ def _create_entity_mutation( def _get_label_effects_from_result(result: ExecutionResult) -> Mapping[EntityT[Any], list[EntityLabelMutation]]: - effects: DefaultDict[EntityT[Any], list[EntityLabelMutation]] = defaultdict(list) + effects: defaultdict[EntityT[Any], list[EntityLabelMutation]] = defaultdict(list) for label_effect in result.effects.get(LabelEffect, []): # assert for typing diff --git a/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/helpers.py b/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/helpers.py index b410c4e..4db7849 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/helpers.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/helpers.py @@ -1,18 +1,18 @@ -from typing import Any, Dict, Optional +from typing import Any from osprey.worker.sinks.sink.output_sink_utils.constants import EntityType USER_ID_FEATURE_NAME = 'UserId' # assuming that if userid exists, it's in feature called 'UserId' -def get_user_id(entity_id: str, entity_type: str) -> Optional[int]: +def get_user_id(entity_id: str, entity_type: str) -> int | None: return int(entity_id) if entity_type == EntityType.USER else None -def get_guild_id(entity_id: str, entity_type: str) -> Optional[int]: +def get_guild_id(entity_id: str, entity_type: str) -> int | None: return int(entity_id) if entity_type == EntityType.GUILD else None -def get_user_id_from_extracted_features(extracted_features: Dict[str, Any]) -> Optional[int]: +def get_user_id_from_extracted_features(extracted_features: dict[str, Any]) -> int | None: user_id = extracted_features.get(USER_ID_FEATURE_NAME) return int(user_id) if (user_id and user_id.isnumeric()) else None diff --git a/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/models.py b/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/models.py index dc24bf4..eb42372 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/models.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/output_sink_utils/models.py @@ -1,5 +1,3 @@ -from typing import List, Optional - from pydantic import BaseModel from .constants import OspreyAnalyticsEvents @@ -13,13 +11,13 @@ class OspreyBulkJobAnalyticsEvent(BaseModel): label_name: str label_reason: str no_limit: bool - expiration_date: Optional[str] + expiration_date: str | None class OspreyRulesVisualizerGenGraphAnalyticsEvent(BaseModel): name: str = 'event' event_type: str = OspreyAnalyticsEvents.RULES_VISUALIZER_GEN_GRAPH - source_features: List[str] + source_features: list[str] path: str request_method: str timestamp: str diff --git a/osprey_worker/src/osprey/worker/sinks/sink/rules_sink.py b/osprey_worker/src/osprey/worker/sinks/sink/rules_sink.py index bf5ca89..ab1b466 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/rules_sink.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/rules_sink.py @@ -2,7 +2,6 @@ import logging import os from dataclasses import dataclass from random import randint -from typing import Optional import gevent import sentry_sdk @@ -85,8 +84,8 @@ class RulesRunner: self._udf_helpers = udf_helpers def classify_one( - self, action: Action, tag: str, parent_tracer_span: Optional[TracerSpan] = None - ) -> Optional[ExecutionResult]: + self, action: Action, tag: str, parent_tracer_span: TracerSpan | None = None + ) -> ExecutionResult | None: sample_config = self._sampler.sample(action) tags = [ tag, @@ -99,7 +98,7 @@ class RulesRunner: if sample_config.drop: metrics.increment('dropped_message', tags=tags) return None - result: Optional[ExecutionResult] = None + result: ExecutionResult | None = None # noinspection PyBroadException try: with metrics.timed('handled_message', tags=tags, use_ms=True): diff --git a/osprey_worker/src/osprey/worker/sinks/sink/tests/test_bulk_label_sink.py b/osprey_worker/src/osprey/worker/sinks/sink/tests/test_bulk_label_sink.py index c0f19c4..adf2ab3 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/tests/test_bulk_label_sink.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/tests/test_bulk_label_sink.py @@ -1,6 +1,6 @@ +from collections.abc import Sequence from dataclasses import dataclass from datetime import datetime -from typing import Dict, List, Optional, Sequence from unittest.mock import MagicMock, call import pytest @@ -25,7 +25,7 @@ from pytest_mock import MockFixture from ..input_stream import StaticInputStream # Druid might also return null/empty values, we need to make sure we handle those in our sink. -_TASK_NULLISH_ENTITIES: List[Dict[str, Optional[str]]] = [{'UserId': None}, {'UserId': ''}] +_TASK_NULLISH_ENTITIES: list[dict[str, str | None]] = [{'UserId': None}, {'UserId': ''}] _TASK_TOTAL_VALID_ENTITIES = 10 _TASK_TOTAL_ENTITIES_RETURNED = _TASK_TOTAL_VALID_ENTITIES + len(_TASK_NULLISH_ENTITIES) @@ -33,7 +33,7 @@ _TASK_TOTAL_ENTITIES_RETURNED = _TASK_TOTAL_VALID_ENTITIES + len(_TASK_NULLISH_E @pytest.fixture(autouse=True) def mock_top_n_druid_query(mocker: MockFixture) -> None: execute = mocker.patch('osprey.worker.sinks.sink.bulk_label_sink.TopNDruidQuery.execute') - fake_result: List[Dict[str, Optional[str]]] = [{'UserId': str(x)} for x in range(_TASK_TOTAL_VALID_ENTITIES)] + fake_result: list[dict[str, str | None]] = [{'UserId': str(x)} for x in range(_TASK_TOTAL_VALID_ENTITIES)] fake_result += _TASK_NULLISH_ENTITIES execute.return_value = ({'result': fake_result},) diff --git a/osprey_worker/src/osprey/worker/sinks/sink/tests/test_input_stream.py b/osprey_worker/src/osprey/worker/sinks/sink/tests/test_input_stream.py index df32f66..2150397 100644 --- a/osprey_worker/src/osprey/worker/sinks/sink/tests/test_input_stream.py +++ b/osprey_worker/src/osprey/worker/sinks/sink/tests/test_input_stream.py @@ -1,4 +1,4 @@ -from typing import Iterator, List +from collections.abc import Iterator import gevent import gevent.event @@ -6,7 +6,7 @@ from osprey.worker.sinks.sink.input_stream import BaseInputStream def test_does_not_lock_non_generator_iterator() -> None: - waiting_events: List[gevent.event.Event] = [] + waiting_events: list[gevent.event.Event] = [] class MyIterator(Iterator[int]): def __init__(self) -> None: @@ -46,7 +46,7 @@ def test_does_not_lock_non_generator_iterator() -> None: def test_does_lock_generator_iterator() -> None: - waiting_events: List[gevent.event.Event] = [] + waiting_events: list[gevent.event.Event] = [] class GeneratorStream(BaseInputStream[int]): def _gen(self) -> Iterator[int]: diff --git a/osprey_worker/src/osprey/worker/sinks/utils/acking_contexts.py b/osprey_worker/src/osprey/worker/sinks/utils/acking_contexts.py index 80d68df..5a5029d 100644 --- a/osprey_worker/src/osprey/worker/sinks/utils/acking_contexts.py +++ b/osprey_worker/src/osprey/worker/sinks/utils/acking_contexts.py @@ -1,6 +1,6 @@ from datetime import datetime from types import TracebackType -from typing import Dict, List, Optional, Type, TypeVar, Union +from typing import Type, TypeVar import gevent from google.api_core.exceptions import DeadlineExceeded @@ -52,22 +52,22 @@ class PullPubSubMessageContext(BaseAckingContext[_T]): item: _T, subscriber: SubscriberClient, subscription_path: str, - ack_ids: List[str], - publish_time: Optional[datetime] = None, - attributes: Optional[Dict[str, str]] = None, + ack_ids: list[str], + publish_time: datetime | None = None, + attributes: dict[str, str] | None = None, ): super().__init__(item) self._subscriber = subscriber self._subscription_path = subscription_path self._original_ack_ids = ack_ids # True to ACK, False to NACK. Defaults to ACK all. - self._ack_statuses: Dict[str, bool] = {ack_id: True for ack_id in ack_ids} + self._ack_statuses: dict[str, bool] = {ack_id: True for ack_id in ack_ids} self._timeout = 1.5 self._publish_time = publish_time if publish_time else datetime.now() self._attributes = attributes @property - def original_ack_ids(self) -> List[str]: + def original_ack_ids(self) -> list[str]: return self._original_ack_ids def mark_ack_id_for_nack(self, ack_id_to_nack: str) -> None: @@ -80,9 +80,9 @@ class PullPubSubMessageContext(BaseAckingContext[_T]): def __exit__( self, - exc_type: Union[Type[BaseException], None], - exc_value: Union[BaseException, None], - exc_traceback: Union[TracebackType, None], + exc_type: Type[BaseException] | None, + exc_value: BaseException | None, + exc_traceback: TracebackType | None, ) -> None: # if exc_type is not None: # logger.error(f'Exception in PullPubSubMessageContext, NACKing all messages: {exc_value}') diff --git a/osprey_worker/src/osprey/worker/sinks/utils/bulk_actions.py b/osprey_worker/src/osprey/worker/sinks/utils/bulk_actions.py index 482fb89..ba354f8 100644 --- a/osprey_worker/src/osprey/worker/sinks/utils/bulk_actions.py +++ b/osprey_worker/src/osprey/worker/sinks/utils/bulk_actions.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import List from osprey.engine.executor.execution_context import Action from osprey.engine.utils.types import add_slots @@ -8,4 +7,4 @@ from osprey.engine.utils.types import add_slots @add_slots @dataclass class BulkActions: - actions: List[Action] + actions: list[Action] diff --git a/osprey_worker/src/osprey/worker/sinks/utils/gevent.py b/osprey_worker/src/osprey/worker/sinks/utils/gevent.py index 08a3825..9068e7d 100644 --- a/osprey_worker/src/osprey/worker/sinks/utils/gevent.py +++ b/osprey_worker/src/osprey/worker/sinks/utils/gevent.py @@ -1,5 +1,3 @@ -from typing import Optional - from gevent import sleep from gevent.lock import RLock @@ -10,7 +8,7 @@ class FairRLock(RLock): # type: ignore the lock to re-acquire it, even if there is another greenlet waiting to acquire the lock, thus starving all other lockers.""" - def acquire(self, blocking: bool = True, timeout: Optional[float] = None) -> bool: + def acquire(self, blocking: bool = True, timeout: float | None = None) -> bool: if blocking and not self._block.locked() and self._block.linkcount(): sleep(0) diff --git a/osprey_worker/src/osprey/worker/stress/consumer.py b/osprey_worker/src/osprey/worker/stress/consumer.py index fe8439e..0fa636f 100644 --- a/osprey_worker/src/osprey/worker/stress/consumer.py +++ b/osprey_worker/src/osprey/worker/stress/consumer.py @@ -16,7 +16,6 @@ import json import threading import time from dataclasses import dataclass -from typing import Optional from kafka import KafkaConsumer @@ -27,7 +26,7 @@ class ConsumerConfig: topic: str group_id: str # If set, only record action_ids in this set. None = open-loop, count all. - action_id_filter: Optional[frozenset[int]] = None + action_id_filter: frozenset[int] | None = None # Max wall-clock time to keep reading after start() is called. max_runtime_seconds: float = 60.0 # If we've matched every id in action_id_filter, stop early. @@ -46,15 +45,15 @@ class Consumer: self._consumer_factory = consumer_factory self._consumed: dict[int, float] = {} self._stop_event = threading.Event() - self._thread: Optional[threading.Thread] = None - self._error: Optional[BaseException] = None + self._thread: threading.Thread | None = None + self._error: BaseException | None = None @property def consumed(self) -> dict[int, float]: return dict(self._consumed) @property - def error(self) -> Optional[BaseException]: + def error(self) -> BaseException | None: return self._error def start(self) -> None: @@ -66,7 +65,7 @@ class Consumer: def stop(self) -> None: self._stop_event.set() - def wait(self, timeout: Optional[float] = None) -> None: + def wait(self, timeout: float | None = None) -> None: if self._thread is None: return self._thread.join(timeout=timeout) diff --git a/osprey_worker/src/osprey/worker/stress/tests/test_consumer.py b/osprey_worker/src/osprey/worker/stress/tests/test_consumer.py index eb7b422..6fe2da7 100644 --- a/osprey_worker/src/osprey/worker/stress/tests/test_consumer.py +++ b/osprey_worker/src/osprey/worker/stress/tests/test_consumer.py @@ -1,7 +1,8 @@ import json import threading import time -from typing import Any, Iterator, List +from collections.abc import Iterator +from typing import Any from osprey.worker.stress.consumer import Consumer, ConsumerConfig @@ -27,7 +28,7 @@ class FakeKafkaConsumer: def __init__(self, *args: Any, **kwargs: Any) -> None: self._lock = threading.Lock() - self._queue: List[FakeMessage] = [] + self._queue: list[FakeMessage] = [] self._has_message = threading.Event() self.kwargs = kwargs self.close_called = False diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/app.py b/osprey_worker/src/osprey/worker/ui_api/osprey/app.py index 2586df2..407462f 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/app.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/app.py @@ -9,7 +9,7 @@ from werkzeug.exceptions import HTTPException ddtrace.patch_all(gevent=True) from http import HTTPStatus -from typing import NoReturn, Tuple, Union +from typing import NoReturn import sentry_sdk from flask import Flask, Response @@ -40,7 +40,7 @@ def _register_with_prefix(app, blueprint): app.register_blueprint(blueprint, url_prefix='/api') -def health() -> Union[str, Tuple[str, int]]: +def health() -> str | tuple[str, int]: # TODO: Real health reporting healthy = True if not healthy: diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/cli.py b/osprey_worker/src/osprey/worker/ui_api/osprey/cli.py index 60b4274..9f961f0 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/cli.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/cli.py @@ -5,7 +5,7 @@ patch_all() # please ensure this occurs before *any* other imports ! import os # noqa: E402 from datetime import datetime, timedelta -from typing import Dict, Optional, TextIO +from typing import TextIO import click # noqa: E402 import simplejson as json @@ -46,8 +46,8 @@ def export_all_actions( start: datetime, end: datetime, output: TextIO, - action_name: Optional[str], - query_filter: Optional[str], + action_name: str | None, + query_filter: str | None, ) -> None: """ Queries druid for ids that match a given query or action name within a date range (default is last 24 hours). @@ -72,13 +72,13 @@ def export_all_actions( if action_name: query_filter = f'ActionName == "{action_name}"' - def query_druid(next_page: Optional[str] = None) -> PaginatedScanResult: + def query_druid(next_page: str | None = None) -> PaginatedScanResult: assert query_filter is not None return PaginatedScanDruidQuery( start=start, end=end, query_filter=query_filter, next_page=next_page, entity=None ).execute() - def row(event: StoredExecutionResult) -> Dict[str, str]: + def row(event: StoredExecutionResult) -> dict[str, str]: d = event.dict() return {'id': d['id'], 'timestamp': d['timestamp'], 'action_data': d['action_data']} diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/conftest.py b/osprey_worker/src/osprey/worker/ui_api/osprey/conftest.py index 8216e01..0f3f50c 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/conftest.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/conftest.py @@ -11,7 +11,8 @@ patch_all(patch_gevent=False, patch_ddtrace=False) import os import textwrap -from typing import TYPE_CHECKING, Iterator +from collections.abc import Iterator +from typing import TYPE_CHECKING from unittest.mock import patch import pytest diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/abilities.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/abilities.py index ed1c471..e56fffd 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/abilities.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/abilities.py @@ -1,9 +1,10 @@ from __future__ import annotations from abc import ABC, abstractmethod +from collections.abc import Callable from dataclasses import asdict from functools import wraps -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Generic, Optional, Set, Type, TypeVar, Union +from typing import TYPE_CHECKING, Any, ClassVar, Generic, Type, TypeVar from flask import abort from osprey.worker.ui_api.osprey.lib.druid import BaseDruidQuery @@ -26,7 +27,7 @@ class AbilityRegistry: sets `ability.class_name` on registration """ - registry: Dict[str, Type[Ability[Any, Any]]] = {} + registry: dict[str, Type[Ability[Any, Any]]] = {} def register(self, name: str) -> Callable[[Type[AbilityT]], Type[AbilityT]]: def inner_wrapper(wrapped_class: Type[AbilityT]) -> Type[AbilityT]: @@ -66,7 +67,7 @@ class HashableEntityKey(ExplicitHash): ModelT = TypeVar('ModelT', bound=BaseModel) -ItemT = TypeVar('ItemT', bound=Union[int, str, ExplicitHash]) +ItemT = TypeVar('ItemT', bound=int | str | ExplicitHash) # Note: @@ -90,9 +91,9 @@ class Ability(ABC, GenericModel, Generic[ModelT, ItemT]): # - At least one of these 3 variables has to be present in any given Ability. Empty abilities are not allowed # - allow_specific and allow_all_except are sets so they cannot be empty if they are present # - allow_all cannot be false if it is present - allow_all: Optional[bool] = None - allow_specific: Optional[Set[ItemT]] = None - allow_all_except: Optional[Set[ItemT]] = None + allow_all: bool | None = None + allow_specific: set[ItemT] | None = None + allow_all_except: set[ItemT] | None = None class Config: allow_population_by_field_name = True @@ -117,9 +118,9 @@ class Ability(ABC, GenericModel, Generic[ModelT, ItemT]): @root_validator def ability_root_validator(cls, values: Any) -> Any: - allow_all_value: Optional[bool] = values.get('allow_all') - allow_all_except_value: Optional[Set[ItemT]] = values.get('allow_all_except') - allow_specific_value: Optional[Set[ItemT]] = values.get('allow_specific') + allow_all_value: bool | None = values.get('allow_all') + allow_all_except_value: set[ItemT] | None = values.get('allow_all_except') + allow_specific_value: set[ItemT] | None = values.get('allow_specific') if allow_all_value is None and allow_all_except_value is None and allow_specific_value is None: raise ValueError('`allow_all`, `allow_all_except`, and `allow_specific` cannot all be None') if allow_all_value is not None and allow_all_value is False: @@ -173,7 +174,7 @@ class QueryFilterAbility(Ability[ModelT, ItemT], Generic[ModelT, ItemT]): # The default query filter (None) # This method works on the query that is going to be sent to Druid. @abstractmethod - def _get_query_filter(self) -> Optional[Dict[str, Any]]: + def _get_query_filter(self) -> dict[str, Any] | None: raise NotImplementedError() @@ -184,7 +185,7 @@ Start DataCensorAbility classes @dataclass(unsafe_hash=True) class DictPath: - action_name: Optional[str] + action_name: str | None path: str is_star_path: bool # True if this path applies to everything @@ -289,8 +290,8 @@ class DataCensorAbility(Ability[ModelT, ItemT], Generic[ModelT, ItemT]): if TYPE_CHECKING: # Duplicate these type definitions from the superclass to work around a bug in the Pydantic mypy plugin: # https://github.com/samuelcolvin/pydantic/issues/2613 - allow_specific: Optional[Set[ItemT]] - allow_all_except: Optional[Set[ItemT]] + allow_specific: set[ItemT] | None + allow_all_except: set[ItemT] | None def _request_is_allowed(self, input_model: BaseModel) -> bool: return True @@ -307,8 +308,8 @@ class DataCensorAbility(Ability[ModelT, ItemT], Generic[ModelT, ItemT]): @classmethod def censor_all_leafs( - cls, data: Dict[str, Any], json_path_exceptions: Optional[Set[DictPath]] = None - ) -> Dict[str, Any]: + cls, data: dict[str, Any], json_path_exceptions: set[DictPath] | None = None + ) -> dict[str, Any]: """ This method censors all of `data`, excluding any paths in `json_path_exceptions` """ @@ -320,7 +321,7 @@ class DataCensorAbility(Ability[ModelT, ItemT], Generic[ModelT, ItemT]): return data @staticmethod - def censor_leafs(data: Dict[str, Any], field: str, json_path_exceptions: Optional[Set[DictPath]] = None) -> None: + def censor_leafs(data: dict[str, Any], field: str, json_path_exceptions: set[DictPath] | None = None) -> None: """ This method recursively censors all leaf values beneath data[field]. Any leafs with paths matching the `json_path_exceptions` are skipped (uncensored). @@ -335,8 +336,8 @@ class DataCensorAbility(Ability[ModelT, ItemT], Generic[ModelT, ItemT]): return def _recursively_censor_leafs( - node: Any, json_path_exceptions: Set[DictPath], current_path: DictPath - ) -> Optional[Any]: + node: Any, json_path_exceptions: set[DictPath], current_path: DictPath + ) -> Any | None: """ This method recursively censors all leaf values beneath the given `node`. Any leafs matching the `json_path_exceptions` will be skipped (uncensored). @@ -357,15 +358,15 @@ class DataCensorAbility(Ability[ModelT, ItemT], Generic[ModelT, ItemT]): start_path = DictPath(field) data[field] = _recursively_censor_leafs(data[field], json_path_exceptions, start_path) - def censor_data(self, data: Dict[str, Any], action_name: str) -> Dict[str, Any]: + def censor_data(self, data: dict[str, Any], action_name: str) -> dict[str, Any]: """ - A method that takes a Dict and outputs a censored version based on the + A method that takes a dict and outputs a censored version based on the ability's permissions/allowances. """ if self.allow_all_except: - def _censor_at_path(data: Dict[str, Any], path: DictPath) -> None: + def _censor_at_path(data: dict[str, Any], path: DictPath) -> None: """ Recursively censors all leaf values at the provided `path` """ @@ -451,7 +452,7 @@ def make_marker_ability() -> Type[Ability[_MarkerAbilityModel, _MarkerAbilityAll return True @root_validator(allow_reuse=True) - def root_validator(cls, values: Dict[str, object]) -> Dict[str, object]: + def root_validator(cls, values: dict[str, object]) -> dict[str, object]: assert values['allow_all'], f'Marker ability {values["name"]} must have `allow_all` set to `true`' return values @@ -500,7 +501,7 @@ class CanViewEventsByEntity(Ability[BaseDruidQuery, HashableEntityKey]): @register_ability('CAN_VIEW_EVENTS_BY_ACTION') class CanViewEventsByAction(QueryFilterAbility[BaseDruidQuery, str]): - def _get_query_filter(self) -> Optional[Dict[str, Any]]: + def _get_query_filter(self) -> dict[str, Any] | None: if self.allow_all: return None # if allow all is set, then we don't need to inject an acl filter into the query diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/auth.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/auth.py index 3b2cb7b..baa5568 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/auth.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/auth.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Dict - from flask import Flask, request from osprey.worker.lib.osprey_shared.logging import get_logger from osprey.worker.ui_api.osprey.lib.users import User @@ -13,12 +11,12 @@ def set_dummy_claim() -> None: set_claims({'email': request.headers.get('X-Test-Email', 'local-dev@localhost')}) -def set_claims(claims: Dict[object, object]) -> None: +def set_claims(claims: dict[object, object]) -> None: request.claims = claims # type: ignore[attr-defined] def get_current_user_email() -> str: - claims: Dict[object, object] = request.claims # type: ignore[attr-defined] + claims: dict[object, object] = request.claims # type: ignore[attr-defined] email = claims.get('email') assert isinstance(email, str), f'Could not get email from claims {claims!r}' return email diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid.py index c5b9c0f..a843e39 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid.py @@ -2,9 +2,10 @@ import base64 import json import logging import math +from collections.abc import Sequence from datetime import datetime, timedelta, timezone from enum import Enum -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union +from typing import TYPE_CHECKING, Any from osprey.engine.query_language import parse_query_to_validated_ast from osprey.engine.query_language.ast_druid_translator import DruidQueryTransformer @@ -39,16 +40,16 @@ class Ordering(str, Enum): class PaginatedScanResult(BaseModel): - action_ids: List[int] - next_page: Optional[str] + action_ids: list[int] + next_page: str | None class EntityFilter(BaseModel): id: str type: str - feature_filters: Optional[List[str]] + feature_filters: list[str] | None - def wrap_filter(self, query_filter: Optional[Dict[str, Any]]) -> Dict[str, Any]: + def wrap_filter(self, query_filter: dict[str, Any] | None) -> dict[str, Any]: feature_to_entity_mapping = ENGINE.instance().get_feature_name_to_entity_type_mapping() filters = ( feature_name @@ -71,15 +72,15 @@ class BaseDruidQuery(BaseModel, JsonBodyMarshaller): start: datetime end: datetime query_filter: str - entity: Optional[EntityFilter] + entity: EntityFilter | None def _query_with_filter( self, query_type: DruidQueryTypes, - start: Optional[datetime] = None, - end: Optional[datetime] = None, - order: Optional[Ordering] = None, - query_filter_abilities: Sequence[Optional['QueryFilterAbility[Any, Any]']] = (), + start: datetime | None = None, + end: datetime | None = None, + order: Ordering | None = None, + query_filter_abilities: Sequence['QueryFilterAbility[Any, Any]'] | None = (), **kwargs: Any, ) -> Any: transformed_filter = parse_query_filter(self.query_filter) @@ -146,7 +147,7 @@ class BaseDruidQuery(BaseModel, JsonBodyMarshaller): class TimeseriesDruidQuery(BaseDruidQuery): granularity: str - aggregation_dimensions: Optional[List[str]] = None + aggregation_dimensions: list[str] | None = None def execute(self) -> Any: aggregations = {'count': {'type': 'count'}} @@ -200,7 +201,7 @@ class DimensionData(BaseModel): class PeriodData(BaseModel): timestamp: datetime - result: List[DimensionData] + result: list[DimensionData] class DimensionDifference(BaseModel): @@ -212,13 +213,13 @@ class DimensionDifference(BaseModel): class ComparisonData(BaseModel): - differences: List[DimensionDifference] + differences: list[DimensionDifference] class TopNPoPResponse(BaseModel): - current_period: List[PeriodData] - previous_period: List[PeriodData] | None - comparison: List[ComparisonData] | None + current_period: list[PeriodData] + previous_period: list[PeriodData] | None + comparison: list[ComparisonData] | None class TopNDruidQuery(BaseDruidQuery): @@ -258,7 +259,7 @@ class TopNDruidQuery(BaseDruidQuery): return pop_results - def _sanitize_results(self, results: List[Dict[str, Any]]) -> List[PeriodData]: + def _sanitize_results(self, results: list[dict[str, Any]]) -> list[PeriodData]: """ Sanitizes raw Druid query results into PeriodData objects. @@ -266,7 +267,7 @@ class TopNDruidQuery(BaseDruidQuery): results: Raw results from Druid query containing timestamp and dimension results Returns: - List of PeriodData objects with properly formatted timestamps and dimension data + list of PeriodData objects with properly formatted timestamps and dimension data """ sanitized_results = [] for result in results: @@ -296,7 +297,7 @@ class TopNDruidQuery(BaseDruidQuery): return sanitized_results def _analyze_pop_results( - self, current_results: List[PeriodData], previous_results: List[PeriodData] + self, current_results: list[PeriodData], previous_results: list[PeriodData] ) -> TopNPoPResponse: # Extract the list of rows from the first (and only) element of each results list. current_data = current_results if current_results else [] @@ -348,8 +349,8 @@ class TopNDruidQuery(BaseDruidQuery): ) def _execute_single_period( - self, start: Optional[datetime] = None, end: Optional[datetime] = None, **kwargs: Any - ) -> List[Dict[str, Any]]: + self, start: datetime | None = None, end: datetime | None = None, **kwargs: Any + ) -> list[dict[str, Any]]: assert self.precision >= 0 and self.precision < 1, ( 'Precision specified was not valid; Must be a float between 0 and 1!' ) @@ -368,9 +369,9 @@ class TopNDruidQuery(BaseDruidQuery): **kwargs, ) - def _get_dimension_parameter(self) -> Union[str, Dict[str, Any]]: - dimension_type: Optional[str] = ENGINE.instance().get_feature_name_to_entity_type_mapping().get(self.dimension) - dimension_parameter: Union[str, Dict[str, Any]] = self.dimension + def _get_dimension_parameter(self) -> str | dict[str, Any]: + dimension_type: str | None = ENGINE.instance().get_feature_name_to_entity_type_mapping().get(self.dimension) + dimension_parameter: str | dict[str, Any] = self.dimension # If dimension is not a float type, return as-is if (dimension_type is not None and dimension_type.lower() != 'float') or self.precision == 0: @@ -406,14 +407,14 @@ class TopNDruidQuery(BaseDruidQuery): class PaginatedScanDruidQuery(BaseDruidQuery): limit: int = 100 - next_page: Optional[str] = None + next_page: str | None = None order: Ordering = Ordering.DESCENDING def execute( - self, query_filter_abilities: Sequence[Optional['QueryFilterAbility[Any, Any]']] = () + self, query_filter_abilities: Sequence['QueryFilterAbility[Any, Any]'] | None = () ) -> PaginatedScanResult: paginated_limit = self.limit + 1 - kwargs: Dict[str, Any] = {'resultFormat': 'compactedList'} + kwargs: dict[str, Any] = {'resultFormat': 'compactedList'} if self.next_page: date_in_milliseconds = int(base64.b64decode(self.next_page.encode('utf-8'))) @@ -438,7 +439,7 @@ class PaginatedScanDruidQuery(BaseDruidQuery): if not results: return PaginatedScanResult(action_ids=[], next_page=None) - events: List[Any] = [] + events: list[Any] = [] for result in results: events += result['events'] @@ -453,7 +454,7 @@ class PaginatedScanDruidQuery(BaseDruidQuery): return PaginatedScanResult(action_ids=action_ids, next_page=next_page) -def parse_query_filter(query_filter: str) -> Optional[Dict[str, Any]]: +def parse_query_filter(query_filter: str) -> dict[str, Any] | None: if query_filter == '': return None diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid_client_holder.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid_client_holder.py index 9ed9902..01bfb92 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid_client_holder.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/druid_client_holder.py @@ -1,5 +1,3 @@ -from typing import Optional - from osprey.worker.lib.config import Config from osprey.worker.lib.singletons import CONFIG from pydruid.client import PyDruid @@ -7,8 +5,8 @@ from pydruid.client import PyDruid class DruidClientHolder: def __init__(self) -> None: - self._client: Optional[PyDruid] = None - self._datasource: Optional[str] = None + self._client: PyDruid | None = None + self._datasource: str | None = None CONFIG.instance().register_configuration_callback(self.init_from_config) def init_from_config(self, config: Config) -> None: diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/marshal.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/marshal.py index 4b75544..867517e 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/marshal.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/marshal.py @@ -1,7 +1,8 @@ from abc import ABC +from collections.abc import Callable from functools import wraps from http import HTTPStatus -from typing import Any, Callable, Type, TypeVar +from typing import Any, Type, TypeVar from flask import Request, abort, jsonify, request from pydantic import ValidationError diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/tests/test_abilities.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/tests/test_abilities.py index 7989efb..d7fee3c 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/tests/test_abilities.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/tests/test_abilities.py @@ -1,5 +1,5 @@ import copy -from typing import Any, Dict, Optional +from typing import Any from osprey.worker.ui_api.osprey.lib.abilities import ( CENSOR_TEXT, @@ -28,7 +28,7 @@ class TestAbility(Ability[FakeRequest, str]): @_ability_registry.register('TEST_QUERY_FILTER_ABILITY') class TestQueryFilterAbility(QueryFilterAbility[FakeRequest, str]): - def _get_query_filter(self) -> Optional[Dict[str, Any]]: + def _get_query_filter(self) -> dict[str, Any] | None: if self.allow_all: return None diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/users.py b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/users.py index af64185..895334a 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/lib/users.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/lib/users.py @@ -1,7 +1,8 @@ from __future__ import annotations from collections import defaultdict -from typing import Any, Dict, List, Mapping, Optional, Type +from collections.abc import Mapping +from typing import Any, Type from osprey.worker.lib.singletons import ENGINE from osprey.worker.lib.sources_config.subkeys.acl_config import AclConfig @@ -24,23 +25,23 @@ class User: # consuming a `TemporaryAbilityToken` self.is_unregistered_user = acl_config.users.get(email) is None - self._abilities: List[Ability[BaseModel, Any]] = acl_config.get_abilities_for_user(self.email) + self._abilities: list[Ability[BaseModel, Any]] = acl_config.get_abilities_for_user(self.email) - def get_ability(self, ability_class: Type[AbilityT]) -> Optional[AbilityT]: + def get_ability(self, ability_class: Type[AbilityT]) -> AbilityT | None: """ Returns a single instance of `ability_class` that has all of the user's `ability_class` properties merged If the user does not have any `ability_class`, this returns `None` """ - abilities: List[AbilityT] = [ability for ability in self._abilities if isinstance(ability, ability_class)] + abilities: list[AbilityT] = [ability for ability in self._abilities if isinstance(ability, ability_class)] return self._merge_abilities(ability_class, abilities) if abilities else None def get_all_abilities(self) -> Mapping[str, Ability[Any, Any]]: """ - Returns a Dict mapping `ability_name` to a single `Ability` that has all of the user's `Ability` allowances + Returns a dict mapping `ability_name` to a single `Ability` that has all of the user's `Ability` allowances merged """ - ability_name_to_ability_list: Dict[str, List[Ability[Any, Any]]] = defaultdict(list) + ability_name_to_ability_list: dict[str, list[Ability[Any, Any]]] = defaultdict(list) for ability in self._abilities: ability_name_to_ability_list[ability.name].append(ability) @@ -52,7 +53,7 @@ class User: return ability_name_to_merged_ability - def _merge_abilities(self, ability_class: Type[AbilityT], ability_list: List[AbilityT]) -> AbilityT: + def _merge_abilities(self, ability_class: Type[AbilityT], ability_list: list[AbilityT]) -> AbilityT: """ Returns a single instance of Ability that has all of the user's Abilities (of the same type) merged. diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/validators/entities.py b/osprey_worker/src/osprey/worker/ui_api/osprey/validators/entities.py index 8af962f..a0c81fe 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/validators/entities.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/validators/entities.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Optional, Type +from typing import Type from flask import Request from osprey.engine.language_types.entities import EntityT @@ -31,9 +31,9 @@ class EntityLabelMutation(BaseModel): label_name: str status: LabelStatus reason: str - expires_at: Optional[datetime] + expires_at: datetime | None class ManualEntityLabelMutationRequest(BaseModel, EntityMarshaller): entity: EntityT[str] - mutations: List[EntityLabelMutation] + mutations: list[EntityLabelMutation] diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/validators/events.py b/osprey_worker/src/osprey/worker/ui_api/osprey/validators/events.py index e71542d..a4e2def 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/validators/events.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/validators/events.py @@ -1,14 +1,13 @@ from datetime import datetime -from typing import List, Optional from osprey.worker.ui_api.osprey.lib.druid import TopNDruidQuery class BulkLabelTopNRequest(TopNDruidQuery): - excluded_entities: List[str] = [] + excluded_entities: list[str] = [] expected_entities: int no_limit: bool label_name: str label_status: str label_reason: str - label_expiry: Optional[datetime] + label_expiry: datetime | None diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/_engine_ast_utils.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/_engine_ast_utils.py index 2b1afa2..0dbbf4e 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/_engine_ast_utils.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/_engine_ast_utils.py @@ -1,6 +1,6 @@ """Shared engine-AST traversal helpers used by views (features.py, rules.py, ...).""" -from typing import Any, Optional, Set +from typing import Any from osprey.engine.ast.grammar import ( Attribute, @@ -19,7 +19,7 @@ from osprey.engine.ast.grammar import ( ) -def get_func_identifier(call: Call) -> Optional[str]: +def get_func_identifier(call: Call) -> str | None: """Get the function name from a Call node.""" if isinstance(call.func, Name): return call.func.identifier @@ -68,7 +68,7 @@ def ast_to_string(node: Any) -> str: return str(node) -def collect_name_references(node: Any, out: Set[str]) -> None: +def collect_name_references(node: Any, out: set[str]) -> None: """Recursively collect all Name.identifier values referenced by an expression node. Skip the function-identifier position of Call nodes (we don't treat e.g. diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/abilities.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/abilities.py index d37db7e..9ce228b 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/abilities.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/abilities.py @@ -1,4 +1,5 @@ -from typing import Any, Mapping +from collections.abc import Mapping +from typing import Any from flask import Blueprint, abort, redirect from osprey.worker.lib.storage.temporary_ability_token import ConsumptionResult, TemporaryAbilityToken diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/docs.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/docs.py index 31d60fa..5480f18 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/docs.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/docs.py @@ -1,5 +1,6 @@ from collections import defaultdict -from typing import Any, List, Optional, Sequence +from collections.abc import Sequence +from typing import Any from flask import Blueprint from osprey.engine.udf.base import MethodSpec @@ -13,7 +14,7 @@ blueprint = Blueprint('docs', __name__) class UdfCategory(BaseModel): - name: Optional[str] + name: str | None udfs: Sequence[MethodSpec] @@ -32,8 +33,8 @@ def udf_docs() -> Any: specs_by_category[udf.category].append(udf.get_method_spec()) categories = [] - # Need the extra `list(...)` here to make mypy happy (otherwise it thinks `sorted` outputs a `List[str]`). - sorted_category_names: List[Optional[str]] = list(sorted(name for name in specs_by_category if name is not None)) + # Need the extra `list(...)` here to make mypy happy (otherwise it thinks `sorted` outputs a `list[str]`). + sorted_category_names: list[str | None] = list(sorted(name for name in specs_by_category if name is not None)) if None in specs_by_category: sorted_category_names.append(None) @@ -49,7 +50,7 @@ def udf_docs() -> Any: class FeatureLocationsDocsResponse(BaseModel): - locations: List[FeatureLocation] + locations: list[FeatureLocation] @blueprint.route('/docs/feature-locations', methods=['GET']) diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/events.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/events.py index 96249da..db0c656 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/events.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/events.py @@ -2,7 +2,7 @@ import csv import logging import tempfile from http.client import NOT_FOUND -from typing import Any, Dict, List, Optional, Set +from typing import Any from flask import Blueprint, Response, abort, jsonify from osprey.worker.lib.storage.stored_execution_result import ( @@ -110,8 +110,8 @@ def timeseries_query(request_model: TimeseriesDruidQuery) -> Any: class ScanQueryResult(BaseModel): - events: List[Dict[str, object]] - next_page: Optional[str] + events: list[dict[str, object]] + next_page: str | None class Config: arbitrary_types_allowed = True @@ -126,7 +126,9 @@ def scan_query(request_model: PaginatedScanDruidQuery) -> Any: require_ability_with_request(request_model, CanViewEventsByAction) query_filter_ability = get_current_user().get_ability(CanViewEventsByAction) - paginated_scan_results = request_model.execute(query_filter_abilities=[query_filter_ability]) + paginated_scan_results = request_model.execute( + query_filter_abilities=[query_filter_ability] if query_filter_ability else [] + ) action_data_censor_ability = get_current_user().get_ability(CanViewActionData) feature_data_censor_ability = get_current_user().get_ability(CanViewFeatureData) @@ -151,7 +153,7 @@ def topn_query_csv(topn_druid_query: TopNDruidQuery) -> Any: topn_results: TopNPoPResponse = topn_druid_query.execute() - topn_rows: List[Any] = [] + topn_rows: list[Any] = [] fieldnames = [ topn_druid_query.dimension, 'current_count', @@ -159,7 +161,7 @@ def topn_query_csv(topn_druid_query: TopNDruidQuery) -> Any: # we might have some PoP items that have diffs, and some that do not. we want to make sure we export # both without duplicating anything - included_dimension_keys: Set[str] = set() + included_dimension_keys: set[str] = set() # if this is a PoP comparison query, we will want to do something a little different to include more # data in the CSV response~ this data includes previous period counts and the difference calculations if topn_results.comparison: @@ -186,7 +188,7 @@ def topn_query_csv(topn_druid_query: TopNDruidQuery) -> Any: # now, regardless of whether we have a comparison or not, we want to include any remaining results that # have not been included yet. i.e. a comparison query may have some results that do not have diffs. for current_period in topn_results.current_period: - result: List[DimensionData] = current_period.result + result: list[DimensionData] = current_period.result for current_result in result: # this is not a beautiful solution, but it should work to snag the dimensions # for non-pop based on how we sanitize the results into DimensionData models diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/features.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/features.py index e306052..a1d4f20 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/features.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/features.py @@ -1,6 +1,6 @@ import logging from pathlib import PurePosixPath -from typing import Any, Dict, List, Optional, Set +from typing import Any from flask import Blueprint, jsonify from osprey.engine.ast.grammar import ( @@ -45,7 +45,7 @@ _NON_FEATURE_CALLS: frozenset[str] = frozenset( ) -def _format_annotation(annotation: Any) -> Optional[str]: +def _format_annotation(annotation: Any) -> str | None: """Format a type annotation AST node into a readable string like 'str', 'Entity[int]', 'Optional[str]'.""" if annotation is None: return None @@ -75,7 +75,7 @@ def _derive_category(file_path: str) -> str: return parts[0] -def _find_assign_for_feature(sources: Any, feature_name: str, source_path: str, source_line: int) -> Optional[Assign]: +def _find_assign_for_feature(sources: Any, feature_name: str, source_path: str, source_line: int) -> Assign | None: """Look up the Assign AST node for a feature in its source file. First try exact (file, line) match. Fall back to first Assign in the file @@ -124,13 +124,13 @@ def _extraction_fn_from_value(value: Any) -> str: return type(value).__name__ -def _extract_features_from_engine() -> List[Dict[str, Any]]: +def _extract_features_from_engine() -> list[dict[str, Any]]: """Walk the engine AST and return the catalog of extracted features with references.""" engine = ENGINE.instance() sources = engine.execution_graph.validated_sources.sources locations = engine.get_known_feature_locations() - features: Dict[str, Dict[str, Any]] = {} + features: dict[str, dict[str, Any]] = {} for loc in locations: assign = _find_assign_for_feature(sources, loc.name, loc.source_path, loc.source_line) @@ -154,9 +154,9 @@ def _extract_features_from_engine() -> List[Dict[str, Any]]: } feature_names = set(features.keys()) - rule_refs: Dict[str, Set[str]] = {} - feature_refs: Dict[str, Set[str]] = {} - whenrules_refs: Dict[str, int] = {} + rule_refs: dict[str, set[str]] = {} + feature_refs: dict[str, set[str]] = {} + whenrules_refs: dict[str, int] = {} for source in sources: for statement in source.ast_root.statements: @@ -167,7 +167,7 @@ def _extract_features_from_engine() -> List[Dict[str, Any]]: and get_func_identifier(statement.value) == 'Rule' ): rule_name = statement.target.identifier - refs: Set[str] = set() + refs: set[str] = set() when_all_arg = statement.value.find_argument('when_all') if when_all_arg: collect_name_references(when_all_arg.value, refs) @@ -176,7 +176,7 @@ def _extract_features_from_engine() -> List[Dict[str, Any]]: continue # WhenRules(...) calls — bare statement OR assigned. - call_node: Optional[Call] = None + call_node: Call | None = None if isinstance(statement, Call) and get_func_identifier(statement) == 'WhenRules': call_node = statement elif ( @@ -224,8 +224,8 @@ def features_list() -> Any: """Return the catalog of extracted features across the rules engine.""" features = _extract_features_from_engine() - categories: Dict[str, int] = {} - extraction_fns: Dict[str, int] = {} + categories: dict[str, int] = {} + extraction_fns: dict[str, int] = {} for f in features: categories[f['category']] = categories.get(f['category'], 0) + 1 extraction_fns[f['extraction_fn']] = extraction_fns.get(f['extraction_fn'], 0) + 1 diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/queries.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/queries.py index 360deb7..63ad22f 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/queries.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/queries.py @@ -1,5 +1,5 @@ from http.client import BAD_REQUEST -from typing import Any, Optional +from typing import Any from flask import Blueprint, Response, abort, jsonify, request from osprey.engine.ast_validator.validation_context import ValidationFailed @@ -28,7 +28,7 @@ def create_query_record() -> Any: @blueprint.route('/queries', methods=['GET']) def get_queries() -> Any: - before: Optional[int] = request.args.get('before') + before: int | None = request.args.get('before') user_email = request.args.get('user_email') if user_email: diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules.py index 5342ba7..2ca5e8f 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules.py @@ -1,5 +1,5 @@ import logging -from typing import Any, Dict, List, Optional, Set +from typing import Any from flask import Blueprint, jsonify from osprey.engine.ast.grammar import ( @@ -36,7 +36,7 @@ def _description_to_string(value: Any) -> str: raise TypeError(f'BUG: Rule description was {value!r}, should have been caught by validator.') -def _extract_rules_from_engine() -> tuple[List[Dict[str, Any]], int]: +def _extract_rules_from_engine() -> tuple[list[dict[str, Any]], int]: """Walk the engine once, collecting Rule defs and WhenRules → Rule reference counts. WhenRules can appear in a source iterated before the Rule they reference @@ -47,14 +47,14 @@ def _extract_rules_from_engine() -> tuple[List[Dict[str, Any]], int]: engine = ENGINE.instance() sources = engine.execution_graph.validated_sources.sources - whenrules_ref_count: Dict[str, int] = {} + whenrules_ref_count: dict[str, int] = {} when_rules_total = 0 - rules: List[Dict[str, Any]] = [] + rules: list[dict[str, Any]] = [] for source in sources: for statement in source.ast_root.statements: # WhenRules(...) — bare statement or assigned - call_node: Optional[Call] = None + call_node: Call | None = None if isinstance(statement, Call) and get_func_identifier(statement) == 'WhenRules': call_node = statement elif ( @@ -83,7 +83,7 @@ def _extract_rules_from_engine() -> tuple[List[Dict[str, Any]], int]: rule_name = statement.target.identifier call = statement.value - when_all: List[str] = [] + when_all: list[str] = [] when_all_arg = call.find_argument('when_all') if when_all_arg is not None and isinstance(when_all_arg.value, AstList): for item in when_all_arg.value.items: @@ -96,7 +96,7 @@ def _extract_rules_from_engine() -> tuple[List[Dict[str, Any]], int]: if description_arg is not None: description = _description_to_string(description_arg.value) - refs: Set[str] = set() + refs: set[str] = set() if when_all_arg is not None: collect_name_references(when_all_arg.value, refs) if description_arg is not None: diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules_visualizer.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules_visualizer.py index 1063dcf..d6ecde2 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules_visualizer.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/rules_visualizer.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, List +from typing import Any from flask import Blueprint, jsonify from osprey.engine.executor.execution_visualizer import RenderedDigraph, render_graph @@ -14,11 +14,11 @@ blueprint = Blueprint('rules_visualizer', __name__) class BaseActionsViewQuery(BaseModel, JsonBodyMarshaller): - action_names: List[str] + action_names: list[str] class BaseLabelsViewQuery(BaseModel, JsonBodyMarshaller): - label_names: List[str] + label_names: list[str] show_upstream: bool = False show_downstream: bool = True diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_config.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_config.py index 470539c..71cef97 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_config.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_config.py @@ -98,10 +98,10 @@ def test_get_ui_config(client: 'FlaskClient[Response]') -> None: Int: ExtractLiteral[int] = 123 Float: ExtractLiteral[float] = 123.4 Bool: ExtractLiteral[bool] = True - OStr: ExtractLiteral[Optional[str]] = 'hello' - OInt: ExtractLiteral[Optional[int]] = 123 - OFloat: ExtractLiteral[Optional[float]] = 123.4 - OBool: ExtractLiteral[Optional[bool]] = True + OStr: ExtractLiteral[str | None] = 'hello' + OInt: ExtractLiteral[int | None] = 123 + OFloat: ExtractLiteral[float | None] = 123.4 + OBool: ExtractLiteral[bool | None] = True LStr: ExtractLiteral[List[str]] = ['hello'] LInt: ExtractLiteral[List[int]] = [123] LFloat: ExtractLiteral[List[float]] = [123.4] diff --git a/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_events.py b/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_events.py index 215bbf6..02411e9 100644 --- a/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_events.py +++ b/osprey_worker/src/osprey/worker/ui_api/osprey/views/tests/test_events.py @@ -1,7 +1,8 @@ import json +from collections.abc import Mapping from datetime import datetime from operator import itemgetter -from typing import Any, Dict, Mapping +from typing import Any from unittest import mock import pytest @@ -54,7 +55,7 @@ config_b = { @pytest.fixture() -def model_url() -> Dict[str, Any]: +def model_url() -> dict[str, Any]: return {'model': PaginatedScanDruidQuery(**_base_druid_query.dict()), 'url': 'events.scan_query'} @@ -113,7 +114,7 @@ def test_events_auth_reject_get( @pytest.mark.use_rules_sources(config_a) def test_events_scan_request_missing_ability( - app: Flask, client: 'FlaskClient[Response]', model_url: Dict[str, Any] + app: Flask, client: 'FlaskClient[Response]', model_url: dict[str, Any] ) -> None: res = client.post(url_for(model_url['url']), content_type='application/json', data=model_url['model'].json()) assert res.status_code == 401 @@ -125,7 +126,7 @@ def test_events_scan_request_missing_ability( def test_events_scan_request( app: Flask, client: 'FlaskClient[Response]', - model_url: Dict[str, Any], + model_url: dict[str, Any], mock_druid_client: Any, fake_druid: Any, ) -> None: diff --git a/uv.lock b/uv.lock index ae0e384..aa53c40 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 1 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '4' and platform_machine == 'x86_64'", @@ -142,9 +142,9 @@ dev = [ name = "absl-py" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543 } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, + { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750 }, ] [[package]] @@ -154,9 +154,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycares" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9b/22/a2d928e0e42baad0471d12ec44c71152ac870486e8298dddb2893b888c29/aiodns-4.0.4.tar.gz", hash = "sha256:cb10e0c0d2591636716ad2fe402e977c16d71bdaf76bb8cb49e8a6633596f736", size = 29918, upload-time = "2026-05-20T01:54:15.557Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/22/a2d928e0e42baad0471d12ec44c71152ac870486e8298dddb2893b888c29/aiodns-4.0.4.tar.gz", hash = "sha256:cb10e0c0d2591636716ad2fe402e977c16d71bdaf76bb8cb49e8a6633596f736", size = 29918 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/70/72e4ab117425ccdc4d10bd523a94c1baa051a15586057d64a4c6888f9e3f/aiodns-4.0.4-py3-none-any.whl", hash = "sha256:c24dd605bac70a1676ce503f967a98483ff163507198557d8e9db16267e6cfd2", size = 12696, upload-time = "2026-05-20T01:54:14.134Z" }, + { url = "https://files.pythonhosted.org/packages/7f/70/72e4ab117425ccdc4d10bd523a94c1baa051a15586057d64a4c6888f9e3f/aiodns-4.0.4-py3-none-any.whl", hash = "sha256:c24dd605bac70a1676ce503f967a98483ff163507198557d8e9db16267e6cfd2", size = 12696 }, ] [[package]] @@ -166,9 +166,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, ] [[package]] @@ -178,73 +178,73 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393, upload-time = "2025-07-30T10:01:40.97Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328, upload-time = "2025-07-30T10:01:41.916Z" }, - { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269, upload-time = "2025-07-30T10:01:42.716Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558, upload-time = "2025-07-30T10:01:43.943Z" }, - { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364, upload-time = "2025-07-30T10:01:44.887Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637, upload-time = "2025-07-30T10:01:46.225Z" }, - { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934, upload-time = "2025-07-30T10:01:47.203Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158, upload-time = "2025-07-30T10:01:48.341Z" }, - { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597, upload-time = "2025-07-30T10:01:49.112Z" }, - { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231, upload-time = "2025-07-30T10:01:49.92Z" }, - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/3c0a35f46e52108d4707c44b95cfe2afcafc50800b5450c197454569b776/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3d3f05610594151994ca9ccb3c771115bdb4daef161976a266f0dd8aa9996b8f", size = 54393 }, + { url = "https://files.pythonhosted.org/packages/9d/f4/98bbd6ee89febd4f212696f13c03ca302b8552e7dbf9c8efa11ea4a388c3/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8b8efee945193e667a396cbc7b4fb7d357297d6234d30a489905d96caabde56b", size = 29328 }, + { url = "https://files.pythonhosted.org/packages/43/24/90a01c0ef12ac91a6be05969f29944643bc1e5e461155ae6559befa8f00b/argon2_cffi_bindings-25.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3c6702abc36bf3ccba3f802b799505def420a1b7039862014a65db3205967f5a", size = 31269 }, + { url = "https://files.pythonhosted.org/packages/d4/d3/942aa10782b2697eee7af5e12eeff5ebb325ccfb86dd8abda54174e377e4/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c70058c6ab1e352304ac7e3b52554daadacd8d453c1752e547c76e9c99ac44", size = 86558 }, + { url = "https://files.pythonhosted.org/packages/0d/82/b484f702fec5536e71836fc2dbc8c5267b3f6e78d2d539b4eaa6f0db8bf8/argon2_cffi_bindings-25.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2fd3bfbff3c5d74fef31a722f729bf93500910db650c925c2d6ef879a7e51cb", size = 92364 }, + { url = "https://files.pythonhosted.org/packages/c9/c1/a606ff83b3f1735f3759ad0f2cd9e038a0ad11a3de3b6c673aa41c24bb7b/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4f9665de60b1b0e99bcd6be4f17d90339698ce954cfd8d9cf4f91c995165a92", size = 85637 }, + { url = "https://files.pythonhosted.org/packages/44/b4/678503f12aceb0262f84fa201f6027ed77d71c5019ae03b399b97caa2f19/argon2_cffi_bindings-25.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ba92837e4a9aa6a508c8d2d7883ed5a8f6c308c89a4790e1e447a220deb79a85", size = 91934 }, + { url = "https://files.pythonhosted.org/packages/f0/c7/f36bd08ef9bd9f0a9cff9428406651f5937ce27b6c5b07b92d41f91ae541/argon2_cffi_bindings-25.1.0-cp314-cp314t-win32.whl", hash = "sha256:84a461d4d84ae1295871329b346a97f68eade8c53b6ed9a7ca2d7467f3c8ff6f", size = 28158 }, + { url = "https://files.pythonhosted.org/packages/b3/80/0106a7448abb24a2c467bf7d527fe5413b7fdfa4ad6d6a96a43a62ef3988/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b55aec3565b65f56455eebc9b9f34130440404f27fe21c3b375bf1ea4d8fbae6", size = 32597 }, + { url = "https://files.pythonhosted.org/packages/05/b8/d663c9caea07e9180b2cb662772865230715cbd573ba3b5e81793d580316/argon2_cffi_bindings-25.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:87c33a52407e4c41f3b70a9c2d3f6056d88b10dad7695be708c5021673f55623", size = 28231 }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, ] [[package]] name = "blinker" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, ] [[package]] name = "bytecode" version = "0.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/c4/4818b392104bd426171fc2ce9c79c8edb4019ba6505747626d0f7107766c/bytecode-0.17.0.tar.gz", hash = "sha256:0c37efa5bd158b1b873f530cceea2c645611d55bd2dc2a4758b09f185749b6fd", size = 105863, upload-time = "2025-09-03T19:55:45.703Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/c4/4818b392104bd426171fc2ce9c79c8edb4019ba6505747626d0f7107766c/bytecode-0.17.0.tar.gz", hash = "sha256:0c37efa5bd158b1b873f530cceea2c645611d55bd2dc2a4758b09f185749b6fd", size = 105863 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/80/379e685099841f8501a19fb58b496512ef432331fed38276c3938ab09d8e/bytecode-0.17.0-py3-none-any.whl", hash = "sha256:64fb10cde1db7ef5cc39bd414ecebd54ba3b40e1c4cf8121ca5e72f170916ff8", size = 43045, upload-time = "2025-09-03T19:55:43.879Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/379e685099841f8501a19fb58b496512ef432331fed38276c3938ab09d8e/bytecode-0.17.0-py3-none-any.whl", hash = "sha256:64fb10cde1db7ef5cc39bd414ecebd54ba3b40e1c4cf8121ca5e72f170916ff8", size = 43045 }, ] [[package]] name = "cachetools" version = "5.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, + { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080 }, ] [[package]] name = "certifi" version = "2026.5.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134 }, ] [[package]] @@ -254,183 +254,183 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, - { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, - { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, - { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, - { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, - { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, - { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344 }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560 }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613 }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476 }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374 }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597 }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574 }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971 }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972 }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078 }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076 }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820 }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635 }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271 }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048 }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529 }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097 }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519 }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572 }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963 }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361 }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932 }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557 }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762 }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230 }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043 }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446 }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101 }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948 }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422 }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499 }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928 }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302 }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909 }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402 }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780 }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320 }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487 }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049 }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793 }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300 }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244 }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828 }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926 }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328 }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650 }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687 }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773 }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013 }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593 }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354 }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480 }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584 }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443 }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487 }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726 }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195 }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, ] [[package]] name = "charset-normalizer" version = "3.4.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, - { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, - { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, - { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, - { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, - { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, - { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, - { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, - { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, - { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, - { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, - { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, - { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, - { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, - { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, - { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, - { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, - { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, - { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, - { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, - { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, - { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, - { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, - { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, - { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, - { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, - { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, - { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, - { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, - { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, - { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, - { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, - { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, - { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, - { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, - { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, - { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, - { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, - { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, - { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, - { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705 }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419 }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901 }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742 }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061 }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239 }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173 }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841 }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304 }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455 }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036 }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739 }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277 }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819 }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281 }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843 }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328 }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061 }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031 }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239 }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589 }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733 }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652 }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229 }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552 }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806 }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316 }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274 }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468 }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460 }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330 }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828 }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627 }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008 }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303 }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282 }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595 }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986 }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711 }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036 }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998 }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056 }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537 }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176 }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723 }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085 }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819 }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915 }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234 }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042 }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706 }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727 }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882 }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860 }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564 }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276 }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238 }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189 }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352 }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024 }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869 }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541 }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634 }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384 }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133 }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257 }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851 }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393 }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251 }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609 }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014 }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979 }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238 }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110 }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824 }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103 }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194 }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827 }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168 }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018 }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958 }, ] [[package]] name = "click" version = "7.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/6f/be940c8b1f1d69daceeb0032fee6c34d7bd70e3e649ccac0951500b4720e/click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", size = 297279, upload-time = "2020-04-27T20:22:45.014Z" } +sdist = { url = "https://files.pythonhosted.org/packages/27/6f/be940c8b1f1d69daceeb0032fee6c34d7bd70e3e649ccac0951500b4720e/click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", size = 297279 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc", size = 82780, upload-time = "2020-04-27T20:22:42.629Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc", size = 82780 }, ] [[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, upload-time = "2022-10-25T02:36:22.414Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } wheels = [ - { 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" }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] [[package]] @@ -440,9 +440,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/be/68c69e50e45aaecbf22d06f2d658f50531c8709d797c2f97378a4454f3de/datadog-0.51.0.tar.gz", hash = "sha256:3279534f831ae0b4ae2d8ce42ef038b4ab38e667d7ed6ff7437982d7a0cf5250", size = 352649, upload-time = "2025-01-27T18:24:11.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/be/68c69e50e45aaecbf22d06f2d658f50531c8709d797c2f97378a4454f3de/datadog-0.51.0.tar.gz", hash = "sha256:3279534f831ae0b4ae2d8ce42ef038b4ab38e667d7ed6ff7437982d7a0cf5250", size = 352649 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/56/c48c12fdbbaece1a0ca2eacb9be549c34e562baff437ef4c66c4b236a247/datadog-0.51.0-py2.py3-none-any.whl", hash = "sha256:a9764f091c96af4e0996d4400b168fc5fba380f911d6d672c9dcd4773e29ea3f", size = 121813, upload-time = "2025-01-27T18:24:09.045Z" }, + { url = "https://files.pythonhosted.org/packages/fb/56/c48c12fdbbaece1a0ca2eacb9be549c34e562baff437ef4c66c4b236a247/datadog-0.51.0-py2.py3-none-any.whl", hash = "sha256:a9764f091c96af4e0996d4400b168fc5fba380f911d6d672c9dcd4773e29ea3f", size = 121813 }, ] [[package]] @@ -459,81 +459,81 @@ dependencies = [ { name = "wrapt" }, { name = "xmltodict" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/b8/60762d73e919c05165717a0a185b9e3401b3049ed3de6f45867b86efc419/ddtrace-2.21.12.tar.gz", hash = "sha256:a37e948be2f9821ef8782697252c7e937edf0c847dda3f7e12a94f47ba6442a2", size = 9404597, upload-time = "2025-10-24T09:14:44Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/8f/c3c10fb734141035aa494580bbf4facb21e9cffab41a1ebeae33c0a11647/ddtrace-2.21.12-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:e2b2c98f8ebaeeb393e2f24f96e0ddb12777df67dfcbbd35020646582c37ab9a", size = 4819930, upload-time = "2025-10-24T09:12:10.88Z" }, - { url = "https://files.pythonhosted.org/packages/a8/21/3ff7ebb9a58a4aa9897db9ef15f413873b5d4f0feb9276b09275ad34ddef/ddtrace-2.21.12-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:2cb3cdcaffb1eb18a83f67e087e9929c6660bb22c294c9d716427a595a123b0f", size = 3275998, upload-time = "2025-10-24T09:12:12.689Z" }, - { url = "https://files.pythonhosted.org/packages/1d/f4/7ea150e228d274e4ec35e1ce6acb2012149e15aabe052a7b9d779d3c388f/ddtrace-2.21.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf2ab315a71c07fc9034b2f66a6d165393b9226cfe88fb5572cebb1930a3c647", size = 6075694, upload-time = "2025-10-24T09:12:14.349Z" }, - { url = "https://files.pythonhosted.org/packages/87/e1/14a9611a6880586a5a7e7585dd4f7162e6fe82eb7dfdc15219ea6ff22019/ddtrace-2.21.12-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e0392f1fa5963a6b18cad1d6b4fef1c199d3b4ca16ac3b75d8cc7f101c23adb", size = 2841006, upload-time = "2025-10-24T09:12:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/f7/be/38c9c74629939ce19dc0e924b162b7ee1791cb3b82f75ebf3febe80660f4/ddtrace-2.21.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b8b3d5532900a07fdee8167b6f3137b53573581c424b33877271545529244f9", size = 6395297, upload-time = "2025-10-24T09:12:18.022Z" }, - { url = "https://files.pythonhosted.org/packages/26/08/aba2f8c38b8f9ad366f999ce16ec947978e2f21c40b36da4987dddb1309d/ddtrace-2.21.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27d258f88f495a3249c4296db18f07ed94db20b3c09487f09fede1674740a0b5", size = 7064493, upload-time = "2025-10-24T09:12:20.222Z" }, - { url = "https://files.pythonhosted.org/packages/0c/15/f1c8ad989e382f5c536a1dc5849e340a5564ca5298a625886cc1fe340d08/ddtrace-2.21.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4ffb46f775fa3f6c4f1b24fa3c48ed5338f5d0ac8d3e66c0d1ff2a054b5680a5", size = 3904168, upload-time = "2025-10-24T09:12:22.166Z" }, - { url = "https://files.pythonhosted.org/packages/a7/3c/0ac708a924da84004dfb80530916462ed3460805cf9a1818345dfcda0413/ddtrace-2.21.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebe7aa7306ab4931a0273b4f6d21aa45a2098a0bbb48526cf9217862e75012af", size = 7444121, upload-time = "2025-10-24T09:12:24.547Z" }, - { url = "https://files.pythonhosted.org/packages/d7/d2/a9620916a403fc34673df5e52822768f243dc53c7fcf9f75f51dec6a284e/ddtrace-2.21.12-cp311-cp311-win32.whl", hash = "sha256:f1cf9f22b48709d7b6865e509ff26f49184160b78dd57bc41dcb08dd25e9b4a9", size = 3098483, upload-time = "2025-10-24T09:12:26.492Z" }, - { url = "https://files.pythonhosted.org/packages/88/2c/ff2cdb65a426262bac23da7bc2ef8a93521e0f21e81328672f5251360a7e/ddtrace-2.21.12-cp311-cp311-win_amd64.whl", hash = "sha256:1cc79b43b41812b9048f8f641fe106cbf18e01ff32ed68a8753ad16331e1136f", size = 3342940, upload-time = "2025-10-24T09:12:28.646Z" }, - { url = "https://files.pythonhosted.org/packages/11/aa/bde4d33ca3e465fe9ec7f5632eb8a52b50068500503b85fc6b8d5ad07fdb/ddtrace-2.21.12-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:b9fab2b672b775930b81406f0ed25e5d8979f3d5c02da1c20fb991edfd939b29", size = 4812461, upload-time = "2025-10-24T09:12:30.808Z" }, - { url = "https://files.pythonhosted.org/packages/9f/82/ad0481f24e7c4af65dfa50e7802ab5f761280933ce876d21f7273f8893c8/ddtrace-2.21.12-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:9296c761fffaf2c28beaaf4f7e79b88578d8fd02cf8cbbb27e28385dd59efd65", size = 3272541, upload-time = "2025-10-24T09:12:33.129Z" }, - { url = "https://files.pythonhosted.org/packages/84/7e/198090d21dd3a32220e2f13039baba153700ceeeba8041aef8c24d611be9/ddtrace-2.21.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f4c0ebc9398b9a1ac8719f62274a869561668e3e81eaed6e94a34dd50950c68", size = 6042921, upload-time = "2025-10-24T09:12:35.325Z" }, - { url = "https://files.pythonhosted.org/packages/96/5e/a4fff09e7e415f558a6ed4413e42c10b9e68e47fef2df3d3ac4aeff8c4e3/ddtrace-2.21.12-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b7469b3f2fe33466e8169fe61c030ca5970e3099ce39753d27dbd622df7820a", size = 2802801, upload-time = "2025-10-24T09:12:37.266Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/5453740ce2f5d407f42f9f3f751a270a8412785d775549cba4b6d42e03b1/ddtrace-2.21.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02149b106ad18808a832355ebe21b23f4ecf3e5eb2fde33100af4c968ff30a0", size = 6368257, upload-time = "2025-10-24T09:12:39.814Z" }, - { url = "https://files.pythonhosted.org/packages/cc/29/b666574c013b6dd6bf448ff195c34868e377afae993c65f827687f4ff580/ddtrace-2.21.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9a5340f5d08338882d2ed943ddab7659db86ed1325022dff9c03d333467140d2", size = 7030927, upload-time = "2025-10-24T09:12:42.292Z" }, - { url = "https://files.pythonhosted.org/packages/85/21/7a252a853dd569b43e9f2635fd0fbc7cafc0f5795a1d93bc78557a30dbe0/ddtrace-2.21.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:29a25fdb1780b274438ae91721ef9dcd7a1f2eb91586c4e4ab5ffa67dcce037b", size = 3866034, upload-time = "2025-10-24T09:12:44.883Z" }, - { url = "https://files.pythonhosted.org/packages/e7/8d/a147b16eef450eba269b061c9cde125508158160810f2e4488b585b5a357/ddtrace-2.21.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d8883562ec3dc1475ccdaa8b0a0778d2167a9a6d092b26dbecf4904670393f9", size = 7408275, upload-time = "2025-10-24T09:12:47.726Z" }, - { url = "https://files.pythonhosted.org/packages/c3/84/12eafbfb26c2ae9774b790322092b75412c3defa9287ab871b3de060e315/ddtrace-2.21.12-cp312-cp312-win32.whl", hash = "sha256:60ec39f891bf546e4455dea2f71bf5bec68e1642787c349f8fc5f81acc77b4ff", size = 3086971, upload-time = "2025-10-24T09:12:50.046Z" }, - { url = "https://files.pythonhosted.org/packages/be/65/958ec4d0e1751da1c218da2e4e7c7cfa911b17df60f9f89537737d9e2370/ddtrace-2.21.12-cp312-cp312-win_amd64.whl", hash = "sha256:db9d0555faf065b56e18f925eef201f80395b66d04d86538f41b0c1106151b6f", size = 3328037, upload-time = "2025-10-24T09:12:52.278Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3e/6e0900bb9408b0c93a40a5669f8d2e9e9e07dda2b80f757ee3597d247cc5/ddtrace-2.21.12-cp313-cp313-macosx_12_0_universal2.whl", hash = "sha256:29bbb2d72a8d8f4388974a035801f4651edf0cfad97ff67fae3f9d17863d7200", size = 4797212, upload-time = "2025-10-24T09:12:54.651Z" }, - { url = "https://files.pythonhosted.org/packages/04/4f/2d7def75daf3a7a33729c89845f5f766f3837b3297f08691588e8d9ece0f/ddtrace-2.21.12-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:46f63ec7b1e80f62e4b9bedaec123be3f607bf7e026d980db5656f55c501e970", size = 3265051, upload-time = "2025-10-24T09:12:56.86Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/d5a6b3d1132ee26075f7d631aac1cdc00c71f4340132460cf38870d553fa/ddtrace-2.21.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:033d2aabe9b20b2bd6fc6ae226883e21219317a83e2a6ef72ddf76dd00df9a1e", size = 6001434, upload-time = "2025-10-24T09:13:00.009Z" }, - { url = "https://files.pythonhosted.org/packages/7a/f2/4120b60c1f846d654efdc9367a227aad3058536424936fdae306425df2ef/ddtrace-2.21.12-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ffd0ad30dafd1e2f98843b215f9b75f7d08ec4054def06cda9fb75af5c3d2b4", size = 2799520, upload-time = "2025-10-24T09:13:02.852Z" }, - { url = "https://files.pythonhosted.org/packages/6c/58/7fa01a3b3ecc41e67c5f5decf1e18031e6e41721c53fcfb8ea3841b13108/ddtrace-2.21.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a829d411a689120bebf67a2018fb2012b3147da6f25041d71b4d15e32f2afb79", size = 6326996, upload-time = "2025-10-24T09:13:05.165Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e6/71c0a664a3eebf9fc38bbd90b47b89271d30dd0cb796624af7b2af35a80f/ddtrace-2.21.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d98497bcba7d89694e8232180442f7d9c0dddd2f3043f59a02b54609d1abe2e", size = 6985268, upload-time = "2025-10-24T09:13:07.737Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fb/1791292d992fe0877052eb4ac3fdd0809ee9f361cc0dcbb9fbef80625956/ddtrace-2.21.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:dc6cd4601658c2bf8e33c176a02a5927bf004bed6f18474f27bba311846ffdca", size = 3863893, upload-time = "2025-10-24T09:13:10.24Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c1/11db5d337f7d24f57e4bf080d4362604aef51668f846ef30ec61568a1584/ddtrace-2.21.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:384abf79063dfa5dc08e067b29b016c03d8209b7fc155684fe5fe56a39282eee", size = 7365578, upload-time = "2025-10-24T09:13:13.045Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/bf/b8/60762d73e919c05165717a0a185b9e3401b3049ed3de6f45867b86efc419/ddtrace-2.21.12.tar.gz", hash = "sha256:a37e948be2f9821ef8782697252c7e937edf0c847dda3f7e12a94f47ba6442a2", size = 9404597 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/8f/c3c10fb734141035aa494580bbf4facb21e9cffab41a1ebeae33c0a11647/ddtrace-2.21.12-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:e2b2c98f8ebaeeb393e2f24f96e0ddb12777df67dfcbbd35020646582c37ab9a", size = 4819930 }, + { url = "https://files.pythonhosted.org/packages/a8/21/3ff7ebb9a58a4aa9897db9ef15f413873b5d4f0feb9276b09275ad34ddef/ddtrace-2.21.12-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:2cb3cdcaffb1eb18a83f67e087e9929c6660bb22c294c9d716427a595a123b0f", size = 3275998 }, + { url = "https://files.pythonhosted.org/packages/1d/f4/7ea150e228d274e4ec35e1ce6acb2012149e15aabe052a7b9d779d3c388f/ddtrace-2.21.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf2ab315a71c07fc9034b2f66a6d165393b9226cfe88fb5572cebb1930a3c647", size = 6075694 }, + { url = "https://files.pythonhosted.org/packages/87/e1/14a9611a6880586a5a7e7585dd4f7162e6fe82eb7dfdc15219ea6ff22019/ddtrace-2.21.12-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e0392f1fa5963a6b18cad1d6b4fef1c199d3b4ca16ac3b75d8cc7f101c23adb", size = 2841006 }, + { url = "https://files.pythonhosted.org/packages/f7/be/38c9c74629939ce19dc0e924b162b7ee1791cb3b82f75ebf3febe80660f4/ddtrace-2.21.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b8b3d5532900a07fdee8167b6f3137b53573581c424b33877271545529244f9", size = 6395297 }, + { url = "https://files.pythonhosted.org/packages/26/08/aba2f8c38b8f9ad366f999ce16ec947978e2f21c40b36da4987dddb1309d/ddtrace-2.21.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27d258f88f495a3249c4296db18f07ed94db20b3c09487f09fede1674740a0b5", size = 7064493 }, + { url = "https://files.pythonhosted.org/packages/0c/15/f1c8ad989e382f5c536a1dc5849e340a5564ca5298a625886cc1fe340d08/ddtrace-2.21.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4ffb46f775fa3f6c4f1b24fa3c48ed5338f5d0ac8d3e66c0d1ff2a054b5680a5", size = 3904168 }, + { url = "https://files.pythonhosted.org/packages/a7/3c/0ac708a924da84004dfb80530916462ed3460805cf9a1818345dfcda0413/ddtrace-2.21.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebe7aa7306ab4931a0273b4f6d21aa45a2098a0bbb48526cf9217862e75012af", size = 7444121 }, + { url = "https://files.pythonhosted.org/packages/d7/d2/a9620916a403fc34673df5e52822768f243dc53c7fcf9f75f51dec6a284e/ddtrace-2.21.12-cp311-cp311-win32.whl", hash = "sha256:f1cf9f22b48709d7b6865e509ff26f49184160b78dd57bc41dcb08dd25e9b4a9", size = 3098483 }, + { url = "https://files.pythonhosted.org/packages/88/2c/ff2cdb65a426262bac23da7bc2ef8a93521e0f21e81328672f5251360a7e/ddtrace-2.21.12-cp311-cp311-win_amd64.whl", hash = "sha256:1cc79b43b41812b9048f8f641fe106cbf18e01ff32ed68a8753ad16331e1136f", size = 3342940 }, + { url = "https://files.pythonhosted.org/packages/11/aa/bde4d33ca3e465fe9ec7f5632eb8a52b50068500503b85fc6b8d5ad07fdb/ddtrace-2.21.12-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:b9fab2b672b775930b81406f0ed25e5d8979f3d5c02da1c20fb991edfd939b29", size = 4812461 }, + { url = "https://files.pythonhosted.org/packages/9f/82/ad0481f24e7c4af65dfa50e7802ab5f761280933ce876d21f7273f8893c8/ddtrace-2.21.12-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:9296c761fffaf2c28beaaf4f7e79b88578d8fd02cf8cbbb27e28385dd59efd65", size = 3272541 }, + { url = "https://files.pythonhosted.org/packages/84/7e/198090d21dd3a32220e2f13039baba153700ceeeba8041aef8c24d611be9/ddtrace-2.21.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f4c0ebc9398b9a1ac8719f62274a869561668e3e81eaed6e94a34dd50950c68", size = 6042921 }, + { url = "https://files.pythonhosted.org/packages/96/5e/a4fff09e7e415f558a6ed4413e42c10b9e68e47fef2df3d3ac4aeff8c4e3/ddtrace-2.21.12-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b7469b3f2fe33466e8169fe61c030ca5970e3099ce39753d27dbd622df7820a", size = 2802801 }, + { url = "https://files.pythonhosted.org/packages/0b/17/5453740ce2f5d407f42f9f3f751a270a8412785d775549cba4b6d42e03b1/ddtrace-2.21.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02149b106ad18808a832355ebe21b23f4ecf3e5eb2fde33100af4c968ff30a0", size = 6368257 }, + { url = "https://files.pythonhosted.org/packages/cc/29/b666574c013b6dd6bf448ff195c34868e377afae993c65f827687f4ff580/ddtrace-2.21.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9a5340f5d08338882d2ed943ddab7659db86ed1325022dff9c03d333467140d2", size = 7030927 }, + { url = "https://files.pythonhosted.org/packages/85/21/7a252a853dd569b43e9f2635fd0fbc7cafc0f5795a1d93bc78557a30dbe0/ddtrace-2.21.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:29a25fdb1780b274438ae91721ef9dcd7a1f2eb91586c4e4ab5ffa67dcce037b", size = 3866034 }, + { url = "https://files.pythonhosted.org/packages/e7/8d/a147b16eef450eba269b061c9cde125508158160810f2e4488b585b5a357/ddtrace-2.21.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d8883562ec3dc1475ccdaa8b0a0778d2167a9a6d092b26dbecf4904670393f9", size = 7408275 }, + { url = "https://files.pythonhosted.org/packages/c3/84/12eafbfb26c2ae9774b790322092b75412c3defa9287ab871b3de060e315/ddtrace-2.21.12-cp312-cp312-win32.whl", hash = "sha256:60ec39f891bf546e4455dea2f71bf5bec68e1642787c349f8fc5f81acc77b4ff", size = 3086971 }, + { url = "https://files.pythonhosted.org/packages/be/65/958ec4d0e1751da1c218da2e4e7c7cfa911b17df60f9f89537737d9e2370/ddtrace-2.21.12-cp312-cp312-win_amd64.whl", hash = "sha256:db9d0555faf065b56e18f925eef201f80395b66d04d86538f41b0c1106151b6f", size = 3328037 }, + { url = "https://files.pythonhosted.org/packages/d2/3e/6e0900bb9408b0c93a40a5669f8d2e9e9e07dda2b80f757ee3597d247cc5/ddtrace-2.21.12-cp313-cp313-macosx_12_0_universal2.whl", hash = "sha256:29bbb2d72a8d8f4388974a035801f4651edf0cfad97ff67fae3f9d17863d7200", size = 4797212 }, + { url = "https://files.pythonhosted.org/packages/04/4f/2d7def75daf3a7a33729c89845f5f766f3837b3297f08691588e8d9ece0f/ddtrace-2.21.12-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:46f63ec7b1e80f62e4b9bedaec123be3f607bf7e026d980db5656f55c501e970", size = 3265051 }, + { url = "https://files.pythonhosted.org/packages/10/1c/d5a6b3d1132ee26075f7d631aac1cdc00c71f4340132460cf38870d553fa/ddtrace-2.21.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:033d2aabe9b20b2bd6fc6ae226883e21219317a83e2a6ef72ddf76dd00df9a1e", size = 6001434 }, + { url = "https://files.pythonhosted.org/packages/7a/f2/4120b60c1f846d654efdc9367a227aad3058536424936fdae306425df2ef/ddtrace-2.21.12-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ffd0ad30dafd1e2f98843b215f9b75f7d08ec4054def06cda9fb75af5c3d2b4", size = 2799520 }, + { url = "https://files.pythonhosted.org/packages/6c/58/7fa01a3b3ecc41e67c5f5decf1e18031e6e41721c53fcfb8ea3841b13108/ddtrace-2.21.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a829d411a689120bebf67a2018fb2012b3147da6f25041d71b4d15e32f2afb79", size = 6326996 }, + { url = "https://files.pythonhosted.org/packages/fe/e6/71c0a664a3eebf9fc38bbd90b47b89271d30dd0cb796624af7b2af35a80f/ddtrace-2.21.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d98497bcba7d89694e8232180442f7d9c0dddd2f3043f59a02b54609d1abe2e", size = 6985268 }, + { url = "https://files.pythonhosted.org/packages/c1/fb/1791292d992fe0877052eb4ac3fdd0809ee9f361cc0dcbb9fbef80625956/ddtrace-2.21.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:dc6cd4601658c2bf8e33c176a02a5927bf004bed6f18474f27bba311846ffdca", size = 3863893 }, + { url = "https://files.pythonhosted.org/packages/b9/c1/11db5d337f7d24f57e4bf080d4362604aef51668f846ef30ec61568a1584/ddtrace-2.21.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:384abf79063dfa5dc08e067b29b016c03d8209b7fc155684fe5fe56a39282eee", size = 7365578 }, ] [[package]] name = "decorator" version = "5.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084, upload-time = "2026-05-18T06:03:28.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084 } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" }, + { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365 }, ] [[package]] name = "deepmerge" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/15/30e36a657a86a3a36428421d052893ede3001ab52c01b906290c371e5d3a/deepmerge-0.3.0.tar.gz", hash = "sha256:f6fd7f1293c535fb599e197e750dbe8674503c5d2a89759b3c72a3c46746d4fd", size = 17422, upload-time = "2021-04-25T20:36:04.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/15/30e36a657a86a3a36428421d052893ede3001ab52c01b906290c371e5d3a/deepmerge-0.3.0.tar.gz", hash = "sha256:f6fd7f1293c535fb599e197e750dbe8674503c5d2a89759b3c72a3c46746d4fd", size = 17422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/4a/bc7b0bf4b357f192eb3d3a12aa42f34a5664cc3daf0f7fc4e0ddf133d6e8/deepmerge-0.3.0-py2.py3-none-any.whl", hash = "sha256:87166dbe9ba1a3348a45c9d4ada6778f518d41afc0b85aa017ea3041facc3f9c", size = 7616, upload-time = "2021-04-25T20:36:03.451Z" }, + { url = "https://files.pythonhosted.org/packages/41/4a/bc7b0bf4b357f192eb3d3a12aa42f34a5664cc3daf0f7fc4e0ddf133d6e8/deepmerge-0.3.0-py2.py3-none-any.whl", hash = "sha256:87166dbe9ba1a3348a45c9d4ada6778f518d41afc0b85aa017ea3041facc3f9c", size = 7616 }, ] [[package]] name = "distlib" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/b2/d6fc3f2347f43dada79e5ff118493e8109c98400a0e29a1d5264a3aa479b/distlib-0.4.1.tar.gz", hash = "sha256:c3804d0d2d4b5fcd44036eb860cb6660485fcdf5c2aba53dc324d805837ea65b", size = 610526, upload-time = "2026-06-02T11:17:40.691Z" } +sdist = { url = "https://files.pythonhosted.org/packages/86/b2/d6fc3f2347f43dada79e5ff118493e8109c98400a0e29a1d5264a3aa479b/distlib-0.4.1.tar.gz", hash = "sha256:c3804d0d2d4b5fcd44036eb860cb6660485fcdf5c2aba53dc324d805837ea65b", size = 610526 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/18/3497c4fa83a76dcb154923fd2075522e8dd6995ecee4093c00ae18160046/distlib-0.4.1-py2.py3-none-any.whl", hash = "sha256:9c2c552c68cbadc619f2d0ed3a69e27c351a3f4c9baa9ffb7df9e9cdc3d19a97", size = 469216, upload-time = "2026-06-02T11:17:38.779Z" }, + { url = "https://files.pythonhosted.org/packages/25/18/3497c4fa83a76dcb154923fd2075522e8dd6995ecee4093c00ae18160046/distlib-0.4.1-py2.py3-none-any.whl", hash = "sha256:9c2c552c68cbadc619f2d0ed3a69e27c351a3f4c9baa9ffb7df9e9cdc3d19a97", size = 469216 }, ] [[package]] name = "dnspython" version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/7d/c871f55054e403fdfd6b8f65fd6d1c4e147ed100d3e9f9ba1fe695403939/dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc", size = 332727, upload-time = "2024-02-18T18:48:48.952Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/7d/c871f55054e403fdfd6b8f65fd6d1c4e147ed100d3e9f9ba1fe695403939/dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc", size = 332727 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50", size = 307696, upload-time = "2024-02-18T18:48:46.786Z" }, + { url = "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50", size = 307696 }, ] [[package]] name = "envier" version = "0.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1a/3e/49a0e2111173a259c96027e17a50361c474336aba04de6f834d816d18ec3/envier-0.5.2.tar.gz", hash = "sha256:4e7e398cb09a8dd360508ef7e12511a152355426d2544b8487a34dad27cc20ad", size = 9503, upload-time = "2024-07-05T10:34:32.905Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/3e/49a0e2111173a259c96027e17a50361c474336aba04de6f834d816d18ec3/envier-0.5.2.tar.gz", hash = "sha256:4e7e398cb09a8dd360508ef7e12511a152355426d2544b8487a34dad27cc20ad", size = 9503 } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/74/99f5d33b4ec2eed9d19d975ab61e3eeddc71c8780a3e46ec9e0f17095451/envier-0.5.2-py3-none-any.whl", hash = "sha256:65099cf3aa9b3b3b4b92db2f7d29e2910672e085b76f7e587d2167561a834add", size = 10050, upload-time = "2024-07-05T10:34:34.247Z" }, + { url = "https://files.pythonhosted.org/packages/39/74/99f5d33b4ec2eed9d19d975ab61e3eeddc71c8780a3e46ec9e0f17095451/envier-0.5.2-py3-none-any.whl", hash = "sha256:65099cf3aa9b3b3b4b92db2f7d29e2910672e085b76f7e587d2167561a834add", size = 10050 }, ] [[package]] @@ -547,7 +547,7 @@ dependencies = [ [[package]] name = "example-plugins" version = "0.1.0" -source = { editable = "example_plugins" } +source = { virtual = "example_plugins" } dependencies = [ { name = "pluggy" }, ] @@ -559,9 +559,9 @@ requires-dist = [{ name = "pluggy", specifier = "==1.5.0" }] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, ] [[package]] @@ -572,18 +572,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "text-unidecode" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/c2/3109f214108c59e8e247d9e6098f9155f888604b6136c464d35e26dbbd9c/Faker-4.18.0.tar.gz", hash = "sha256:6279746aed175a693108238e6d1ab8d7e26d0ec7ff8474f61025b9fdaae15d65", size = 1035436, upload-time = "2020-11-30T15:38:47.153Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/c2/3109f214108c59e8e247d9e6098f9155f888604b6136c464d35e26dbbd9c/Faker-4.18.0.tar.gz", hash = "sha256:6279746aed175a693108238e6d1ab8d7e26d0ec7ff8474f61025b9fdaae15d65", size = 1035436 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/f6/41260bf1ce823fac4d446058a647f6b2edf1d3f4668d06c0ea040af73ed2/Faker-4.18.0-py3-none-any.whl", hash = "sha256:2ba20a4438429cb08d729175d7bb0435ef3c2c4cedc7b1ceb703ee6da8dad906", size = 1079637, upload-time = "2020-11-30T15:38:44.275Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f6/41260bf1ce823fac4d446058a647f6b2edf1d3f4668d06c0ea040af73ed2/Faker-4.18.0-py3-none-any.whl", hash = "sha256:2ba20a4438429cb08d729175d7bb0435ef3c2c4cedc7b1ceb703ee6da8dad906", size = 1079637 }, ] [[package]] name = "filelock" version = "3.29.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812 }, ] [[package]] @@ -596,9 +596,9 @@ dependencies = [ { name = "jinja2" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4d/5b/2d145f5fe718b2f15ebe69240538f06faa8bbb76488bf962091db1f7a26d/Flask-1.1.4.tar.gz", hash = "sha256:0fbeb6180d383a9186d0d6ed954e0042ad9f18e0e8de088b2b419d526927d196", size = 635920, upload-time = "2021-05-14T01:45:58.328Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/5b/2d145f5fe718b2f15ebe69240538f06faa8bbb76488bf962091db1f7a26d/Flask-1.1.4.tar.gz", hash = "sha256:0fbeb6180d383a9186d0d6ed954e0042ad9f18e0e8de088b2b419d526927d196", size = 635920 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/6d/994208daa354f68fd89a34a8bafbeaab26fda84e7af1e35bdaed02b667e6/Flask-1.1.4-py2.py3-none-any.whl", hash = "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22", size = 94591, upload-time = "2021-05-14T01:45:55.061Z" }, + { url = "https://files.pythonhosted.org/packages/e8/6d/994208daa354f68fd89a34a8bafbeaab26fda84e7af1e35bdaed02b667e6/Flask-1.1.4-py2.py3-none-any.whl", hash = "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22", size = 94591 }, ] [[package]] @@ -609,9 +609,9 @@ dependencies = [ { name = "flask" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472, upload-time = "2025-12-12T20:31:42.861Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257, upload-time = "2025-12-12T20:31:41.3Z" }, + { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257 }, ] [[package]] @@ -624,26 +624,26 @@ dependencies = [ { name = "zope-event" }, { name = "zope-interface" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/27/24/a3a7b713acfcf1177207f49ec25c665123f8972f42bee641bcc9f32961f4/gevent-24.2.1.tar.gz", hash = "sha256:432fc76f680acf7cf188c2ee0f5d3ab73b63c1f03114c7cd8a34cebbe5aa2056", size = 6147507, upload-time = "2024-02-14T11:31:10.128Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/34/e561fb53ec80e81a83b76667c004c838a292dde8adf80ff289558b4a4df8/gevent-24.2.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:03aa5879acd6b7076f6a2a307410fb1e0d288b84b03cdfd8c74db8b4bc882fc5", size = 3017855, upload-time = "2024-02-14T11:26:23.685Z" }, - { url = "https://files.pythonhosted.org/packages/4a/db/64295bfd9a51874b715e82ba5ab971f2c298cf283297e4cf5bec37db17d9/gevent-24.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8bb35ce57a63c9a6896c71a285818a3922d8ca05d150fd1fe49a7f57287b836", size = 4877510, upload-time = "2024-02-14T12:09:43.242Z" }, - { url = "https://files.pythonhosted.org/packages/40/9c/8880eef385b31f694222f5c94b2b487a8b37b99aceeed3e93cb0cb038511/gevent-24.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7f87c2c02e03d99b95cfa6f7a776409083a9e4d468912e18c7680437b29222c", size = 5010258, upload-time = "2024-02-14T12:07:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/9c/0e/bf924a9998137d51e8ba84bd600ff5de17e405284811b26307748c0e0f9b/gevent-24.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968581d1717bbcf170758580f5f97a2925854943c45a19be4d47299507db2eb7", size = 5066723, upload-time = "2024-02-14T12:10:56.261Z" }, - { url = "https://files.pythonhosted.org/packages/a1/bc/0f776a3f5a3c57e3f6bbe8abc3d39cc591f58aa03808b50af4f73ae4b238/gevent-24.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7899a38d0ae7e817e99adb217f586d0a4620e315e4de577444ebeeed2c5729be", size = 6700752, upload-time = "2024-02-14T11:53:59.856Z" }, - { url = "https://files.pythonhosted.org/packages/58/b8/aaf9ff71ba9a7012e04400726b0e0e6986460030dfae3168482069422305/gevent-24.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f5e8e8d60e18d5f7fd49983f0c4696deeddaf6e608fbab33397671e2fcc6cc91", size = 6679723, upload-time = "2024-02-14T11:59:14.753Z" }, - { url = "https://files.pythonhosted.org/packages/74/ee/6febc62ddd399b0f060785bea8ae3c994ce47dfe6ec46ece3b1a90cc496b/gevent-24.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682", size = 5434796, upload-time = "2024-02-14T12:25:50.016Z" }, - { url = "https://files.pythonhosted.org/packages/15/12/7c91964af7112b3b435aa836401d8ca212ba9d43bcfea34c770b73515740/gevent-24.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cdf66977a976d6a3cfb006afdf825d1482f84f7b81179db33941f2fc9673bb1d", size = 6776495, upload-time = "2024-02-14T12:01:16.975Z" }, - { url = "https://files.pythonhosted.org/packages/18/b1/bbaf6047b13c4b83cd81007298f4f8ddffd8674c130736423e79e7bb8b6a/gevent-24.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1dffb395e500613e0452b9503153f8f7ba587c67dd4a85fc7cd7aa7430cb02cc", size = 1525019, upload-time = "2024-02-14T11:39:23.072Z" }, - { url = "https://files.pythonhosted.org/packages/50/72/eb98be1cec2a3d0f46d3af49b034deb48a6d6d9a1958ee110bc2e1e600ac/gevent-24.2.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:6c47ae7d1174617b3509f5d884935e788f325eb8f1a7efc95d295c68d83cce40", size = 3007004, upload-time = "2024-02-14T11:28:20.476Z" }, - { url = "https://files.pythonhosted.org/packages/f7/14/4cc83275fcdfa1977224cc266b710dc71b810d6760f575d259ca3be7b4dd/gevent-24.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7cac622e11b4253ac4536a654fe221249065d9a69feb6cdcd4d9af3503602e0", size = 5142074, upload-time = "2024-02-14T12:09:45.269Z" }, - { url = "https://files.pythonhosted.org/packages/56/ce/583d29e524c5666f7d66116e818449bee649bba8088d0ac48bec6c006215/gevent-24.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf5b9c72b884c6f0c4ed26ef204ee1f768b9437330422492c319470954bc4cc7", size = 5307651, upload-time = "2024-02-14T12:07:36.645Z" }, - { url = "https://files.pythonhosted.org/packages/69/e7/072dfbf5c534516dcc91367d5dd5806ec8860b66c1df26b9d603493c1adb/gevent-24.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5de3c676e57177b38857f6e3cdfbe8f38d1cd754b63200c0615eaa31f514b4f", size = 5406093, upload-time = "2024-02-14T12:10:58.794Z" }, - { url = "https://files.pythonhosted.org/packages/d9/d3/f9d0f62cb6cb0421d0da2cffd10bad13b0f5d641c57ce35927bf8554661e/gevent-24.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4faf846ed132fd7ebfbbf4fde588a62d21faa0faa06e6f468b7faa6f436b661", size = 6730420, upload-time = "2024-02-14T11:54:02.399Z" }, - { url = "https://files.pythonhosted.org/packages/5b/eb/6b0e902e29283253324fe32317b805df289f05f0ef3e9859a721d403b71e/gevent-24.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:368a277bd9278ddb0fde308e6a43f544222d76ed0c4166e0d9f6b036586819d9", size = 6711332, upload-time = "2024-02-14T11:59:16.68Z" }, - { url = "https://files.pythonhosted.org/packages/0d/8b/02a07125324e23d64ec342ae7a4cff8dc7271114e787317a5f219027bf1b/gevent-24.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f8a04cf0c5b7139bc6368b461257d4a757ea2fe89b3773e494d235b7dd51119f", size = 5482031, upload-time = "2024-02-14T12:25:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/5f/fe/288ccd562ac20d5e4ae2624313b699ee35c76be1faa9104b414bfe714a67/gevent-24.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9d8d0642c63d453179058abc4143e30718b19a85cbf58c2744c9a63f06a1d388", size = 6812353, upload-time = "2024-02-14T12:01:19.819Z" }, - { url = "https://files.pythonhosted.org/packages/2e/90/d9fcdc22864d0cf471630071c264289b9a803892d6f55e895a69c2e3574b/gevent-24.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:94138682e68ec197db42ad7442d3cf9b328069c3ad8e4e5022e6b5cd3e7ffae5", size = 1523715, upload-time = "2024-02-14T11:31:09.195Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/27/24/a3a7b713acfcf1177207f49ec25c665123f8972f42bee641bcc9f32961f4/gevent-24.2.1.tar.gz", hash = "sha256:432fc76f680acf7cf188c2ee0f5d3ab73b63c1f03114c7cd8a34cebbe5aa2056", size = 6147507 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/34/e561fb53ec80e81a83b76667c004c838a292dde8adf80ff289558b4a4df8/gevent-24.2.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:03aa5879acd6b7076f6a2a307410fb1e0d288b84b03cdfd8c74db8b4bc882fc5", size = 3017855 }, + { url = "https://files.pythonhosted.org/packages/4a/db/64295bfd9a51874b715e82ba5ab971f2c298cf283297e4cf5bec37db17d9/gevent-24.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8bb35ce57a63c9a6896c71a285818a3922d8ca05d150fd1fe49a7f57287b836", size = 4877510 }, + { url = "https://files.pythonhosted.org/packages/40/9c/8880eef385b31f694222f5c94b2b487a8b37b99aceeed3e93cb0cb038511/gevent-24.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7f87c2c02e03d99b95cfa6f7a776409083a9e4d468912e18c7680437b29222c", size = 5010258 }, + { url = "https://files.pythonhosted.org/packages/9c/0e/bf924a9998137d51e8ba84bd600ff5de17e405284811b26307748c0e0f9b/gevent-24.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968581d1717bbcf170758580f5f97a2925854943c45a19be4d47299507db2eb7", size = 5066723 }, + { url = "https://files.pythonhosted.org/packages/a1/bc/0f776a3f5a3c57e3f6bbe8abc3d39cc591f58aa03808b50af4f73ae4b238/gevent-24.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7899a38d0ae7e817e99adb217f586d0a4620e315e4de577444ebeeed2c5729be", size = 6700752 }, + { url = "https://files.pythonhosted.org/packages/58/b8/aaf9ff71ba9a7012e04400726b0e0e6986460030dfae3168482069422305/gevent-24.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f5e8e8d60e18d5f7fd49983f0c4696deeddaf6e608fbab33397671e2fcc6cc91", size = 6679723 }, + { url = "https://files.pythonhosted.org/packages/74/ee/6febc62ddd399b0f060785bea8ae3c994ce47dfe6ec46ece3b1a90cc496b/gevent-24.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682", size = 5434796 }, + { url = "https://files.pythonhosted.org/packages/15/12/7c91964af7112b3b435aa836401d8ca212ba9d43bcfea34c770b73515740/gevent-24.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cdf66977a976d6a3cfb006afdf825d1482f84f7b81179db33941f2fc9673bb1d", size = 6776495 }, + { url = "https://files.pythonhosted.org/packages/18/b1/bbaf6047b13c4b83cd81007298f4f8ddffd8674c130736423e79e7bb8b6a/gevent-24.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1dffb395e500613e0452b9503153f8f7ba587c67dd4a85fc7cd7aa7430cb02cc", size = 1525019 }, + { url = "https://files.pythonhosted.org/packages/50/72/eb98be1cec2a3d0f46d3af49b034deb48a6d6d9a1958ee110bc2e1e600ac/gevent-24.2.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:6c47ae7d1174617b3509f5d884935e788f325eb8f1a7efc95d295c68d83cce40", size = 3007004 }, + { url = "https://files.pythonhosted.org/packages/f7/14/4cc83275fcdfa1977224cc266b710dc71b810d6760f575d259ca3be7b4dd/gevent-24.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7cac622e11b4253ac4536a654fe221249065d9a69feb6cdcd4d9af3503602e0", size = 5142074 }, + { url = "https://files.pythonhosted.org/packages/56/ce/583d29e524c5666f7d66116e818449bee649bba8088d0ac48bec6c006215/gevent-24.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf5b9c72b884c6f0c4ed26ef204ee1f768b9437330422492c319470954bc4cc7", size = 5307651 }, + { url = "https://files.pythonhosted.org/packages/69/e7/072dfbf5c534516dcc91367d5dd5806ec8860b66c1df26b9d603493c1adb/gevent-24.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5de3c676e57177b38857f6e3cdfbe8f38d1cd754b63200c0615eaa31f514b4f", size = 5406093 }, + { url = "https://files.pythonhosted.org/packages/d9/d3/f9d0f62cb6cb0421d0da2cffd10bad13b0f5d641c57ce35927bf8554661e/gevent-24.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4faf846ed132fd7ebfbbf4fde588a62d21faa0faa06e6f468b7faa6f436b661", size = 6730420 }, + { url = "https://files.pythonhosted.org/packages/5b/eb/6b0e902e29283253324fe32317b805df289f05f0ef3e9859a721d403b71e/gevent-24.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:368a277bd9278ddb0fde308e6a43f544222d76ed0c4166e0d9f6b036586819d9", size = 6711332 }, + { url = "https://files.pythonhosted.org/packages/0d/8b/02a07125324e23d64ec342ae7a4cff8dc7271114e787317a5f219027bf1b/gevent-24.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f8a04cf0c5b7139bc6368b461257d4a757ea2fe89b3773e494d235b7dd51119f", size = 5482031 }, + { url = "https://files.pythonhosted.org/packages/5f/fe/288ccd562ac20d5e4ae2624313b699ee35c76be1faa9104b414bfe714a67/gevent-24.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9d8d0642c63d453179058abc4143e30718b19a85cbf58c2744c9a63f06a1d388", size = 6812353 }, + { url = "https://files.pythonhosted.org/packages/2e/90/d9fcdc22864d0cf471630071c264289b9a803892d6f55e895a69c2e3574b/gevent-24.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:94138682e68ec197db42ad7442d3cf9b328069c3ad8e4e5022e6b5cd3e7ffae5", size = 1523715 }, ] [[package]] @@ -657,9 +657,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/14/99c2514b3ccc5aad1e0776f0ae8295c9f7153aead4f41d07dd126cecdc14/google_api_core-2.19.2.tar.gz", hash = "sha256:ca07de7e8aa1c98a8bfca9321890ad2340ef7f2eb136e558cee68f24b94b0a8f", size = 149057, upload-time = "2024-08-27T20:59:18.945Z" } +sdist = { url = "https://files.pythonhosted.org/packages/78/14/99c2514b3ccc5aad1e0776f0ae8295c9f7153aead4f41d07dd126cecdc14/google_api_core-2.19.2.tar.gz", hash = "sha256:ca07de7e8aa1c98a8bfca9321890ad2340ef7f2eb136e558cee68f24b94b0a8f", size = 149057 } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/53/2e340a6ed897fa2bdd6c1bf166b98c047fbb648463dfd2b209ca7d501984/google_api_core-2.19.2-py3-none-any.whl", hash = "sha256:53ec0258f2837dd53bbd3d3df50f5359281b3cc13f800c941dd15a9b5a415af4", size = 139427, upload-time = "2024-08-27T20:59:17.388Z" }, + { url = "https://files.pythonhosted.org/packages/79/53/2e340a6ed897fa2bdd6c1bf166b98c047fbb648463dfd2b209ca7d501984/google_api_core-2.19.2-py3-none-any.whl", hash = "sha256:53ec0258f2837dd53bbd3d3df50f5359281b3cc13f800c941dd15a9b5a415af4", size = 139427 }, ] [package.optional-dependencies] @@ -681,9 +681,9 @@ dependencies = [ { name = "httplib2" }, { name = "uritemplate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/75/7a04c88700a6c186bb7e9979c1b2b15d1944bf66453b778ea69e4efcccb6/google-api-python-client-2.105.0.tar.gz", hash = "sha256:0a8b32cfc2d9b3c1868ae6faef7ee1ab9c89a6cec30be709ea9c97f9a3e5902d", size = 12113230, upload-time = "2023-10-24T15:09:54.089Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/75/7a04c88700a6c186bb7e9979c1b2b15d1944bf66453b778ea69e4efcccb6/google-api-python-client-2.105.0.tar.gz", hash = "sha256:0a8b32cfc2d9b3c1868ae6faef7ee1ab9c89a6cec30be709ea9c97f9a3e5902d", size = 12113230 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/9a/69b094da2ddce819b905e3d63e3bf8713a519a5cec0b109f39a1e5da8926/google_api_python_client-2.105.0-py2.py3-none-any.whl", hash = "sha256:571ce7c41e53415e385aab5a955725f71780550683ffcb71596f5809677d40b7", size = 12635122, upload-time = "2023-10-24T15:09:50.661Z" }, + { url = "https://files.pythonhosted.org/packages/0b/9a/69b094da2ddce819b905e3d63e3bf8713a519a5cec0b109f39a1e5da8926/google_api_python_client-2.105.0-py2.py3-none-any.whl", hash = "sha256:571ce7c41e53415e385aab5a955725f71780550683ffcb71596f5809677d40b7", size = 12635122 }, ] [[package]] @@ -695,9 +695,9 @@ dependencies = [ { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/9b/e92ef23b84fa10a64ce4831390b7a4c2e53c0132568d99d4ae61d04c8855/google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77", size = 281029, upload-time = "2025-06-04T18:04:57.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/9b/e92ef23b84fa10a64ce4831390b7a4c2e53c0132568d99d4ae61d04c8855/google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77", size = 281029 } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca", size = 216137, upload-time = "2025-06-04T18:04:55.573Z" }, + { url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca", size = 216137 }, ] [[package]] @@ -708,9 +708,9 @@ dependencies = [ { name = "google-auth" }, { name = "httplib2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1c/b3/f192c8bc7e41e0ebdbd95afcae4783417a34b6a6af62d22daf22c3fd38fc/google_auth_httplib2-0.4.0.tar.gz", hash = "sha256:d5b030a204b7a4b4d553ba9ca701b62481ee2b74419325580be70f7d85ffed35", size = 11161, upload-time = "2026-05-07T08:03:46.878Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/b3/f192c8bc7e41e0ebdbd95afcae4783417a34b6a6af62d22daf22c3fd38fc/google_auth_httplib2-0.4.0.tar.gz", hash = "sha256:d5b030a204b7a4b4d553ba9ca701b62481ee2b74419325580be70f7d85ffed35", size = 11161 } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/be/954c35a62b9e31de66b0a43c225c9b6bb9e0f98d6b1dc110a2308e3644f5/google_auth_httplib2-0.4.0-py3-none-any.whl", hash = "sha256:8e55cfafa3358cba85f6cad4a886138e88e158d71e7e5c9ee5936a5c1507fb91", size = 9529, upload-time = "2026-05-07T08:02:12.375Z" }, + { url = "https://files.pythonhosted.org/packages/97/be/954c35a62b9e31de66b0a43c225c9b6bb9e0f98d6b1dc110a2308e3644f5/google_auth_httplib2-0.4.0-py3-none-any.whl", hash = "sha256:8e55cfafa3358cba85f6cad4a886138e88e158d71e7e5c9ee5936a5c1507fb91", size = 9529 }, ] [[package]] @@ -723,9 +723,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/ea/85da73d4f162b29d24ad591c4ce02688b44094ee5f3d6c0cc533c2b23b23/google_cloud_appengine_logging-1.6.2.tar.gz", hash = "sha256:4890928464c98da9eecc7bf4e0542eba2551512c0265462c10f3a3d2a6424b90", size = 16587, upload-time = "2025-06-11T22:38:53.525Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ea/85da73d4f162b29d24ad591c4ce02688b44094ee5f3d6c0cc533c2b23b23/google_cloud_appengine_logging-1.6.2.tar.gz", hash = "sha256:4890928464c98da9eecc7bf4e0542eba2551512c0265462c10f3a3d2a6424b90", size = 16587 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/9e/dc1fd7f838dcaf608c465171b1a25d8ce63f9987e2d5c73bda98792097a9/google_cloud_appengine_logging-1.6.2-py3-none-any.whl", hash = "sha256:2b28ed715e92b67e334c6fcfe1deb523f001919560257b25fc8fcda95fd63938", size = 16889, upload-time = "2025-06-11T22:38:52.26Z" }, + { url = "https://files.pythonhosted.org/packages/e4/9e/dc1fd7f838dcaf608c465171b1a25d8ce63f9987e2d5c73bda98792097a9/google_cloud_appengine_logging-1.6.2-py3-none-any.whl", hash = "sha256:2b28ed715e92b67e334c6fcfe1deb523f001919560257b25fc8fcda95fd63938", size = 16889 }, ] [[package]] @@ -736,9 +736,9 @@ dependencies = [ { name = "googleapis-common-protos" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/af/53b4ef636e492d136b3c217e52a07bee569430dda07b8e515d5f2b701b1e/google_cloud_audit_log-0.3.2.tar.gz", hash = "sha256:2598f1533a7d7cdd6c7bf448c12e5519c1d53162d78784e10bcdd1df67791bc3", size = 33377, upload-time = "2025-03-17T11:27:59.808Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/af/53b4ef636e492d136b3c217e52a07bee569430dda07b8e515d5f2b701b1e/google_cloud_audit_log-0.3.2.tar.gz", hash = "sha256:2598f1533a7d7cdd6c7bf448c12e5519c1d53162d78784e10bcdd1df67791bc3", size = 33377 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/74/38a70339e706b174b3c1117ad931aaa0ff0565b599869317a220d1967e1b/google_cloud_audit_log-0.3.2-py3-none-any.whl", hash = "sha256:daaedfb947a0d77f524e1bd2b560242ab4836fe1afd6b06b92f152b9658554ed", size = 32472, upload-time = "2025-03-17T11:27:58.51Z" }, + { url = "https://files.pythonhosted.org/packages/b1/74/38a70339e706b174b3c1117ad931aaa0ff0565b599869317a220d1967e1b/google_cloud_audit_log-0.3.2-py3-none-any.whl", hash = "sha256:daaedfb947a0d77f524e1bd2b560242ab4836fe1afd6b06b92f152b9658554ed", size = 32472 }, ] [[package]] @@ -754,9 +754,9 @@ dependencies = [ { name = "python-dateutil" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/05/633ce6686b1fed2cd364fa4698bfa6d586263cd4795d012584f8097061e1/google_cloud_bigquery-3.27.0.tar.gz", hash = "sha256:379c524054d7b090fa56d0c22662cc6e6458a6229b6754c0e7177e3a73421d2c", size = 456964, upload-time = "2024-11-11T16:50:00.712Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/05/633ce6686b1fed2cd364fa4698bfa6d586263cd4795d012584f8097061e1/google_cloud_bigquery-3.27.0.tar.gz", hash = "sha256:379c524054d7b090fa56d0c22662cc6e6458a6229b6754c0e7177e3a73421d2c", size = 456964 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/40/4b11a4a8839de8ce802a3ccd60b34e70ce10d13d434a560534ba98f0ea3f/google_cloud_bigquery-3.27.0-py2.py3-none-any.whl", hash = "sha256:b53b0431e5ba362976a4cd8acce72194b4116cdf8115030c7b339b884603fcc3", size = 240100, upload-time = "2024-11-11T16:49:58.805Z" }, + { url = "https://files.pythonhosted.org/packages/f5/40/4b11a4a8839de8ce802a3ccd60b34e70ce10d13d434a560534ba98f0ea3f/google_cloud_bigquery-3.27.0-py2.py3-none-any.whl", hash = "sha256:b53b0431e5ba362976a4cd8acce72194b4116cdf8115030c7b339b884603fcc3", size = 240100 }, ] [[package]] @@ -769,9 +769,9 @@ dependencies = [ { name = "grpc-google-iam-v1" }, { name = "proto-plus" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/03/fd96882fb203c91ec65c41e817c767a873ec277657c8a37b7516689d7af1/google-cloud-bigtable-2.10.0.tar.gz", hash = "sha256:9e2714a4468f843066594da33ff474d5de78c6ef6d80d5316550f8819180c80c", size = 284784, upload-time = "2022-05-30T18:02:49.809Z" } +sdist = { url = "https://files.pythonhosted.org/packages/89/03/fd96882fb203c91ec65c41e817c767a873ec277657c8a37b7516689d7af1/google-cloud-bigtable-2.10.0.tar.gz", hash = "sha256:9e2714a4468f843066594da33ff474d5de78c6ef6d80d5316550f8819180c80c", size = 284784 } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/18/456cadee7a85862237c92de0154341fcabcef6ceaa8adfdff32a45482a8d/google_cloud_bigtable-2.10.0-py2.py3-none-any.whl", hash = "sha256:9f4b658dcc37d43f3c5338ebc4961ceba6be3269930453b6edc03dedc25abc08", size = 237603, upload-time = "2022-05-30T18:02:47.89Z" }, + { url = "https://files.pythonhosted.org/packages/75/18/456cadee7a85862237c92de0154341fcabcef6ceaa8adfdff32a45482a8d/google_cloud_bigtable-2.10.0-py2.py3-none-any.whl", hash = "sha256:9f4b658dcc37d43f3c5338ebc4961ceba6be3269930453b6edc03dedc25abc08", size = 237603 }, ] [[package]] @@ -782,9 +782,9 @@ dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/dd/1eef226e470369b26824a505c34482c0b493bc35fe8e0c6b003b5feca21a/google_cloud_core-2.6.0.tar.gz", hash = "sha256:e76149739f90fac1fc6757c09f47eaccb3145b54adbd7759b0f7c4b235f46c83", size = 36001, upload-time = "2026-05-07T08:04:04.124Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/dd/1eef226e470369b26824a505c34482c0b493bc35fe8e0c6b003b5feca21a/google_cloud_core-2.6.0.tar.gz", hash = "sha256:e76149739f90fac1fc6757c09f47eaccb3145b54adbd7759b0f7c4b235f46c83", size = 36001 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/4a/98da8930ab109c73d9a5d13782a9ebb81ea8c111f6d534a567b71d23e52b/google_cloud_core-2.6.0-py3-none-any.whl", hash = "sha256:6d63ac8e5eca6d9e4319d0a1e2265fadcd7f1049904378caecfa01cf52dd869e", size = 29390, upload-time = "2026-05-07T08:02:34.672Z" }, + { url = "https://files.pythonhosted.org/packages/84/4a/98da8930ab109c73d9a5d13782a9ebb81ea8c111f6d534a567b71d23e52b/google_cloud_core-2.6.0-py3-none-any.whl", hash = "sha256:6d63ac8e5eca6d9e4319d0a1e2265fadcd7f1049904378caecfa01cf52dd869e", size = 29390 }, ] [[package]] @@ -798,9 +798,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ec/d4/2e8d1c39be35152b8b15ad8f3e841d048f77fa17ae777f8014ed3eed4b15/google_cloud_kms-3.5.1.tar.gz", hash = "sha256:b5f1ac87f8dc9a6642439e93baa5a63ee2d4d18c140669941689e9ab5abed1d9", size = 327236, upload-time = "2025-05-20T18:46:22.705Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/d4/2e8d1c39be35152b8b15ad8f3e841d048f77fa17ae777f8014ed3eed4b15/google_cloud_kms-3.5.1.tar.gz", hash = "sha256:b5f1ac87f8dc9a6642439e93baa5a63ee2d4d18c140669941689e9ab5abed1d9", size = 327236 } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/86/480d298145d15caf994cd13ee0fac764a3d29d07367550e604f31369d81f/google_cloud_kms-3.5.1-py3-none-any.whl", hash = "sha256:11dc9a1b4edcc6794c5fee7e4e7dbd14b051bde99f4702bd70fec193d152abdc", size = 270815, upload-time = "2025-05-20T18:46:21.116Z" }, + { url = "https://files.pythonhosted.org/packages/78/86/480d298145d15caf994cd13ee0fac764a3d29d07367550e604f31369d81f/google_cloud_kms-3.5.1-py3-none-any.whl", hash = "sha256:11dc9a1b4edcc6794c5fee7e4e7dbd14b051bde99f4702bd70fec193d152abdc", size = 270815 }, ] [[package]] @@ -816,9 +816,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3c/42/84edbb0350016cb35484f38071d8249fac6b0f4611d585e2a2a4acd6fefe/google-cloud-logging-3.4.0.tar.gz", hash = "sha256:cde0f59fadb917468746252baf4b11ea00f6d686ef02139183eaf921f3aee6b4", size = 227885, upload-time = "2022-12-27T22:03:07.855Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/42/84edbb0350016cb35484f38071d8249fac6b0f4611d585e2a2a4acd6fefe/google-cloud-logging-3.4.0.tar.gz", hash = "sha256:cde0f59fadb917468746252baf4b11ea00f6d686ef02139183eaf921f3aee6b4", size = 227885 } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/92/05e3c6a4cab7ff5ccbf00adcfaf002639271bf5a635074053aea7a7a1931/google_cloud_logging-3.4.0-py2.py3-none-any.whl", hash = "sha256:afe1d558346e4a6ff8203bfb4266cff8f5fb46816ad0930a9af0d3956a218838", size = 195189, upload-time = "2022-12-27T22:03:06.194Z" }, + { url = "https://files.pythonhosted.org/packages/29/92/05e3c6a4cab7ff5ccbf00adcfaf002639271bf5a635074053aea7a7a1931/google_cloud_logging-3.4.0-py2.py3-none-any.whl", hash = "sha256:afe1d558346e4a6ff8203bfb4266cff8f5fb46816ad0930a9af0d3956a218838", size = 195189 }, ] [[package]] @@ -835,9 +835,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/5c/1ff5f8e37aad3350e36998c811801997468b9d264835355157e22332e13a/google-cloud-pubsub-2.15.2.tar.gz", hash = "sha256:f3a652ae4436034ed51fc884afbef7f69cbe0325129531545e49f017c1ef1401", size = 267849, upload-time = "2023-03-23T02:40:18.249Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/5c/1ff5f8e37aad3350e36998c811801997468b9d264835355157e22332e13a/google-cloud-pubsub-2.15.2.tar.gz", hash = "sha256:f3a652ae4436034ed51fc884afbef7f69cbe0325129531545e49f017c1ef1401", size = 267849 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/90/5ca683a31d17d0139c37143652b2bc55302d6f4acc2ea18cff688bf83692/google_cloud_pubsub-2.15.2-py2.py3-none-any.whl", hash = "sha256:9ec481211db781dfca0ac182259ecb078ed504062aacbf3d0cb7ce261c9690c9", size = 243122, upload-time = "2023-03-23T02:40:15.793Z" }, + { url = "https://files.pythonhosted.org/packages/4e/90/5ca683a31d17d0139c37143652b2bc55302d6f4acc2ea18cff688bf83692/google_cloud_pubsub-2.15.2-py2.py3-none-any.whl", hash = "sha256:9ec481211db781dfca0ac182259ecb078ed504062aacbf3d0cb7ce261c9690c9", size = 243122 }, ] [[package]] @@ -851,9 +851,9 @@ dependencies = [ { name = "proto-plus" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/7a/2fa6735ec693d822fe08a76709c4d95d9b5b4c02e83e720497355039d2ee/google_cloud_secret_manager-2.24.0.tar.gz", hash = "sha256:ce573d40ffc2fb7d01719243a94ee17aa243ea642a6ae6c337501e58fbf642b5", size = 269516, upload-time = "2025-06-05T22:22:22.965Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/7a/2fa6735ec693d822fe08a76709c4d95d9b5b4c02e83e720497355039d2ee/google_cloud_secret_manager-2.24.0.tar.gz", hash = "sha256:ce573d40ffc2fb7d01719243a94ee17aa243ea642a6ae6c337501e58fbf642b5", size = 269516 } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/af/db1217cae1809e69a4527ee6293b82a9af2a1fb2313ad110c775e8f3c820/google_cloud_secret_manager-2.24.0-py3-none-any.whl", hash = "sha256:9bea1254827ecc14874bc86c63b899489f8f50bfe1442bfb2517530b30b3a89b", size = 218050, upload-time = "2025-06-10T02:02:19.88Z" }, + { url = "https://files.pythonhosted.org/packages/be/af/db1217cae1809e69a4527ee6293b82a9af2a1fb2313ad110c775e8f3c820/google_cloud_secret_manager-2.24.0-py3-none-any.whl", hash = "sha256:9bea1254827ecc14874bc86c63b899489f8f50bfe1442bfb2517530b30b3a89b", size = 218050 }, ] [[package]] @@ -867,39 +867,39 @@ dependencies = [ { name = "google-resumable-media" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/20/51e9676cc112ec7344c0a8690361175dc1f41ed6edf618eae8af87d92a49/google-cloud-storage-2.10.0.tar.gz", hash = "sha256:934b31ead5f3994e5360f9ff5750982c5b6b11604dc072bc452c25965e076dc7", size = 5504936, upload-time = "2023-06-26T20:34:54.303Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/20/51e9676cc112ec7344c0a8690361175dc1f41ed6edf618eae8af87d92a49/google-cloud-storage-2.10.0.tar.gz", hash = "sha256:934b31ead5f3994e5360f9ff5750982c5b6b11604dc072bc452c25965e076dc7", size = 5504936 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/14/c9d4faae7ea4bff4405152cbc762b61100aa6949273b4eb3203d23308670/google_cloud_storage-2.10.0-py2.py3-none-any.whl", hash = "sha256:9433cf28801671de1c80434238fb1e7e4a1ba3087470e90f70c928ea77c2b9d7", size = 114565, upload-time = "2023-06-26T20:34:51.797Z" }, + { url = "https://files.pythonhosted.org/packages/88/14/c9d4faae7ea4bff4405152cbc762b61100aa6949273b4eb3203d23308670/google_cloud_storage-2.10.0-py2.py3-none-any.whl", hash = "sha256:9433cf28801671de1c80434238fb1e7e4a1ba3087470e90f70c928ea77c2b9d7", size = 114565 }, ] [[package]] name = "google-crc32c" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298, upload-time = "2025-12-16T00:20:32.241Z" }, - { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872, upload-time = "2025-12-16T00:33:58.785Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243, upload-time = "2025-12-16T00:40:21.46Z" }, - { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608, upload-time = "2025-12-16T00:40:22.204Z" }, - { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439, upload-time = "2025-12-16T00:35:20.458Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5f/7307325b1198b59324c0fa9807cafb551afb65e831699f2ce211ad5c8240/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113", size = 31300, upload-time = "2025-12-16T00:21:56.723Z" }, - { url = "https://files.pythonhosted.org/packages/21/8e/58c0d5d86e2220e6a37befe7e6a94dd2f6006044b1a33edf1ff6d9f7e319/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb", size = 30867, upload-time = "2025-12-16T00:38:31.302Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364, upload-time = "2025-12-16T00:40:22.96Z" }, - { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740, upload-time = "2025-12-16T00:40:23.96Z" }, - { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437, upload-time = "2025-12-16T00:35:21.395Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297, upload-time = "2025-12-16T00:23:20.709Z" }, - { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867, upload-time = "2025-12-16T00:43:14.628Z" }, - { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344, upload-time = "2025-12-16T00:40:24.742Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694, upload-time = "2025-12-16T00:40:25.505Z" }, - { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435, upload-time = "2025-12-16T00:35:22.107Z" }, - { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301, upload-time = "2025-12-16T00:24:48.527Z" }, - { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868, upload-time = "2025-12-16T00:48:12.163Z" }, - { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload-time = "2025-12-16T00:40:26.268Z" }, - { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload-time = "2025-12-16T00:40:27.028Z" }, - { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload-time = "2025-12-16T00:35:23.142Z" }, - { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615, upload-time = "2025-12-16T00:40:29.298Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800, upload-time = "2025-12-16T00:40:30.322Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298 }, + { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872 }, + { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243 }, + { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608 }, + { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439 }, + { url = "https://files.pythonhosted.org/packages/e9/5f/7307325b1198b59324c0fa9807cafb551afb65e831699f2ce211ad5c8240/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113", size = 31300 }, + { url = "https://files.pythonhosted.org/packages/21/8e/58c0d5d86e2220e6a37befe7e6a94dd2f6006044b1a33edf1ff6d9f7e319/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb", size = 30867 }, + { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364 }, + { url = "https://files.pythonhosted.org/packages/21/3f/3457ea803db0198c9aaca2dd373750972ce28a26f00544b6b85088811939/google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454", size = 33740 }, + { url = "https://files.pythonhosted.org/packages/df/c0/87c2073e0c72515bb8733d4eef7b21548e8d189f094b5dad20b0ecaf64f6/google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962", size = 34437 }, + { url = "https://files.pythonhosted.org/packages/d1/db/000f15b41724589b0e7bc24bc7a8967898d8d3bc8caf64c513d91ef1f6c0/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b", size = 31297 }, + { url = "https://files.pythonhosted.org/packages/d7/0d/8ebed0c39c53a7e838e2a486da8abb0e52de135f1b376ae2f0b160eb4c1a/google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27", size = 30867 }, + { url = "https://files.pythonhosted.org/packages/ce/42/b468aec74a0354b34c8cbf748db20d6e350a68a2b0912e128cabee49806c/google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa", size = 33344 }, + { url = "https://files.pythonhosted.org/packages/1c/e8/b33784d6fc77fb5062a8a7854e43e1e618b87d5ddf610a88025e4de6226e/google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8", size = 33694 }, + { url = "https://files.pythonhosted.org/packages/92/b1/d3cbd4d988afb3d8e4db94ca953df429ed6db7282ed0e700d25e6c7bfc8d/google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f", size = 34435 }, + { url = "https://files.pythonhosted.org/packages/21/88/8ecf3c2b864a490b9e7010c84fd203ec8cf3b280651106a3a74dd1b0ca72/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697", size = 31301 }, + { url = "https://files.pythonhosted.org/packages/36/c6/f7ff6c11f5ca215d9f43d3629163727a272eabc356e5c9b2853df2bfe965/google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651", size = 30868 }, + { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381 }, + { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734 }, + { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878 }, + { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615 }, + { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800 }, ] [[package]] @@ -909,9 +909,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099, upload-time = "2024-08-07T22:20:38.555Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251, upload-time = "2024-08-07T22:20:36.409Z" }, + { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251 }, ] [[package]] @@ -921,9 +921,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903 } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" }, + { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530 }, ] [package.optional-dependencies] @@ -936,9 +936,9 @@ grpc = [ name = "graphviz" version = "0.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/ae/a0ee0dbddc06dbecfaece65c45c8c4729c394b5eb62e04e711e6495cdf64/graphviz-0.20.zip", hash = "sha256:76bdfb73f42e72564ffe9c7299482f9d72f8e6cb8d54bce7b48ab323755e9ba5", size = 255452, upload-time = "2022-04-16T15:32:16.872Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/ae/a0ee0dbddc06dbecfaece65c45c8c4729c394b5eb62e04e711e6495cdf64/graphviz-0.20.zip", hash = "sha256:76bdfb73f42e72564ffe9c7299482f9d72f8e6cb8d54bce7b48ab323755e9ba5", size = 255452 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/ea/81a8018c234ad6219c27155fe3dce349f2ba83e6ebed582c9f8aca46091f/graphviz-0.20-py3-none-any.whl", hash = "sha256:62c5f48bcc534a45b4588c548ff75e419c1f1f3a33d31a91796ae80a7f581e4a", size = 46997, upload-time = "2022-04-16T15:32:15.016Z" }, + { url = "https://files.pythonhosted.org/packages/4d/ea/81a8018c234ad6219c27155fe3dce349f2ba83e6ebed582c9f8aca46091f/graphviz-0.20-py3-none-any.whl", hash = "sha256:62c5f48bcc534a45b4588c548ff75e419c1f1f3a33d31a91796ae80a7f581e4a", size = 46997 }, ] [[package]] @@ -956,9 +956,9 @@ dependencies = [ { name = "grpcio", version = "1.53.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64'" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/4e/8d0ca3b035e41fe0b3f31ebbb638356af720335e5a11154c330169b40777/grpc_google_iam_v1-0.14.2.tar.gz", hash = "sha256:b3e1fc387a1a329e41672197d0ace9de22c78dd7d215048c4c78712073f7bd20", size = 16259, upload-time = "2025-03-17T11:40:23.586Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/4e/8d0ca3b035e41fe0b3f31ebbb638356af720335e5a11154c330169b40777/grpc_google_iam_v1-0.14.2.tar.gz", hash = "sha256:b3e1fc387a1a329e41672197d0ace9de22c78dd7d215048c4c78712073f7bd20", size = 16259 } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/6f/dd9b178aee7835b96c2e63715aba6516a9d50f6bebbd1cc1d32c82a2a6c3/grpc_google_iam_v1-0.14.2-py3-none-any.whl", hash = "sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351", size = 19242, upload-time = "2025-03-17T11:40:22.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/6f/dd9b178aee7835b96c2e63715aba6516a9d50f6bebbd1cc1d32c82a2a6c3/grpc_google_iam_v1-0.14.2-py3-none-any.whl", hash = "sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351", size = 19242 }, ] [[package]] @@ -975,12 +975,13 @@ resolution-markers = [ dependencies = [ { name = "six", marker = "platform_machine == 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/1c/c42834d4fee45c5cf2d9546e97e879a1cbcdecfd16eb1a12144dcb91edae/grpcio-1.49.1.tar.gz", hash = "sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f", size = 22059239, upload-time = "2022-09-22T03:02:44.376Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/1c/c42834d4fee45c5cf2d9546e97e879a1cbcdecfd16eb1a12144dcb91edae/grpcio-1.49.1.tar.gz", hash = "sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f", size = 22059239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/0f/4d614d59f500835cbd27cb90743fb6b299098b0f22b8fd058d3586c933c0/grpcio-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f", size = 4296299, upload-time = "2022-09-22T02:58:01.417Z" }, - { url = "https://files.pythonhosted.org/packages/4d/ea/359a98f8b3b4ff9a2f457a0d20ed81775a64149fbb7617177ed23d9d10c9/grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f", size = 4656437, upload-time = "2022-09-22T02:58:06.23Z" }, - { url = "https://files.pythonhosted.org/packages/fc/89/4952d2dff95f5b95db5943b2d1b55c82a485830b992f52f212b33616b523/grpcio-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811", size = 4888051, upload-time = "2022-09-22T02:58:11.411Z" }, - { url = "https://files.pythonhosted.org/packages/f0/2d/995e7b2a4e7aee713674c6b34d75aed3c7535eb77cb12a1785d95ac35332/grpcio-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2", size = 3618099, upload-time = "2022-09-22T02:58:17.396Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e2/aaccddb8b06637625d847dbb5fe76ec3d15a74d89d983f5202f3666706e3/grpcio-1.49.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b", size = 73399185 }, + { url = "https://files.pythonhosted.org/packages/90/0f/4d614d59f500835cbd27cb90743fb6b299098b0f22b8fd058d3586c933c0/grpcio-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f", size = 4296299 }, + { url = "https://files.pythonhosted.org/packages/4d/ea/359a98f8b3b4ff9a2f457a0d20ed81775a64149fbb7617177ed23d9d10c9/grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f", size = 4656437 }, + { url = "https://files.pythonhosted.org/packages/fc/89/4952d2dff95f5b95db5943b2d1b55c82a485830b992f52f212b33616b523/grpcio-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811", size = 4888051 }, + { url = "https://files.pythonhosted.org/packages/f0/2d/995e7b2a4e7aee713674c6b34d75aed3c7535eb77cb12a1785d95ac35332/grpcio-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2", size = 3618099 }, ] [[package]] @@ -994,17 +995,17 @@ resolution-markers = [ "python_full_version == '3.12.*' and platform_machine != 'x86_64'", "python_full_version < '3.12' and platform_machine != 'x86_64'", ] -sdist = { url = "https://files.pythonhosted.org/packages/13/a8/c224a9d9ae0a9a0866ec37d9951b4407c3df3343a6c0352554e5add9152a/grpcio-1.53.2.tar.gz", hash = "sha256:0c9e42f2499c8603af1d88771dc97e2c6b0310c278337058fd7fd1ddb35ab853", size = 22422194, upload-time = "2023-08-02T16:55:27.288Z" } +sdist = { url = "https://files.pythonhosted.org/packages/13/a8/c224a9d9ae0a9a0866ec37d9951b4407c3df3343a6c0352554e5add9152a/grpcio-1.53.2.tar.gz", hash = "sha256:0c9e42f2499c8603af1d88771dc97e2c6b0310c278337058fd7fd1ddb35ab853", size = 22422194 } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/98/96b6499fd5099ab6a2ab7ddabde4644fea064aafa41db8e5952fd6e49a07/grpcio-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:8166ac6671472d172cc0db50323b7a7504bd534de54aa31354465a00ca44409d", size = 88732207, upload-time = "2023-08-02T16:51:17.326Z" }, - { url = "https://files.pythonhosted.org/packages/ee/4d/88efe77ffa641aa1b0c8b31fa7862d2a8450d0d7e71b3e0f56baa65c18e6/grpcio-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:f7e66d8b31ef2bada7029275debbe12c97397ec7ac70a659837a7b8a6a9dc916", size = 8457838, upload-time = "2023-08-02T16:51:22.035Z" }, - { url = "https://files.pythonhosted.org/packages/d4/2c/b05d13e8bd712fd6128b9c832dd87d7c9cb8873487479bb32e249d40a2ae/grpcio-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:712113946b303db9ae4245a13de213710367850a6c3c53530b70e87989feb8e0", size = 4324710, upload-time = "2023-08-02T16:51:25.665Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b9/2307da723e99f35909c35b227f64dd273f6c9f22744d90ee516864c730db/grpcio-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3761f9a6817e32898eaa5aecd0b0ad69d0c68ab45ea7bf206e8dc4548f025f0", size = 5237001, upload-time = "2023-08-02T16:51:29.595Z" }, - { url = "https://files.pythonhosted.org/packages/da/4a/f0444ac37a2bb120c41ed02970125814a991caa9b833386f8a85aea442cf/grpcio-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c63592103fded38b258f1e520ba8b0a7a0bbc397cddd6520a1f74dc4b5dec0", size = 4962998, upload-time = "2023-08-02T16:51:32.101Z" }, - { url = "https://files.pythonhosted.org/packages/22/40/5fd5ce6d5b5e890b9d6571114be8a6a5aa1d317bd779b29afcf528060f2f/grpcio-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:53d34cbf212f03634d74ba366d595b4a06a3b60fcc731eddbd6fd7ebe4acf981", size = 5456120, upload-time = "2023-08-02T16:51:35.189Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ac/6bf874a7f5d8576a657ae5b956006046b470491a6382db49aa4effb7818d/grpcio-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b789472e9ef75d179295d0c6a1f7f0aefd08189cd1c822b068b0523365a1dbe", size = 5179150, upload-time = "2023-08-02T16:51:37.894Z" }, - { url = "https://files.pythonhosted.org/packages/8a/65/32f100de0f4e8eb260c8416886be1f5048091302cf6c1ccf51e898d22cae/grpcio-1.53.2-cp311-cp311-win32.whl", hash = "sha256:7b44ed75b9d67d17e5a098a0f99a8fd3e5861fd3c4eb54212277a0acdf298434", size = 3309870, upload-time = "2023-08-02T16:51:39.845Z" }, - { url = "https://files.pythonhosted.org/packages/53/70/6c50cffa387319e80689a41487fe3d604243bd3bc7057035782692e1e042/grpcio-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:1d1a320230e0d020880178b8eb453300bd57700b44c3744268370502e7376a9b", size = 3954245, upload-time = "2023-08-02T16:51:42.688Z" }, + { url = "https://files.pythonhosted.org/packages/30/98/96b6499fd5099ab6a2ab7ddabde4644fea064aafa41db8e5952fd6e49a07/grpcio-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:8166ac6671472d172cc0db50323b7a7504bd534de54aa31354465a00ca44409d", size = 88732207 }, + { url = "https://files.pythonhosted.org/packages/ee/4d/88efe77ffa641aa1b0c8b31fa7862d2a8450d0d7e71b3e0f56baa65c18e6/grpcio-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:f7e66d8b31ef2bada7029275debbe12c97397ec7ac70a659837a7b8a6a9dc916", size = 8457838 }, + { url = "https://files.pythonhosted.org/packages/d4/2c/b05d13e8bd712fd6128b9c832dd87d7c9cb8873487479bb32e249d40a2ae/grpcio-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:712113946b303db9ae4245a13de213710367850a6c3c53530b70e87989feb8e0", size = 4324710 }, + { url = "https://files.pythonhosted.org/packages/ff/b9/2307da723e99f35909c35b227f64dd273f6c9f22744d90ee516864c730db/grpcio-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3761f9a6817e32898eaa5aecd0b0ad69d0c68ab45ea7bf206e8dc4548f025f0", size = 5237001 }, + { url = "https://files.pythonhosted.org/packages/da/4a/f0444ac37a2bb120c41ed02970125814a991caa9b833386f8a85aea442cf/grpcio-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c63592103fded38b258f1e520ba8b0a7a0bbc397cddd6520a1f74dc4b5dec0", size = 4962998 }, + { url = "https://files.pythonhosted.org/packages/22/40/5fd5ce6d5b5e890b9d6571114be8a6a5aa1d317bd779b29afcf528060f2f/grpcio-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:53d34cbf212f03634d74ba366d595b4a06a3b60fcc731eddbd6fd7ebe4acf981", size = 5456120 }, + { url = "https://files.pythonhosted.org/packages/e0/ac/6bf874a7f5d8576a657ae5b956006046b470491a6382db49aa4effb7818d/grpcio-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b789472e9ef75d179295d0c6a1f7f0aefd08189cd1c822b068b0523365a1dbe", size = 5179150 }, + { url = "https://files.pythonhosted.org/packages/8a/65/32f100de0f4e8eb260c8416886be1f5048091302cf6c1ccf51e898d22cae/grpcio-1.53.2-cp311-cp311-win32.whl", hash = "sha256:7b44ed75b9d67d17e5a098a0f99a8fd3e5861fd3c4eb54212277a0acdf298434", size = 3309870 }, + { url = "https://files.pythonhosted.org/packages/53/70/6c50cffa387319e80689a41487fe3d604243bd3bc7057035782692e1e042/grpcio-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:1d1a320230e0d020880178b8eb453300bd57700b44c3744268370502e7376a9b", size = 3954245 }, ] [[package]] @@ -1016,9 +1017,9 @@ dependencies = [ { name = "grpcio", version = "1.53.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64'" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/a9/1762cf5ff67c087c79dc7e007554f10973df89c69915ebbeb98547944bb9/grpcio-health-checking-1.44.0.tar.gz", hash = "sha256:e391033c29137fdcef8c405e12f626d1bb1eeaf219f5ea024068cdff43eae7d9", size = 10721, upload-time = "2022-02-17T20:24:42.196Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/a9/1762cf5ff67c087c79dc7e007554f10973df89c69915ebbeb98547944bb9/grpcio-health-checking-1.44.0.tar.gz", hash = "sha256:e391033c29137fdcef8c405e12f626d1bb1eeaf219f5ea024068cdff43eae7d9", size = 10721 } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/95/3ccbc57d507ac2796fb356e843446b48c3c471de2629bd3900fcbc760c4a/grpcio_health_checking-1.44.0-py3-none-any.whl", hash = "sha256:69812dc996ac57c5e944d810fbb8ab6a7ac29533db8134ba5ed30e0e4a552c77", size = 13570, upload-time = "2022-02-17T20:22:37.287Z" }, + { url = "https://files.pythonhosted.org/packages/30/95/3ccbc57d507ac2796fb356e843446b48c3c471de2629bd3900fcbc760c4a/grpcio_health_checking-1.44.0-py3-none-any.whl", hash = "sha256:69812dc996ac57c5e944d810fbb8ab6a7ac29533db8134ba5ed30e0e4a552c77", size = 13570 }, ] [[package]] @@ -1030,9 +1031,9 @@ dependencies = [ { name = "grpcio", version = "1.53.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64'" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/a9/63d053b9c26bcd8c11d4b1888eb400506205b72cf5e4154d014966810b38/grpcio-reflection-1.44.0.tar.gz", hash = "sha256:c116b5beed9fa729ccf7e4815b434ec6d0f016f1fe5c691412b19fb7041fccc0", size = 10491, upload-time = "2022-02-17T20:24:43.379Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/a9/63d053b9c26bcd8c11d4b1888eb400506205b72cf5e4154d014966810b38/grpcio-reflection-1.44.0.tar.gz", hash = "sha256:c116b5beed9fa729ccf7e4815b434ec6d0f016f1fe5c691412b19fb7041fccc0", size = 10491 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/e9/5ae534c0b61650a21b3790784810d1a4ad864eea65c8adea096b21ba2d8d/grpcio_reflection-1.44.0-py3-none-any.whl", hash = "sha256:ba0bb0c1d9fdf7663c1a7dc56e6ca56c473d99d7ae6353106935977c8e3a0a65", size = 14029, upload-time = "2022-02-17T20:22:38.876Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e9/5ae534c0b61650a21b3790784810d1a4ad864eea65c8adea096b21ba2d8d/grpcio_reflection-1.44.0-py3-none-any.whl", hash = "sha256:ba0bb0c1d9fdf7663c1a7dc56e6ca56c473d99d7ae6353106935977c8e3a0a65", size = 14029 }, ] [[package]] @@ -1051,9 +1052,9 @@ dependencies = [ { name = "grpcio", version = "1.49.1", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64'" }, { name = "protobuf", marker = "platform_machine == 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/99/7cd6af0c6da3084fa39818af3e3de1f4ca21127004e87f39a2affe290521/grpcio-status-1.49.1.tar.gz", hash = "sha256:658f48dc146ee0c7b6eebd302d74e0d45c00727c20035ff51d68750dbaccf5d9", size = 13505, upload-time = "2022-09-22T03:02:56.074Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/99/7cd6af0c6da3084fa39818af3e3de1f4ca21127004e87f39a2affe290521/grpcio-status-1.49.1.tar.gz", hash = "sha256:658f48dc146ee0c7b6eebd302d74e0d45c00727c20035ff51d68750dbaccf5d9", size = 13505 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/33/e88da69f7ac4cabac52b6242ae84d8a02852034cc388951938020c5f90ec/grpcio_status-1.49.1-py3-none-any.whl", hash = "sha256:fe4ae9f624f03e50ccf6f6ead60727ab20b17735bb3d0dd506ef355349282378", size = 14432, upload-time = "2022-09-22T03:00:17.503Z" }, + { url = "https://files.pythonhosted.org/packages/2e/33/e88da69f7ac4cabac52b6242ae84d8a02852034cc388951938020c5f90ec/grpcio_status-1.49.1-py3-none-any.whl", hash = "sha256:fe4ae9f624f03e50ccf6f6ead60727ab20b17735bb3d0dd506ef355349282378", size = 14432 }, ] [[package]] @@ -1072,9 +1073,9 @@ dependencies = [ { name = "grpcio", version = "1.53.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64'" }, { name = "protobuf", marker = "platform_machine != 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/6c/ed089e2b0d9215a1405de8790b2d6593780690d2732e0c208da27dfd86c4/grpcio-status-1.53.2.tar.gz", hash = "sha256:9a0823b99218424f012f59f6e9d17e8f569a67f0ca47cbca27dbf3bdf72c2248", size = 13505, upload-time = "2023-08-02T16:55:34.192Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/6c/ed089e2b0d9215a1405de8790b2d6593780690d2732e0c208da27dfd86c4/grpcio-status-1.53.2.tar.gz", hash = "sha256:9a0823b99218424f012f59f6e9d17e8f569a67f0ca47cbca27dbf3bdf72c2248", size = 13505 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/c0/8ee53675cb1aecaa7fcbc9bea6575cb8c19a21dd0ce80fe6e5edb04426f4/grpcio_status-1.53.2-py3-none-any.whl", hash = "sha256:a9642ee829d84bd617ede9c10ff77b9082cc0cb14356b1474b169da50f7db61e", size = 5091, upload-time = "2023-08-02T16:53:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c0/8ee53675cb1aecaa7fcbc9bea6575cb8c19a21dd0ce80fe6e5edb04426f4/grpcio_status-1.53.2-py3-none-any.whl", hash = "sha256:a9642ee829d84bd617ede9c10ff77b9082cc0cb14356b1474b169da50f7db61e", size = 5091 }, ] [[package]] @@ -1093,12 +1094,13 @@ dependencies = [ { name = "protobuf", marker = "platform_machine == 'x86_64'" }, { name = "setuptools", marker = "platform_machine == 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6c/e4/3416d25aebc4477141a491fae2c9494c5e0437a706c59103a936aac7d072/grpcio-tools-1.49.1.tar.gz", hash = "sha256:84cc64e5b46bad43d5d7bd2fd772b656eba0366961187a847e908e2cb735db91", size = 2252679, upload-time = "2022-09-22T03:03:00.279Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/e4/3416d25aebc4477141a491fae2c9494c5e0437a706c59103a936aac7d072/grpcio-tools-1.49.1.tar.gz", hash = "sha256:84cc64e5b46bad43d5d7bd2fd772b656eba0366961187a847e908e2cb735db91", size = 2252679 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/8b/a45a39bf7d1c4956d48179831e4da88c3f6ee14dbdcb273e575bbeb7de20/grpcio_tools-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:ab3d0ee9623720ee585fdf3753b3755d3144a4a8ae35bca8e3655fa2f41056be", size = 2025040, upload-time = "2022-09-22T03:00:55.219Z" }, - { url = "https://files.pythonhosted.org/packages/6d/7f/89dc6036b91f8cbada98b06801ac2f5db60885000feaf88f9d7cabe665b7/grpcio_tools-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e13b3643e7577a3ec13b79689eb4d7548890b1e104c04b9ed6557a3c3dd452", size = 2370982, upload-time = "2022-09-22T03:00:59.807Z" }, - { url = "https://files.pythonhosted.org/packages/01/98/4730bfff6bcd3163db8c3d70689e19a1a5f419152316edfc1f13ff06a5d7/grpcio_tools-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a64bab81b220c50033f584f57978ebbea575f09c1ccee765cd5c462177988098", size = 2731915, upload-time = "2022-09-22T03:01:05.44Z" }, - { url = "https://files.pythonhosted.org/packages/1a/14/9f61820a13429c3719741f0810ed4a055c363f84d528c8f957a72605ce86/grpcio_tools-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:28ff2b978d9509474928b9c096a0cce4eaa9c8f7046136aee1545f6211ed8126", size = 1844039, upload-time = "2022-09-22T03:01:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c1/ba298fe650b67c9e31a7ad88b2fe1d8d22ff2c6a9e131604054835397dfc/grpcio_tools-1.49.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:9e5c13809ab2f245398e8446c4c3b399a62d591db651e46806cccf52a700452e", size = 36912892 }, + { url = "https://files.pythonhosted.org/packages/9c/8b/a45a39bf7d1c4956d48179831e4da88c3f6ee14dbdcb273e575bbeb7de20/grpcio_tools-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:ab3d0ee9623720ee585fdf3753b3755d3144a4a8ae35bca8e3655fa2f41056be", size = 2025040 }, + { url = "https://files.pythonhosted.org/packages/6d/7f/89dc6036b91f8cbada98b06801ac2f5db60885000feaf88f9d7cabe665b7/grpcio_tools-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e13b3643e7577a3ec13b79689eb4d7548890b1e104c04b9ed6557a3c3dd452", size = 2370982 }, + { url = "https://files.pythonhosted.org/packages/01/98/4730bfff6bcd3163db8c3d70689e19a1a5f419152316edfc1f13ff06a5d7/grpcio_tools-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a64bab81b220c50033f584f57978ebbea575f09c1ccee765cd5c462177988098", size = 2731915 }, + { url = "https://files.pythonhosted.org/packages/1a/14/9f61820a13429c3719741f0810ed4a055c363f84d528c8f957a72605ce86/grpcio_tools-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:28ff2b978d9509474928b9c096a0cce4eaa9c8f7046136aee1545f6211ed8126", size = 1844039 }, ] [[package]] @@ -1117,17 +1119,17 @@ dependencies = [ { name = "protobuf", marker = "platform_machine != 'x86_64'" }, { name = "setuptools", marker = "platform_machine != 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/4a/d176f59e4b080f8bcd1242ca9bfa9d1a77a9ef1620725eef846f112b8a99/grpcio-tools-1.53.2.tar.gz", hash = "sha256:1b10f95d1f4af2b9d63c9beccf386b3a5e1a92f14b3f64a9a8385b6ba091e0dc", size = 2257313, upload-time = "2023-08-02T16:55:36.975Z" } +sdist = { url = "https://files.pythonhosted.org/packages/80/4a/d176f59e4b080f8bcd1242ca9bfa9d1a77a9ef1620725eef846f112b8a99/grpcio-tools-1.53.2.tar.gz", hash = "sha256:1b10f95d1f4af2b9d63c9beccf386b3a5e1a92f14b3f64a9a8385b6ba091e0dc", size = 2257313 } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/8f/ee91cf09f72bf86e4784e8f030425d789e6984a8f7882fdef77d53dda8d9/grpcio_tools-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:968c94cb210da93d02c3d41605fc3400cdbd8e30e5ef5910638570a6d9b1be1d", size = 37001525, upload-time = "2023-08-02T16:54:00.483Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/e85a0777d43aed5171be62b1f40ec9bf71e842ea41b94a84a87c404160cb/grpcio_tools-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:a71e2a881eb8e821b6f5eeab2ee450b56597000ec34bfcd0c35b666ad7e64eb9", size = 3881176, upload-time = "2023-08-02T16:54:03.328Z" }, - { url = "https://files.pythonhosted.org/packages/3f/33/01294f84c413e05a5d13c5648b883ecd44f5edacf9f989733cf2207b35ac/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:621e6aa0ee0ca6d24cd0dc0a3ea4e8dd585ee9a7c665f0b5247a08032d89ac9f", size = 2043712, upload-time = "2023-08-02T16:54:05.794Z" }, - { url = "https://files.pythonhosted.org/packages/70/78/10f3decc485435efad896d1851bf0b37c58764760124b85084163cd316a3/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f073ee3d1088d54fd1da5df2f39ae8767397a6e60baaabbf22525e5dc86b759c", size = 2521670, upload-time = "2023-08-02T16:54:08.229Z" }, - { url = "https://files.pythonhosted.org/packages/be/99/c008310b54848e1220b1c919a6a741347795873d304ba73cbc5cf1da5edf/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556f6997fe369a6cfd230335c46cb89d5ac2be65c093b25b8a0e9bfee76cb705", size = 2375360, upload-time = "2023-08-02T16:54:11.017Z" }, - { url = "https://files.pythonhosted.org/packages/9b/e5/5ed9acd22b9ea5aa7c29fca91d8e5e65e12f2633114a9da88c5eefc62a2a/grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:049b16c36c3b0e9e52aa35dec6655000c97f5a26215322804d4149c5690997e4", size = 2970806, upload-time = "2023-08-02T16:54:13.965Z" }, - { url = "https://files.pythonhosted.org/packages/17/8a/293d81ca22c9dd981a033085dd8492c27ad79c4c675a298112772e21b05e/grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ba8cdc56b713e6b27b2f5777e449b4617b549af6ab548aaf265eeda12a4ac6f", size = 2733958, upload-time = "2023-08-02T16:54:18.111Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f5/5e10e0657b82cd46cdc3dbfae8d47fdc424e8185fc1444948798276ea06e/grpcio_tools-1.53.2-cp311-cp311-win32.whl", hash = "sha256:f1bb5564e7dec518b163761771372a010514c1845cc8e96b6e84af3cac4fd864", size = 1427771, upload-time = "2023-08-02T16:54:21.412Z" }, - { url = "https://files.pythonhosted.org/packages/17/f0/137600746a7223a0e8067d2c8daa8d04bc5809fccb45761b0f9beb4b8d64/grpcio_tools-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:c57cd3d0ef5d2ac8cc0ffc7b9226e85364adf50e91aaf3c34589d15e574a7215", size = 1696916, upload-time = "2023-08-02T16:54:23.006Z" }, + { url = "https://files.pythonhosted.org/packages/43/8f/ee91cf09f72bf86e4784e8f030425d789e6984a8f7882fdef77d53dda8d9/grpcio_tools-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:968c94cb210da93d02c3d41605fc3400cdbd8e30e5ef5910638570a6d9b1be1d", size = 37001525 }, + { url = "https://files.pythonhosted.org/packages/a2/d1/e85a0777d43aed5171be62b1f40ec9bf71e842ea41b94a84a87c404160cb/grpcio_tools-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:a71e2a881eb8e821b6f5eeab2ee450b56597000ec34bfcd0c35b666ad7e64eb9", size = 3881176 }, + { url = "https://files.pythonhosted.org/packages/3f/33/01294f84c413e05a5d13c5648b883ecd44f5edacf9f989733cf2207b35ac/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:621e6aa0ee0ca6d24cd0dc0a3ea4e8dd585ee9a7c665f0b5247a08032d89ac9f", size = 2043712 }, + { url = "https://files.pythonhosted.org/packages/70/78/10f3decc485435efad896d1851bf0b37c58764760124b85084163cd316a3/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f073ee3d1088d54fd1da5df2f39ae8767397a6e60baaabbf22525e5dc86b759c", size = 2521670 }, + { url = "https://files.pythonhosted.org/packages/be/99/c008310b54848e1220b1c919a6a741347795873d304ba73cbc5cf1da5edf/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556f6997fe369a6cfd230335c46cb89d5ac2be65c093b25b8a0e9bfee76cb705", size = 2375360 }, + { url = "https://files.pythonhosted.org/packages/9b/e5/5ed9acd22b9ea5aa7c29fca91d8e5e65e12f2633114a9da88c5eefc62a2a/grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:049b16c36c3b0e9e52aa35dec6655000c97f5a26215322804d4149c5690997e4", size = 2970806 }, + { url = "https://files.pythonhosted.org/packages/17/8a/293d81ca22c9dd981a033085dd8492c27ad79c4c675a298112772e21b05e/grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ba8cdc56b713e6b27b2f5777e449b4617b549af6ab548aaf265eeda12a4ac6f", size = 2733958 }, + { url = "https://files.pythonhosted.org/packages/4b/f5/5e10e0657b82cd46cdc3dbfae8d47fdc424e8185fc1444948798276ea06e/grpcio_tools-1.53.2-cp311-cp311-win32.whl", hash = "sha256:f1bb5564e7dec518b163761771372a010514c1845cc8e96b6e84af3cac4fd864", size = 1427771 }, + { url = "https://files.pythonhosted.org/packages/17/f0/137600746a7223a0e8067d2c8daa8d04bc5809fccb45761b0f9beb4b8d64/grpcio_tools-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:c57cd3d0ef5d2ac8cc0ffc7b9226e85364adf50e91aaf3c34589d15e574a7215", size = 1696916 }, ] [[package]] @@ -1145,51 +1147,51 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyparsing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz", hash = "sha256:385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", size = 250800, upload-time = "2026-01-23T11:04:44.165Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz", hash = "sha256:385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", size = 250800 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl", hash = "sha256:dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", size = 91099, upload-time = "2026-01-23T11:04:42.78Z" }, + { url = "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl", hash = "sha256:dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", size = 91099 }, ] [[package]] name = "humanize" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" }, + { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203 }, ] [[package]] name = "identify" version = "2.6.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397 }, ] [[package]] name = "idna" version = "3.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455 }, ] [[package]] name = "infinity" version = "1.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/55/09840b5789d7bda972ae9f2ecd94d2df06b5aeac193505013fbaf6ddc648/infinity-1.5.tar.gz", hash = "sha256:8daa7c15ce2100fdccfde212337e0cd5cf085869f54dc2634b6c30d61461ecda", size = 5378, upload-time = "2020-06-03T10:33:09.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/55/09840b5789d7bda972ae9f2ecd94d2df06b5aeac193505013fbaf6ddc648/infinity-1.5.tar.gz", hash = "sha256:8daa7c15ce2100fdccfde212337e0cd5cf085869f54dc2634b6c30d61461ecda", size = 5378 } [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, ] [[package]] @@ -1199,9 +1201,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "infinity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/24/eb/2d36474125c41b8fbb1c052a329b38fd726ef4c08529564518adcc5836e5/intervals-0.9.2.tar.gz", hash = "sha256:c7ee568c583ca857c0d91af6d90ee5e0e8adef3f5646d0076bfb87305ae43090", size = 16536, upload-time = "2021-07-02T10:09:30.171Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/eb/2d36474125c41b8fbb1c052a329b38fd726ef4c08529564518adcc5836e5/intervals-0.9.2.tar.gz", hash = "sha256:c7ee568c583ca857c0d91af6d90ee5e0e8adef3f5646d0076bfb87305ae43090", size = 16536 } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/6a/71aca90b7ac1da04c9dfafac0d1cd5311aed2faa4a96aa2521eb23f095d6/intervals-0.9.2-py3-none-any.whl", hash = "sha256:7c963abf7b4be2be40322b84e036af5d4ebec0945b5d29df7da1a638b3fea768", size = 8512, upload-time = "2021-07-02T10:09:28.873Z" }, + { url = "https://files.pythonhosted.org/packages/64/6a/71aca90b7ac1da04c9dfafac0d1cd5311aed2faa4a96aa2521eb23f095d6/intervals-0.9.2-py3-none-any.whl", hash = "sha256:7c963abf7b4be2be40322b84e036af5d4ebec0945b5d29df7da1a638b3fea768", size = 8512 }, ] [[package]] @@ -1212,9 +1214,9 @@ dependencies = [ { name = "decorator" }, { name = "ipython" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042, upload-time = "2023-03-09T15:40:57.487Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130, upload-time = "2023-03-09T15:40:55.021Z" }, + { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130 }, ] [[package]] @@ -1234,9 +1236,9 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/80/406f9e3bde1c1fd9bf5a0be9d090f8ae623e401b7670d8f6fdf2ab679891/ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270", size = 4385338, upload-time = "2025-07-01T11:11:30.606Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/80/406f9e3bde1c1fd9bf5a0be9d090f8ae623e401b7670d8f6fdf2ab679891/ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270", size = 4385338 } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066", size = 611021, upload-time = "2025-07-01T11:11:27.85Z" }, + { url = "https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066", size = 611021 }, ] [[package]] @@ -1246,18 +1248,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074 }, ] [[package]] name = "itsdangerous" version = "1.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/1a/f27de07a8a304ad5fa817bbe383d1238ac4396da447fa11ed937039fa04b/itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", size = 53219, upload-time = "2018-10-27T00:17:37.922Z" } +sdist = { url = "https://files.pythonhosted.org/packages/68/1a/f27de07a8a304ad5fa817bbe383d1238ac4396da447fa11ed937039fa04b/itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", size = 53219 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749", size = 16743, upload-time = "2018-10-27T00:17:35.954Z" }, + { url = "https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749", size = 16743 }, ] [[package]] @@ -1267,9 +1269,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812, upload-time = "2026-05-01T23:38:43.919Z" }, + { url = "https://files.pythonhosted.org/packages/9a/93/242e2eab5fe682ffcb8b0084bde703a41d51e17ee0f3a31ff0d9d813620a/jedi-0.20.0-py2.py3-none-any.whl", hash = "sha256:7bdd9c2634f56713299976f4cbd59cb3fa92165cc5e05ea811fb253480728b67", size = 4884812 }, ] [[package]] @@ -1279,9 +1281,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4f/e7/65300e6b32e69768ded990494809106f87da1d436418d5f1367ed3966fd7/Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6", size = 257589, upload-time = "2021-01-31T16:33:09.175Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/e7/65300e6b32e69768ded990494809106f87da1d436418d5f1367ed3966fd7/Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6", size = 257589 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", size = 125699, upload-time = "2021-01-31T16:33:07.289Z" }, + { url = "https://files.pythonhosted.org/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419", size = 125699 }, ] [[package]] @@ -1306,91 +1308,91 @@ requires-dist = [ name = "kafka-python" version = "1.4.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/20/2a2494fe7b4bf4cb36c060f88a55adcd944b7876877691a2f28cd544467b/kafka-python-1.4.7.tar.gz", hash = "sha256:2f29baad4b3efe05a2bb81ac268855aa01cbc68397f15bac77b494ffd7e2cada", size = 290977, upload-time = "2019-09-30T21:13:20.078Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/20/2a2494fe7b4bf4cb36c060f88a55adcd944b7876877691a2f28cd544467b/kafka-python-1.4.7.tar.gz", hash = "sha256:2f29baad4b3efe05a2bb81ac268855aa01cbc68397f15bac77b494ffd7e2cada", size = 290977 } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/c9/9863483a1353700ba87821b4f39085eb18fd1bcbb1e954c697177d67f03f/kafka_python-1.4.7-py2.py3-none-any.whl", hash = "sha256:4fbebebfcb6fc94903fb720fe883d7bbec7298f4f1acb857c21dd3b4b114ba4b", size = 266121, upload-time = "2019-09-30T21:13:17.697Z" }, + { url = "https://files.pythonhosted.org/packages/49/c9/9863483a1353700ba87821b4f39085eb18fd1bcbb1e954c697177d67f03f/kafka_python-1.4.7-py2.py3-none-any.whl", hash = "sha256:4fbebebfcb6fc94903fb720fe883d7bbec7298f4f1acb857c21dd3b4b114ba4b", size = 266121 }, ] [[package]] name = "legacy-cgi" version = "2.6.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/9c/91c7d2c5ebbdf0a1a510bfa0ddeaa2fbb5b78677df5ac0a0aa51cf7125b0/legacy_cgi-2.6.4.tar.gz", hash = "sha256:abb9dfc7835772f7c9317977c63253fd22a7484b5c9bbcdca60a29dcce97c577", size = 24603, upload-time = "2025-10-27T05:20:05.395Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/9c/91c7d2c5ebbdf0a1a510bfa0ddeaa2fbb5b78677df5ac0a0aa51cf7125b0/legacy_cgi-2.6.4.tar.gz", hash = "sha256:abb9dfc7835772f7c9317977c63253fd22a7484b5c9bbcdca60a29dcce97c577", size = 24603 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl", hash = "sha256:7e235ce58bf1e25d1fc9b2d299015e4e2cd37305eccafec1e6bac3fc04b878cd", size = 20035, upload-time = "2025-10-27T05:20:04.289Z" }, + { url = "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl", hash = "sha256:7e235ce58bf1e25d1fc9b2d299015e4e2cd37305eccafec1e6bac3fc04b878cd", size = 20035 }, ] [[package]] name = "librt" version = "0.11.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/87/2bf31fe17587b29e3f93ec31421e2b1e1c3e349b8bf6c7c313dbad1d5340/librt-0.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29", size = 141092, upload-time = "2026-05-10T18:15:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/cf/08/5c5bf772920b7ebac6e32bc91a643e0ab3870199c0b542356d3baa83970a/librt-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9", size = 142035, upload-time = "2026-05-10T18:15:36.242Z" }, - { url = "https://files.pythonhosted.org/packages/06/20/662a03d254e5b000d838e8b345d83303ddb768c080fd488e40634c0fa66b/librt-0.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5", size = 475022, upload-time = "2026-05-10T18:15:37.56Z" }, - { url = "https://files.pythonhosted.org/packages/de/f3/aa81523e45184c6ec23dc7f63263362ec55f80a09d424c012359ecbe7e35/librt-0.11.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b", size = 467273, upload-time = "2026-05-10T18:15:39.182Z" }, - { url = "https://files.pythonhosted.org/packages/6b/6f/59c74b560ca8853834d5501d589c8a2519f4184f273a085ffd0f37a1cc47/librt-0.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89", size = 497083, upload-time = "2026-05-10T18:15:40.634Z" }, - { url = "https://files.pythonhosted.org/packages/fe/7b/5aa4d2c9600a719401160bf7055417df0b2a47439b9d88286ce45e56b65f/librt-0.11.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc", size = 489139, upload-time = "2026-05-10T18:15:41.934Z" }, - { url = "https://files.pythonhosted.org/packages/d6/31/9143803d7da6856a69153785768c4936864430eec0fd9461c3ea527d9922/librt-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5", size = 508442, upload-time = "2026-05-10T18:15:43.206Z" }, - { url = "https://files.pythonhosted.org/packages/2f/5a/bce08184488426bda4ccc2c4964ac048c8f68ae89bd7120082eef4233cfd/librt-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7", size = 514230, upload-time = "2026-05-10T18:15:44.761Z" }, - { url = "https://files.pythonhosted.org/packages/89/8c/bb5e213d254b7505a0e658da199d8ab719086632ce09eef311ab27976523/librt-0.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d", size = 494231, upload-time = "2026-05-10T18:15:46.308Z" }, - { url = "https://files.pythonhosted.org/packages/9d/fb/541cdad5b1ab1300398c74c4c9a497b88e5074c21b1244c8f49731d3a284/librt-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412", size = 537585, upload-time = "2026-05-10T18:15:47.629Z" }, - { url = "https://files.pythonhosted.org/packages/8f/f2/464bb69295c320cb06bddb4f14a4ec67934ee14b2bffb12b19fb7ab287ba/librt-0.11.0-cp311-cp311-win32.whl", hash = "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d", size = 100509, upload-time = "2026-05-10T18:15:49.157Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e7/a17ee1788f9e4fbf548c19f4afa07c92089b9e24fef6cb2410863781ef4c/librt-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73", size = 118628, upload-time = "2026-05-10T18:15:50.345Z" }, - { url = "https://files.pythonhosted.org/packages/cc/c7/6c766214f9f9903bcfcfbef97d807af8d8f5aa3502d247858ab17582d212/librt-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c", size = 103122, upload-time = "2026-05-10T18:15:52.068Z" }, - { url = "https://files.pythonhosted.org/packages/8b/d0/07c77e067f0838949b43bd89232c29d72efebb9d2801a9750184eb706b71/librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", size = 144147, upload-time = "2026-05-10T18:15:53.227Z" }, - { url = "https://files.pythonhosted.org/packages/7a/24/8493538fa4f62f982686398a5b8f68008138a75086abdea19ade64bf4255/librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", size = 143614, upload-time = "2026-05-10T18:15:54.657Z" }, - { url = "https://files.pythonhosted.org/packages/ff/1e/f8bad050810d9171f34a1648ed910e56814c2ba61639f2bd53c6377ae24b/librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", size = 485538, upload-time = "2026-05-10T18:15:56.117Z" }, - { url = "https://files.pythonhosted.org/packages/c0/fe/3594ebfbaf03084ba4b120c9ba5c3183fd938a48725e9bbe6ff0a5159ad8/librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", size = 479623, upload-time = "2026-05-10T18:15:57.544Z" }, - { url = "https://files.pythonhosted.org/packages/b0/da/5d1876984b3746c85dbd219dbfcb73c85f54ee263fd32e5b2a632ec14571/librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", size = 513082, upload-time = "2026-05-10T18:15:58.805Z" }, - { url = "https://files.pythonhosted.org/packages/19/6e/55bdf5d5ca00c3e18430690bf2c953d8d3ffd3c337418173d33dec985dc9/librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", size = 508105, upload-time = "2026-05-10T18:16:00.2Z" }, - { url = "https://files.pythonhosted.org/packages/07/10/f1f23a7c595ee90ece4d35c851e5d104b1311a887ed1b4ac4c35bbd13da8/librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", size = 522268, upload-time = "2026-05-10T18:16:01.708Z" }, - { url = "https://files.pythonhosted.org/packages/b6/02/5720f5697a7f54b78b3aefbe20df3a48cedcff1276618c4aa481177942ed/librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", size = 527348, upload-time = "2026-05-10T18:16:03.496Z" }, - { url = "https://files.pythonhosted.org/packages/50/db/b4a47c6f91db4ff76348a0b3dd0cc65e090a078b765a810a62ff9434c3d3/librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", size = 516294, upload-time = "2026-05-10T18:16:05.173Z" }, - { url = "https://files.pythonhosted.org/packages/9e/58/9384b2f4eb1ed1d273d40948a7c5c4b2360213b402ef3be4641c06299f9c/librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", size = 553608, upload-time = "2026-05-10T18:16:06.839Z" }, - { url = "https://files.pythonhosted.org/packages/21/7b/5aa8848a7c6a9278c79375146da1812e695754ceec5f005e6043461a7315/librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", size = 101879, upload-time = "2026-05-10T18:16:08.103Z" }, - { url = "https://files.pythonhosted.org/packages/37/33/8a745436944947575b584231750a41417de1a38cf6a2e9251d1065651c09/librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", size = 119831, upload-time = "2026-05-10T18:16:09.174Z" }, - { url = "https://files.pythonhosted.org/packages/59/67/a6739ac96e28b7855808bdb0370e250606104a859750d209e5a0716fe7ab/librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", size = 103470, upload-time = "2026-05-10T18:16:10.369Z" }, - { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" }, - { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" }, - { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" }, - { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" }, - { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" }, - { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" }, - { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" }, - { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" }, - { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" }, - { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" }, - { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345, upload-time = "2026-05-10T18:16:30.674Z" }, - { url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131, upload-time = "2026-05-10T18:16:32.037Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024, upload-time = "2026-05-10T18:16:33.493Z" }, - { url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221, upload-time = "2026-05-10T18:16:34.864Z" }, - { url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174, upload-time = "2026-05-10T18:16:36.705Z" }, - { url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216, upload-time = "2026-05-10T18:16:38.418Z" }, - { url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921, upload-time = "2026-05-10T18:16:39.848Z" }, - { url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850, upload-time = "2026-05-10T18:16:41.471Z" }, - { url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237, upload-time = "2026-05-10T18:16:43.15Z" }, - { url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261, upload-time = "2026-05-10T18:16:44.408Z" }, - { url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965, upload-time = "2026-05-10T18:16:46.039Z" }, - { url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151, upload-time = "2026-05-10T18:16:47.133Z" }, - { url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850, upload-time = "2026-05-10T18:16:48.597Z" }, - { url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138, upload-time = "2026-05-10T18:16:49.839Z" }, - { url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976, upload-time = "2026-05-10T18:16:51.062Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927, upload-time = "2026-05-10T18:16:52.632Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698, upload-time = "2026-05-10T18:16:53.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162, upload-time = "2026-05-10T18:16:55.589Z" }, - { url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494, upload-time = "2026-05-10T18:16:56.975Z" }, - { url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858, upload-time = "2026-05-10T18:16:58.374Z" }, - { url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318, upload-time = "2026-05-10T18:16:59.676Z" }, - { url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115, upload-time = "2026-05-10T18:17:01.007Z" }, - { url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918, upload-time = "2026-05-10T18:17:02.682Z" }, - { url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562, upload-time = "2026-05-10T18:17:03.99Z" }, - { url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327, upload-time = "2026-05-10T18:17:05.465Z" }, - { url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572, upload-time = "2026-05-10T18:17:06.809Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/87/2bf31fe17587b29e3f93ec31421e2b1e1c3e349b8bf6c7c313dbad1d5340/librt-0.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29", size = 141092 }, + { url = "https://files.pythonhosted.org/packages/cf/08/5c5bf772920b7ebac6e32bc91a643e0ab3870199c0b542356d3baa83970a/librt-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9", size = 142035 }, + { url = "https://files.pythonhosted.org/packages/06/20/662a03d254e5b000d838e8b345d83303ddb768c080fd488e40634c0fa66b/librt-0.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5", size = 475022 }, + { url = "https://files.pythonhosted.org/packages/de/f3/aa81523e45184c6ec23dc7f63263362ec55f80a09d424c012359ecbe7e35/librt-0.11.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b", size = 467273 }, + { url = "https://files.pythonhosted.org/packages/6b/6f/59c74b560ca8853834d5501d589c8a2519f4184f273a085ffd0f37a1cc47/librt-0.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89", size = 497083 }, + { url = "https://files.pythonhosted.org/packages/fe/7b/5aa4d2c9600a719401160bf7055417df0b2a47439b9d88286ce45e56b65f/librt-0.11.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc", size = 489139 }, + { url = "https://files.pythonhosted.org/packages/d6/31/9143803d7da6856a69153785768c4936864430eec0fd9461c3ea527d9922/librt-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5", size = 508442 }, + { url = "https://files.pythonhosted.org/packages/2f/5a/bce08184488426bda4ccc2c4964ac048c8f68ae89bd7120082eef4233cfd/librt-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7", size = 514230 }, + { url = "https://files.pythonhosted.org/packages/89/8c/bb5e213d254b7505a0e658da199d8ab719086632ce09eef311ab27976523/librt-0.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d", size = 494231 }, + { url = "https://files.pythonhosted.org/packages/9d/fb/541cdad5b1ab1300398c74c4c9a497b88e5074c21b1244c8f49731d3a284/librt-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412", size = 537585 }, + { url = "https://files.pythonhosted.org/packages/8f/f2/464bb69295c320cb06bddb4f14a4ec67934ee14b2bffb12b19fb7ab287ba/librt-0.11.0-cp311-cp311-win32.whl", hash = "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d", size = 100509 }, + { url = "https://files.pythonhosted.org/packages/6d/e7/a17ee1788f9e4fbf548c19f4afa07c92089b9e24fef6cb2410863781ef4c/librt-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73", size = 118628 }, + { url = "https://files.pythonhosted.org/packages/cc/c7/6c766214f9f9903bcfcfbef97d807af8d8f5aa3502d247858ab17582d212/librt-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c", size = 103122 }, + { url = "https://files.pythonhosted.org/packages/8b/d0/07c77e067f0838949b43bd89232c29d72efebb9d2801a9750184eb706b71/librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", size = 144147 }, + { url = "https://files.pythonhosted.org/packages/7a/24/8493538fa4f62f982686398a5b8f68008138a75086abdea19ade64bf4255/librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", size = 143614 }, + { url = "https://files.pythonhosted.org/packages/ff/1e/f8bad050810d9171f34a1648ed910e56814c2ba61639f2bd53c6377ae24b/librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", size = 485538 }, + { url = "https://files.pythonhosted.org/packages/c0/fe/3594ebfbaf03084ba4b120c9ba5c3183fd938a48725e9bbe6ff0a5159ad8/librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", size = 479623 }, + { url = "https://files.pythonhosted.org/packages/b0/da/5d1876984b3746c85dbd219dbfcb73c85f54ee263fd32e5b2a632ec14571/librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", size = 513082 }, + { url = "https://files.pythonhosted.org/packages/19/6e/55bdf5d5ca00c3e18430690bf2c953d8d3ffd3c337418173d33dec985dc9/librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", size = 508105 }, + { url = "https://files.pythonhosted.org/packages/07/10/f1f23a7c595ee90ece4d35c851e5d104b1311a887ed1b4ac4c35bbd13da8/librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", size = 522268 }, + { url = "https://files.pythonhosted.org/packages/b6/02/5720f5697a7f54b78b3aefbe20df3a48cedcff1276618c4aa481177942ed/librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", size = 527348 }, + { url = "https://files.pythonhosted.org/packages/50/db/b4a47c6f91db4ff76348a0b3dd0cc65e090a078b765a810a62ff9434c3d3/librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", size = 516294 }, + { url = "https://files.pythonhosted.org/packages/9e/58/9384b2f4eb1ed1d273d40948a7c5c4b2360213b402ef3be4641c06299f9c/librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", size = 553608 }, + { url = "https://files.pythonhosted.org/packages/21/7b/5aa8848a7c6a9278c79375146da1812e695754ceec5f005e6043461a7315/librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", size = 101879 }, + { url = "https://files.pythonhosted.org/packages/37/33/8a745436944947575b584231750a41417de1a38cf6a2e9251d1065651c09/librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", size = 119831 }, + { url = "https://files.pythonhosted.org/packages/59/67/a6739ac96e28b7855808bdb0370e250606104a859750d209e5a0716fe7ab/librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", size = 103470 }, + { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119 }, + { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565 }, + { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395 }, + { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383 }, + { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010 }, + { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433 }, + { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595 }, + { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255 }, + { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847 }, + { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920 }, + { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898 }, + { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812 }, + { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448 }, + { url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345 }, + { url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131 }, + { url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024 }, + { url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221 }, + { url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174 }, + { url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216 }, + { url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921 }, + { url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850 }, + { url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237 }, + { url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261 }, + { url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965 }, + { url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151 }, + { url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850 }, + { url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138 }, + { url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976 }, + { url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927 }, + { url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698 }, + { url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162 }, + { url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494 }, + { url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858 }, + { url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318 }, + { url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115 }, + { url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918 }, + { url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562 }, + { url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327 }, + { url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572 }, ] [[package]] @@ -1400,9 +1402,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "uc-micro-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158, upload-time = "2026-03-01T07:48:47.683Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/de/88b3be5c31b22333b3ca2f6ff1de4e863d8fe45aaea7485f591970ec1d3e/linkify_it_py-2.1.0-py3-none-any.whl", hash = "sha256:0d252c1594ecba2ecedc444053db5d3a9b7ec1b0dd929c8f1d74dce89f86c05e", size = 19878, upload-time = "2026-03-01T07:48:46.098Z" }, + { url = "https://files.pythonhosted.org/packages/b4/de/88b3be5c31b22333b3ca2f6ff1de4e863d8fe45aaea7485f591970ec1d3e/linkify_it_py-2.1.0-py3-none-any.whl", hash = "sha256:0d252c1594ecba2ecedc444053db5d3a9b7ec1b0dd929c8f1d74dce89f86c05e", size = 19878 }, ] [[package]] @@ -1412,9 +1414,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687 }, ] [package.optional-dependencies] @@ -1426,7 +1428,7 @@ linkify = [ name = "markupsafe" version = "2.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/10/ff66fea6d1788c458663a84d88787bae15d45daa16f6b3ef33322a51fc7e/MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", size = 18596, upload-time = "2021-05-18T17:18:22.856Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/10/ff66fea6d1788c458663a84d88787bae15d45daa16f6b3ef33322a51fc7e/MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", size = 18596 } [[package]] name = "matplotlib-inline" @@ -1435,9 +1437,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150, upload-time = "2026-05-08T17:33:33.49Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/c0/9f7c9a46090390368a4d7bcb76bb87a4a36c421e4c0792cdb53486ffac7a/matplotlib_inline-0.2.2.tar.gz", hash = "sha256:72f3fe8fce36b70d4a5b612f899090cd0401deddc4ea90e1572b9f4bfb058c79", size = 8150 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" }, + { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534 }, ] [[package]] @@ -1447,18 +1449,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl", hash = "sha256:214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d", size = 66663, upload-time = "2026-05-13T09:03:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl", hash = "sha256:214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d", size = 66663 }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] [[package]] @@ -1470,38 +1472,38 @@ dependencies = [ { name = "rich" }, { name = "textual" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/db/56ff21f47be261ab781105b233d1851d3f2fcdd4f08ebf689f6d6fd84f0d/memray-1.19.2.tar.gz", hash = "sha256:680cb90ac4564d140673ac9d8b7a7e07a8405bd1fb8f933da22616f93124ca84", size = 2410256, upload-time = "2026-03-13T15:22:31.825Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/bf/b8f28adbd3e1eeeb88e188053a26164b195ebcf66f8af6b30003a83f5660/memray-1.19.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:c8d35a9f5b222165c5aedbfc18b79dc5161a724963a4fca8d1053faa0b571195", size = 2181644, upload-time = "2026-03-13T15:20:41.756Z" }, - { url = "https://files.pythonhosted.org/packages/21/66/0791e5514b475d6300d13ebe87839db1606b2dc2fbe00fecce4da2fb405d/memray-1.19.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3735567011cc22339aee2c59b5fc94d1bdd4a23f9990e02a2c3cccc9c3cf6de4", size = 2164670, upload-time = "2026-03-13T15:20:44.14Z" }, - { url = "https://files.pythonhosted.org/packages/0f/aa/086878e99693b174b0d04d0b267231862fb6a3cfc35cab2920284c2a2e38/memray-1.19.2-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ab78af759eebcb8d8ecef173042515711d2dcc9600d5dd446d1592b24a89b7d9", size = 9777844, upload-time = "2026-03-13T15:20:46.266Z" }, - { url = "https://files.pythonhosted.org/packages/40/a6/40247667e72b5d8322c5dc2ef30513238b3480be1e482faaaf9cc573ff38/memray-1.19.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f3ae7983297d168cdcc2d05cd93a4934b9b6fe0d341a91ac5b71bf45f9cec06c", size = 10021548, upload-time = "2026-03-13T15:20:49.079Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bb/50603e8f7fe950b3f6a6e09a80413a8f25c4a9d360d8b3b027a8841e1fe8/memray-1.19.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08a4316d7a92eb415024b46988844ed0fd44b2d02ca00fa4a21f2481c1f803e6", size = 9400168, upload-time = "2026-03-13T15:20:51.801Z" }, - { url = "https://files.pythonhosted.org/packages/e2/89/a21e0b639496ed59d2a733e60869ff2e685c5a78891474a494e09a17dc7c/memray-1.19.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dbdb14fd31e2a031312755dc76146aeff9d0889e82ccffe231f1f20f50526f57", size = 12234413, upload-time = "2026-03-13T15:20:54.454Z" }, - { url = "https://files.pythonhosted.org/packages/13/4e/8685c202ddd76860cd8fc5f7f552115ea6f317e9f5f16219a56f336e351e/memray-1.19.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:22d4482f559ffa91a9727693e7e338856bee5e316f922839bf8b96e0f9b8a4de", size = 2183484, upload-time = "2026-03-13T15:20:56.696Z" }, - { url = "https://files.pythonhosted.org/packages/89/79/602f55d5466f1f587cdddf0324f82752bd0319ea814bc7cca2efb8593bc8/memray-1.19.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fd1476868177ee8d9f7f85e5a085a20cc3c3a8228a23ced72749265885d55ca", size = 2162900, upload-time = "2026-03-13T15:20:58.174Z" }, - { url = "https://files.pythonhosted.org/packages/02/1b/402207971653b9861bbbe449cbed7d82e7bb9b953dd6ac93dd4d78e76fa2/memray-1.19.2-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:23375d50faa199e1c1bc2e89f08691f6812478fddb49a1b82bebe6ef5a56df2c", size = 9731991, upload-time = "2026-03-13T15:21:00.299Z" }, - { url = "https://files.pythonhosted.org/packages/3f/7d/895ce73fcf9ab0a2b675ed49bbc91cbca14bda187e2b4df86ccefeb1c9bc/memray-1.19.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8ef3d8e4fba0b26280b550278a0660554283135cbccc34e2d49ba82a1945eb61", size = 9997104, upload-time = "2026-03-13T15:21:02.959Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b9/586bf51a1321cde736d886ca8ac3d4b1f910e4f3f813d7c8eb22498ee16f/memray-1.19.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4d6cf9597ae5d60f7893a0b7b6b9af9c349121446b3c1e7b9ac1d8b5d45a505", size = 9373508, upload-time = "2026-03-13T15:21:05.945Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f1/7cb51edeeceaaee770d4222e833369fbc927227d27e0a917b5ad6f4b2f85/memray-1.19.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:716a0a0e9048d21da98f9107fa030a76138eb694a16a81ad15eace54fddef4cd", size = 12222756, upload-time = "2026-03-13T15:21:08.9Z" }, - { url = "https://files.pythonhosted.org/packages/34/10/cbf57c122988d6e3bd148aa374e91e0e2f156cc7db1ac6397eb6db3946d1/memray-1.19.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:13aa87ad34cc88b3f31f7205e0a4543c391032e8600dc0c0cbf22555ff816d97", size = 2182910, upload-time = "2026-03-13T15:21:11.357Z" }, - { url = "https://files.pythonhosted.org/packages/5c/0e/7979dfe7e2b034431e44e3bab86356d9bc2c4f3ed0eb1594cb0ceb38c859/memray-1.19.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d6b249618a3e4fa8e10291445a2b2dfaf6f188e7cc1765966aac8fb52cb22066", size = 2161575, upload-time = "2026-03-13T15:21:13.051Z" }, - { url = "https://files.pythonhosted.org/packages/f9/92/2f0ca3936cdf4c59bc8c59fc8738ce8854ba24fd8519988f2ece0eba10fa/memray-1.19.2-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:34985e5e638ef8d4d54de8173c5e4481c478930f545bd0eb4738a631beb63d04", size = 9732172, upload-time = "2026-03-13T15:21:15.115Z" }, - { url = "https://files.pythonhosted.org/packages/52/23/de78510b4e3a0668b793d8b5dff03f2af20eef97943ca5b3263effff799c/memray-1.19.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee0fcfafd1e8535bdc0d0ed75bcdd48d436a6f62d467df91871366cbb3bbaebc", size = 9999447, upload-time = "2026-03-13T15:21:18.099Z" }, - { url = "https://files.pythonhosted.org/packages/00/0d/b0e50537470f93bddfa2c134177fe9332c20be44a571588866776ff92b82/memray-1.19.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:846185c393ff0dc6bca55819b1c83b510b77d8d561b7c0c50f4873f69579e35d", size = 9379158, upload-time = "2026-03-13T15:21:21.003Z" }, - { url = "https://files.pythonhosted.org/packages/5c/53/78f6de5c7208821b15cfbbb9da44ab4a5a881a7cc5075f9435a1700320e8/memray-1.19.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cc31327ed71e9f6ef7e9ed558e764f0e9c3f01da13ad8547734eb65fbeade1d", size = 12226753, upload-time = "2026-03-13T15:21:24.041Z" }, - { url = "https://files.pythonhosted.org/packages/e1/f4/3d8205b9f46657d26d54d1e644f27d09955b737189354a01907d8a08c7e2/memray-1.19.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:410377c0eae8d544421f74b919a18e119279fe1a2fa5ff381404b55aeb4c6514", size = 2184823, upload-time = "2026-03-13T15:21:27.176Z" }, - { url = "https://files.pythonhosted.org/packages/fb/07/7a342801317eff410a8267b55cb7514e156ee1f574e690852eb240bbe9fd/memray-1.19.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a53dc4032581ed075fcb62a4acc0ced14fb90a8269159d4e53dfac7af269c255", size = 2163669, upload-time = "2026-03-13T15:21:29.123Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/2c342b1472f9f03018bb88c80760cdfa6979404d63c4300c607fd0562607/memray-1.19.2-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:a7630865fbf3823aa2d1a6f7536f7aec88cf8ccf5b2498aad44adbc733f6bd2e", size = 9732615, upload-time = "2026-03-13T15:21:31.038Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/2cf960526c9b1f6d46977fc70e11de29ca6b9eafeeb42d1cec7d3bcb056a/memray-1.19.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c23e2b4be22a23cf5cae08854549e3460869a36c5f4bedc739b646ac97da4a60", size = 9979299, upload-time = "2026-03-13T15:21:34.072Z" }, - { url = "https://files.pythonhosted.org/packages/e1/78/73ee3d0ebee3c38fbb2d51766854d2932beec6481063532a6019bf340a2d/memray-1.19.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:95b6c02ca7f8555b5bee1c54c50cbbcf2033e07ebca95dade2ac3a27bb36b320", size = 9375722, upload-time = "2026-03-13T15:21:36.884Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c6/2f02475e85ccd32fa306736986f1f77f99365066ecdc859f5078148ebc40/memray-1.19.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:907470e2684568eb91a993ae69a08b1430494c8f2f6ef489b4b78519d9dae3d0", size = 12220041, upload-time = "2026-03-13T15:21:40.16Z" }, - { url = "https://files.pythonhosted.org/packages/76/12/01bb32188c011e6d802469e04c1d7c8054eb8300164e2269c830f5b26a8e/memray-1.19.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:124138f35fea36c434256c417f1b8cb32f78769f208530c1e56bf2c2b7654120", size = 2201353, upload-time = "2026-03-13T15:21:42.607Z" }, - { url = "https://files.pythonhosted.org/packages/e5/e0/d9b59f8be00f27440f60b95da5db6515a1c44c481651b8d2fa8f3468fc35/memray-1.19.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:240192dc98ff0b3501055521bfd73566d339808b11bd5af10865afe6ae18abef", size = 2180420, upload-time = "2026-03-13T15:21:44.623Z" }, - { url = "https://files.pythonhosted.org/packages/a5/5c/30aca63f4b88dca79ba679675200938652c816edee34c12565d2f17ea936/memray-1.19.2-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:edb7a3c2a9e97fb409b352f6c316598c7c0c3c22732e73704d25b9eb75ae2f2d", size = 9697953, upload-time = "2026-03-13T15:21:47.088Z" }, - { url = "https://files.pythonhosted.org/packages/9f/02/9e4a68bdd5ebc9079f97bdf287cc0ccc51c18e9edc205de7d41648315809/memray-1.19.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b6a43db4c1466446a905a77944813253231ac0269f758c6c6bc03ceb1821c1b6", size = 9944517, upload-time = "2026-03-13T15:21:50.125Z" }, - { url = "https://files.pythonhosted.org/packages/4a/f0/3adad59ebed6841c2f88b43c9b90cc9c03ff086129a8aef3cff23c92d6ac/memray-1.19.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf951dae8d27d502fbc549f6784460a70cce05b1e71bf5446d8692a74051f14f", size = 9365528, upload-time = "2026-03-13T15:21:53.141Z" }, - { url = "https://files.pythonhosted.org/packages/45/0e/083e00fe74e576b463e7b00e4214b8962f27bd70c5c77e494c0211a77342/memray-1.19.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8033b78232555bb1856b3298bef2898ec8b334d3d465c1822c665206d1fa910a", size = 12143894, upload-time = "2026-03-13T15:21:56.486Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e9/db/56ff21f47be261ab781105b233d1851d3f2fcdd4f08ebf689f6d6fd84f0d/memray-1.19.2.tar.gz", hash = "sha256:680cb90ac4564d140673ac9d8b7a7e07a8405bd1fb8f933da22616f93124ca84", size = 2410256 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/bf/b8f28adbd3e1eeeb88e188053a26164b195ebcf66f8af6b30003a83f5660/memray-1.19.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:c8d35a9f5b222165c5aedbfc18b79dc5161a724963a4fca8d1053faa0b571195", size = 2181644 }, + { url = "https://files.pythonhosted.org/packages/21/66/0791e5514b475d6300d13ebe87839db1606b2dc2fbe00fecce4da2fb405d/memray-1.19.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3735567011cc22339aee2c59b5fc94d1bdd4a23f9990e02a2c3cccc9c3cf6de4", size = 2164670 }, + { url = "https://files.pythonhosted.org/packages/0f/aa/086878e99693b174b0d04d0b267231862fb6a3cfc35cab2920284c2a2e38/memray-1.19.2-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ab78af759eebcb8d8ecef173042515711d2dcc9600d5dd446d1592b24a89b7d9", size = 9777844 }, + { url = "https://files.pythonhosted.org/packages/40/a6/40247667e72b5d8322c5dc2ef30513238b3480be1e482faaaf9cc573ff38/memray-1.19.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f3ae7983297d168cdcc2d05cd93a4934b9b6fe0d341a91ac5b71bf45f9cec06c", size = 10021548 }, + { url = "https://files.pythonhosted.org/packages/b3/bb/50603e8f7fe950b3f6a6e09a80413a8f25c4a9d360d8b3b027a8841e1fe8/memray-1.19.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08a4316d7a92eb415024b46988844ed0fd44b2d02ca00fa4a21f2481c1f803e6", size = 9400168 }, + { url = "https://files.pythonhosted.org/packages/e2/89/a21e0b639496ed59d2a733e60869ff2e685c5a78891474a494e09a17dc7c/memray-1.19.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dbdb14fd31e2a031312755dc76146aeff9d0889e82ccffe231f1f20f50526f57", size = 12234413 }, + { url = "https://files.pythonhosted.org/packages/13/4e/8685c202ddd76860cd8fc5f7f552115ea6f317e9f5f16219a56f336e351e/memray-1.19.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:22d4482f559ffa91a9727693e7e338856bee5e316f922839bf8b96e0f9b8a4de", size = 2183484 }, + { url = "https://files.pythonhosted.org/packages/89/79/602f55d5466f1f587cdddf0324f82752bd0319ea814bc7cca2efb8593bc8/memray-1.19.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fd1476868177ee8d9f7f85e5a085a20cc3c3a8228a23ced72749265885d55ca", size = 2162900 }, + { url = "https://files.pythonhosted.org/packages/02/1b/402207971653b9861bbbe449cbed7d82e7bb9b953dd6ac93dd4d78e76fa2/memray-1.19.2-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:23375d50faa199e1c1bc2e89f08691f6812478fddb49a1b82bebe6ef5a56df2c", size = 9731991 }, + { url = "https://files.pythonhosted.org/packages/3f/7d/895ce73fcf9ab0a2b675ed49bbc91cbca14bda187e2b4df86ccefeb1c9bc/memray-1.19.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8ef3d8e4fba0b26280b550278a0660554283135cbccc34e2d49ba82a1945eb61", size = 9997104 }, + { url = "https://files.pythonhosted.org/packages/a0/b9/586bf51a1321cde736d886ca8ac3d4b1f910e4f3f813d7c8eb22498ee16f/memray-1.19.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4d6cf9597ae5d60f7893a0b7b6b9af9c349121446b3c1e7b9ac1d8b5d45a505", size = 9373508 }, + { url = "https://files.pythonhosted.org/packages/5d/f1/7cb51edeeceaaee770d4222e833369fbc927227d27e0a917b5ad6f4b2f85/memray-1.19.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:716a0a0e9048d21da98f9107fa030a76138eb694a16a81ad15eace54fddef4cd", size = 12222756 }, + { url = "https://files.pythonhosted.org/packages/34/10/cbf57c122988d6e3bd148aa374e91e0e2f156cc7db1ac6397eb6db3946d1/memray-1.19.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:13aa87ad34cc88b3f31f7205e0a4543c391032e8600dc0c0cbf22555ff816d97", size = 2182910 }, + { url = "https://files.pythonhosted.org/packages/5c/0e/7979dfe7e2b034431e44e3bab86356d9bc2c4f3ed0eb1594cb0ceb38c859/memray-1.19.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d6b249618a3e4fa8e10291445a2b2dfaf6f188e7cc1765966aac8fb52cb22066", size = 2161575 }, + { url = "https://files.pythonhosted.org/packages/f9/92/2f0ca3936cdf4c59bc8c59fc8738ce8854ba24fd8519988f2ece0eba10fa/memray-1.19.2-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:34985e5e638ef8d4d54de8173c5e4481c478930f545bd0eb4738a631beb63d04", size = 9732172 }, + { url = "https://files.pythonhosted.org/packages/52/23/de78510b4e3a0668b793d8b5dff03f2af20eef97943ca5b3263effff799c/memray-1.19.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee0fcfafd1e8535bdc0d0ed75bcdd48d436a6f62d467df91871366cbb3bbaebc", size = 9999447 }, + { url = "https://files.pythonhosted.org/packages/00/0d/b0e50537470f93bddfa2c134177fe9332c20be44a571588866776ff92b82/memray-1.19.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:846185c393ff0dc6bca55819b1c83b510b77d8d561b7c0c50f4873f69579e35d", size = 9379158 }, + { url = "https://files.pythonhosted.org/packages/5c/53/78f6de5c7208821b15cfbbb9da44ab4a5a881a7cc5075f9435a1700320e8/memray-1.19.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cc31327ed71e9f6ef7e9ed558e764f0e9c3f01da13ad8547734eb65fbeade1d", size = 12226753 }, + { url = "https://files.pythonhosted.org/packages/e1/f4/3d8205b9f46657d26d54d1e644f27d09955b737189354a01907d8a08c7e2/memray-1.19.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:410377c0eae8d544421f74b919a18e119279fe1a2fa5ff381404b55aeb4c6514", size = 2184823 }, + { url = "https://files.pythonhosted.org/packages/fb/07/7a342801317eff410a8267b55cb7514e156ee1f574e690852eb240bbe9fd/memray-1.19.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a53dc4032581ed075fcb62a4acc0ced14fb90a8269159d4e53dfac7af269c255", size = 2163669 }, + { url = "https://files.pythonhosted.org/packages/d4/00/2c342b1472f9f03018bb88c80760cdfa6979404d63c4300c607fd0562607/memray-1.19.2-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:a7630865fbf3823aa2d1a6f7536f7aec88cf8ccf5b2498aad44adbc733f6bd2e", size = 9732615 }, + { url = "https://files.pythonhosted.org/packages/fe/ae/2cf960526c9b1f6d46977fc70e11de29ca6b9eafeeb42d1cec7d3bcb056a/memray-1.19.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c23e2b4be22a23cf5cae08854549e3460869a36c5f4bedc739b646ac97da4a60", size = 9979299 }, + { url = "https://files.pythonhosted.org/packages/e1/78/73ee3d0ebee3c38fbb2d51766854d2932beec6481063532a6019bf340a2d/memray-1.19.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:95b6c02ca7f8555b5bee1c54c50cbbcf2033e07ebca95dade2ac3a27bb36b320", size = 9375722 }, + { url = "https://files.pythonhosted.org/packages/3b/c6/2f02475e85ccd32fa306736986f1f77f99365066ecdc859f5078148ebc40/memray-1.19.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:907470e2684568eb91a993ae69a08b1430494c8f2f6ef489b4b78519d9dae3d0", size = 12220041 }, + { url = "https://files.pythonhosted.org/packages/76/12/01bb32188c011e6d802469e04c1d7c8054eb8300164e2269c830f5b26a8e/memray-1.19.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:124138f35fea36c434256c417f1b8cb32f78769f208530c1e56bf2c2b7654120", size = 2201353 }, + { url = "https://files.pythonhosted.org/packages/e5/e0/d9b59f8be00f27440f60b95da5db6515a1c44c481651b8d2fa8f3468fc35/memray-1.19.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:240192dc98ff0b3501055521bfd73566d339808b11bd5af10865afe6ae18abef", size = 2180420 }, + { url = "https://files.pythonhosted.org/packages/a5/5c/30aca63f4b88dca79ba679675200938652c816edee34c12565d2f17ea936/memray-1.19.2-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:edb7a3c2a9e97fb409b352f6c316598c7c0c3c22732e73704d25b9eb75ae2f2d", size = 9697953 }, + { url = "https://files.pythonhosted.org/packages/9f/02/9e4a68bdd5ebc9079f97bdf287cc0ccc51c18e9edc205de7d41648315809/memray-1.19.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b6a43db4c1466446a905a77944813253231ac0269f758c6c6bc03ceb1821c1b6", size = 9944517 }, + { url = "https://files.pythonhosted.org/packages/4a/f0/3adad59ebed6841c2f88b43c9b90cc9c03ff086129a8aef3cff23c92d6ac/memray-1.19.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf951dae8d27d502fbc549f6784460a70cce05b1e71bf5446d8692a74051f14f", size = 9365528 }, + { url = "https://files.pythonhosted.org/packages/45/0e/083e00fe74e576b463e7b00e4214b8962f27bd70c5c77e494c0211a77342/memray-1.19.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8033b78232555bb1856b3298bef2898ec8b334d3d465c1822c665206d1fa910a", size = 12143894 }, ] [[package]] @@ -1515,78 +1517,78 @@ dependencies = [ { name = "typing-extensions" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/df/6dfc6540f96a74125a11653cce717603fd5b7d0001a8e847b3e54e72d238/minio-7.2.20.tar.gz", hash = "sha256:95898b7a023fbbfde375985aa77e2cd6a0762268db79cf886f002a9ea8e68598", size = 136113, upload-time = "2025-11-27T00:37:15.569Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/df/6dfc6540f96a74125a11653cce717603fd5b7d0001a8e847b3e54e72d238/minio-7.2.20.tar.gz", hash = "sha256:95898b7a023fbbfde375985aa77e2cd6a0762268db79cf886f002a9ea8e68598", size = 136113 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/9a/b697530a882588a84db616580f2ba5d1d515c815e11c30d219145afeec87/minio-7.2.20-py3-none-any.whl", hash = "sha256:eb33dd2fb80e04c3726a76b13241c6be3c4c46f8d81e1d58e757786f6501897e", size = 93751, upload-time = "2025-11-27T00:37:13.993Z" }, + { url = "https://files.pythonhosted.org/packages/3e/9a/b697530a882588a84db616580f2ba5d1d515c815e11c30d219145afeec87/minio-7.2.20-py3-none-any.whl", hash = "sha256:eb33dd2fb80e04c3726a76b13241c6be3c4c46f8d81e1d58e757786f6501897e", size = 93751 }, ] [[package]] name = "mmh3" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/54/78c7f04ceee4913cbe7b33e253867c1da2291c80dfa6062dc6aaabb6cef8/mmh3-3.0.0.tar.gz", hash = "sha256:d1ec578c09a07d3518ec9be540b87546397fa3455de73c166fcce51eaa5c41c5", size = 10359, upload-time = "2021-02-23T14:45:45.962Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/54/78c7f04ceee4913cbe7b33e253867c1da2291c80dfa6062dc6aaabb6cef8/mmh3-3.0.0.tar.gz", hash = "sha256:d1ec578c09a07d3518ec9be540b87546397fa3455de73c166fcce51eaa5c41c5", size = 10359 } [[package]] name = "msgpack" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960, upload-time = "2026-06-18T16:13:52.594Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/6b/e9b1cdc042c4458801d2545ed782a95f3d6ba8e270cce8745b8603c7f748/msgpack-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29a3f6e9667868429d8240dfd063ea5ffdc1321c13d783aa23827a38de0dcb22", size = 82812, upload-time = "2026-06-18T16:12:45.022Z" }, - { url = "https://files.pythonhosted.org/packages/0c/3a/dd518a1bf78ed1e9ad8afe57307c079a00eafe4b3068932a27ca1ea56b4f/msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aded5bdf32609dc7987a49bbbd15a8ef096193f96dd8bbeb791de729e650acf5", size = 82739, upload-time = "2026-06-18T16:12:46.025Z" }, - { url = "https://files.pythonhosted.org/packages/70/e0/7ba9e1542bf0771a27b8b37c1316e3f95ae9d748fd765284655c476ad4ef/msgpack-1.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:146ee4e9ce80b365c6d4c47073da9da7bcec473e58194ceee5dd7620ace77e06", size = 414233, upload-time = "2026-06-18T16:12:47.029Z" }, - { url = "https://files.pythonhosted.org/packages/03/8d/671d81534ea0e2b0e8a121be100020da09eb78861fe3aa8f3ef7dcd3bed1/msgpack-1.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a28d076ca7c82b9c8728ad90b7147489449557038bed50e4241eb832395169b4", size = 423843, upload-time = "2026-06-18T16:12:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b6/e5c737515ed1f166664b87601b532f58cbb73d8aa6a90b99f7c2c5037e8e/msgpack-1.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d31c0ac0c640f877804c67cb2bc9f4e23dc2db97e96c2e67fa27d38283b41f8", size = 390772, upload-time = "2026-06-18T16:12:49.624Z" }, - { url = "https://files.pythonhosted.org/packages/a8/46/62ed8c2e87d7021eab19921594d961ef3aa3794eec76c716dc30f3bfd433/msgpack-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ff92d7feeaf5bc26c51495b69e2f99ed97ab79346fb6555f44be7dd2ac6503b", size = 409559, upload-time = "2026-06-18T16:12:50.936Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/59aa3887b860bbf43532835e192b1c388a17590d6068ae4f8b2bc74c906e/msgpack-1.2.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:779197a6513bab3c3632265e3d0f7cb3227e62510841a6f34f1eaa37efbb345e", size = 387838, upload-time = "2026-06-18T16:12:52.161Z" }, - { url = "https://files.pythonhosted.org/packages/09/11/f8563e471093420cf6478cb3271a0175d8402b82d879783d4035d2d03360/msgpack-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67f6dd22fa72a93752643f07889796d62739a13415ee630169a8ce764f86cf9f", size = 421732, upload-time = "2026-06-18T16:12:53.556Z" }, - { url = "https://files.pythonhosted.org/packages/57/cf/e673683c4c6c90c1022b24c65af4b03eda72b182a1176ef6449069d66acc/msgpack-1.2.1-cp311-cp311-win32.whl", hash = "sha256:91054a783328e0ea7954b8771095705c8d2243b814743fbaadf14552c9c52c5d", size = 64091, upload-time = "2026-06-18T16:12:54.821Z" }, - { url = "https://files.pythonhosted.org/packages/3f/07/ca212739d179f9083bff2c7c08c24101c3555a334fadc2b876b18768a3ae/msgpack-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2eda0b7ebb1283a98d3e4492ac933c8af6aff59fd3df1c3ed024f536af4b1dc8", size = 70462, upload-time = "2026-06-18T16:12:55.898Z" }, - { url = "https://files.pythonhosted.org/packages/6d/be/6798347b425e26f35db82e69dd83c09716c856a3714e7bffc4c0860fd830/msgpack-1.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ee967f7c7e1df2890c671ff2ee51a28ded0efc95da3e507176dee881ce36c66", size = 65059, upload-time = "2026-06-18T16:12:57.053Z" }, - { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531, upload-time = "2026-06-18T16:12:58.249Z" }, - { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657, upload-time = "2026-06-18T16:12:59.396Z" }, - { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634, upload-time = "2026-06-18T16:13:00.383Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989, upload-time = "2026-06-18T16:13:01.776Z" }, - { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544, upload-time = "2026-06-18T16:13:03.637Z" }, - { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842, upload-time = "2026-06-18T16:13:05.012Z" }, - { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108, upload-time = "2026-06-18T16:13:06.232Z" }, - { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939, upload-time = "2026-06-18T16:13:07.478Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504, upload-time = "2026-06-18T16:13:08.822Z" }, - { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421, upload-time = "2026-06-18T16:13:09.828Z" }, - { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775, upload-time = "2026-06-18T16:13:11.056Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ac/dcddcab6f6c20ecb387ca5e980371cdb3f87ff69aeca388be97eebc4c074/msgpack-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a70e3cf2804a300d921bb0940426e35f4e489a23adfb77a808892241db0a064", size = 83151, upload-time = "2026-06-18T16:13:12.173Z" }, - { url = "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:491cc39455ca765fad51fb451bf2915eb2cf41192ab5801ce8d67c1d614fe056", size = 82351, upload-time = "2026-06-18T16:13:13.194Z" }, - { url = "https://files.pythonhosted.org/packages/e3/10/ddf7b06db879e8792d13934ddda09ff20bd2a583fd84c9b59aae9b0e650b/msgpack-1.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f310233ef7fb9c14e201c93639fe5f5260b005f56f0b29048e999c30935596cc", size = 407518, upload-time = "2026-06-18T16:13:14.233Z" }, - { url = "https://files.pythonhosted.org/packages/79/d3/36a46a8ed992b781acbc05928bd5bee3c810cb0c3563bf81a7b0c04a1a76/msgpack-1.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:787c9bebb5833e8f6fc8abca3c0597683d8d87f56a8842b6b89c75a5f3176e2d", size = 416405, upload-time = "2026-06-18T16:13:15.435Z" }, - { url = "https://files.pythonhosted.org/packages/f9/84/e8e9598b557c0ba6ddae901a73780a4c75ac667dddf59414b1e56a42fb34/msgpack-1.2.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc871b997a9370d855b7394465f2f350e847a5b806dd38dcc9c989e7d87da155", size = 376257, upload-time = "2026-06-18T16:13:17.022Z" }, - { url = "https://files.pythonhosted.org/packages/40/16/738fe6d875ad7e2a9429c165322a4ec088f4f273cdfae63d96a89c467961/msgpack-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85f57e960d877f2977f6430896191b04a21f8901b3b4baf2e4604329f4db5402", size = 397469, upload-time = "2026-06-18T16:13:18.287Z" }, - { url = "https://files.pythonhosted.org/packages/ca/be/6d5952df75a7f24f35833af764c3a6860780364cb3a0030beb8099e1b2b4/msgpack-1.2.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1233ee2dd0cefba127583de50ea654677277047d238303521db35def3d7b2e7c", size = 372802, upload-time = "2026-06-18T16:13:19.685Z" }, - { url = "https://files.pythonhosted.org/packages/e1/39/e2ef7dbf0473bcb8dc7c50bf782a892d67414877b63e47fc88eb189ef5e6/msgpack-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e3dc2feb0876209d9c38aa56cb1de169bd6c4348f1aa48271f241226590993e6", size = 411273, upload-time = "2026-06-18T16:13:21.028Z" }, - { url = "https://files.pythonhosted.org/packages/ef/c5/133f4512a56e983a93445c836c9d94d88f3bc2e0980ff4b9e577bd8416ce/msgpack-1.2.1-cp313-cp313-win32.whl", hash = "sha256:6d09badf350af2be9d189184e04e64cf54ad93569ab3d96fca58bd3e84aad707", size = 64471, upload-time = "2026-06-18T16:13:22.293Z" }, - { url = "https://files.pythonhosted.org/packages/e2/98/577e10b055096a7dd40732358cabaf7180a20c79ed1dcdbb618e4b9deac7/msgpack-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:33f14fba63278b714efe6ad07e50ea5f03d91537aa6a1c5f1ceca4cf44013ca9", size = 71274, upload-time = "2026-06-18T16:13:23.455Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ee/0c0048e7cfbef23c6a94791b8959ab28155232e7956de8a305b5ff588f05/msgpack-1.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc5febcd4c99effbc02b528e49d6fd0760b2b7d48c05239e345a5fa6e743d9a", size = 64795, upload-time = "2026-06-18T16:13:24.687Z" }, - { url = "https://files.pythonhosted.org/packages/77/58/cce442852c6b9e1639c7c8ac8fd9143121cb32dab0f308df4d1426a8eb9c/msgpack-1.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:05f340e47e7e47d2da8db9b53e1bb1d294369e9ef45a747441309f6650b8351d", size = 83610, upload-time = "2026-06-18T16:13:25.724Z" }, - { url = "https://files.pythonhosted.org/packages/60/5c/15b4c7a0182f75ffa90751958ba36a9c01cafee367d49a3edc10ed140b01/msgpack-1.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:810b916696c86ef0deb3b74588480224df4c1b071136c34183e4a2a4284d7ac7", size = 83138, upload-time = "2026-06-18T16:13:26.781Z" }, - { url = "https://files.pythonhosted.org/packages/b8/a6/99e58722feaffc5f2fbcc0c8c0d1451ab9f84097f7af87291b46af2390f4/msgpack-1.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca0dacff965c47afdc3749a8469d7302a8f801d6a28758d55120d75e66ce6889", size = 406090, upload-time = "2026-06-18T16:13:28.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/03/8c63e8cf52958534ef688625965ab04c269a6cadd8caef16758b380a821a/msgpack-1.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e2bf9280bceb5efca998435904b5d3e9fdbcc11d90dc9df30aec7973252b720", size = 412106, upload-time = "2026-06-18T16:13:29.427Z" }, - { url = "https://files.pythonhosted.org/packages/63/d2/155d9e71b40e41fd934bc0c48b9b2770f22263e1ac20aad8e29fdca7be3f/msgpack-1.2.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6c4be5d1c02a42b066ca6ddb71adf36432868fdcdb6ee87e634e86e0674190", size = 374851, upload-time = "2026-06-18T16:13:30.631Z" }, - { url = "https://files.pythonhosted.org/packages/98/48/deaf2326262a8d5ea3295ce9649912ecd3f551ba7ec8e33c665d2ba583f3/msgpack-1.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec0e675d59150a6269ddc9139087c722292664a37d071a849c05c473350f1f2d", size = 396168, upload-time = "2026-06-18T16:13:31.977Z" }, - { url = "https://files.pythonhosted.org/packages/10/2a/b4410f906c2ec0008f1608d3ab5143afc3ad3f4e6da0fed3ea2231d0bef4/msgpack-1.2.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:dd3bfe82d53edfe4b7fc9a7ec9761e23a7a5b1dac22264505af428253c29ed24", size = 371959, upload-time = "2026-06-18T16:13:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/59/86/1edc67270099a528fa2093ea60fe191233cd238e4bd30cfacf7db79fc959/msgpack-1.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5ad5467fc3f68b5468e06c5f788d712e9f8ffc8b0cd1bcb160c105c1ee92dae7", size = 408457, upload-time = "2026-06-18T16:13:34.567Z" }, - { url = "https://files.pythonhosted.org/packages/82/90/8b630fef07d8c5ab457b71ff2c217910c83d333c7a68472c186e87cc504a/msgpack-1.2.1-cp314-cp314-win32.whl", hash = "sha256:98b58bdb89c46190e4609bb36abe17c6d4105ad13f9c5f8f6f64d320f8ced3fb", size = 65942, upload-time = "2026-06-18T16:13:36.056Z" }, - { url = "https://files.pythonhosted.org/packages/16/f1/467b81e98b24dd3885d7b1857728797b4ffc76a7a7483af4fb321a07de3c/msgpack-1.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:74847557e28ce71bd3c438a447ca90e4b507e997ddbdef8a12a7b283b86c156b", size = 72627, upload-time = "2026-06-18T16:13:37.079Z" }, - { url = "https://files.pythonhosted.org/packages/a7/1d/5d8c4c89985feb6acefb82a09e501c60392261856d2408d20bfe4f0360b1/msgpack-1.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:b50b727bd652bdc37d950336c848ef20ec54a4cafc38dce19b1cd86ad625d0f7", size = 66908, upload-time = "2026-06-18T16:13:38.23Z" }, - { url = "https://files.pythonhosted.org/packages/1b/02/ad2afb678b4de94496cd432b581759b756a92c1192d8c767edd6b132efdc/msgpack-1.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8d00f177ca88a77c1cf848d204a38f249751650b601cb6532acc68805d8a8273", size = 86000, upload-time = "2026-06-18T16:13:39.44Z" }, - { url = "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5bb9c386f0a329c035ddbab4b72d1028bf9627add8dda41070288563d57ed1b1", size = 86544, upload-time = "2026-06-18T16:13:40.447Z" }, - { url = "https://files.pythonhosted.org/packages/a9/b4/b774d7eb95561739907fec675582f83203cf41c597a418c2589b4bfb8e9d/msgpack-1.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20466cca18c49c7292a8984bc15d65857b171e7264bdcb5f96baf8be238791fc", size = 427661, upload-time = "2026-06-18T16:13:41.574Z" }, - { url = "https://files.pythonhosted.org/packages/b2/f9/3243191dc9937e00756c8bc1b0272fed8f23758e43df2a3b46f533e5090f/msgpack-1.2.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:196300e7e5d6e74d50f1607ab9c06c4a1484c383cd22defd727902591f7e8dde", size = 426375, upload-time = "2026-06-18T16:13:42.936Z" }, - { url = "https://files.pythonhosted.org/packages/23/c7/1693111db9944ba4ad4b67a1e788400d78a0b6af7a6523dc7e4e58f8274b/msgpack-1.2.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575957e79cd51903a4e8495a242442949641e08f1efd5197b43bebd3ea7682b4", size = 380495, upload-time = "2026-06-18T16:13:44.306Z" }, - { url = "https://files.pythonhosted.org/packages/3e/2b/92f86956a0c13e8662f7e2ad630c4eb4db07497b967589bd5245e018b2c1/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8c2ed1e48cc0f460bf3c7780e7137ff21a4e18433451916f2442c1b21036cd7d", size = 410897, upload-time = "2026-06-18T16:13:45.629Z" }, - { url = "https://files.pythonhosted.org/packages/da/ea/1479f72d200313a76fc2f823a79d1e07ed052ab7b8a0280640aa7b95de42/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f6277e5f783c36786a145e0247fc189a03f35f84b251646e53592d2bc12b355", size = 378519, upload-time = "2026-06-18T16:13:46.998Z" }, - { url = "https://files.pythonhosted.org/packages/f5/4d/fa006060ffa1011d32bfae826fe766fe73e02982183601633b7121058ab3/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9389552ecf4784886345ead0647e4edc96bee37cbab05b75540f542f766c48c", size = 419815, upload-time = "2026-06-18T16:13:48.205Z" }, - { url = "https://files.pythonhosted.org/packages/2f/e1/aab6c946570496b78e67804721f3d5e2d62a93081b9b37df77764ef56347/msgpack-1.2.1-cp314-cp314t-win32.whl", hash = "sha256:c1c79a604a2969a868a78b6ebd27a887e00c624f14f66b3038e0590cb23332d1", size = 70914, upload-time = "2026-06-18T16:13:49.385Z" }, - { url = "https://files.pythonhosted.org/packages/13/0a/e608956488a2af014cfe6e3d665e090b8ee42aa14b07f8f95b8880d66b09/msgpack-1.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f12038a35fabd52e56a3547bab42401af49a45caa6dd00b34c44de235bc93ee2", size = 77999, upload-time = "2026-06-18T16:13:50.467Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8a/27e2e57055176e366a46b85d02d68e7a5bcfbdd8474c9706375d965f24d3/msgpack-1.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0adcf06ffde0777c0e1a9b771a2b1c4226ba1bbf748c8efcc02fcdeca3299107", size = 71160, upload-time = "2026-06-18T16:13:51.498Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/6b/e9b1cdc042c4458801d2545ed782a95f3d6ba8e270cce8745b8603c7f748/msgpack-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29a3f6e9667868429d8240dfd063ea5ffdc1321c13d783aa23827a38de0dcb22", size = 82812 }, + { url = "https://files.pythonhosted.org/packages/0c/3a/dd518a1bf78ed1e9ad8afe57307c079a00eafe4b3068932a27ca1ea56b4f/msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aded5bdf32609dc7987a49bbbd15a8ef096193f96dd8bbeb791de729e650acf5", size = 82739 }, + { url = "https://files.pythonhosted.org/packages/70/e0/7ba9e1542bf0771a27b8b37c1316e3f95ae9d748fd765284655c476ad4ef/msgpack-1.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:146ee4e9ce80b365c6d4c47073da9da7bcec473e58194ceee5dd7620ace77e06", size = 414233 }, + { url = "https://files.pythonhosted.org/packages/03/8d/671d81534ea0e2b0e8a121be100020da09eb78861fe3aa8f3ef7dcd3bed1/msgpack-1.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a28d076ca7c82b9c8728ad90b7147489449557038bed50e4241eb832395169b4", size = 423843 }, + { url = "https://files.pythonhosted.org/packages/d2/b6/e5c737515ed1f166664b87601b532f58cbb73d8aa6a90b99f7c2c5037e8e/msgpack-1.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d31c0ac0c640f877804c67cb2bc9f4e23dc2db97e96c2e67fa27d38283b41f8", size = 390772 }, + { url = "https://files.pythonhosted.org/packages/a8/46/62ed8c2e87d7021eab19921594d961ef3aa3794eec76c716dc30f3bfd433/msgpack-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ff92d7feeaf5bc26c51495b69e2f99ed97ab79346fb6555f44be7dd2ac6503b", size = 409559 }, + { url = "https://files.pythonhosted.org/packages/70/ff/59aa3887b860bbf43532835e192b1c388a17590d6068ae4f8b2bc74c906e/msgpack-1.2.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:779197a6513bab3c3632265e3d0f7cb3227e62510841a6f34f1eaa37efbb345e", size = 387838 }, + { url = "https://files.pythonhosted.org/packages/09/11/f8563e471093420cf6478cb3271a0175d8402b82d879783d4035d2d03360/msgpack-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67f6dd22fa72a93752643f07889796d62739a13415ee630169a8ce764f86cf9f", size = 421732 }, + { url = "https://files.pythonhosted.org/packages/57/cf/e673683c4c6c90c1022b24c65af4b03eda72b182a1176ef6449069d66acc/msgpack-1.2.1-cp311-cp311-win32.whl", hash = "sha256:91054a783328e0ea7954b8771095705c8d2243b814743fbaadf14552c9c52c5d", size = 64091 }, + { url = "https://files.pythonhosted.org/packages/3f/07/ca212739d179f9083bff2c7c08c24101c3555a334fadc2b876b18768a3ae/msgpack-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2eda0b7ebb1283a98d3e4492ac933c8af6aff59fd3df1c3ed024f536af4b1dc8", size = 70462 }, + { url = "https://files.pythonhosted.org/packages/6d/be/6798347b425e26f35db82e69dd83c09716c856a3714e7bffc4c0860fd830/msgpack-1.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ee967f7c7e1df2890c671ff2ee51a28ded0efc95da3e507176dee881ce36c66", size = 65059 }, + { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531 }, + { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657 }, + { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634 }, + { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989 }, + { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544 }, + { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842 }, + { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108 }, + { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939 }, + { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504 }, + { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421 }, + { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775 }, + { url = "https://files.pythonhosted.org/packages/b0/ac/dcddcab6f6c20ecb387ca5e980371cdb3f87ff69aeca388be97eebc4c074/msgpack-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a70e3cf2804a300d921bb0940426e35f4e489a23adfb77a808892241db0a064", size = 83151 }, + { url = "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:491cc39455ca765fad51fb451bf2915eb2cf41192ab5801ce8d67c1d614fe056", size = 82351 }, + { url = "https://files.pythonhosted.org/packages/e3/10/ddf7b06db879e8792d13934ddda09ff20bd2a583fd84c9b59aae9b0e650b/msgpack-1.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f310233ef7fb9c14e201c93639fe5f5260b005f56f0b29048e999c30935596cc", size = 407518 }, + { url = "https://files.pythonhosted.org/packages/79/d3/36a46a8ed992b781acbc05928bd5bee3c810cb0c3563bf81a7b0c04a1a76/msgpack-1.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:787c9bebb5833e8f6fc8abca3c0597683d8d87f56a8842b6b89c75a5f3176e2d", size = 416405 }, + { url = "https://files.pythonhosted.org/packages/f9/84/e8e9598b557c0ba6ddae901a73780a4c75ac667dddf59414b1e56a42fb34/msgpack-1.2.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc871b997a9370d855b7394465f2f350e847a5b806dd38dcc9c989e7d87da155", size = 376257 }, + { url = "https://files.pythonhosted.org/packages/40/16/738fe6d875ad7e2a9429c165322a4ec088f4f273cdfae63d96a89c467961/msgpack-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85f57e960d877f2977f6430896191b04a21f8901b3b4baf2e4604329f4db5402", size = 397469 }, + { url = "https://files.pythonhosted.org/packages/ca/be/6d5952df75a7f24f35833af764c3a6860780364cb3a0030beb8099e1b2b4/msgpack-1.2.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1233ee2dd0cefba127583de50ea654677277047d238303521db35def3d7b2e7c", size = 372802 }, + { url = "https://files.pythonhosted.org/packages/e1/39/e2ef7dbf0473bcb8dc7c50bf782a892d67414877b63e47fc88eb189ef5e6/msgpack-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e3dc2feb0876209d9c38aa56cb1de169bd6c4348f1aa48271f241226590993e6", size = 411273 }, + { url = "https://files.pythonhosted.org/packages/ef/c5/133f4512a56e983a93445c836c9d94d88f3bc2e0980ff4b9e577bd8416ce/msgpack-1.2.1-cp313-cp313-win32.whl", hash = "sha256:6d09badf350af2be9d189184e04e64cf54ad93569ab3d96fca58bd3e84aad707", size = 64471 }, + { url = "https://files.pythonhosted.org/packages/e2/98/577e10b055096a7dd40732358cabaf7180a20c79ed1dcdbb618e4b9deac7/msgpack-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:33f14fba63278b714efe6ad07e50ea5f03d91537aa6a1c5f1ceca4cf44013ca9", size = 71274 }, + { url = "https://files.pythonhosted.org/packages/ba/ee/0c0048e7cfbef23c6a94791b8959ab28155232e7956de8a305b5ff588f05/msgpack-1.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc5febcd4c99effbc02b528e49d6fd0760b2b7d48c05239e345a5fa6e743d9a", size = 64795 }, + { url = "https://files.pythonhosted.org/packages/77/58/cce442852c6b9e1639c7c8ac8fd9143121cb32dab0f308df4d1426a8eb9c/msgpack-1.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:05f340e47e7e47d2da8db9b53e1bb1d294369e9ef45a747441309f6650b8351d", size = 83610 }, + { url = "https://files.pythonhosted.org/packages/60/5c/15b4c7a0182f75ffa90751958ba36a9c01cafee367d49a3edc10ed140b01/msgpack-1.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:810b916696c86ef0deb3b74588480224df4c1b071136c34183e4a2a4284d7ac7", size = 83138 }, + { url = "https://files.pythonhosted.org/packages/b8/a6/99e58722feaffc5f2fbcc0c8c0d1451ab9f84097f7af87291b46af2390f4/msgpack-1.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca0dacff965c47afdc3749a8469d7302a8f801d6a28758d55120d75e66ce6889", size = 406090 }, + { url = "https://files.pythonhosted.org/packages/19/03/8c63e8cf52958534ef688625965ab04c269a6cadd8caef16758b380a821a/msgpack-1.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e2bf9280bceb5efca998435904b5d3e9fdbcc11d90dc9df30aec7973252b720", size = 412106 }, + { url = "https://files.pythonhosted.org/packages/63/d2/155d9e71b40e41fd934bc0c48b9b2770f22263e1ac20aad8e29fdca7be3f/msgpack-1.2.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6c4be5d1c02a42b066ca6ddb71adf36432868fdcdb6ee87e634e86e0674190", size = 374851 }, + { url = "https://files.pythonhosted.org/packages/98/48/deaf2326262a8d5ea3295ce9649912ecd3f551ba7ec8e33c665d2ba583f3/msgpack-1.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec0e675d59150a6269ddc9139087c722292664a37d071a849c05c473350f1f2d", size = 396168 }, + { url = "https://files.pythonhosted.org/packages/10/2a/b4410f906c2ec0008f1608d3ab5143afc3ad3f4e6da0fed3ea2231d0bef4/msgpack-1.2.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:dd3bfe82d53edfe4b7fc9a7ec9761e23a7a5b1dac22264505af428253c29ed24", size = 371959 }, + { url = "https://files.pythonhosted.org/packages/59/86/1edc67270099a528fa2093ea60fe191233cd238e4bd30cfacf7db79fc959/msgpack-1.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5ad5467fc3f68b5468e06c5f788d712e9f8ffc8b0cd1bcb160c105c1ee92dae7", size = 408457 }, + { url = "https://files.pythonhosted.org/packages/82/90/8b630fef07d8c5ab457b71ff2c217910c83d333c7a68472c186e87cc504a/msgpack-1.2.1-cp314-cp314-win32.whl", hash = "sha256:98b58bdb89c46190e4609bb36abe17c6d4105ad13f9c5f8f6f64d320f8ced3fb", size = 65942 }, + { url = "https://files.pythonhosted.org/packages/16/f1/467b81e98b24dd3885d7b1857728797b4ffc76a7a7483af4fb321a07de3c/msgpack-1.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:74847557e28ce71bd3c438a447ca90e4b507e997ddbdef8a12a7b283b86c156b", size = 72627 }, + { url = "https://files.pythonhosted.org/packages/a7/1d/5d8c4c89985feb6acefb82a09e501c60392261856d2408d20bfe4f0360b1/msgpack-1.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:b50b727bd652bdc37d950336c848ef20ec54a4cafc38dce19b1cd86ad625d0f7", size = 66908 }, + { url = "https://files.pythonhosted.org/packages/1b/02/ad2afb678b4de94496cd432b581759b756a92c1192d8c767edd6b132efdc/msgpack-1.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8d00f177ca88a77c1cf848d204a38f249751650b601cb6532acc68805d8a8273", size = 86000 }, + { url = "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5bb9c386f0a329c035ddbab4b72d1028bf9627add8dda41070288563d57ed1b1", size = 86544 }, + { url = "https://files.pythonhosted.org/packages/a9/b4/b774d7eb95561739907fec675582f83203cf41c597a418c2589b4bfb8e9d/msgpack-1.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20466cca18c49c7292a8984bc15d65857b171e7264bdcb5f96baf8be238791fc", size = 427661 }, + { url = "https://files.pythonhosted.org/packages/b2/f9/3243191dc9937e00756c8bc1b0272fed8f23758e43df2a3b46f533e5090f/msgpack-1.2.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:196300e7e5d6e74d50f1607ab9c06c4a1484c383cd22defd727902591f7e8dde", size = 426375 }, + { url = "https://files.pythonhosted.org/packages/23/c7/1693111db9944ba4ad4b67a1e788400d78a0b6af7a6523dc7e4e58f8274b/msgpack-1.2.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575957e79cd51903a4e8495a242442949641e08f1efd5197b43bebd3ea7682b4", size = 380495 }, + { url = "https://files.pythonhosted.org/packages/3e/2b/92f86956a0c13e8662f7e2ad630c4eb4db07497b967589bd5245e018b2c1/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8c2ed1e48cc0f460bf3c7780e7137ff21a4e18433451916f2442c1b21036cd7d", size = 410897 }, + { url = "https://files.pythonhosted.org/packages/da/ea/1479f72d200313a76fc2f823a79d1e07ed052ab7b8a0280640aa7b95de42/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f6277e5f783c36786a145e0247fc189a03f35f84b251646e53592d2bc12b355", size = 378519 }, + { url = "https://files.pythonhosted.org/packages/f5/4d/fa006060ffa1011d32bfae826fe766fe73e02982183601633b7121058ab3/msgpack-1.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9389552ecf4784886345ead0647e4edc96bee37cbab05b75540f542f766c48c", size = 419815 }, + { url = "https://files.pythonhosted.org/packages/2f/e1/aab6c946570496b78e67804721f3d5e2d62a93081b9b37df77764ef56347/msgpack-1.2.1-cp314-cp314t-win32.whl", hash = "sha256:c1c79a604a2969a868a78b6ebd27a887e00c624f14f66b3038e0590cb23332d1", size = 70914 }, + { url = "https://files.pythonhosted.org/packages/13/0a/e608956488a2af014cfe6e3d665e090b8ee42aa14b07f8f95b8880d66b09/msgpack-1.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f12038a35fabd52e56a3547bab42401af49a45caa6dd00b34c44de235bc93ee2", size = 77999 }, + { url = "https://files.pythonhosted.org/packages/d2/8a/27e2e57055176e366a46b85d02d68e7a5bcfbdd8474c9706375d965f24d3/msgpack-1.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0adcf06ffde0777c0e1a9b771a2b1c4226ba1bbf748c8efcc02fcdeca3299107", size = 71160 }, ] [[package]] @@ -1599,44 +1601,44 @@ dependencies = [ { name = "pathspec" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0b/3d/5b373635b3146264eb7a68d09e5ca11c305bbb058dfffbb47c47daf4f632/mypy-1.20.1.tar.gz", hash = "sha256:6fc3f4ecd52de81648fed1945498bf42fa2993ddfad67c9056df36ae5757f804", size = 3815892, upload-time = "2026-04-13T02:46:51.474Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/0d/555ab7453cc4a4a8643b7f21c842b1a84c36b15392061ae7b052ee119320/mypy-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c01eb9bac2c6a962d00f9d23421cd2913840e65bba365167d057bd0b4171a92e", size = 14336012, upload-time = "2026-04-13T02:45:39.935Z" }, - { url = "https://files.pythonhosted.org/packages/57/26/85a28893f7db8a16ebb41d1e9dfcb4475844d06a88480b6639e32a74d6ef/mypy-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55d12ddbd8a9cac5b276878bd534fa39fff5bf543dc6ae18f25d30c8d7d27fca", size = 13224636, upload-time = "2026-04-13T02:45:49.659Z" }, - { url = "https://files.pythonhosted.org/packages/93/41/bd4cd3c2caeb6c448b669222b8cfcbdee4a03b89431527b56fca9e56b6f3/mypy-1.20.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0aa322c1468b6cdfc927a44ce130f79bb44bcd34eb4a009eb9f96571fd80955", size = 13663471, upload-time = "2026-04-13T02:46:20.276Z" }, - { url = "https://files.pythonhosted.org/packages/3e/56/7ee8c471e10402d64b6517ae10434541baca053cffd81090e4097d5609d4/mypy-1.20.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f8bc95899cf676b6e2285779a08a998cc3a7b26f1026752df9d2741df3c79e8", size = 14532344, upload-time = "2026-04-13T02:46:44.205Z" }, - { url = "https://files.pythonhosted.org/packages/b5/95/b37d1fa859a433f6156742e12f62b0bb75af658544fb6dada9363918743a/mypy-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:47c2b90191a870a04041e910277494b0d92f0711be9e524d45c074fe60c00b65", size = 14776670, upload-time = "2026-04-13T02:45:52.481Z" }, - { url = "https://files.pythonhosted.org/packages/03/77/b302e4cb0b80d2bdf6bf4fce5864bb4cbfa461f7099cea544eaf2457df78/mypy-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:9857dc8d2ec1a392ffbda518075beb00ac58859979c79f9e6bdcb7277082c2f2", size = 10816524, upload-time = "2026-04-13T02:45:37.711Z" }, - { url = "https://files.pythonhosted.org/packages/7f/21/d969d7a68eb964993ebcc6170d5ecaf0cf65830c58ac3344562e16dc42a9/mypy-1.20.1-cp311-cp311-win_arm64.whl", hash = "sha256:09d8df92bb25b6065ab91b178da843dda67b33eb819321679a6e98a907ce0e10", size = 9750419, upload-time = "2026-04-13T02:45:08.542Z" }, - { url = "https://files.pythonhosted.org/packages/69/1b/75a7c825a02781ca10bc2f2f12fba2af5202f6d6005aad8d2d1f264d8d78/mypy-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:36ee2b9c6599c230fea89bbd79f401f9f9f8e9fcf0c777827789b19b7da90f51", size = 14494077, upload-time = "2026-04-13T02:45:55.085Z" }, - { url = "https://files.pythonhosted.org/packages/b0/54/5e5a569ea5c2b4d48b729fb32aa936eeb4246e4fc3e6f5b3d36a2dfbefb9/mypy-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fba3fb0968a7b48806b0c90f38d39296f10766885a94c83bd21399de1e14eb28", size = 13319495, upload-time = "2026-04-13T02:45:29.674Z" }, - { url = "https://files.pythonhosted.org/packages/6f/a4/a1945b19f33e91721b59deee3abb484f2fa5922adc33bb166daf5325d76d/mypy-1.20.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef1415a637cd3627d6304dfbeddbadd21079dafc2a8a753c477ce4fc0c2af54f", size = 13696948, upload-time = "2026-04-13T02:46:15.006Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c6/75e969781c2359b2f9c15b061f28ec6d67c8b61865ceda176e85c8e7f2de/mypy-1.20.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef3461b1ad5cd446e540016e90b5984657edda39f982f4cc45ca317b628f5a37", size = 14706744, upload-time = "2026-04-13T02:46:00.482Z" }, - { url = "https://files.pythonhosted.org/packages/a8/6e/b221b1de981fc4262fe3e0bf9ec272d292dfe42394a689c2d49765c144c4/mypy-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:542dd63c9e1339b6092eb25bd515f3a32a1453aee8c9521d2ddb17dacd840237", size = 14949035, upload-time = "2026-04-13T02:45:06.021Z" }, - { url = "https://files.pythonhosted.org/packages/ca/4b/298ba2de0aafc0da3ff2288da06884aae7ba6489bc247c933f87847c41b3/mypy-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:1d55c7cd8ca22e31f93af2a01160a9e95465b5878de23dba7e48116052f20a8d", size = 10883216, upload-time = "2026-04-13T02:45:47.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/f9/5e25b8f0b8cb92f080bfed9c21d3279b2a0b6a601cdca369a039ba84789d/mypy-1.20.1-cp312-cp312-win_arm64.whl", hash = "sha256:f5b84a79070586e0d353ee07b719d9d0a4aa7c8ee90c0ea97747e98cbe193019", size = 9814299, upload-time = "2026-04-13T02:45:21.934Z" }, - { url = "https://files.pythonhosted.org/packages/21/e8/ef0991aa24c8f225df10b034f3c2681213cb54cf247623c6dec9a5744e70/mypy-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f3886c03e40afefd327bd70b3f634b39ea82e87f314edaa4d0cce4b927ddcc1", size = 14500739, upload-time = "2026-04-13T02:46:05.442Z" }, - { url = "https://files.pythonhosted.org/packages/23/73/416ebec3047636ed89fa871dc8c54bf05e9e20aa9499da59790d7adb312d/mypy-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e860eb3904f9764e83bafd70c8250bdffdc7dde6b82f486e8156348bf7ceb184", size = 13314735, upload-time = "2026-04-13T02:46:47.154Z" }, - { url = "https://files.pythonhosted.org/packages/10/1e/1505022d9c9ac2e014a384eb17638fb37bf8e9d0a833ea60605b66f8f7ba/mypy-1.20.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4b5aac6e785719da51a84f5d09e9e843d473170a9045b1ea7ea1af86225df4b", size = 13704356, upload-time = "2026-04-13T02:45:19.773Z" }, - { url = "https://files.pythonhosted.org/packages/98/91/275b01f5eba5c467a3318ec214dd865abb66e9c811231c8587287b92876a/mypy-1.20.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f37b6cd0fe2ad3a20f05ace48ca3523fc52ff86940e34937b439613b6854472e", size = 14696420, upload-time = "2026-04-13T02:45:24.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/57/b3779e134e1b7250d05f874252780d0a88c068bc054bcff99ca20a3a2986/mypy-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4bbb0f6b54ce7cc350ef4a770650d15fa70edd99ad5267e227133eda9c94218", size = 14936093, upload-time = "2026-04-13T02:45:32.087Z" }, - { url = "https://files.pythonhosted.org/packages/be/33/81b64991b0f3f278c3b55c335888794af190b2d59031a5ad1401bcb69f1e/mypy-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:c3dc20f8ec76eecd77148cdd2f1542ed496e51e185713bf488a414f862deb8f2", size = 10889659, upload-time = "2026-04-13T02:46:02.926Z" }, - { url = "https://files.pythonhosted.org/packages/1b/fd/7adcb8053572edf5ef8f3db59599dfeeee3be9cc4c8c97e2d28f66f42ac5/mypy-1.20.1-cp313-cp313-win_arm64.whl", hash = "sha256:a9d62bbac5d6d46718e2b0330b25e6264463ed832722b8f7d4440ff1be3ca895", size = 9815515, upload-time = "2026-04-13T02:46:32.103Z" }, - { url = "https://files.pythonhosted.org/packages/40/cd/db831e84c81d57d4886d99feee14e372f64bbec6a9cb1a88a19e243f2ef5/mypy-1.20.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:12927b9c0ed794daedcf1dab055b6c613d9d5659ac511e8d936d96f19c087d12", size = 14483064, upload-time = "2026-04-13T02:45:26.901Z" }, - { url = "https://files.pythonhosted.org/packages/d5/82/74e62e7097fa67da328ac8ece8de09133448c04d20ddeaeba251a3000f01/mypy-1.20.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:752507dd481e958b2c08fc966d3806c962af5a9433b5bf8f3bdd7175c20e34fe", size = 13335694, upload-time = "2026-04-13T02:46:12.514Z" }, - { url = "https://files.pythonhosted.org/packages/74/c4/97e9a0abe4f3cdbbf4d079cb87a03b786efeccf5bf2b89fe4f96939ab2e6/mypy-1.20.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c614655b5a065e56274c6cbbe405f7cf7e96c0654db7ba39bc680238837f7b08", size = 13726365, upload-time = "2026-04-13T02:45:17.422Z" }, - { url = "https://files.pythonhosted.org/packages/d7/aa/a19d884a8d28fcd3c065776323029f204dbc774e70ec9c85eba228b680de/mypy-1.20.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c3f6221a76f34d5100c6d35b3ef6b947054123c3f8d6938a4ba00b1308aa572", size = 14693472, upload-time = "2026-04-13T02:46:41.253Z" }, - { url = "https://files.pythonhosted.org/packages/84/44/cc9324bd21cf786592b44bf3b5d224b3923c1230ec9898d508d00241d465/mypy-1.20.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4bdfc06303ac06500af71ea0cdbe995c502b3c9ba32f3f8313523c137a25d1b6", size = 14919266, upload-time = "2026-04-13T02:46:28.37Z" }, - { url = "https://files.pythonhosted.org/packages/6e/dc/779abb25a8c63e8f44bf5a336217fa92790fa17e0c40e0c725d10cb01bbd/mypy-1.20.1-cp314-cp314-win_amd64.whl", hash = "sha256:0131edd7eba289973d1ba1003d1a37c426b85cdef76650cd02da6420898a5eb3", size = 11049713, upload-time = "2026-04-13T02:45:57.673Z" }, - { url = "https://files.pythonhosted.org/packages/28/08/4172be2ad7de9119b5a92ca36abbf641afdc5cb1ef4ae0c3a8182f29674f/mypy-1.20.1-cp314-cp314-win_arm64.whl", hash = "sha256:33f02904feb2c07e1fdf7909026206396c9deeb9e6f34d466b4cfedb0aadbbe4", size = 9999819, upload-time = "2026-04-13T02:46:35.039Z" }, - { url = "https://files.pythonhosted.org/packages/2d/af/af9e46b0c8eabbce9fc04a477564170f47a1c22b308822282a59b7ff315f/mypy-1.20.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:168472149dd8cc505c98cefd21ad77e4257ed6022cd5ed2fe2999bed56977a5a", size = 15547508, upload-time = "2026-04-13T02:46:25.588Z" }, - { url = "https://files.pythonhosted.org/packages/a7/cd/39c9e4ad6ba33e069e5837d772a9e6c304b4a5452a14a975d52b36444650/mypy-1.20.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:eb674600309a8f22790cca883a97c90299f948183ebb210fbef6bcee07cb1986", size = 14399557, upload-time = "2026-04-13T02:46:10.021Z" }, - { url = "https://files.pythonhosted.org/packages/83/c1/3fd71bdc118ffc502bf57559c909927bb7e011f327f7bb8e0488e98a5870/mypy-1.20.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef2b2e4cc464ba9795459f2586923abd58a0055487cbe558cb538ea6e6bc142a", size = 15045789, upload-time = "2026-04-13T02:45:10.81Z" }, - { url = "https://files.pythonhosted.org/packages/8e/73/6f07ff8b57a7d7b3e6e5bf34685d17632382395c8bb53364ec331661f83e/mypy-1.20.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dee461d396dd46b3f0ed5a098dbc9b8860c81c46ad44fa071afcfbc149f167c9", size = 15850795, upload-time = "2026-04-13T02:45:03.349Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e2/f7dffec1c7767078f9e9adf0c786d1fe0ff30964a77eb213c09b8b58cb76/mypy-1.20.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e364926308b3e66f1361f81a566fc1b2f8cd47fc8525e8136d4058a65a4b4f02", size = 16088539, upload-time = "2026-04-13T02:46:17.841Z" }, - { url = "https://files.pythonhosted.org/packages/1a/76/e0dee71035316e75a69d73aec2f03c39c21c967b97e277fd0ef8fd6aec66/mypy-1.20.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a0c17fbd746d38c70cbc42647cfd884f845a9708a4b160a8b4f7e70d41f4d7fa", size = 12575567, upload-time = "2026-04-13T02:45:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/22/a8/7ed43c9d9c3d1468f86605e323a5d97e411a448790a00f07e779f3211a46/mypy-1.20.1-cp314-cp314t-win_arm64.whl", hash = "sha256:db2cb89654626a912efda69c0d5c1d22d948265e2069010d3dde3abf751c7d08", size = 10378823, upload-time = "2026-04-13T02:45:13.35Z" }, - { url = "https://files.pythonhosted.org/packages/d8/28/926bd972388e65a39ee98e188ccf67e81beb3aacfd5d6b310051772d974b/mypy-1.20.1-py3-none-any.whl", hash = "sha256:1aae28507f253fe82d883790d1c0a0d35798a810117c88184097fe8881052f06", size = 2636553, upload-time = "2026-04-13T02:46:30.45Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0b/3d/5b373635b3146264eb7a68d09e5ca11c305bbb058dfffbb47c47daf4f632/mypy-1.20.1.tar.gz", hash = "sha256:6fc3f4ecd52de81648fed1945498bf42fa2993ddfad67c9056df36ae5757f804", size = 3815892 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/0d/555ab7453cc4a4a8643b7f21c842b1a84c36b15392061ae7b052ee119320/mypy-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c01eb9bac2c6a962d00f9d23421cd2913840e65bba365167d057bd0b4171a92e", size = 14336012 }, + { url = "https://files.pythonhosted.org/packages/57/26/85a28893f7db8a16ebb41d1e9dfcb4475844d06a88480b6639e32a74d6ef/mypy-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55d12ddbd8a9cac5b276878bd534fa39fff5bf543dc6ae18f25d30c8d7d27fca", size = 13224636 }, + { url = "https://files.pythonhosted.org/packages/93/41/bd4cd3c2caeb6c448b669222b8cfcbdee4a03b89431527b56fca9e56b6f3/mypy-1.20.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0aa322c1468b6cdfc927a44ce130f79bb44bcd34eb4a009eb9f96571fd80955", size = 13663471 }, + { url = "https://files.pythonhosted.org/packages/3e/56/7ee8c471e10402d64b6517ae10434541baca053cffd81090e4097d5609d4/mypy-1.20.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f8bc95899cf676b6e2285779a08a998cc3a7b26f1026752df9d2741df3c79e8", size = 14532344 }, + { url = "https://files.pythonhosted.org/packages/b5/95/b37d1fa859a433f6156742e12f62b0bb75af658544fb6dada9363918743a/mypy-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:47c2b90191a870a04041e910277494b0d92f0711be9e524d45c074fe60c00b65", size = 14776670 }, + { url = "https://files.pythonhosted.org/packages/03/77/b302e4cb0b80d2bdf6bf4fce5864bb4cbfa461f7099cea544eaf2457df78/mypy-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:9857dc8d2ec1a392ffbda518075beb00ac58859979c79f9e6bdcb7277082c2f2", size = 10816524 }, + { url = "https://files.pythonhosted.org/packages/7f/21/d969d7a68eb964993ebcc6170d5ecaf0cf65830c58ac3344562e16dc42a9/mypy-1.20.1-cp311-cp311-win_arm64.whl", hash = "sha256:09d8df92bb25b6065ab91b178da843dda67b33eb819321679a6e98a907ce0e10", size = 9750419 }, + { url = "https://files.pythonhosted.org/packages/69/1b/75a7c825a02781ca10bc2f2f12fba2af5202f6d6005aad8d2d1f264d8d78/mypy-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:36ee2b9c6599c230fea89bbd79f401f9f9f8e9fcf0c777827789b19b7da90f51", size = 14494077 }, + { url = "https://files.pythonhosted.org/packages/b0/54/5e5a569ea5c2b4d48b729fb32aa936eeb4246e4fc3e6f5b3d36a2dfbefb9/mypy-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fba3fb0968a7b48806b0c90f38d39296f10766885a94c83bd21399de1e14eb28", size = 13319495 }, + { url = "https://files.pythonhosted.org/packages/6f/a4/a1945b19f33e91721b59deee3abb484f2fa5922adc33bb166daf5325d76d/mypy-1.20.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef1415a637cd3627d6304dfbeddbadd21079dafc2a8a753c477ce4fc0c2af54f", size = 13696948 }, + { url = "https://files.pythonhosted.org/packages/b2/c6/75e969781c2359b2f9c15b061f28ec6d67c8b61865ceda176e85c8e7f2de/mypy-1.20.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef3461b1ad5cd446e540016e90b5984657edda39f982f4cc45ca317b628f5a37", size = 14706744 }, + { url = "https://files.pythonhosted.org/packages/a8/6e/b221b1de981fc4262fe3e0bf9ec272d292dfe42394a689c2d49765c144c4/mypy-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:542dd63c9e1339b6092eb25bd515f3a32a1453aee8c9521d2ddb17dacd840237", size = 14949035 }, + { url = "https://files.pythonhosted.org/packages/ca/4b/298ba2de0aafc0da3ff2288da06884aae7ba6489bc247c933f87847c41b3/mypy-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:1d55c7cd8ca22e31f93af2a01160a9e95465b5878de23dba7e48116052f20a8d", size = 10883216 }, + { url = "https://files.pythonhosted.org/packages/c7/f9/5e25b8f0b8cb92f080bfed9c21d3279b2a0b6a601cdca369a039ba84789d/mypy-1.20.1-cp312-cp312-win_arm64.whl", hash = "sha256:f5b84a79070586e0d353ee07b719d9d0a4aa7c8ee90c0ea97747e98cbe193019", size = 9814299 }, + { url = "https://files.pythonhosted.org/packages/21/e8/ef0991aa24c8f225df10b034f3c2681213cb54cf247623c6dec9a5744e70/mypy-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f3886c03e40afefd327bd70b3f634b39ea82e87f314edaa4d0cce4b927ddcc1", size = 14500739 }, + { url = "https://files.pythonhosted.org/packages/23/73/416ebec3047636ed89fa871dc8c54bf05e9e20aa9499da59790d7adb312d/mypy-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e860eb3904f9764e83bafd70c8250bdffdc7dde6b82f486e8156348bf7ceb184", size = 13314735 }, + { url = "https://files.pythonhosted.org/packages/10/1e/1505022d9c9ac2e014a384eb17638fb37bf8e9d0a833ea60605b66f8f7ba/mypy-1.20.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4b5aac6e785719da51a84f5d09e9e843d473170a9045b1ea7ea1af86225df4b", size = 13704356 }, + { url = "https://files.pythonhosted.org/packages/98/91/275b01f5eba5c467a3318ec214dd865abb66e9c811231c8587287b92876a/mypy-1.20.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f37b6cd0fe2ad3a20f05ace48ca3523fc52ff86940e34937b439613b6854472e", size = 14696420 }, + { url = "https://files.pythonhosted.org/packages/a1/57/b3779e134e1b7250d05f874252780d0a88c068bc054bcff99ca20a3a2986/mypy-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4bbb0f6b54ce7cc350ef4a770650d15fa70edd99ad5267e227133eda9c94218", size = 14936093 }, + { url = "https://files.pythonhosted.org/packages/be/33/81b64991b0f3f278c3b55c335888794af190b2d59031a5ad1401bcb69f1e/mypy-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:c3dc20f8ec76eecd77148cdd2f1542ed496e51e185713bf488a414f862deb8f2", size = 10889659 }, + { url = "https://files.pythonhosted.org/packages/1b/fd/7adcb8053572edf5ef8f3db59599dfeeee3be9cc4c8c97e2d28f66f42ac5/mypy-1.20.1-cp313-cp313-win_arm64.whl", hash = "sha256:a9d62bbac5d6d46718e2b0330b25e6264463ed832722b8f7d4440ff1be3ca895", size = 9815515 }, + { url = "https://files.pythonhosted.org/packages/40/cd/db831e84c81d57d4886d99feee14e372f64bbec6a9cb1a88a19e243f2ef5/mypy-1.20.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:12927b9c0ed794daedcf1dab055b6c613d9d5659ac511e8d936d96f19c087d12", size = 14483064 }, + { url = "https://files.pythonhosted.org/packages/d5/82/74e62e7097fa67da328ac8ece8de09133448c04d20ddeaeba251a3000f01/mypy-1.20.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:752507dd481e958b2c08fc966d3806c962af5a9433b5bf8f3bdd7175c20e34fe", size = 13335694 }, + { url = "https://files.pythonhosted.org/packages/74/c4/97e9a0abe4f3cdbbf4d079cb87a03b786efeccf5bf2b89fe4f96939ab2e6/mypy-1.20.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c614655b5a065e56274c6cbbe405f7cf7e96c0654db7ba39bc680238837f7b08", size = 13726365 }, + { url = "https://files.pythonhosted.org/packages/d7/aa/a19d884a8d28fcd3c065776323029f204dbc774e70ec9c85eba228b680de/mypy-1.20.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c3f6221a76f34d5100c6d35b3ef6b947054123c3f8d6938a4ba00b1308aa572", size = 14693472 }, + { url = "https://files.pythonhosted.org/packages/84/44/cc9324bd21cf786592b44bf3b5d224b3923c1230ec9898d508d00241d465/mypy-1.20.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4bdfc06303ac06500af71ea0cdbe995c502b3c9ba32f3f8313523c137a25d1b6", size = 14919266 }, + { url = "https://files.pythonhosted.org/packages/6e/dc/779abb25a8c63e8f44bf5a336217fa92790fa17e0c40e0c725d10cb01bbd/mypy-1.20.1-cp314-cp314-win_amd64.whl", hash = "sha256:0131edd7eba289973d1ba1003d1a37c426b85cdef76650cd02da6420898a5eb3", size = 11049713 }, + { url = "https://files.pythonhosted.org/packages/28/08/4172be2ad7de9119b5a92ca36abbf641afdc5cb1ef4ae0c3a8182f29674f/mypy-1.20.1-cp314-cp314-win_arm64.whl", hash = "sha256:33f02904feb2c07e1fdf7909026206396c9deeb9e6f34d466b4cfedb0aadbbe4", size = 9999819 }, + { url = "https://files.pythonhosted.org/packages/2d/af/af9e46b0c8eabbce9fc04a477564170f47a1c22b308822282a59b7ff315f/mypy-1.20.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:168472149dd8cc505c98cefd21ad77e4257ed6022cd5ed2fe2999bed56977a5a", size = 15547508 }, + { url = "https://files.pythonhosted.org/packages/a7/cd/39c9e4ad6ba33e069e5837d772a9e6c304b4a5452a14a975d52b36444650/mypy-1.20.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:eb674600309a8f22790cca883a97c90299f948183ebb210fbef6bcee07cb1986", size = 14399557 }, + { url = "https://files.pythonhosted.org/packages/83/c1/3fd71bdc118ffc502bf57559c909927bb7e011f327f7bb8e0488e98a5870/mypy-1.20.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef2b2e4cc464ba9795459f2586923abd58a0055487cbe558cb538ea6e6bc142a", size = 15045789 }, + { url = "https://files.pythonhosted.org/packages/8e/73/6f07ff8b57a7d7b3e6e5bf34685d17632382395c8bb53364ec331661f83e/mypy-1.20.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dee461d396dd46b3f0ed5a098dbc9b8860c81c46ad44fa071afcfbc149f167c9", size = 15850795 }, + { url = "https://files.pythonhosted.org/packages/ec/e2/f7dffec1c7767078f9e9adf0c786d1fe0ff30964a77eb213c09b8b58cb76/mypy-1.20.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e364926308b3e66f1361f81a566fc1b2f8cd47fc8525e8136d4058a65a4b4f02", size = 16088539 }, + { url = "https://files.pythonhosted.org/packages/1a/76/e0dee71035316e75a69d73aec2f03c39c21c967b97e277fd0ef8fd6aec66/mypy-1.20.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a0c17fbd746d38c70cbc42647cfd884f845a9708a4b160a8b4f7e70d41f4d7fa", size = 12575567 }, + { url = "https://files.pythonhosted.org/packages/22/a8/7ed43c9d9c3d1468f86605e323a5d97e411a448790a00f07e779f3211a46/mypy-1.20.1-cp314-cp314t-win_arm64.whl", hash = "sha256:db2cb89654626a912efda69c0d5c1d22d948265e2069010d3dde3abf751c7d08", size = 10378823 }, + { url = "https://files.pythonhosted.org/packages/d8/28/926bd972388e65a39ee98e188ccf67e81beb3aacfd5d6b310051772d974b/mypy-1.20.1-py3-none-any.whl", hash = "sha256:1aae28507f253fe82d883790d1c0a0d35798a810117c88184097fe8881052f06", size = 2636553 }, ] [[package]] @@ -1656,18 +1658,18 @@ dependencies = [ { name = "protobuf" }, { name = "types-protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4d/6f/282d64d66bf48ce60e38a6560753f784e0f88ab245ac2fb5e93f701a36cd/mypy-protobuf-3.6.0.tar.gz", hash = "sha256:02f242eb3409f66889f2b1a3aa58356ec4d909cdd0f93115622e9e70366eca3c", size = 24445, upload-time = "2024-04-01T20:24:42.837Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/6f/282d64d66bf48ce60e38a6560753f784e0f88ab245ac2fb5e93f701a36cd/mypy-protobuf-3.6.0.tar.gz", hash = "sha256:02f242eb3409f66889f2b1a3aa58356ec4d909cdd0f93115622e9e70366eca3c", size = 24445 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/73/d6b999782ae22f16971cc05378b3b33f6a89ede3b9619e8366aa23484bca/mypy_protobuf-3.6.0-py3-none-any.whl", hash = "sha256:56176e4d569070e7350ea620262478b49b7efceba4103d468448f1d21492fd6c", size = 16434, upload-time = "2024-04-01T20:24:40.583Z" }, + { url = "https://files.pythonhosted.org/packages/e8/73/d6b999782ae22f16971cc05378b3b33f6a89ede3b9619e8366aa23484bca/mypy_protobuf-3.6.0-py3-none-any.whl", hash = "sha256:56176e4d569070e7350ea620262478b49b7efceba4103d468448f1d21492fd6c", size = 16434 }, ] [[package]] name = "nodeenv" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438 }, ] [[package]] @@ -1697,9 +1699,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b4/1c/125e1c936c0873796771b7f04f6c93b9f1bf5d424cea90fda94a99f61da8/opentelemetry_api-1.42.1.tar.gz", hash = "sha256:56c63bea9f77b62856be8c47600474acad853b2924b99b1687c4cb6297166716", size = 72296, upload-time = "2026-05-21T16:32:49.335Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/1c/125e1c936c0873796771b7f04f6c93b9f1bf5d424cea90fda94a99f61da8/opentelemetry_api-1.42.1.tar.gz", hash = "sha256:56c63bea9f77b62856be8c47600474acad853b2924b99b1687c4cb6297166716", size = 72296 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/ca/9520cc1f3dfbbd03ac5903bbf55833e257bc64b1cf30fa8b0d6df374d821/opentelemetry_api-1.42.1-py3-none-any.whl", hash = "sha256:51a69edacadbc03a8950ace1c4c21099cacc538820ac2c9e36277e78cebba714", size = 61311, upload-time = "2026-05-21T16:32:28.822Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ca/9520cc1f3dfbbd03ac5903bbf55833e257bc64b1cf30fa8b0d6df374d821/opentelemetry_api-1.42.1-py3-none-any.whl", hash = "sha256:51a69edacadbc03a8950ace1c4c21099cacc538820ac2c9e36277e78cebba714", size = 61311 }, ] [[package]] @@ -1716,7 +1718,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "aiodns" }, - { name = "osprey-rpc", editable = "osprey_rpc" }, + { name = "osprey-rpc", virtual = "osprey_rpc" }, { name = "osprey-worker", editable = "osprey_worker" }, { name = "pycares" }, ] @@ -1724,7 +1726,7 @@ requires-dist = [ [[package]] name = "osprey-rpc" version = "0.1.0" -source = { editable = "osprey_rpc" } +source = { virtual = "osprey_rpc" } [[package]] name = "osprey-worker" @@ -1738,34 +1740,34 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "flask-cors", specifier = ">=6.0.1" }, - { name = "osprey-rpc", editable = "osprey_rpc" }, + { name = "osprey-rpc", virtual = "osprey_rpc" }, ] [[package]] name = "packaging" version = "26.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134 } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195 }, ] [[package]] name = "parso" version = "0.8.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824, upload-time = "2026-05-01T23:13:02.138Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/4b/90c937815137d43ce71ba043cd3566221e9df6b9c805f24b5d138c9d40a7/parso-0.8.7.tar.gz", hash = "sha256:eaaac4c9fdd5e9e8852dc778d2d7405897ec510f2a298071453e5e3a07914bb1", size = 401824 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025, upload-time = "2026-05-01T23:12:58.867Z" }, + { url = "https://files.pythonhosted.org/packages/99/5d/8268b644392ee874ee82a635cd0df1773de230bde356c38de28e298392cc/parso-0.8.7-py2.py3-none-any.whl", hash = "sha256:a8926eb2a1b915486941fdbd31e86a4baf88fe8c210f25f2f35ecec5b574ca1c", size = 107025 }, ] [[package]] name = "pathspec" version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328 }, ] [[package]] @@ -1775,51 +1777,51 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, ] [[package]] name = "phone-iso3166" version = "0.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/eb/d3fe2c10189f5b3beabc095e9112177096c807cfb6ce6880f75b08125408/phone-iso3166-0.3.8.tar.gz", hash = "sha256:0a220e13bdf1aee53bd95f235f09e7931d758240223bd4c69b6764af8b4e4cb6", size = 40067, upload-time = "2021-12-01T09:13:23.468Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/eb/d3fe2c10189f5b3beabc095e9112177096c807cfb6ce6880f75b08125408/phone-iso3166-0.3.8.tar.gz", hash = "sha256:0a220e13bdf1aee53bd95f235f09e7931d758240223bd4c69b6764af8b4e4cb6", size = 40067 } [[package]] name = "plac" version = "1.4.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/09/26ef2d614cabdcc52a7f383d0dc7967bf46be3c9700898c594e37b710c3d/plac-1.4.5.tar.gz", hash = "sha256:5f05bf85235c017fcd76c73c8101d4ff8e96beb3dc58b9a37de49cac7de82d14", size = 38988, upload-time = "2025-04-04T14:03:25.651Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/09/26ef2d614cabdcc52a7f383d0dc7967bf46be3c9700898c594e37b710c3d/plac-1.4.5.tar.gz", hash = "sha256:5f05bf85235c017fcd76c73c8101d4ff8e96beb3dc58b9a37de49cac7de82d14", size = 38988 } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/36/38676114a0dbee137ec366daa86603d667a07e9a52667d5ebf5c580100ba/plac-1.4.5-py2.py3-none-any.whl", hash = "sha256:87187786b4e446688b1cf5112e18fed8a23ab3b316c25fe91266a10bd1736b16", size = 22468, upload-time = "2025-04-04T14:03:24.761Z" }, + { url = "https://files.pythonhosted.org/packages/15/36/38676114a0dbee137ec366daa86603d667a07e9a52667d5ebf5c580100ba/plac-1.4.5-py2.py3-none-any.whl", hash = "sha256:87187786b4e446688b1cf5112e18fed8a23ab3b316c25fe91266a10bd1736b16", size = 22468 }, ] [[package]] name = "platformdirs" version = "4.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, + { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743 }, ] [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, ] [[package]] name = "ply" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130, upload-time = "2018-02-15T19:01:31.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", size = 159130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567, upload-time = "2018-02-15T19:01:27.172Z" }, + { url = "https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce", size = 49567 }, ] [[package]] @@ -1833,9 +1835,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525, upload-time = "2026-04-21T20:31:41.613Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525 } wheels = [ - { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" }, + { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472 }, ] [[package]] @@ -1845,9 +1847,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, ] [[package]] @@ -1857,99 +1859,99 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/56/e647b0c675392d2da368da7b6f158f7368b18542fd6f7d7400a2f39de000/proto_plus-1.28.0.tar.gz", hash = "sha256:38e5696342835b08fc116f30a25665b29531cda9d5d5643e9b81fc312385abd9", size = 57221, upload-time = "2026-05-07T08:04:50.811Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/56/e647b0c675392d2da368da7b6f158f7368b18542fd6f7d7400a2f39de000/proto_plus-1.28.0.tar.gz", hash = "sha256:38e5696342835b08fc116f30a25665b29531cda9d5d5643e9b81fc312385abd9", size = 57221 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/20/b122d4626976acb81132036d2ad1bb35a1a8775fceb837ec30964622516a/proto_plus-1.28.0-py3-none-any.whl", hash = "sha256:a630604310899e73c59ec302e5765c058d412b2f090b9c79c8822589f14955b8", size = 50410, upload-time = "2026-05-07T08:03:31.962Z" }, + { url = "https://files.pythonhosted.org/packages/7c/20/b122d4626976acb81132036d2ad1bb35a1a8775fceb837ec30964622516a/proto_plus-1.28.0-py3-none-any.whl", hash = "sha256:a630604310899e73c59ec302e5765c058d412b2f090b9c79c8822589f14955b8", size = 50410 }, ] [[package]] name = "protobuf" version = "4.25.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920, upload-time = "2025-05-28T14:22:25.153Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920 } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745, upload-time = "2025-05-28T14:22:10.524Z" }, - { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736, upload-time = "2025-05-28T14:22:13.156Z" }, - { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537, upload-time = "2025-05-28T14:22:14.768Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005, upload-time = "2025-05-28T14:22:16.052Z" }, - { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924, upload-time = "2025-05-28T14:22:17.105Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757, upload-time = "2025-05-28T14:22:24.135Z" }, + { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745 }, + { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736 }, + { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537 }, + { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005 }, + { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924 }, + { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757 }, ] [[package]] name = "psycogreen" version = "1.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/72/4a7965cf54e341006ad74cdc72cd6572c789bc4f4e3fadc78672f1fbcfbd/psycogreen-1.0.2.tar.gz", hash = "sha256:c429845a8a49cf2f76b71265008760bcd7c7c77d80b806db4dc81116dbcd130d", size = 5411, upload-time = "2020-02-22T19:55:22.02Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/72/4a7965cf54e341006ad74cdc72cd6572c789bc4f4e3fadc78672f1fbcfbd/psycogreen-1.0.2.tar.gz", hash = "sha256:c429845a8a49cf2f76b71265008760bcd7c7c77d80b806db4dc81116dbcd130d", size = 5411 } [[package]] name = "psycopg2-binary" version = "2.9.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2", size = 385764, upload-time = "2024-10-16T11:24:58.126Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/8f/9feb01291d0d7a0a4c6a6bab24094135c2b59c6a81943752f632c75896d6/psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff", size = 3043397, upload-time = "2024-10-16T11:19:40.033Z" }, - { url = "https://files.pythonhosted.org/packages/15/30/346e4683532011561cd9c8dfeac6a8153dd96452fee0b12666058ab7893c/psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c", size = 3274806, upload-time = "2024-10-16T11:19:43.5Z" }, - { url = "https://files.pythonhosted.org/packages/66/6e/4efebe76f76aee7ec99166b6c023ff8abdc4e183f7b70913d7c047701b79/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c", size = 2851370, upload-time = "2024-10-16T11:19:46.986Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fd/ff83313f86b50f7ca089b161b8e0a22bb3c319974096093cd50680433fdb/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb", size = 3080780, upload-time = "2024-10-16T11:19:50.242Z" }, - { url = "https://files.pythonhosted.org/packages/e6/c4/bfadd202dcda8333a7ccafdc51c541dbdfce7c2c7cda89fa2374455d795f/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341", size = 3264583, upload-time = "2024-10-16T11:19:54.424Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f1/09f45ac25e704ac954862581f9f9ae21303cc5ded3d0b775532b407f0e90/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a", size = 3019831, upload-time = "2024-10-16T11:19:57.762Z" }, - { url = "https://files.pythonhosted.org/packages/9e/2e/9beaea078095cc558f215e38f647c7114987d9febfc25cb2beed7c3582a5/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b", size = 2871822, upload-time = "2024-10-16T11:20:04.693Z" }, - { url = "https://files.pythonhosted.org/packages/01/9e/ef93c5d93f3dc9fc92786ffab39e323b9aed066ba59fdc34cf85e2722271/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7", size = 2820975, upload-time = "2024-10-16T11:20:11.401Z" }, - { url = "https://files.pythonhosted.org/packages/a5/f0/049e9631e3268fe4c5a387f6fc27e267ebe199acf1bc1bc9cbde4bd6916c/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e", size = 2919320, upload-time = "2024-10-16T11:20:17.959Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9a/bcb8773b88e45fb5a5ea8339e2104d82c863a3b8558fbb2aadfe66df86b3/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68", size = 2957617, upload-time = "2024-10-16T11:20:24.711Z" }, - { url = "https://files.pythonhosted.org/packages/e2/6b/144336a9bf08a67d217b3af3246abb1d027095dab726f0687f01f43e8c03/psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392", size = 1024618, upload-time = "2024-10-16T11:20:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/61/69/3b3d7bd583c6d3cbe5100802efa5beacaacc86e37b653fc708bf3d6853b8/psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4", size = 1163816, upload-time = "2024-10-16T11:20:30.777Z" }, - { url = "https://files.pythonhosted.org/packages/49/7d/465cc9795cf76f6d329efdafca74693714556ea3891813701ac1fee87545/psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0", size = 3044771, upload-time = "2024-10-16T11:20:35.234Z" }, - { url = "https://files.pythonhosted.org/packages/8b/31/6d225b7b641a1a2148e3ed65e1aa74fc86ba3fee850545e27be9e1de893d/psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a", size = 3275336, upload-time = "2024-10-16T11:20:38.742Z" }, - { url = "https://files.pythonhosted.org/packages/30/b7/a68c2b4bff1cbb1728e3ec864b2d92327c77ad52edcd27922535a8366f68/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539", size = 2851637, upload-time = "2024-10-16T11:20:42.145Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b1/cfedc0e0e6f9ad61f8657fd173b2f831ce261c02a08c0b09c652b127d813/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526", size = 3082097, upload-time = "2024-10-16T11:20:46.185Z" }, - { url = "https://files.pythonhosted.org/packages/18/ed/0a8e4153c9b769f59c02fb5e7914f20f0b2483a19dae7bf2db54b743d0d0/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1", size = 3264776, upload-time = "2024-10-16T11:20:50.879Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/d09da68c6a0cdab41566b74e0a6068a425f077169bed0946559b7348ebe9/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e", size = 3020968, upload-time = "2024-10-16T11:20:56.819Z" }, - { url = "https://files.pythonhosted.org/packages/94/28/4d6f8c255f0dfffb410db2b3f9ac5218d959a66c715c34cac31081e19b95/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f", size = 2872334, upload-time = "2024-10-16T11:21:02.411Z" }, - { url = "https://files.pythonhosted.org/packages/05/f7/20d7bf796593c4fea95e12119d6cc384ff1f6141a24fbb7df5a668d29d29/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00", size = 2822722, upload-time = "2024-10-16T11:21:09.01Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e4/0c407ae919ef626dbdb32835a03b6737013c3cc7240169843965cada2bdf/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5", size = 2920132, upload-time = "2024-10-16T11:21:16.339Z" }, - { url = "https://files.pythonhosted.org/packages/2d/70/aa69c9f69cf09a01da224909ff6ce8b68faeef476f00f7ec377e8f03be70/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47", size = 2959312, upload-time = "2024-10-16T11:21:25.584Z" }, - { url = "https://files.pythonhosted.org/packages/d3/bd/213e59854fafe87ba47814bf413ace0dcee33a89c8c8c814faca6bc7cf3c/psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64", size = 1025191, upload-time = "2024-10-16T11:21:29.912Z" }, - { url = "https://files.pythonhosted.org/packages/92/29/06261ea000e2dc1e22907dbbc483a1093665509ea586b29b8986a0e56733/psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0", size = 1164031, upload-time = "2024-10-16T11:21:34.211Z" }, - { url = "https://files.pythonhosted.org/packages/3e/30/d41d3ba765609c0763505d565c4d12d8f3c79793f0d0f044ff5a28bf395b/psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d", size = 3044699, upload-time = "2024-10-16T11:21:42.841Z" }, - { url = "https://files.pythonhosted.org/packages/35/44/257ddadec7ef04536ba71af6bc6a75ec05c5343004a7ec93006bee66c0bc/psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb", size = 3275245, upload-time = "2024-10-16T11:21:51.989Z" }, - { url = "https://files.pythonhosted.org/packages/1b/11/48ea1cd11de67f9efd7262085588790a95d9dfcd9b8a687d46caf7305c1a/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7", size = 2851631, upload-time = "2024-10-16T11:21:57.584Z" }, - { url = "https://files.pythonhosted.org/packages/62/e0/62ce5ee650e6c86719d621a761fe4bc846ab9eff8c1f12b1ed5741bf1c9b/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d", size = 3082140, upload-time = "2024-10-16T11:22:02.005Z" }, - { url = "https://files.pythonhosted.org/packages/27/ce/63f946c098611f7be234c0dd7cb1ad68b0b5744d34f68062bb3c5aa510c8/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73", size = 3264762, upload-time = "2024-10-16T11:22:06.412Z" }, - { url = "https://files.pythonhosted.org/packages/43/25/c603cd81402e69edf7daa59b1602bd41eb9859e2824b8c0855d748366ac9/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673", size = 3020967, upload-time = "2024-10-16T11:22:11.583Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d6/8708d8c6fca531057fa170cdde8df870e8b6a9b136e82b361c65e42b841e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f", size = 2872326, upload-time = "2024-10-16T11:22:16.406Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712, upload-time = "2024-10-16T11:22:21.366Z" }, - { url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155, upload-time = "2024-10-16T11:22:25.684Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356, upload-time = "2024-10-16T11:22:30.562Z" }, - { url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224, upload-time = "2025-01-04T20:09:19.234Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2", size = 385764 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/8f/9feb01291d0d7a0a4c6a6bab24094135c2b59c6a81943752f632c75896d6/psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff", size = 3043397 }, + { url = "https://files.pythonhosted.org/packages/15/30/346e4683532011561cd9c8dfeac6a8153dd96452fee0b12666058ab7893c/psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c", size = 3274806 }, + { url = "https://files.pythonhosted.org/packages/66/6e/4efebe76f76aee7ec99166b6c023ff8abdc4e183f7b70913d7c047701b79/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c", size = 2851370 }, + { url = "https://files.pythonhosted.org/packages/7f/fd/ff83313f86b50f7ca089b161b8e0a22bb3c319974096093cd50680433fdb/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb", size = 3080780 }, + { url = "https://files.pythonhosted.org/packages/e6/c4/bfadd202dcda8333a7ccafdc51c541dbdfce7c2c7cda89fa2374455d795f/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341", size = 3264583 }, + { url = "https://files.pythonhosted.org/packages/5d/f1/09f45ac25e704ac954862581f9f9ae21303cc5ded3d0b775532b407f0e90/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a", size = 3019831 }, + { url = "https://files.pythonhosted.org/packages/9e/2e/9beaea078095cc558f215e38f647c7114987d9febfc25cb2beed7c3582a5/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b", size = 2871822 }, + { url = "https://files.pythonhosted.org/packages/01/9e/ef93c5d93f3dc9fc92786ffab39e323b9aed066ba59fdc34cf85e2722271/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7", size = 2820975 }, + { url = "https://files.pythonhosted.org/packages/a5/f0/049e9631e3268fe4c5a387f6fc27e267ebe199acf1bc1bc9cbde4bd6916c/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e", size = 2919320 }, + { url = "https://files.pythonhosted.org/packages/dc/9a/bcb8773b88e45fb5a5ea8339e2104d82c863a3b8558fbb2aadfe66df86b3/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68", size = 2957617 }, + { url = "https://files.pythonhosted.org/packages/e2/6b/144336a9bf08a67d217b3af3246abb1d027095dab726f0687f01f43e8c03/psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392", size = 1024618 }, + { url = "https://files.pythonhosted.org/packages/61/69/3b3d7bd583c6d3cbe5100802efa5beacaacc86e37b653fc708bf3d6853b8/psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4", size = 1163816 }, + { url = "https://files.pythonhosted.org/packages/49/7d/465cc9795cf76f6d329efdafca74693714556ea3891813701ac1fee87545/psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0", size = 3044771 }, + { url = "https://files.pythonhosted.org/packages/8b/31/6d225b7b641a1a2148e3ed65e1aa74fc86ba3fee850545e27be9e1de893d/psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a", size = 3275336 }, + { url = "https://files.pythonhosted.org/packages/30/b7/a68c2b4bff1cbb1728e3ec864b2d92327c77ad52edcd27922535a8366f68/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539", size = 2851637 }, + { url = "https://files.pythonhosted.org/packages/0b/b1/cfedc0e0e6f9ad61f8657fd173b2f831ce261c02a08c0b09c652b127d813/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526", size = 3082097 }, + { url = "https://files.pythonhosted.org/packages/18/ed/0a8e4153c9b769f59c02fb5e7914f20f0b2483a19dae7bf2db54b743d0d0/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1", size = 3264776 }, + { url = "https://files.pythonhosted.org/packages/10/db/d09da68c6a0cdab41566b74e0a6068a425f077169bed0946559b7348ebe9/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e", size = 3020968 }, + { url = "https://files.pythonhosted.org/packages/94/28/4d6f8c255f0dfffb410db2b3f9ac5218d959a66c715c34cac31081e19b95/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f", size = 2872334 }, + { url = "https://files.pythonhosted.org/packages/05/f7/20d7bf796593c4fea95e12119d6cc384ff1f6141a24fbb7df5a668d29d29/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00", size = 2822722 }, + { url = "https://files.pythonhosted.org/packages/4d/e4/0c407ae919ef626dbdb32835a03b6737013c3cc7240169843965cada2bdf/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5", size = 2920132 }, + { url = "https://files.pythonhosted.org/packages/2d/70/aa69c9f69cf09a01da224909ff6ce8b68faeef476f00f7ec377e8f03be70/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47", size = 2959312 }, + { url = "https://files.pythonhosted.org/packages/d3/bd/213e59854fafe87ba47814bf413ace0dcee33a89c8c8c814faca6bc7cf3c/psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64", size = 1025191 }, + { url = "https://files.pythonhosted.org/packages/92/29/06261ea000e2dc1e22907dbbc483a1093665509ea586b29b8986a0e56733/psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0", size = 1164031 }, + { url = "https://files.pythonhosted.org/packages/3e/30/d41d3ba765609c0763505d565c4d12d8f3c79793f0d0f044ff5a28bf395b/psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d", size = 3044699 }, + { url = "https://files.pythonhosted.org/packages/35/44/257ddadec7ef04536ba71af6bc6a75ec05c5343004a7ec93006bee66c0bc/psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb", size = 3275245 }, + { url = "https://files.pythonhosted.org/packages/1b/11/48ea1cd11de67f9efd7262085588790a95d9dfcd9b8a687d46caf7305c1a/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7", size = 2851631 }, + { url = "https://files.pythonhosted.org/packages/62/e0/62ce5ee650e6c86719d621a761fe4bc846ab9eff8c1f12b1ed5741bf1c9b/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d", size = 3082140 }, + { url = "https://files.pythonhosted.org/packages/27/ce/63f946c098611f7be234c0dd7cb1ad68b0b5744d34f68062bb3c5aa510c8/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73", size = 3264762 }, + { url = "https://files.pythonhosted.org/packages/43/25/c603cd81402e69edf7daa59b1602bd41eb9859e2824b8c0855d748366ac9/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673", size = 3020967 }, + { url = "https://files.pythonhosted.org/packages/5f/d6/8708d8c6fca531057fa170cdde8df870e8b6a9b136e82b361c65e42b841e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f", size = 2872326 }, + { url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712 }, + { url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155 }, + { url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356 }, + { url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224 }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, ] [[package]] name = "pyasn1" version = "0.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997 }, ] [[package]] @@ -1959,9 +1961,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892 } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259 }, ] [[package]] @@ -1971,95 +1973,95 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/a0/9c823651872e6a0face3f0311de2a40c8bbcb9c8dcb15680bd019ac56ac7/pycares-5.0.1.tar.gz", hash = "sha256:5a3c249c830432631439815f9a818463416f2a8cbdb1e988e78757de9ae75081", size = 652222, upload-time = "2026-01-01T12:37:00.604Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/78/43b09f4b8e5fb8a6024661b458b48987abdb39304c78117b106b10a029f1/pycares-5.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c29ca77ff9712e20787201ca8e76ad89384771c0e058a0a4f3dc05afbc4b32de", size = 136177, upload-time = "2026-01-01T12:35:11.567Z" }, - { url = "https://files.pythonhosted.org/packages/19/05/194c0e039ff52b166b50e79ff166c61f931fbca2bf94fc0dbaaf39041518/pycares-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f11424bf5cf6226d0b136ed47daa58434e377c61b62d0100d1de7793f8e34a72", size = 130960, upload-time = "2026-01-01T12:35:12.828Z" }, - { url = "https://files.pythonhosted.org/packages/0d/84/5fce65cc058c5ab619c0dd1370d539667235a5565da72ca77f3f741cdc70/pycares-5.0.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d765afb52d579879f5c4f005763827d3b1eb86b23139e9614e6089c9f98db017", size = 220584, upload-time = "2026-01-01T12:35:14.005Z" }, - { url = "https://files.pythonhosted.org/packages/f6/74/d82304297308f6c24a17961bf589b53eefa5f7f2724158c842c67fa0b302/pycares-5.0.1-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ea0d57ba5add4bfbcc40cbdfa92bbb8a5ef0c4c21881e26c7229d9bdc92a4533", size = 252166, upload-time = "2026-01-01T12:35:15.293Z" }, - { url = "https://files.pythonhosted.org/packages/39/a2/0ead3ba4228a490b52eb44d43514dae172c90421bb30a3659516e5b251a2/pycares-5.0.1-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9ec2aa3553d33e6220aeb1a05f4853fb83fce4cec3e0dea2dc970338ea47dc", size = 239085, upload-time = "2026-01-01T12:35:16.594Z" }, - { url = "https://files.pythonhosted.org/packages/26/ad/e59f173933f0e696a6afbbd63935114d1400524a72da4f2cbafc6002a398/pycares-5.0.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5c63fb2498b05e9f5670a1bf3b900c5d09343b3b6d5001a9714d593f9eb54de1", size = 222936, upload-time = "2026-01-01T12:35:17.521Z" }, - { url = "https://files.pythonhosted.org/packages/98/fa/d85bfe663a9c292efd8e699779027612c0c65ff50dc4cc9eb7a143613460/pycares-5.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:71316f7a87c15a8d32127ff01374dc2c969c37410693cc0cf6532590b7f18e7a", size = 223506, upload-time = "2026-01-01T12:35:18.535Z" }, - { url = "https://files.pythonhosted.org/packages/2a/6b/4c225a5b10a4c9f88891a20bfe363eca1b1ce7d5244b396e5683c6070998/pycares-5.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a2117dffbb78615bfdb41ad77b17038689e4e01c66f153649e80d268c6228b4f", size = 251633, upload-time = "2026-01-01T12:35:19.819Z" }, - { url = "https://files.pythonhosted.org/packages/26/ce/ba2349413b5197b72ec19c46e07f6be3a324f80a7b1579c7cbb1b82d6dc2/pycares-5.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7d7c4f5d8b88b586ef2288142b806250020e6490b9f2bd8fd5f634a78fd20fcf", size = 237703, upload-time = "2026-01-01T12:35:20.827Z" }, - { url = "https://files.pythonhosted.org/packages/84/2f/1fd794e6fca10d9e20569113d10a4f92cc2b4242d3eb45524419a37cca6b/pycares-5.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:433b9a4b5a7e10ef8aef0b957e6cd0bfc1bb5bc730d2729f04e93c91c25979c0", size = 222622, upload-time = "2026-01-01T12:35:22.518Z" }, - { url = "https://files.pythonhosted.org/packages/c9/07/7db7977649b210092a7e02d550fcebdfa69bc995c684a3b960c88a5dc4ce/pycares-5.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:cf2699883b88713670d3f9c0a1e44ac24c70aeace9f8c6aa7f0b9f222d5b08a5", size = 117438, upload-time = "2026-01-01T12:35:23.402Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ca/f322ddaa8b3414667de8faeea944ce9d3ddfaf1455839f499a21fcea4cec/pycares-5.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:9528dc11749e5e098c996475b60f879e1db5a6cb3dd0cdc747530620bb1a8941", size = 108920, upload-time = "2026-01-01T12:35:24.599Z" }, - { url = "https://files.pythonhosted.org/packages/75/67/e84ba11d3fec3bf1322c3b302c4df13c85e0a1bc48f16d65cd0f59ad9853/pycares-5.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ee551be4f3f3ac814ac8547586c464c9035e914f5122a534d25de147fa745e1", size = 136241, upload-time = "2026-01-01T12:35:25.439Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ae/50fbb3b4e52b9f1d16a36ffabd051ef8b2106b3f0a0d1c1113904d187a9d/pycares-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:252d4e5a52a68f825eaa90e16b595f9baee22c760f51e286ab612c6829b96de3", size = 131069, upload-time = "2026-01-01T12:35:26.293Z" }, - { url = "https://files.pythonhosted.org/packages/0e/ea/f431599f1ac42149ea4768e516db7cdae3a503a6646319ae63ab66da1486/pycares-5.0.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c1aa549b8c2f2e224215c793d660270778dcba9abc3b85abbc7c41eabe4f1e5", size = 221120, upload-time = "2026-01-01T12:35:27.143Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4f/0a7a6c8b3a64ee5149e935c167cd8ba5d1fdd766ec03e273dbc7502f7bea/pycares-5.0.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:db7c9c9f16e8311998667a7488e817f8cbeedec2447bac827c71804663f1437e", size = 252228, upload-time = "2026-01-01T12:35:28.443Z" }, - { url = "https://files.pythonhosted.org/packages/49/3d/7f9fd20e97ee30c4b959f87ab26e47ddcef666e5e7717e45f2245fe9d70a/pycares-5.0.1-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b9c4c8bb69bab863f677fa166653bb872bfa5d5a742f1f30bebc2d53b6e71db", size = 239473, upload-time = "2026-01-01T12:35:29.794Z" }, - { url = "https://files.pythonhosted.org/packages/a4/d0/c67967a10abd89529cb9aded9d73f43e5de00cf21243638ef529f6757262/pycares-5.0.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09ef90da8da3026fcba4ed223bd71e8057608d5b3fec4f5990b52ae1e8c855cc", size = 223831, upload-time = "2026-01-01T12:35:30.781Z" }, - { url = "https://files.pythonhosted.org/packages/4f/9a/94aacaf22a20b7d342c8f18bf006be57967beef6319adc668d4d86b627be/pycares-5.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ce193ebd54f4c74538b751ebb0923a9208c234ff180589d4d3cec134c001840e", size = 223963, upload-time = "2026-01-01T12:35:31.691Z" }, - { url = "https://files.pythonhosted.org/packages/e6/e1/3666aab6fc5e7d0c669b981fe0407e6a4b67e4e6a37ac429d440274663d5/pycares-5.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:36b9ff18ef231277f99a846feade50b417187a96f742689a9d08b9594e386de4", size = 251813, upload-time = "2026-01-01T12:35:32.918Z" }, - { url = "https://files.pythonhosted.org/packages/94/44/ddab5fbc16ad0084a827167ae8628f54c7a55ce6b743585e6f47a5dd527e/pycares-5.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5e40ea4a0ef0c01a02ef7f7390a58c62d237d5ad48d36bc3245e9c2ac181cc22", size = 238181, upload-time = "2026-01-01T12:35:34.078Z" }, - { url = "https://files.pythonhosted.org/packages/66/27/05467933e0e5c4e712302a2d7499797bc3029bf4d0d8ffbfe737254482b7/pycares-5.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3f323b0ddfd2c7896af6fba4f8851d34d3d13387566aa573d93330fb01cb1038", size = 223552, upload-time = "2026-01-01T12:35:35.076Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e2/14f3837e943d46ee12441fe6aaa418fdb2f698d42e179f368eaa9829744b/pycares-5.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bdc6bcafb72a97b3cdd529fc87210e59e67feb647a7e138110656023599b84da", size = 117478, upload-time = "2026-01-01T12:35:36.133Z" }, - { url = "https://files.pythonhosted.org/packages/d3/c3/3284061f18188d5085338e1f1fd4f03d9c135657acf16f8020b9dd3be5fc/pycares-5.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:f8ef4c70c1edaf022875a8f9ff6c0c064f82831225acc91aa1b4f4d389e2e03a", size = 108889, upload-time = "2026-01-01T12:35:37.135Z" }, - { url = "https://files.pythonhosted.org/packages/92/0a/6bd9bdc2d0ee23ff3aabab7747212e2c5323a081b9b745624d62df88f7e9/pycares-5.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d1b2c6b152c65f14d0e12d741fabb78a487f0f0d22773eede8d8cfc97af612b", size = 136242, upload-time = "2026-01-01T12:35:38.372Z" }, - { url = "https://files.pythonhosted.org/packages/18/2a/2e9f888fc076cfe7a3493a3c4113e787cc4b4533f531dfb562ac9b04898f/pycares-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8c8ffcc9a48cfc296fe1aefc07d2c8e29a7f97e4bb366ce17effea6a38825f70", size = 131070, upload-time = "2026-01-01T12:35:39.262Z" }, - { url = "https://files.pythonhosted.org/packages/ec/5b/83b5aaf7b6ed102f63cd768a747b6cb5d4624f2eaecd84868d103b9dbf39/pycares-5.0.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8efc38c2703e3530b823a4165a7b28d7ce0fdcf41960fb7a4ca834a0f8cfe79", size = 221137, upload-time = "2026-01-01T12:35:40.155Z" }, - { url = "https://files.pythonhosted.org/packages/33/d3/d77ab0b33fb805d02896c385176c462e3386d94457a5e508245c39f41829/pycares-5.0.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e380bf6eff42c260f829a0a14547e13375e949053a966c23ca204a13647ef265", size = 252252, upload-time = "2026-01-01T12:35:41.287Z" }, - { url = "https://files.pythonhosted.org/packages/14/32/8afbc798bce26dfcc5bc1f6bf1560d31cdd0af837ff52cbede657bf9262e/pycares-5.0.1-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:35dd5858ee1246bd092a212b5e85a8ef70853f7cfaf16b99569bf4af3ae4695d", size = 239447, upload-time = "2026-01-01T12:35:42.614Z" }, - { url = "https://files.pythonhosted.org/packages/61/1b/a056393fda383b2eda5dab20bd0dd034fd631bf5ae754aabb20da815bdfe/pycares-5.0.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c257c6e7bf310cdb5823aa9d9a28f1e370fed8c653a968d38a954a8f8e0375ce", size = 223822, upload-time = "2026-01-01T12:35:43.594Z" }, - { url = "https://files.pythonhosted.org/packages/ca/c7/9817f0fb954ab9926f88403f2b91a3e4984a277e2b7a4563e0118e4e1ffa/pycares-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07711acb0ef75758f081fb7436acaccc91e8afd5ae34fd35d4edc44297e81f27", size = 223986, upload-time = "2026-01-01T12:35:44.893Z" }, - { url = "https://files.pythonhosted.org/packages/e1/a9/c0ea15c871c77e8c20bcaab18f56ae83988ea4c302155d106cc6a1bd83a9/pycares-5.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:30e5db1ae85cffb031dd8bc1b37903cd74c6d37eb737643bbca3ff2cd4bc6ae2", size = 251838, upload-time = "2026-01-01T12:35:46.271Z" }, - { url = "https://files.pythonhosted.org/packages/be/a4/fe4068abfadf3e06cc22333e87e4730de3c170075572041d5545926062a3/pycares-5.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:efbe7f89425a14edbc94787042309be77cb3674415eb6079b356e1f9552ba747", size = 238238, upload-time = "2026-01-01T12:35:47.196Z" }, - { url = "https://files.pythonhosted.org/packages/a7/25/4f140518768d974af4221cfd574a30d99d40b3d5c54c479da2c1553be59e/pycares-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5de9e7ce52d638d78723c24704eb032e60b96fbb6fe90c6b3110882987251377", size = 223574, upload-time = "2026-01-01T12:35:48.191Z" }, - { url = "https://files.pythonhosted.org/packages/1e/0a/6e4afa4a2baffd1eba6c18a90cda17681d4838d3cab5a485e471386e04dc/pycares-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:0e99af0a1ce015ab6cc6bd85ce158d95ed89fb3b654515f1d0989d1afcf11026", size = 117472, upload-time = "2026-01-01T12:35:50.674Z" }, - { url = "https://files.pythonhosted.org/packages/57/d0/a99f97e9aa8c8404fc899540cf30be63cda0df5150e3c0837423917c7e4c/pycares-5.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:2a511c9f3b11b7ce9f159c956ea1b8f2de7f419d7ca9fa24528d582cb015dbf9", size = 108889, upload-time = "2026-01-01T12:35:51.902Z" }, - { url = "https://files.pythonhosted.org/packages/38/b2/4af99ff17acb81377c971831520540d1859bf401dc85712eb4abc2e6751f/pycares-5.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e330e3561be259ad7a1b7b0ce282c872938625f76587fae7ac8d6bc5af1d0c3d", size = 136635, upload-time = "2026-01-01T12:35:53.365Z" }, - { url = "https://files.pythonhosted.org/packages/42/da/e2e1683811c427492ee0e86e8fae8d55eb5cca032220438599991fdad866/pycares-5.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82bd37fec2a3fa62add30d4a3854720f7b051386e2f18e6e8f4ee94b89b5a7b0", size = 131093, upload-time = "2026-01-01T12:35:54.28Z" }, - { url = "https://files.pythonhosted.org/packages/cd/2a/9cf2120cafc19e5c589d5252a9ddd3108cc87e9db09938d16317807de03b/pycares-5.0.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:258c38aaa82ad1d565b4591cdb93d2c191be8e0a2c70926999c8e0b717a01f2a", size = 221096, upload-time = "2026-01-01T12:35:57.096Z" }, - { url = "https://files.pythonhosted.org/packages/2c/cc/c5fbf6377e2d6b1f1618f147ad898e5d8ae1585fc726d6301f07aeda6cac/pycares-5.0.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ccc1b2df8a09ca20eefbe20b9f7a484d376525c0fb173cfadd692320013c6bc5", size = 252330, upload-time = "2026-01-01T12:35:58.182Z" }, - { url = "https://files.pythonhosted.org/packages/3b/df/17a7c518c45bb994f76d9064d2519674e2a3950f895abbe6af123ead04ac/pycares-5.0.1-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3c4dfc80cc8b43dc79e02a15486c58eead5cae0a40906d6be64e2522285b5b39", size = 239799, upload-time = "2026-01-01T12:36:00.378Z" }, - { url = "https://files.pythonhosted.org/packages/3f/6c/d79c94809742b56b9180a9a9ec2937607db0b8eb34b8ca75d86d3114d6dd/pycares-5.0.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f498a6606247bfe896c2a4d837db711eb7b0ba23e409e16e4b23def4bada4b9d", size = 223501, upload-time = "2026-01-01T12:36:02.695Z" }, - { url = "https://files.pythonhosted.org/packages/69/08/83084b67cbce08f44fd803b88816fc80d2fe2fb3d483d5432925df44371b/pycares-5.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a7d197835cdb4b202a3b12562b32799e27bb132262d4aa1ac3ee9d440e8ec22c", size = 223708, upload-time = "2026-01-01T12:36:04.357Z" }, - { url = "https://files.pythonhosted.org/packages/15/57/63a6e9ef356c5149b8ec72a694e02207fd8ae643895aeb78a9f0c07f1502/pycares-5.0.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f78ab823732b050d658eb735d553726663c9bccdeeee0653247533a23eb2e255", size = 251816, upload-time = "2026-01-01T12:36:05.618Z" }, - { url = "https://files.pythonhosted.org/packages/43/1c/1c85c6355cf7bc3ae86a1024d60f9cabdc12af63306a5f59370ac8718a41/pycares-5.0.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f444ab7f318e9b2c209b45496fb07bff5e7ada606e15d5253a162964aa078527", size = 238259, upload-time = "2026-01-01T12:36:07.609Z" }, - { url = "https://files.pythonhosted.org/packages/5d/7f/bd5ff5a460e50433f993560e4e5d229559a8bf271dbdf6be832faf1973b5/pycares-5.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9de80997de7538619b7dd28ec4371e5172e3f9480e4fc648726d3d5ba661ca05", size = 223732, upload-time = "2026-01-01T12:36:09.893Z" }, - { url = "https://files.pythonhosted.org/packages/b5/fe/e77738366e00dc0918bbeb0c8fc63579e5d9cec748a2b838e207e548b5d9/pycares-5.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:206ce9f3cb9d51f5065c81b23c22996230fbc2cf58ae22834c623631b2b473aa", size = 120847, upload-time = "2026-01-01T12:36:11.494Z" }, - { url = "https://files.pythonhosted.org/packages/81/17/758e9af7ee8589ac6deddf7ea56d75b982f155bc2052ef61c45d5f371389/pycares-5.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:45fb3b07231120e8cb5b75be7f15f16115003e9251991dc37a3e5c63733d63b5", size = 112595, upload-time = "2026-01-01T12:36:12.973Z" }, - { url = "https://files.pythonhosted.org/packages/56/12/4f1d418fed957fc96089c69d9ec82314b3b91c48c7f9463385842acad9c4/pycares-5.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:602f3eac4b880a2527d21f52b2319cb10fde9225d103d338c4d0b2b07f136849", size = 137061, upload-time = "2026-01-01T12:36:15.027Z" }, - { url = "https://files.pythonhosted.org/packages/29/8c/559cea98a8a5d0f38b50b4b812a07fdbcdb1a961bed9e2e9d5d343e53c6f/pycares-5.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1c3736deef003f0c57bc4e7f94d54270d0824350a8f5ceaba3a20b2ce8fb427", size = 131551, upload-time = "2026-01-01T12:36:16.74Z" }, - { url = "https://files.pythonhosted.org/packages/34/cd/aee5d8070888d7be509d4f32a348e2821309ec67980498e5a974cd9e4990/pycares-5.0.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e63328df86d37150ce697fb5d9313d1d468dd4dddee1d09342cb2ed241ce6ad9", size = 230409, upload-time = "2026-01-01T12:36:18.909Z" }, - { url = "https://files.pythonhosted.org/packages/5e/94/15d5cf7d8e7af4b4ce3e19ea117dfe565c08d60d82f043ad23843703a135/pycares-5.0.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57f6fd696213329d9a69b9664a68b1ff2a71ccbdc1fc928a42c9a92858c1ec5d", size = 261297, upload-time = "2026-01-01T12:36:20.771Z" }, - { url = "https://files.pythonhosted.org/packages/af/46/24f6ddc7a37ec6eaa1c38f617f39624211d8e7cdca49b644bfc5f467f275/pycares-5.0.1-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d0878edabfbecb48a29e8769284003d8dbc05936122fe361849cd5fa52722e0", size = 248071, upload-time = "2026-01-01T12:36:22.925Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f0/7eb7fe44f0db55b9083725ab7a084874c2dc02806d9613e07e719838c2ab/pycares-5.0.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50e21f27a91be122e066ddd78c2d0d2769e547561481d8342a9d652a345b89f7", size = 232073, upload-time = "2026-01-01T12:36:25.773Z" }, - { url = "https://files.pythonhosted.org/packages/1d/cd/993b17e0c049a56b5af4df3fd053acc57b37e17e0dcd709b2d337c22d57d/pycares-5.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:97ceda969f5a5d5c6b15558b658c29e4301b3a2c4615523797b5f9d4ac74772e", size = 232815, upload-time = "2026-01-01T12:36:27.798Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ff/170177bcc5dff31e735f209f5de63362f513ac18846c83d50e4e68f57866/pycares-5.0.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4d1713e602ab09882c3e65499b2cc763bff0371117327cad704cf524268c2604", size = 261111, upload-time = "2026-01-01T12:36:29.94Z" }, - { url = "https://files.pythonhosted.org/packages/4d/4a/4c6497b8ca9279b4038ee8c7e2c49504008d594d06a044e00678b30c10fe/pycares-5.0.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:954a379055d6c66b2e878b52235b382168d1a3230793ff44454019394aecac5e", size = 246311, upload-time = "2026-01-01T12:36:31.352Z" }, - { url = "https://files.pythonhosted.org/packages/06/19/1603f51f0d73bf34017a9e6967540c2bc138f9541aa7cc1ef38990b3ce9d/pycares-5.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:145d8a20f7fd1d58a2e49b7ef4309ec9bdcab479ac65c2e49480e20d3f890c23", size = 232027, upload-time = "2026-01-01T12:36:34.374Z" }, - { url = "https://files.pythonhosted.org/packages/7a/de/c000a682757b84688722ac232a24a86b6f195f1f4732432ecf35d0a768a5/pycares-5.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ebc9daba03c7ff3f62616c84c6cb37517445d15df00e1754852d6006039eb4a4", size = 121267, upload-time = "2026-01-01T12:36:35.741Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c4/8bfffecd08b9b198113fcff5f0ab84bbe696f07dec46dd1ccae0e7b28c23/pycares-5.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:e0a86eff6bf9e91d5dd8876b1b82ee45704f46b1104c24291d3dea2c1fc8ebcb", size = 113043, upload-time = "2026-01-01T12:36:37.895Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/df/a0/9c823651872e6a0face3f0311de2a40c8bbcb9c8dcb15680bd019ac56ac7/pycares-5.0.1.tar.gz", hash = "sha256:5a3c249c830432631439815f9a818463416f2a8cbdb1e988e78757de9ae75081", size = 652222 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/78/43b09f4b8e5fb8a6024661b458b48987abdb39304c78117b106b10a029f1/pycares-5.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c29ca77ff9712e20787201ca8e76ad89384771c0e058a0a4f3dc05afbc4b32de", size = 136177 }, + { url = "https://files.pythonhosted.org/packages/19/05/194c0e039ff52b166b50e79ff166c61f931fbca2bf94fc0dbaaf39041518/pycares-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f11424bf5cf6226d0b136ed47daa58434e377c61b62d0100d1de7793f8e34a72", size = 130960 }, + { url = "https://files.pythonhosted.org/packages/0d/84/5fce65cc058c5ab619c0dd1370d539667235a5565da72ca77f3f741cdc70/pycares-5.0.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d765afb52d579879f5c4f005763827d3b1eb86b23139e9614e6089c9f98db017", size = 220584 }, + { url = "https://files.pythonhosted.org/packages/f6/74/d82304297308f6c24a17961bf589b53eefa5f7f2724158c842c67fa0b302/pycares-5.0.1-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ea0d57ba5add4bfbcc40cbdfa92bbb8a5ef0c4c21881e26c7229d9bdc92a4533", size = 252166 }, + { url = "https://files.pythonhosted.org/packages/39/a2/0ead3ba4228a490b52eb44d43514dae172c90421bb30a3659516e5b251a2/pycares-5.0.1-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9ec2aa3553d33e6220aeb1a05f4853fb83fce4cec3e0dea2dc970338ea47dc", size = 239085 }, + { url = "https://files.pythonhosted.org/packages/26/ad/e59f173933f0e696a6afbbd63935114d1400524a72da4f2cbafc6002a398/pycares-5.0.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5c63fb2498b05e9f5670a1bf3b900c5d09343b3b6d5001a9714d593f9eb54de1", size = 222936 }, + { url = "https://files.pythonhosted.org/packages/98/fa/d85bfe663a9c292efd8e699779027612c0c65ff50dc4cc9eb7a143613460/pycares-5.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:71316f7a87c15a8d32127ff01374dc2c969c37410693cc0cf6532590b7f18e7a", size = 223506 }, + { url = "https://files.pythonhosted.org/packages/2a/6b/4c225a5b10a4c9f88891a20bfe363eca1b1ce7d5244b396e5683c6070998/pycares-5.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a2117dffbb78615bfdb41ad77b17038689e4e01c66f153649e80d268c6228b4f", size = 251633 }, + { url = "https://files.pythonhosted.org/packages/26/ce/ba2349413b5197b72ec19c46e07f6be3a324f80a7b1579c7cbb1b82d6dc2/pycares-5.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7d7c4f5d8b88b586ef2288142b806250020e6490b9f2bd8fd5f634a78fd20fcf", size = 237703 }, + { url = "https://files.pythonhosted.org/packages/84/2f/1fd794e6fca10d9e20569113d10a4f92cc2b4242d3eb45524419a37cca6b/pycares-5.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:433b9a4b5a7e10ef8aef0b957e6cd0bfc1bb5bc730d2729f04e93c91c25979c0", size = 222622 }, + { url = "https://files.pythonhosted.org/packages/c9/07/7db7977649b210092a7e02d550fcebdfa69bc995c684a3b960c88a5dc4ce/pycares-5.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:cf2699883b88713670d3f9c0a1e44ac24c70aeace9f8c6aa7f0b9f222d5b08a5", size = 117438 }, + { url = "https://files.pythonhosted.org/packages/fc/ca/f322ddaa8b3414667de8faeea944ce9d3ddfaf1455839f499a21fcea4cec/pycares-5.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:9528dc11749e5e098c996475b60f879e1db5a6cb3dd0cdc747530620bb1a8941", size = 108920 }, + { url = "https://files.pythonhosted.org/packages/75/67/e84ba11d3fec3bf1322c3b302c4df13c85e0a1bc48f16d65cd0f59ad9853/pycares-5.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ee551be4f3f3ac814ac8547586c464c9035e914f5122a534d25de147fa745e1", size = 136241 }, + { url = "https://files.pythonhosted.org/packages/ce/ae/50fbb3b4e52b9f1d16a36ffabd051ef8b2106b3f0a0d1c1113904d187a9d/pycares-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:252d4e5a52a68f825eaa90e16b595f9baee22c760f51e286ab612c6829b96de3", size = 131069 }, + { url = "https://files.pythonhosted.org/packages/0e/ea/f431599f1ac42149ea4768e516db7cdae3a503a6646319ae63ab66da1486/pycares-5.0.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c1aa549b8c2f2e224215c793d660270778dcba9abc3b85abbc7c41eabe4f1e5", size = 221120 }, + { url = "https://files.pythonhosted.org/packages/6e/4f/0a7a6c8b3a64ee5149e935c167cd8ba5d1fdd766ec03e273dbc7502f7bea/pycares-5.0.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:db7c9c9f16e8311998667a7488e817f8cbeedec2447bac827c71804663f1437e", size = 252228 }, + { url = "https://files.pythonhosted.org/packages/49/3d/7f9fd20e97ee30c4b959f87ab26e47ddcef666e5e7717e45f2245fe9d70a/pycares-5.0.1-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b9c4c8bb69bab863f677fa166653bb872bfa5d5a742f1f30bebc2d53b6e71db", size = 239473 }, + { url = "https://files.pythonhosted.org/packages/a4/d0/c67967a10abd89529cb9aded9d73f43e5de00cf21243638ef529f6757262/pycares-5.0.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09ef90da8da3026fcba4ed223bd71e8057608d5b3fec4f5990b52ae1e8c855cc", size = 223831 }, + { url = "https://files.pythonhosted.org/packages/4f/9a/94aacaf22a20b7d342c8f18bf006be57967beef6319adc668d4d86b627be/pycares-5.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ce193ebd54f4c74538b751ebb0923a9208c234ff180589d4d3cec134c001840e", size = 223963 }, + { url = "https://files.pythonhosted.org/packages/e6/e1/3666aab6fc5e7d0c669b981fe0407e6a4b67e4e6a37ac429d440274663d5/pycares-5.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:36b9ff18ef231277f99a846feade50b417187a96f742689a9d08b9594e386de4", size = 251813 }, + { url = "https://files.pythonhosted.org/packages/94/44/ddab5fbc16ad0084a827167ae8628f54c7a55ce6b743585e6f47a5dd527e/pycares-5.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5e40ea4a0ef0c01a02ef7f7390a58c62d237d5ad48d36bc3245e9c2ac181cc22", size = 238181 }, + { url = "https://files.pythonhosted.org/packages/66/27/05467933e0e5c4e712302a2d7499797bc3029bf4d0d8ffbfe737254482b7/pycares-5.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3f323b0ddfd2c7896af6fba4f8851d34d3d13387566aa573d93330fb01cb1038", size = 223552 }, + { url = "https://files.pythonhosted.org/packages/3e/e2/14f3837e943d46ee12441fe6aaa418fdb2f698d42e179f368eaa9829744b/pycares-5.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bdc6bcafb72a97b3cdd529fc87210e59e67feb647a7e138110656023599b84da", size = 117478 }, + { url = "https://files.pythonhosted.org/packages/d3/c3/3284061f18188d5085338e1f1fd4f03d9c135657acf16f8020b9dd3be5fc/pycares-5.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:f8ef4c70c1edaf022875a8f9ff6c0c064f82831225acc91aa1b4f4d389e2e03a", size = 108889 }, + { url = "https://files.pythonhosted.org/packages/92/0a/6bd9bdc2d0ee23ff3aabab7747212e2c5323a081b9b745624d62df88f7e9/pycares-5.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d1b2c6b152c65f14d0e12d741fabb78a487f0f0d22773eede8d8cfc97af612b", size = 136242 }, + { url = "https://files.pythonhosted.org/packages/18/2a/2e9f888fc076cfe7a3493a3c4113e787cc4b4533f531dfb562ac9b04898f/pycares-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8c8ffcc9a48cfc296fe1aefc07d2c8e29a7f97e4bb366ce17effea6a38825f70", size = 131070 }, + { url = "https://files.pythonhosted.org/packages/ec/5b/83b5aaf7b6ed102f63cd768a747b6cb5d4624f2eaecd84868d103b9dbf39/pycares-5.0.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8efc38c2703e3530b823a4165a7b28d7ce0fdcf41960fb7a4ca834a0f8cfe79", size = 221137 }, + { url = "https://files.pythonhosted.org/packages/33/d3/d77ab0b33fb805d02896c385176c462e3386d94457a5e508245c39f41829/pycares-5.0.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e380bf6eff42c260f829a0a14547e13375e949053a966c23ca204a13647ef265", size = 252252 }, + { url = "https://files.pythonhosted.org/packages/14/32/8afbc798bce26dfcc5bc1f6bf1560d31cdd0af837ff52cbede657bf9262e/pycares-5.0.1-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:35dd5858ee1246bd092a212b5e85a8ef70853f7cfaf16b99569bf4af3ae4695d", size = 239447 }, + { url = "https://files.pythonhosted.org/packages/61/1b/a056393fda383b2eda5dab20bd0dd034fd631bf5ae754aabb20da815bdfe/pycares-5.0.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c257c6e7bf310cdb5823aa9d9a28f1e370fed8c653a968d38a954a8f8e0375ce", size = 223822 }, + { url = "https://files.pythonhosted.org/packages/ca/c7/9817f0fb954ab9926f88403f2b91a3e4984a277e2b7a4563e0118e4e1ffa/pycares-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07711acb0ef75758f081fb7436acaccc91e8afd5ae34fd35d4edc44297e81f27", size = 223986 }, + { url = "https://files.pythonhosted.org/packages/e1/a9/c0ea15c871c77e8c20bcaab18f56ae83988ea4c302155d106cc6a1bd83a9/pycares-5.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:30e5db1ae85cffb031dd8bc1b37903cd74c6d37eb737643bbca3ff2cd4bc6ae2", size = 251838 }, + { url = "https://files.pythonhosted.org/packages/be/a4/fe4068abfadf3e06cc22333e87e4730de3c170075572041d5545926062a3/pycares-5.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:efbe7f89425a14edbc94787042309be77cb3674415eb6079b356e1f9552ba747", size = 238238 }, + { url = "https://files.pythonhosted.org/packages/a7/25/4f140518768d974af4221cfd574a30d99d40b3d5c54c479da2c1553be59e/pycares-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5de9e7ce52d638d78723c24704eb032e60b96fbb6fe90c6b3110882987251377", size = 223574 }, + { url = "https://files.pythonhosted.org/packages/1e/0a/6e4afa4a2baffd1eba6c18a90cda17681d4838d3cab5a485e471386e04dc/pycares-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:0e99af0a1ce015ab6cc6bd85ce158d95ed89fb3b654515f1d0989d1afcf11026", size = 117472 }, + { url = "https://files.pythonhosted.org/packages/57/d0/a99f97e9aa8c8404fc899540cf30be63cda0df5150e3c0837423917c7e4c/pycares-5.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:2a511c9f3b11b7ce9f159c956ea1b8f2de7f419d7ca9fa24528d582cb015dbf9", size = 108889 }, + { url = "https://files.pythonhosted.org/packages/38/b2/4af99ff17acb81377c971831520540d1859bf401dc85712eb4abc2e6751f/pycares-5.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e330e3561be259ad7a1b7b0ce282c872938625f76587fae7ac8d6bc5af1d0c3d", size = 136635 }, + { url = "https://files.pythonhosted.org/packages/42/da/e2e1683811c427492ee0e86e8fae8d55eb5cca032220438599991fdad866/pycares-5.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82bd37fec2a3fa62add30d4a3854720f7b051386e2f18e6e8f4ee94b89b5a7b0", size = 131093 }, + { url = "https://files.pythonhosted.org/packages/cd/2a/9cf2120cafc19e5c589d5252a9ddd3108cc87e9db09938d16317807de03b/pycares-5.0.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:258c38aaa82ad1d565b4591cdb93d2c191be8e0a2c70926999c8e0b717a01f2a", size = 221096 }, + { url = "https://files.pythonhosted.org/packages/2c/cc/c5fbf6377e2d6b1f1618f147ad898e5d8ae1585fc726d6301f07aeda6cac/pycares-5.0.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ccc1b2df8a09ca20eefbe20b9f7a484d376525c0fb173cfadd692320013c6bc5", size = 252330 }, + { url = "https://files.pythonhosted.org/packages/3b/df/17a7c518c45bb994f76d9064d2519674e2a3950f895abbe6af123ead04ac/pycares-5.0.1-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3c4dfc80cc8b43dc79e02a15486c58eead5cae0a40906d6be64e2522285b5b39", size = 239799 }, + { url = "https://files.pythonhosted.org/packages/3f/6c/d79c94809742b56b9180a9a9ec2937607db0b8eb34b8ca75d86d3114d6dd/pycares-5.0.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f498a6606247bfe896c2a4d837db711eb7b0ba23e409e16e4b23def4bada4b9d", size = 223501 }, + { url = "https://files.pythonhosted.org/packages/69/08/83084b67cbce08f44fd803b88816fc80d2fe2fb3d483d5432925df44371b/pycares-5.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a7d197835cdb4b202a3b12562b32799e27bb132262d4aa1ac3ee9d440e8ec22c", size = 223708 }, + { url = "https://files.pythonhosted.org/packages/15/57/63a6e9ef356c5149b8ec72a694e02207fd8ae643895aeb78a9f0c07f1502/pycares-5.0.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f78ab823732b050d658eb735d553726663c9bccdeeee0653247533a23eb2e255", size = 251816 }, + { url = "https://files.pythonhosted.org/packages/43/1c/1c85c6355cf7bc3ae86a1024d60f9cabdc12af63306a5f59370ac8718a41/pycares-5.0.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f444ab7f318e9b2c209b45496fb07bff5e7ada606e15d5253a162964aa078527", size = 238259 }, + { url = "https://files.pythonhosted.org/packages/5d/7f/bd5ff5a460e50433f993560e4e5d229559a8bf271dbdf6be832faf1973b5/pycares-5.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9de80997de7538619b7dd28ec4371e5172e3f9480e4fc648726d3d5ba661ca05", size = 223732 }, + { url = "https://files.pythonhosted.org/packages/b5/fe/e77738366e00dc0918bbeb0c8fc63579e5d9cec748a2b838e207e548b5d9/pycares-5.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:206ce9f3cb9d51f5065c81b23c22996230fbc2cf58ae22834c623631b2b473aa", size = 120847 }, + { url = "https://files.pythonhosted.org/packages/81/17/758e9af7ee8589ac6deddf7ea56d75b982f155bc2052ef61c45d5f371389/pycares-5.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:45fb3b07231120e8cb5b75be7f15f16115003e9251991dc37a3e5c63733d63b5", size = 112595 }, + { url = "https://files.pythonhosted.org/packages/56/12/4f1d418fed957fc96089c69d9ec82314b3b91c48c7f9463385842acad9c4/pycares-5.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:602f3eac4b880a2527d21f52b2319cb10fde9225d103d338c4d0b2b07f136849", size = 137061 }, + { url = "https://files.pythonhosted.org/packages/29/8c/559cea98a8a5d0f38b50b4b812a07fdbcdb1a961bed9e2e9d5d343e53c6f/pycares-5.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1c3736deef003f0c57bc4e7f94d54270d0824350a8f5ceaba3a20b2ce8fb427", size = 131551 }, + { url = "https://files.pythonhosted.org/packages/34/cd/aee5d8070888d7be509d4f32a348e2821309ec67980498e5a974cd9e4990/pycares-5.0.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e63328df86d37150ce697fb5d9313d1d468dd4dddee1d09342cb2ed241ce6ad9", size = 230409 }, + { url = "https://files.pythonhosted.org/packages/5e/94/15d5cf7d8e7af4b4ce3e19ea117dfe565c08d60d82f043ad23843703a135/pycares-5.0.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57f6fd696213329d9a69b9664a68b1ff2a71ccbdc1fc928a42c9a92858c1ec5d", size = 261297 }, + { url = "https://files.pythonhosted.org/packages/af/46/24f6ddc7a37ec6eaa1c38f617f39624211d8e7cdca49b644bfc5f467f275/pycares-5.0.1-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d0878edabfbecb48a29e8769284003d8dbc05936122fe361849cd5fa52722e0", size = 248071 }, + { url = "https://files.pythonhosted.org/packages/fa/f0/7eb7fe44f0db55b9083725ab7a084874c2dc02806d9613e07e719838c2ab/pycares-5.0.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50e21f27a91be122e066ddd78c2d0d2769e547561481d8342a9d652a345b89f7", size = 232073 }, + { url = "https://files.pythonhosted.org/packages/1d/cd/993b17e0c049a56b5af4df3fd053acc57b37e17e0dcd709b2d337c22d57d/pycares-5.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:97ceda969f5a5d5c6b15558b658c29e4301b3a2c4615523797b5f9d4ac74772e", size = 232815 }, + { url = "https://files.pythonhosted.org/packages/7a/ff/170177bcc5dff31e735f209f5de63362f513ac18846c83d50e4e68f57866/pycares-5.0.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4d1713e602ab09882c3e65499b2cc763bff0371117327cad704cf524268c2604", size = 261111 }, + { url = "https://files.pythonhosted.org/packages/4d/4a/4c6497b8ca9279b4038ee8c7e2c49504008d594d06a044e00678b30c10fe/pycares-5.0.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:954a379055d6c66b2e878b52235b382168d1a3230793ff44454019394aecac5e", size = 246311 }, + { url = "https://files.pythonhosted.org/packages/06/19/1603f51f0d73bf34017a9e6967540c2bc138f9541aa7cc1ef38990b3ce9d/pycares-5.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:145d8a20f7fd1d58a2e49b7ef4309ec9bdcab479ac65c2e49480e20d3f890c23", size = 232027 }, + { url = "https://files.pythonhosted.org/packages/7a/de/c000a682757b84688722ac232a24a86b6f195f1f4732432ecf35d0a768a5/pycares-5.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ebc9daba03c7ff3f62616c84c6cb37517445d15df00e1754852d6006039eb4a4", size = 121267 }, + { url = "https://files.pythonhosted.org/packages/b2/c4/8bfffecd08b9b198113fcff5f0ab84bbe696f07dec46dd1ccae0e7b28c23/pycares-5.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:e0a86eff6bf9e91d5dd8876b1b82ee45704f46b1104c24291d3dea2c1fc8ebcb", size = 113043 }, ] [[package]] name = "pycparser" version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172 }, ] [[package]] name = "pycryptodome" version = "3.21.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/52/13b9db4a913eee948152a079fe58d035bd3d1a519584155da8e786f767e6/pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", size = 4818071, upload-time = "2024-10-02T10:23:18.339Z" } +sdist = { url = "https://files.pythonhosted.org/packages/13/52/13b9db4a913eee948152a079fe58d035bd3d1a519584155da8e786f767e6/pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", size = 4818071 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/88/5e83de10450027c96c79dc65ac45e9d0d7a7fef334f39d3789a191f33602/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", size = 2495937, upload-time = "2024-10-02T10:22:29.156Z" }, - { url = "https://files.pythonhosted.org/packages/66/e1/8f28cd8cf7f7563319819d1e172879ccce2333781ae38da61c28fe22d6ff/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", size = 1634629, upload-time = "2024-10-02T10:22:31.82Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c1/f75a1aaff0c20c11df8dc8e2bf8057e7f73296af7dfd8cbb40077d1c930d/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", size = 2168708, upload-time = "2024-10-02T10:22:34.5Z" }, - { url = "https://files.pythonhosted.org/packages/ea/66/6f2b7ddb457b19f73b82053ecc83ba768680609d56dd457dbc7e902c41aa/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", size = 2254555, upload-time = "2024-10-02T10:22:37.259Z" }, - { url = "https://files.pythonhosted.org/packages/2c/2b/152c330732a887a86cbf591ed69bd1b489439b5464806adb270f169ec139/pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", size = 2294143, upload-time = "2024-10-02T10:22:39.909Z" }, - { url = "https://files.pythonhosted.org/packages/55/92/517c5c498c2980c1b6d6b9965dffbe31f3cd7f20f40d00ec4069559c5902/pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", size = 2160509, upload-time = "2024-10-02T10:22:42.165Z" }, - { url = "https://files.pythonhosted.org/packages/39/1f/c74288f54d80a20a78da87df1818c6464ac1041d10988bb7d982c4153fbc/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", size = 2329480, upload-time = "2024-10-02T10:22:44.482Z" }, - { url = "https://files.pythonhosted.org/packages/39/1b/d0b013bf7d1af7cf0a6a4fce13f5fe5813ab225313755367b36e714a63f8/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", size = 2254397, upload-time = "2024-10-02T10:22:46.875Z" }, - { url = "https://files.pythonhosted.org/packages/14/71/4cbd3870d3e926c34706f705d6793159ac49d9a213e3ababcdade5864663/pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", size = 1775641, upload-time = "2024-10-02T10:22:48.703Z" }, - { url = "https://files.pythonhosted.org/packages/43/1d/81d59d228381576b92ecede5cd7239762c14001a828bdba30d64896e9778/pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", size = 1812863, upload-time = "2024-10-02T10:22:50.548Z" }, + { url = "https://files.pythonhosted.org/packages/a7/88/5e83de10450027c96c79dc65ac45e9d0d7a7fef334f39d3789a191f33602/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", size = 2495937 }, + { url = "https://files.pythonhosted.org/packages/66/e1/8f28cd8cf7f7563319819d1e172879ccce2333781ae38da61c28fe22d6ff/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", size = 1634629 }, + { url = "https://files.pythonhosted.org/packages/6a/c1/f75a1aaff0c20c11df8dc8e2bf8057e7f73296af7dfd8cbb40077d1c930d/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", size = 2168708 }, + { url = "https://files.pythonhosted.org/packages/ea/66/6f2b7ddb457b19f73b82053ecc83ba768680609d56dd457dbc7e902c41aa/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", size = 2254555 }, + { url = "https://files.pythonhosted.org/packages/2c/2b/152c330732a887a86cbf591ed69bd1b489439b5464806adb270f169ec139/pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", size = 2294143 }, + { url = "https://files.pythonhosted.org/packages/55/92/517c5c498c2980c1b6d6b9965dffbe31f3cd7f20f40d00ec4069559c5902/pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", size = 2160509 }, + { url = "https://files.pythonhosted.org/packages/39/1f/c74288f54d80a20a78da87df1818c6464ac1041d10988bb7d982c4153fbc/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", size = 2329480 }, + { url = "https://files.pythonhosted.org/packages/39/1b/d0b013bf7d1af7cf0a6a4fce13f5fe5813ab225313755367b36e714a63f8/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", size = 2254397 }, + { url = "https://files.pythonhosted.org/packages/14/71/4cbd3870d3e926c34706f705d6793159ac49d9a213e3ababcdade5864663/pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", size = 1775641 }, + { url = "https://files.pythonhosted.org/packages/43/1d/81d59d228381576b92ecede5cd7239762c14001a828bdba30d64896e9778/pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", size = 1812863 }, ] [[package]] @@ -2069,29 +2071,29 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7b/da/fd89f987a376c807cd81ea0eff4589aade783bbb702637b4734ef2c743a2/pydantic-1.10.26.tar.gz", hash = "sha256:8c6aa39b494c5af092e690127c283d84f363ac36017106a9e66cb33a22ac412e", size = 357906, upload-time = "2025-12-18T15:47:46.557Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/c1/d521e64c8130e1ad9d22c270bed3fabcc0940c9539b076b639c88fd32a8d/pydantic-1.10.26-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:116233e53889bcc536f617e38c1b8337d7fa9c280f0fd7a4045947515a785637", size = 2428347, upload-time = "2025-12-18T15:46:39.41Z" }, - { url = "https://files.pythonhosted.org/packages/2c/08/f4b804a00c16e3ea994cb640a7c25c579b4f1fa674cde6a19fa0dfb0ae4f/pydantic-1.10.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3cfdd361addb6eb64ccd26ac356ad6514cee06a61ab26b27e16b5ed53108f77", size = 2212605, upload-time = "2025-12-18T15:46:41.006Z" }, - { url = "https://files.pythonhosted.org/packages/5d/78/0df4b9efef29bbc5e39f247fcba99060d15946b4463d82a5589cf7923d71/pydantic-1.10.26-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0e4451951a9a93bf9a90576f3e25240b47ee49ab5236adccb8eff6ac943adf0f", size = 2753560, upload-time = "2025-12-18T15:46:43.215Z" }, - { url = "https://files.pythonhosted.org/packages/68/66/6ab6c1d3a116d05d2508fce64f96e35242938fac07544d611e11d0d363a0/pydantic-1.10.26-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9858ed44c6bea5f29ffe95308db9e62060791c877766c67dd5f55d072c8612b5", size = 2859235, upload-time = "2025-12-18T15:46:45.112Z" }, - { url = "https://files.pythonhosted.org/packages/61/4e/f1676bb0fcdf6ed2ce4670d7d1fc1d6c3a06d84497644acfbe02649503f1/pydantic-1.10.26-cp311-cp311-win_amd64.whl", hash = "sha256:ac1089f723e2106ebde434377d31239e00870a7563245072968e5af5cc4d33df", size = 2066646, upload-time = "2025-12-18T15:46:46.816Z" }, - { url = "https://files.pythonhosted.org/packages/02/6c/cd97a5a776c4515e6ee2ae81c2f2c5be51376dda6c31f965d7746ce0019f/pydantic-1.10.26-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:468d5b9cacfcaadc76ed0a4645354ab6f263ec01a63fb6d05630ea1df6ae453f", size = 2433795, upload-time = "2025-12-18T15:46:49.321Z" }, - { url = "https://files.pythonhosted.org/packages/47/12/de20affa30dcef728fcf9cc98e13ff4438c7a630de8d2f90eb38eba0891c/pydantic-1.10.26-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2c1b0b914be31671000ca25cf7ea17fcaaa68cfeadf6924529c5c5aa24b7ab1f", size = 2227387, upload-time = "2025-12-18T15:46:50.877Z" }, - { url = "https://files.pythonhosted.org/packages/7b/1d/9d65dcc5b8c17ba590f1f9f486e9306346831902318b7ee93f63516f4003/pydantic-1.10.26-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15b13b9f8ba8867095769e1156e0d7fbafa1f65b898dd40fd1c02e34430973cb", size = 2629594, upload-time = "2025-12-18T15:46:53.42Z" }, - { url = "https://files.pythonhosted.org/packages/3f/76/acb41409356789e23e1a7ef58f93821410c96409183ce314ddb58d97f23e/pydantic-1.10.26-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad7025ca324ae263d4313998e25078dcaec5f9ed0392c06dedb57e053cc8086b", size = 2745305, upload-time = "2025-12-18T15:46:55.987Z" }, - { url = "https://files.pythonhosted.org/packages/22/72/a98c0c5e527a66057d969fedd61675223c7975ade61acebbca9f1abd6dc0/pydantic-1.10.26-cp312-cp312-win_amd64.whl", hash = "sha256:4482b299874dabb88a6c3759e3d85c6557c407c3b586891f7d808d8a38b66b9c", size = 1937647, upload-time = "2025-12-18T15:46:57.905Z" }, - { url = "https://files.pythonhosted.org/packages/28/b9/17a5a5a421c23ac27486b977724a42c9d5f8b7f0f4aab054251066223900/pydantic-1.10.26-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1ae7913bb40a96c87e3d3f6fe4e918ef53bf181583de4e71824360a9b11aef1c", size = 2494599, upload-time = "2025-12-18T15:47:00.209Z" }, - { url = "https://files.pythonhosted.org/packages/e6/8e/6e3bd4241076cf227b443d7577245dd5d181ecf40b3182fcb908bc8c197d/pydantic-1.10.26-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8154c13f58d4de5d3a856bb6c909c7370f41fb876a5952a503af6b975265f4ba", size = 2254391, upload-time = "2025-12-18T15:47:02.268Z" }, - { url = "https://files.pythonhosted.org/packages/a8/30/a1c4092eda2145ecbead6c92db489b223e101e1ba0da82576d0cf73dd422/pydantic-1.10.26-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f8af0507bf6118b054a9765fb2e402f18a8b70c964f420d95b525eb711122d62", size = 2609445, upload-time = "2025-12-18T15:47:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/3a/2a/0491f1729ee4b7b6bc859ec22f69752f0c09bee1b66ac6f5f701136f34c3/pydantic-1.10.26-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dcb5a7318fb43189fde6af6f21ac7149c4bcbcfffc54bc87b5becddc46084847", size = 2732124, upload-time = "2025-12-18T15:47:07.464Z" }, - { url = "https://files.pythonhosted.org/packages/2a/56/b59f3b2f84e1df2b04ae768a1bb04d9f0288ff71b67cdcbb07683757b2c0/pydantic-1.10.26-cp313-cp313-win_amd64.whl", hash = "sha256:71cde228bc0600cf8619f0ee62db050d1880dcc477eba0e90b23011b4ee0f314", size = 1939888, upload-time = "2025-12-18T15:47:09.618Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8b/0c3dc02d4b97790b0f199bf933f677c14e7be4a8d21307c5f2daae06aa41/pydantic-1.10.26-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6b40730cc81d53d515dc0b8bb5c9b43fadb9bed46de4a3c03bd95e8571616dba", size = 2502689, upload-time = "2025-12-18T15:47:12.308Z" }, - { url = "https://files.pythonhosted.org/packages/d4/9d/d31aeea45542b2ae4b09ecba92b88aaba696b801c31919811aa979a1242d/pydantic-1.10.26-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c3bbb9c0eecdf599e4db9b372fa9cc55be12e80a0d9c6d307950a39050cb0e37", size = 2269494, upload-time = "2025-12-18T15:47:14.53Z" }, - { url = "https://files.pythonhosted.org/packages/78/c1/3a4d069593283ca4dd0006039ba33644e21e432cddc09da706ac50441610/pydantic-1.10.26-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc2e3fe7bc4993626ef6b6fa855defafa1d6f8996aa1caef2deb83c5ac4d043a", size = 2620047, upload-time = "2025-12-18T15:47:17.089Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0e/340c3d29197d99c15ab04093d43bb9c9d0fd17c2a34b80cb9d36ed732b09/pydantic-1.10.26-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:36d9e46b588aaeb1dcd2409fa4c467fe0b331f3cc9f227b03a7a00643704e962", size = 2747625, upload-time = "2025-12-18T15:47:19.21Z" }, - { url = "https://files.pythonhosted.org/packages/1e/58/f12ab3727339b172c830b32151919456b67787cdfe8808b2568b322fb15c/pydantic-1.10.26-cp314-cp314-win_amd64.whl", hash = "sha256:81ce3c8616d12a7be31b4aadfd3434f78f6b44b75adbfaec2fe1ad4f7f999b8c", size = 1976436, upload-time = "2025-12-18T15:47:21.384Z" }, - { url = "https://files.pythonhosted.org/packages/1f/98/556e82f00b98486def0b8af85da95e69d2be7e367cf2431408e108bc3095/pydantic-1.10.26-py3-none-any.whl", hash = "sha256:c43ad70dc3ce7787543d563792426a16fd7895e14be4b194b5665e36459dd917", size = 166975, upload-time = "2025-12-18T15:47:44.927Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/7b/da/fd89f987a376c807cd81ea0eff4589aade783bbb702637b4734ef2c743a2/pydantic-1.10.26.tar.gz", hash = "sha256:8c6aa39b494c5af092e690127c283d84f363ac36017106a9e66cb33a22ac412e", size = 357906 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/c1/d521e64c8130e1ad9d22c270bed3fabcc0940c9539b076b639c88fd32a8d/pydantic-1.10.26-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:116233e53889bcc536f617e38c1b8337d7fa9c280f0fd7a4045947515a785637", size = 2428347 }, + { url = "https://files.pythonhosted.org/packages/2c/08/f4b804a00c16e3ea994cb640a7c25c579b4f1fa674cde6a19fa0dfb0ae4f/pydantic-1.10.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3cfdd361addb6eb64ccd26ac356ad6514cee06a61ab26b27e16b5ed53108f77", size = 2212605 }, + { url = "https://files.pythonhosted.org/packages/5d/78/0df4b9efef29bbc5e39f247fcba99060d15946b4463d82a5589cf7923d71/pydantic-1.10.26-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0e4451951a9a93bf9a90576f3e25240b47ee49ab5236adccb8eff6ac943adf0f", size = 2753560 }, + { url = "https://files.pythonhosted.org/packages/68/66/6ab6c1d3a116d05d2508fce64f96e35242938fac07544d611e11d0d363a0/pydantic-1.10.26-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9858ed44c6bea5f29ffe95308db9e62060791c877766c67dd5f55d072c8612b5", size = 2859235 }, + { url = "https://files.pythonhosted.org/packages/61/4e/f1676bb0fcdf6ed2ce4670d7d1fc1d6c3a06d84497644acfbe02649503f1/pydantic-1.10.26-cp311-cp311-win_amd64.whl", hash = "sha256:ac1089f723e2106ebde434377d31239e00870a7563245072968e5af5cc4d33df", size = 2066646 }, + { url = "https://files.pythonhosted.org/packages/02/6c/cd97a5a776c4515e6ee2ae81c2f2c5be51376dda6c31f965d7746ce0019f/pydantic-1.10.26-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:468d5b9cacfcaadc76ed0a4645354ab6f263ec01a63fb6d05630ea1df6ae453f", size = 2433795 }, + { url = "https://files.pythonhosted.org/packages/47/12/de20affa30dcef728fcf9cc98e13ff4438c7a630de8d2f90eb38eba0891c/pydantic-1.10.26-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2c1b0b914be31671000ca25cf7ea17fcaaa68cfeadf6924529c5c5aa24b7ab1f", size = 2227387 }, + { url = "https://files.pythonhosted.org/packages/7b/1d/9d65dcc5b8c17ba590f1f9f486e9306346831902318b7ee93f63516f4003/pydantic-1.10.26-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15b13b9f8ba8867095769e1156e0d7fbafa1f65b898dd40fd1c02e34430973cb", size = 2629594 }, + { url = "https://files.pythonhosted.org/packages/3f/76/acb41409356789e23e1a7ef58f93821410c96409183ce314ddb58d97f23e/pydantic-1.10.26-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad7025ca324ae263d4313998e25078dcaec5f9ed0392c06dedb57e053cc8086b", size = 2745305 }, + { url = "https://files.pythonhosted.org/packages/22/72/a98c0c5e527a66057d969fedd61675223c7975ade61acebbca9f1abd6dc0/pydantic-1.10.26-cp312-cp312-win_amd64.whl", hash = "sha256:4482b299874dabb88a6c3759e3d85c6557c407c3b586891f7d808d8a38b66b9c", size = 1937647 }, + { url = "https://files.pythonhosted.org/packages/28/b9/17a5a5a421c23ac27486b977724a42c9d5f8b7f0f4aab054251066223900/pydantic-1.10.26-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1ae7913bb40a96c87e3d3f6fe4e918ef53bf181583de4e71824360a9b11aef1c", size = 2494599 }, + { url = "https://files.pythonhosted.org/packages/e6/8e/6e3bd4241076cf227b443d7577245dd5d181ecf40b3182fcb908bc8c197d/pydantic-1.10.26-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8154c13f58d4de5d3a856bb6c909c7370f41fb876a5952a503af6b975265f4ba", size = 2254391 }, + { url = "https://files.pythonhosted.org/packages/a8/30/a1c4092eda2145ecbead6c92db489b223e101e1ba0da82576d0cf73dd422/pydantic-1.10.26-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f8af0507bf6118b054a9765fb2e402f18a8b70c964f420d95b525eb711122d62", size = 2609445 }, + { url = "https://files.pythonhosted.org/packages/3a/2a/0491f1729ee4b7b6bc859ec22f69752f0c09bee1b66ac6f5f701136f34c3/pydantic-1.10.26-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dcb5a7318fb43189fde6af6f21ac7149c4bcbcfffc54bc87b5becddc46084847", size = 2732124 }, + { url = "https://files.pythonhosted.org/packages/2a/56/b59f3b2f84e1df2b04ae768a1bb04d9f0288ff71b67cdcbb07683757b2c0/pydantic-1.10.26-cp313-cp313-win_amd64.whl", hash = "sha256:71cde228bc0600cf8619f0ee62db050d1880dcc477eba0e90b23011b4ee0f314", size = 1939888 }, + { url = "https://files.pythonhosted.org/packages/d2/8b/0c3dc02d4b97790b0f199bf933f677c14e7be4a8d21307c5f2daae06aa41/pydantic-1.10.26-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6b40730cc81d53d515dc0b8bb5c9b43fadb9bed46de4a3c03bd95e8571616dba", size = 2502689 }, + { url = "https://files.pythonhosted.org/packages/d4/9d/d31aeea45542b2ae4b09ecba92b88aaba696b801c31919811aa979a1242d/pydantic-1.10.26-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c3bbb9c0eecdf599e4db9b372fa9cc55be12e80a0d9c6d307950a39050cb0e37", size = 2269494 }, + { url = "https://files.pythonhosted.org/packages/78/c1/3a4d069593283ca4dd0006039ba33644e21e432cddc09da706ac50441610/pydantic-1.10.26-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc2e3fe7bc4993626ef6b6fa855defafa1d6f8996aa1caef2deb83c5ac4d043a", size = 2620047 }, + { url = "https://files.pythonhosted.org/packages/e0/0e/340c3d29197d99c15ab04093d43bb9c9d0fd17c2a34b80cb9d36ed732b09/pydantic-1.10.26-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:36d9e46b588aaeb1dcd2409fa4c467fe0b331f3cc9f227b03a7a00643704e962", size = 2747625 }, + { url = "https://files.pythonhosted.org/packages/1e/58/f12ab3727339b172c830b32151919456b67787cdfe8808b2568b322fb15c/pydantic-1.10.26-cp314-cp314-win_amd64.whl", hash = "sha256:81ce3c8616d12a7be31b4aadfd3434f78f6b44b75adbfaec2fe1ad4f7f999b8c", size = 1976436 }, + { url = "https://files.pythonhosted.org/packages/1f/98/556e82f00b98486def0b8af85da95e69d2be7e367cf2431408e108bc3095/pydantic-1.10.26-py3-none-any.whl", hash = "sha256:c43ad70dc3ce7787543d563792426a16fd7895e14be4b194b5665e36459dd917", size = 166975 }, ] [[package]] @@ -2101,24 +2103,24 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/45/2f64d8c14b487274e825d793dc634f9f1040537aa6cb93d1ea8fc4498d65/pydruid-0.6.9.tar.gz", hash = "sha256:63c41b33ab47fbb71cc25d3f3316cad78f18bfe947fa108862dd841d1f44fe49", size = 135508, upload-time = "2024-05-16T19:40:32.469Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/45/2f64d8c14b487274e825d793dc634f9f1040537aa6cb93d1ea8fc4498d65/pydruid-0.6.9.tar.gz", hash = "sha256:63c41b33ab47fbb71cc25d3f3316cad78f18bfe947fa108862dd841d1f44fe49", size = 135508 } [[package]] name = "pygments" version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151 }, ] [[package]] name = "pyparsing" version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574 } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781 }, ] [[package]] @@ -2132,9 +2134,9 @@ dependencies = [ { name = "pluggy" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249 }, ] [[package]] @@ -2145,9 +2147,9 @@ dependencies = [ { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514 } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, + { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930 }, ] [[package]] @@ -2159,9 +2161,9 @@ dependencies = [ { name = "pytest" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/23/32b36d2f769805c0f3069ca8d9eeee77b27fcf86d41d40c6061ddce51c7d/pytest-flask-1.3.0.tar.gz", hash = "sha256:58be1c97b21ba3c4d47e0a7691eb41007748506c36bf51004f78df10691fa95e", size = 35816, upload-time = "2023-10-23T14:53:20.696Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/23/32b36d2f769805c0f3069ca8d9eeee77b27fcf86d41d40c6061ddce51c7d/pytest-flask-1.3.0.tar.gz", hash = "sha256:58be1c97b21ba3c4d47e0a7691eb41007748506c36bf51004f78df10691fa95e", size = 35816 } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/03/7a917fda3d0e96b4e80ab1f83a6628ec4ee4a882523b49417d3891bacc9e/pytest_flask-1.3.0-py3-none-any.whl", hash = "sha256:c0e36e6b0fddc3b91c4362661db83fa694d1feb91fa505475be6732b5bc8c253", size = 13105, upload-time = "2023-10-23T14:53:18.959Z" }, + { url = "https://files.pythonhosted.org/packages/de/03/7a917fda3d0e96b4e80ab1f83a6628ec4ee4a882523b49417d3891bacc9e/pytest_flask-1.3.0-py3-none-any.whl", hash = "sha256:c0e36e6b0fddc3b91c4362661db83fa694d1feb91fa505475be6732b5bc8c253", size = 13105 }, ] [[package]] @@ -2171,9 +2173,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/28/67172c96ba684058a4d24ffe144d64783d2a270d0af0d9e792737bddc75c/pytest_mock-3.14.1.tar.gz", hash = "sha256:159e9edac4c451ce77a5cdb9fc5d1100708d2dd4ba3c3df572f14097351af80e", size = 33241, upload-time = "2025-05-26T13:58:45.167Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/28/67172c96ba684058a4d24ffe144d64783d2a270d0af0d9e792737bddc75c/pytest_mock-3.14.1.tar.gz", hash = "sha256:159e9edac4c451ce77a5cdb9fc5d1100708d2dd4ba3c3df572f14097351af80e", size = 33241 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/05/77b60e520511c53d1c1ca75f1930c7dd8e971d0c4379b7f4b3f9644685ba/pytest_mock-3.14.1-py3-none-any.whl", hash = "sha256:178aefcd11307d874b4cd3100344e7e2d888d9791a6a1d9bfe90fbc1b74fd1d0", size = 9923, upload-time = "2025-05-26T13:58:43.487Z" }, + { url = "https://files.pythonhosted.org/packages/b2/05/77b60e520511c53d1c1ca75f1930c7dd8e971d0c4379b7f4b3f9644685ba/pytest_mock-3.14.1-py3-none-any.whl", hash = "sha256:178aefcd11307d874b4cd3100344e7e2d888d9791a6a1d9bfe90fbc1b74fd1d0", size = 9923 }, ] [[package]] @@ -2183,9 +2185,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1d/66/02ae17461b14a52ce5a29ae2900156b9110d1de34721ccc16ccd79419876/pytest_order-1.3.0.tar.gz", hash = "sha256:51608fec3d3ee9c0adaea94daa124a5c4c1d2bb99b00269f098f414307f23dde", size = 47544, upload-time = "2024-08-22T12:29:54.512Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/66/02ae17461b14a52ce5a29ae2900156b9110d1de34721ccc16ccd79419876/pytest_order-1.3.0.tar.gz", hash = "sha256:51608fec3d3ee9c0adaea94daa124a5c4c1d2bb99b00269f098f414307f23dde", size = 47544 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/73/59b038d1aafca89f8e9936eaa8ffa6bb6138d00459d13a32ce070be4f280/pytest_order-1.3.0-py3-none-any.whl", hash = "sha256:2cd562a21380345dd8d5774aa5fd38b7849b6ee7397ca5f6999bbe6e89f07f6e", size = 14609, upload-time = "2024-08-22T12:29:53.156Z" }, + { url = "https://files.pythonhosted.org/packages/1b/73/59b038d1aafca89f8e9936eaa8ffa6bb6138d00459d13a32ce070be4f280/pytest_order-1.3.0-py3-none-any.whl", hash = "sha256:2cd562a21380345dd8d5774aa5fd38b7849b6ee7397ca5f6999bbe6e89f07f6e", size = 14609 }, ] [[package]] @@ -2195,9 +2197,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/99/5b2e99737edeb28c71bcbec5b5dda19d0d9ef3ca3e92e3e925e7c0bb364c/python-dateutil-2.8.0.tar.gz", hash = "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e", size = 327134, upload-time = "2019-02-05T14:12:37.493Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/99/5b2e99737edeb28c71bcbec5b5dda19d0d9ef3ca3e92e3e925e7c0bb364c/python-dateutil-2.8.0.tar.gz", hash = "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e", size = 327134 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/17/c62faccbfbd163c7f57f3844689e3a78bae1f403648a6afb1d0866d87fbb/python_dateutil-2.8.0-py2.py3-none-any.whl", hash = "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", size = 226803, upload-time = "2019-02-05T14:12:35.322Z" }, + { url = "https://files.pythonhosted.org/packages/41/17/c62faccbfbd163c7f57f3844689e3a78bae1f403648a6afb1d0866d87fbb/python_dateutil-2.8.0-py2.py3-none-any.whl", hash = "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", size = 226803 }, ] [[package]] @@ -2208,129 +2210,129 @@ dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/12/38c1a0b1e64806780c9563e3fc9f6e472251839662587cfbe9bfaf2ae10a/python_discovery-1.4.0.tar.gz", hash = "sha256:eb8bc7daad3c226c147e45bb4e970a1feb1bf4048ee178e6db59e197b8010ce3", size = 68455, upload-time = "2026-05-28T01:15:37.639Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/12/38c1a0b1e64806780c9563e3fc9f6e472251839662587cfbe9bfaf2ae10a/python_discovery-1.4.0.tar.gz", hash = "sha256:eb8bc7daad3c226c147e45bb4e970a1feb1bf4048ee178e6db59e197b8010ce3", size = 68455 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/8d/3d316429f65029532bb1e28ff77b797d86b5ac3915bb44ca4e19aa283d43/python_discovery-1.4.0-py3-none-any.whl", hash = "sha256:26ed78d703e234879a66244c7d4114563fb13ec5cd30a2d1357e5fb4850782da", size = 33217, upload-time = "2026-05-28T01:15:36.573Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8d/3d316429f65029532bb1e28ff77b797d86b5ac3915bb44ca4e19aa283d43/python_discovery-1.4.0-py3-none-any.whl", hash = "sha256:26ed78d703e234879a66244c7d4114563fb13ec5cd30a2d1357e5fb4850782da", size = 33217 }, ] [[package]] name = "python-json-logger" version = "0.1.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/60/c8/58af72880f3ea88419df3fbc2fd08fc47c7ec069e66b90773add12dd0f63/python-json-logger-0.1.10.tar.gz", hash = "sha256:cf2caaf34bd2eff394915b6242de4d0245de79971712439380ece6f149748cde", size = 5915, upload-time = "2018-11-07T13:45:05.927Z" } +sdist = { url = "https://files.pythonhosted.org/packages/60/c8/58af72880f3ea88419df3fbc2fd08fc47c7ec069e66b90773add12dd0f63/python-json-logger-0.1.10.tar.gz", hash = "sha256:cf2caaf34bd2eff394915b6242de4d0245de79971712439380ece6f149748cde", size = 5915 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/2e/8d99d075689d9b57548586bd9f5b286f0634f8e6fdb8db57a7ffdd8f86bf/python_json_logger-0.1.10-py2.py3-none-any.whl", hash = "sha256:3e000053837500f9eb28d6228d7cb99fabfc1874d34b40c08289207292abaf2e", size = 5046, upload-time = "2018-11-07T13:45:03.267Z" }, + { url = "https://files.pythonhosted.org/packages/84/2e/8d99d075689d9b57548586bd9f5b286f0634f8e6fdb8db57a7ffdd8f86bf/python_json_logger-0.1.10-py2.py3-none-any.whl", hash = "sha256:3e000053837500f9eb28d6228d7cb99fabfc1874d34b40c08289207292abaf2e", size = 5046 }, ] [[package]] name = "pytz" version = "2022.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/5f/a0f653311adff905bbcaa6d3dfaf97edcf4d26138393c6ccd37a484851fb/pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", size = 320473, upload-time = "2022-03-20T00:37:10.116Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/5f/a0f653311adff905bbcaa6d3dfaf97edcf4d26138393c6ccd37a484851fb/pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", size = 320473 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/2e/dec1cc18c51b8df33c7c4d0a321b084cf38e1733b98f9d15018880fb4970/pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c", size = 503520, upload-time = "2022-03-20T00:37:06.783Z" }, + { url = "https://files.pythonhosted.org/packages/60/2e/dec1cc18c51b8df33c7c4d0a321b084cf38e1733b98f9d15018880fb4970/pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c", size = 503520 }, ] [[package]] name = "pyyaml" version = "6.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/e5/af35f7ea75cf72f2cd079c95ee16797de7cd71f29ea7c68ae5ce7be1eda0/PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", size = 125201, upload-time = "2023-07-18T00:00:23.308Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/e5/af35f7ea75cf72f2cd079c95ee16797de7cd71f29ea7c68ae5ce7be1eda0/PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", size = 125201 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/0d/26fb23e8863e0aeaac0c64e03fd27367ad2ae3f3cccf3798ee98ce160368/PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", size = 187867, upload-time = "2023-07-17T23:57:34.35Z" }, - { url = "https://files.pythonhosted.org/packages/28/09/55f715ddbf95a054b764b547f617e22f1d5e45d83905660e9a088078fe67/PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", size = 167530, upload-time = "2023-07-17T23:57:36.975Z" }, - { url = "https://files.pythonhosted.org/packages/5e/94/7d5ee059dfb92ca9e62f4057dcdec9ac08a9e42679644854dc01177f8145/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", size = 732244, upload-time = "2023-07-17T23:57:43.774Z" }, - { url = "https://files.pythonhosted.org/packages/06/92/e0224aa6ebf9dc54a06a4609da37da40bb08d126f5535d81bff6b417b2ae/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", size = 752871, upload-time = "2023-07-17T23:57:51.921Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5e/efd033ab7199a0b2044dab3b9f7a4f6670e6a52c089de572e928d2873b06/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", size = 757729, upload-time = "2023-07-17T23:57:59.865Z" }, - { url = "https://files.pythonhosted.org/packages/03/5c/c4671451b2f1d76ebe352c0945d4cd13500adb5d05f5a51ee296d80152f7/PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", size = 748528, upload-time = "2023-08-28T18:43:23.207Z" }, - { url = "https://files.pythonhosted.org/packages/73/9c/766e78d1efc0d1fca637a6b62cea1b4510a7fb93617eb805223294fef681/PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", size = 130286, upload-time = "2023-07-17T23:58:02.964Z" }, - { url = "https://files.pythonhosted.org/packages/b3/34/65bb4b2d7908044963ebf614fe0fdb080773fc7030d7e39c8d3eddcd4257/PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", size = 144699, upload-time = "2023-07-17T23:58:05.586Z" }, - { url = "https://files.pythonhosted.org/packages/bc/06/1b305bf6aa704343be85444c9d011f626c763abb40c0edc1cad13bfd7f86/PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", size = 178692, upload-time = "2023-08-28T18:43:24.924Z" }, - { url = "https://files.pythonhosted.org/packages/84/02/404de95ced348b73dd84f70e15a41843d817ff8c1744516bf78358f2ffd2/PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", size = 165622, upload-time = "2023-08-28T18:43:26.54Z" }, - { url = "https://files.pythonhosted.org/packages/c7/4c/4a2908632fc980da6d918b9de9c1d9d7d7e70b2672b1ad5166ed27841ef7/PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", size = 696937, upload-time = "2024-01-18T20:40:22.92Z" }, - { url = "https://files.pythonhosted.org/packages/b4/33/720548182ffa8344418126017aa1d4ab4aeec9a2275f04ce3f3573d8ace8/PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", size = 724969, upload-time = "2023-08-28T18:43:28.56Z" }, - { url = "https://files.pythonhosted.org/packages/4f/78/77b40157b6cb5f2d3d31a3d9b2efd1ba3505371f76730d267e8b32cf4b7f/PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", size = 712604, upload-time = "2023-08-28T18:43:30.206Z" }, - { url = "https://files.pythonhosted.org/packages/2e/97/3e0e089ee85e840f4b15bfa00e4e63d84a3691ababbfea92d6f820ea6f21/PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", size = 126098, upload-time = "2023-08-28T18:43:31.835Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/fbade56564ad486809c27b322d0f7e6a89c01f6b4fe208402e90d4443a99/PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", size = 138675, upload-time = "2023-08-28T18:43:33.613Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0d/26fb23e8863e0aeaac0c64e03fd27367ad2ae3f3cccf3798ee98ce160368/PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", size = 187867 }, + { url = "https://files.pythonhosted.org/packages/28/09/55f715ddbf95a054b764b547f617e22f1d5e45d83905660e9a088078fe67/PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", size = 167530 }, + { url = "https://files.pythonhosted.org/packages/5e/94/7d5ee059dfb92ca9e62f4057dcdec9ac08a9e42679644854dc01177f8145/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", size = 732244 }, + { url = "https://files.pythonhosted.org/packages/06/92/e0224aa6ebf9dc54a06a4609da37da40bb08d126f5535d81bff6b417b2ae/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", size = 752871 }, + { url = "https://files.pythonhosted.org/packages/7b/5e/efd033ab7199a0b2044dab3b9f7a4f6670e6a52c089de572e928d2873b06/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", size = 757729 }, + { url = "https://files.pythonhosted.org/packages/03/5c/c4671451b2f1d76ebe352c0945d4cd13500adb5d05f5a51ee296d80152f7/PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", size = 748528 }, + { url = "https://files.pythonhosted.org/packages/73/9c/766e78d1efc0d1fca637a6b62cea1b4510a7fb93617eb805223294fef681/PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", size = 130286 }, + { url = "https://files.pythonhosted.org/packages/b3/34/65bb4b2d7908044963ebf614fe0fdb080773fc7030d7e39c8d3eddcd4257/PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", size = 144699 }, + { url = "https://files.pythonhosted.org/packages/bc/06/1b305bf6aa704343be85444c9d011f626c763abb40c0edc1cad13bfd7f86/PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", size = 178692 }, + { url = "https://files.pythonhosted.org/packages/84/02/404de95ced348b73dd84f70e15a41843d817ff8c1744516bf78358f2ffd2/PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", size = 165622 }, + { url = "https://files.pythonhosted.org/packages/c7/4c/4a2908632fc980da6d918b9de9c1d9d7d7e70b2672b1ad5166ed27841ef7/PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", size = 696937 }, + { url = "https://files.pythonhosted.org/packages/b4/33/720548182ffa8344418126017aa1d4ab4aeec9a2275f04ce3f3573d8ace8/PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", size = 724969 }, + { url = "https://files.pythonhosted.org/packages/4f/78/77b40157b6cb5f2d3d31a3d9b2efd1ba3505371f76730d267e8b32cf4b7f/PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", size = 712604 }, + { url = "https://files.pythonhosted.org/packages/2e/97/3e0e089ee85e840f4b15bfa00e4e63d84a3691ababbfea92d6f820ea6f21/PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", size = 126098 }, + { url = "https://files.pythonhosted.org/packages/2b/9f/fbade56564ad486809c27b322d0f7e6a89c01f6b4fe208402e90d4443a99/PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", size = 138675 }, ] [[package]] name = "rapidfuzz" version = "3.14.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/21/ef6157213316e85790041254259907eb722e00b03480256c0545d98acd33/rapidfuzz-3.14.5.tar.gz", hash = "sha256:ba10ac57884ce82112f7ed910b67e7fb6072d8ef2c06e30dc63c0f604a112e0e", size = 57901753, upload-time = "2026-04-07T11:16:31.931Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/f9/3c41a7be8855803f4f6c713b472226a98d31d41869d98f64f4ca790510d6/rapidfuzz-3.14.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e251126d48615e1f02b4a178f2cd0cd4f0332b8a019c01a2e10480f7552554b4", size = 1952372, upload-time = "2026-04-07T11:13:58.32Z" }, - { url = "https://files.pythonhosted.org/packages/9e/89/c2557e37531d03465193bff0ab9de70b468420a807d71a26a65100635459/rapidfuzz-3.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ab449c9abd0d4e1f8145dce0798a4c822a1a1933d613c764a641bea88b8bdab", size = 1159782, upload-time = "2026-04-07T11:14:00.127Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b2/ffeeb7eca1a897d51b998f4c0ef0281696c3b06abcca4f88f9def708ffe1/rapidfuzz-3.14.5-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb2829fedd672dd7107267189dabe2bbe07972801d636014417c6861eb89e358", size = 1383677, upload-time = "2026-04-07T11:14:01.696Z" }, - { url = "https://files.pythonhosted.org/packages/6b/d0/4539e42a2d596e068f7738f279638a4a74edd1fbb6f8594e2458058979c6/rapidfuzz-3.14.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d50e5861872935fece391351cbb5ba21d1bced277cf5e1143d207a0a35f1925", size = 3168906, upload-time = "2026-04-07T11:14:03.29Z" }, - { url = "https://files.pythonhosted.org/packages/5e/1c/3ec897eb9d8b05308aa8ef6ae4ed64b088ad521a3f9d8ff469e7e97bc2b0/rapidfuzz-3.14.5-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:7092a216728f80c960bd6b3807275d1ee318b168986bd5dc523349581d4890b8", size = 1478176, upload-time = "2026-04-07T11:14:04.94Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ba/970c03a12ce20a5399e22afe9f8932fd4cd1265b8a8461d0e63b00eb4eae/rapidfuzz-3.14.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9669753caef7fdc6529f6adcc5883ed98d65976445d9322e7dbdb6b697feee13", size = 2402441, upload-time = "2026-04-07T11:14:07.228Z" }, - { url = "https://files.pythonhosted.org/packages/81/93/61d351cae60c1d0e21ba5ff1a1015ad045539ed215da9d6e302204ed887a/rapidfuzz-3.14.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:823b1b9d9230809d8edcc18872770764bfe8ef4357995e16744047c8ccf0e489", size = 2511628, upload-time = "2026-04-07T11:14:09.234Z" }, - { url = "https://files.pythonhosted.org/packages/87/52/374d2d4f60fd98155142a869323aa221e30868cfa1f15171a0f64070c247/rapidfuzz-3.14.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f0b2af76b7e7060c09e1a0dfa9410eb19369cbe6164509bff2ef94094b54d2b6", size = 4275480, upload-time = "2026-04-07T11:14:11.332Z" }, - { url = "https://files.pythonhosted.org/packages/d8/04/82e7989bc9ec20a15b720a335c5cb6b0724bf6582013898f90a3280cfccd/rapidfuzz-3.14.5-cp311-cp311-win32.whl", hash = "sha256:c5801a89604c65ab4cc9e91b23bc4076d0ca80efd8c976fb63843d7879a85d7f", size = 1725627, upload-time = "2026-04-07T11:14:13.217Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b5/eca8ac5609bc9bcb02bb6ff87fa5983cc92b8772d66a431556ab8a8c178f/rapidfuzz-3.14.5-cp311-cp311-win_amd64.whl", hash = "sha256:d7ca16637c0ede8243f84074044bd0b2335a0341421f8227c85756de2d18c819", size = 1545977, upload-time = "2026-04-07T11:14:14.766Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e1/dbf318de28f65fa2cdd0a9dfbdee380f8199eb83b19259bc4f8592551b4e/rapidfuzz-3.14.5-cp311-cp311-win_arm64.whl", hash = "sha256:8c90cdf8516d9057e502aa6003cea71cf5ec27cc44699ca52412b502a04761bb", size = 816827, upload-time = "2026-04-07T11:14:16.788Z" }, - { url = "https://files.pythonhosted.org/packages/d3/e3/574435c6aafb80254c191ef40d7aca2cb2bb97a095ec9395e9fa59ac307a/rapidfuzz-3.14.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0d3378f471ef440473a396ce2f8e97ee12f89a78b495540e0a5617bbfe895638", size = 1944601, upload-time = "2026-04-07T11:14:18.771Z" }, - { url = "https://files.pythonhosted.org/packages/d0/1f/fbad3102a255ecc112ce9a7e779bacab7fd14398217be8868dc9082ba363/rapidfuzz-3.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e910eebca9fd0eba245c0555e764597e8a0cccb673a92da2dc2397050725f48", size = 1164293, upload-time = "2026-04-07T11:14:20.534Z" }, - { url = "https://files.pythonhosted.org/packages/88/37/a3eb7ff6121ed3a5f199a8c38cc86c8e481816f879cb0e0b738b078c9a7e/rapidfuzz-3.14.5-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01550fe5f60fd176aa66b7611289d46dc4aa4b1b904874c7b6d1d54e581c5ec1", size = 1371999, upload-time = "2026-04-07T11:14:22.63Z" }, - { url = "https://files.pythonhosted.org/packages/79/72/97a9728c711c7c1b06e107d3f0623880fb4ef90e147ed13c551a1730e7cc/rapidfuzz-3.14.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48bee0b91bebfaec41e1081e351000659ab7570cc4598d617aa04d5bf827f9e6", size = 3145715, upload-time = "2026-04-07T11:14:24.508Z" }, - { url = "https://files.pythonhosted.org/packages/ed/54/d5caabbea233ac90c286c87c260e49d7641467e87438a18d858e41c82e91/rapidfuzz-3.14.5-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:7e580cb04ad849ae9b786fa21383c6b994b6e6c1444ad1cb9f22392759d72741", size = 1456304, upload-time = "2026-04-07T11:14:26.515Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a7/2d1a81250ac8c01a0100c026018e76f0e7a097ff63e4c553e02a6938c6fb/rapidfuzz-3.14.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:09d6c9ba091854f07817055d795d604179c12a8f308ba4c7d56f3719dfea1646", size = 2389089, upload-time = "2026-04-07T11:14:28.635Z" }, - { url = "https://files.pythonhosted.org/packages/65/0d/c47c3872203ae88e6506997c0b576ad731f5261daa25d559be09c9756658/rapidfuzz-3.14.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1e989f86113be66574113b9c7bdf4793f3f863d248e47d911b355e05ca6b6b10", size = 2493404, upload-time = "2026-04-07T11:14:30.577Z" }, - { url = "https://files.pythonhosted.org/packages/8f/2f/71e0a5a3130792146c8a200a2dd1e52aa16f7c1074012e17f2601eea9a90/rapidfuzz-3.14.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ebd1a18e2e47bc0b292a07e6ed9c3642f8aaa672d12253885f599b50807a4f9", size = 4251709, upload-time = "2026-04-07T11:14:32.451Z" }, - { url = "https://files.pythonhosted.org/packages/86/45/d39874901abacef325adb5b34ae416817c8486dfb4fb87c7a9b74ec5b072/rapidfuzz-3.14.5-cp312-cp312-win32.whl", hash = "sha256:9981d38a703b86f0e315a3cd229fd1906fe1d91c989ed121fb975b3c849f89f5", size = 1710069, upload-time = "2026-04-07T11:14:34.37Z" }, - { url = "https://files.pythonhosted.org/packages/85/0b/f65572c53de8a1c704bda707f63a447b67bdbe95d7cdc70d18885e191df5/rapidfuzz-3.14.5-cp312-cp312-win_amd64.whl", hash = "sha256:d8375e3da319593389727c3187ccaf3e0e84199accc530866b8e0f2b79af05e9", size = 1540630, upload-time = "2026-04-07T11:14:36.287Z" }, - { url = "https://files.pythonhosted.org/packages/5e/c3/143be3a578f989758cae516f3270d5cbb49783a7bfdf57cc27a670e00456/rapidfuzz-3.14.5-cp312-cp312-win_arm64.whl", hash = "sha256:478b59bb018a6780d73f33e38d0b3ec5e968a6c1ed42876b993dd456b7aa20e8", size = 813137, upload-time = "2026-04-07T11:14:38.289Z" }, - { url = "https://files.pythonhosted.org/packages/11/66/252803f2010ba699618cdc048b6e1f7cc1f433c08b4a9a17579b92ab0142/rapidfuzz-3.14.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebd8fd343bf8492a1e60bcb6dc99f90f74f65d98d8241a6b3e1fed225b76ecd6", size = 1940205, upload-time = "2026-04-07T11:14:40.319Z" }, - { url = "https://files.pythonhosted.org/packages/ea/59/b2afd98e41af9cd54554a4c1c423d84cdd60e6b1c0a09496f033b55f60ec/rapidfuzz-3.14.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6737b35d5af7479c5bf9710f7b17edd9d2c43128d974d25fb4ea653e42c64609", size = 1159639, upload-time = "2026-04-07T11:14:42.52Z" }, - { url = "https://files.pythonhosted.org/packages/a3/31/7aa7e62c4c516a7af322ed0c4f0774208b72d457d0cfec808bad0df12f4a/rapidfuzz-3.14.5-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b002c7994cc9f2bc9d9856f0fbaee6e8072c983873846c92f25cefba5b2a925f", size = 1367194, upload-time = "2026-04-07T11:14:44.25Z" }, - { url = "https://files.pythonhosted.org/packages/90/79/2fc252a63bc91d3c3b234d0a3a6ad4ebc460037a23cdcdaf9285f986e6c9/rapidfuzz-3.14.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17a34330cd2a538c1ce5d400b61ba358c5b72c654b928ff87b362e88f8b864c7", size = 3151805, upload-time = "2026-04-07T11:14:46.21Z" }, - { url = "https://files.pythonhosted.org/packages/17/54/0c83508f2683ea70e2d05f8527eb07328acf7bb1e9d97a3bece5702378e7/rapidfuzz-3.14.5-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:95d937e74c1a7a1287dfb03b62a827be08ede10a155cf1af73bbf47f2b73ee6e", size = 1455667, upload-time = "2026-04-07T11:14:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/71/1b/070175e873177814d58850a01ebe80e20ae11e93eb4da894d563988660fa/rapidfuzz-3.14.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:46b92a9970dcc34f0096901c792644094cab49554ac3547f35e3aebbdf0a3610", size = 2388246, upload-time = "2026-04-07T11:14:50.098Z" }, - { url = "https://files.pythonhosted.org/packages/c9/dd/77caf7aaf9c2be050ad1f128d7c24ff0f59079aa62c5f62f9df41c0af45e/rapidfuzz-3.14.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e012177c8e8a8a0754ae0d6027d63042aa5ff036d9f40f07cb3466a6082e21b8", size = 2494333, upload-time = "2026-04-07T11:14:52.303Z" }, - { url = "https://files.pythonhosted.org/packages/2c/e2/dd7e1f2aa31a8fbbfc16b0610af1d770ffaf1287490f3c8c5b1c52da264f/rapidfuzz-3.14.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a2ae6f53f99c9a0eca7a0afc5b4e45fc73bc1dd4ac74c00509031d76df80ed98", size = 4258579, upload-time = "2026-04-07T11:14:54.538Z" }, - { url = "https://files.pythonhosted.org/packages/9c/0a/ac99e1ba347ba0e85e0bb60b74231d55fb93c0eff43f2920ccb413d0be08/rapidfuzz-3.14.5-cp313-cp313-win32.whl", hash = "sha256:4a60f0057231188e3bd30216f7b4e0f279b11fa4ec818bb6c1d9f014d1562fbc", size = 1709231, upload-time = "2026-04-07T11:14:56.524Z" }, - { url = "https://files.pythonhosted.org/packages/cf/cb/0e251d731b3166378644238e8f0cf9e89858c024e19f75ca9f7e3ae83fd5/rapidfuzz-3.14.5-cp313-cp313-win_amd64.whl", hash = "sha256:11bfc2ed8fbe4ab86bd516fadefab126f90e6dcadffa761739fcb304707dfd35", size = 1538519, upload-time = "2026-04-07T11:14:58.635Z" }, - { url = "https://files.pythonhosted.org/packages/30/6f/4548132acc947db6d5346a248e44a8b3a22d608ef30e770fb578caaf2d00/rapidfuzz-3.14.5-cp313-cp313-win_arm64.whl", hash = "sha256:b486b5218808f6f4dc471b114b1054e63553db69705c97da0271f47bd706aedd", size = 812628, upload-time = "2026-04-07T11:15:00.552Z" }, - { url = "https://files.pythonhosted.org/packages/00/60/69b177577290c5eab892c6f75fe89c3aff3f9ae80298a78d9372b1cecb9a/rapidfuzz-3.14.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:39ef8658aaf67d51667e7bdaf7096f432333377d8302ac43c70b5df8a4cf89b8", size = 1970231, upload-time = "2026-04-07T11:15:02.603Z" }, - { url = "https://files.pythonhosted.org/packages/48/38/2fd790052659cc4e2907b63c25433f0987864b445c1aeec1a302ef5ad948/rapidfuzz-3.14.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ad37a0be705b544af6296da8edddc260d10a8ae5462530fc9991f66498bb1f9", size = 1194394, upload-time = "2026-04-07T11:15:04.572Z" }, - { url = "https://files.pythonhosted.org/packages/80/f4/28430ad8472fc3536e8ebd51a864a226e979cfe924c6e3f83d111373aa74/rapidfuzz-3.14.5-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d45e06f60729e07d9b20c205f7e5cff90b6ef2584e852eecf46e045aea69627d", size = 1377051, upload-time = "2026-04-07T11:15:06.728Z" }, - { url = "https://files.pythonhosted.org/packages/77/7e/9aeacabcfd1e77397968362e5b98fe14248b8307011136b17daf99752a8e/rapidfuzz-3.14.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e52da10236aa6212de71b9e170bace65b64b129c0dea7fc243d6c9ce976f5074", size = 3160565, upload-time = "2026-04-07T11:15:08.667Z" }, - { url = "https://files.pythonhosted.org/packages/56/f4/db4dd7be0cd2f2022117ac5407d905f435d60e48baaea313a567ad27e865/rapidfuzz-3.14.5-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:440d30faaf682ca496170a7f0cc5453ec942e3e079f0fd802c9a7f938dfb50a3", size = 1442113, upload-time = "2026-04-07T11:15:11.138Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/0e9f6aa57f3e32a767216f797e56dc96b720fcecfb9d8ee907ecc82f8d66/rapidfuzz-3.14.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:56227a61fd3d17b0cd9793132431f3a3d07c8654be96794ba9f89fe0fc8b2d09", size = 2396618, upload-time = "2026-04-07T11:15:13.154Z" }, - { url = "https://files.pythonhosted.org/packages/60/94/44a78e39ffce17cbdd3e2b53b696acc751d5d153be0f499d052b07a4d904/rapidfuzz-3.14.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:2e83cd2e25bb4edd97b689d9979d9c3acccdaaf26ceac08212ceece202febcfa", size = 2478220, upload-time = "2026-04-07T11:15:15.193Z" }, - { url = "https://files.pythonhosted.org/packages/dd/df/454311469a09a507e9d784a35796742bec22e4cebe75551e2da4e0e290fd/rapidfuzz-3.14.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:af3b859726cd3374287e405e14b9634563c078c5531a4f62375508addebddad1", size = 4265027, upload-time = "2026-04-07T11:15:17.28Z" }, - { url = "https://files.pythonhosted.org/packages/fc/01/175465a9ab3e3b70ba669058372f009d1d49c1746e2dcd56b69df188d3a5/rapidfuzz-3.14.5-cp313-cp313t-win32.whl", hash = "sha256:8ce1d850b3c0178440efde9e884d98421b5e87ff925f364d6d79e23910d7593f", size = 1766814, upload-time = "2026-04-07T11:15:19.687Z" }, - { url = "https://files.pythonhosted.org/packages/1b/a0/a9b84a47af06ebed94a1439eb2f02adebfb8628bcd30af1fe3e02f5ef56c/rapidfuzz-3.14.5-cp313-cp313t-win_amd64.whl", hash = "sha256:c84af70bcf34e99aee894e46a0f1ac77f17d0ef828179c387407642e2466d28a", size = 1582448, upload-time = "2026-04-07T11:15:21.98Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f1/5937800238b3f8248e70860d79f69ba8f73e764fff47e36bc9e2f26dbcc6/rapidfuzz-3.14.5-cp313-cp313t-win_arm64.whl", hash = "sha256:aac0ad28c686a5e72b81668b906c030ee28050b244544b8af68e12fb32543895", size = 832932, upload-time = "2026-04-07T11:15:24.358Z" }, - { url = "https://files.pythonhosted.org/packages/81/41/aa3ffb3355e62e1bf91f6599b3092e866bc88487a07c524004943c7676df/rapidfuzz-3.14.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1a31cc6d7d03e7318a0974c038959c59e19c752b81115f2e9138b3331cd64d45", size = 1943327, upload-time = "2026-04-07T11:15:26.266Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e1/c2141f1840a41e07ad2db6f724945f8f8ff3065463899a22939152dd6e09/rapidfuzz-3.14.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0298d357e2bc59d572da4db0bc631009b6f8f6c9bc8c11e99a12b833f16b6575", size = 1161755, upload-time = "2026-04-07T11:15:28.659Z" }, - { url = "https://files.pythonhosted.org/packages/ca/07/66e753eeaa353161d1d331b7dd517bb349b0bacfebe8496d7b26be26f81f/rapidfuzz-3.14.5-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59b3dba758661a318995655435c6ab20a04ade79fa51e75bc8dc107cac8df280", size = 1376571, upload-time = "2026-04-07T11:15:31.225Z" }, - { url = "https://files.pythonhosted.org/packages/c8/85/9535df0b78ba51f478c9ce7eb6d1f85535cc31fe356773b48fd9d3e563ca/rapidfuzz-3.14.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4900143d82071bdda533b00300c40b14b963ff826b3642cc463b6dd0f036585e", size = 3156468, upload-time = "2026-04-07T11:15:33.428Z" }, - { url = "https://files.pythonhosted.org/packages/81/ee/b667eb93bba6dc4e0de658edd778e1619dc4d6aab68fa5e5c7f075152735/rapidfuzz-3.14.5-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:feedf219672eef83ea6be6f3bb093bba396a8560fc75be85ba225f082903df0a", size = 1458311, upload-time = "2026-04-07T11:15:35.557Z" }, - { url = "https://files.pythonhosted.org/packages/7d/ce/479074f5624364a48df3403c538797ef22d3ac49c19dc76c3f79fcdcc70c/rapidfuzz-3.14.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:419e4397a36e2665ec992d8d64c20ba4b2a42500c76ecadeca78a4f19cb9cc32", size = 2398228, upload-time = "2026-04-07T11:15:37.669Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/a8982f649150fffbdcd6f17565974501f6ab33b2795267bffbd4a7ba905b/rapidfuzz-3.14.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:97131ab2be39043054ee28d99e09efe316e6d53449b7e962dfcf3c2de8b2b246", size = 2497226, upload-time = "2026-04-07T11:15:39.857Z" }, - { url = "https://files.pythonhosted.org/packages/19/52/5267c03ef6759831b7d4625a0c9c06e87baa2fae084b61ac9c388858317b/rapidfuzz-3.14.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:593c00dac4e30231c35bf3b4f1da8ec0998762e9e94425586a5d636fcd57f9d0", size = 4262283, upload-time = "2026-04-07T11:15:42.279Z" }, - { url = "https://files.pythonhosted.org/packages/71/c0/2579f343a97f5254c43bb5853baccc01488357dcb64a27bcb869b7888a4a/rapidfuzz-3.14.5-cp314-cp314-win32.whl", hash = "sha256:0084b687b02b4e569b46d8d6d4ad25659528e6081cd6d067ca453a69035f07e4", size = 1744614, upload-time = "2026-04-07T11:15:44.498Z" }, - { url = "https://files.pythonhosted.org/packages/17/eb/8edfed1e80119dc9c35b11df4bc701eea85622ad681fff0263b6961d3224/rapidfuzz-3.14.5-cp314-cp314-win_amd64.whl", hash = "sha256:5dfa89d78f22cd773054caff44827b846161a29f2dcf7e78b8f90d086621e502", size = 1588971, upload-time = "2026-04-07T11:15:46.86Z" }, - { url = "https://files.pythonhosted.org/packages/f6/04/5676df93c85cfa57a3045d8047318df9f3cd58c7b8a99340dd95f874795e/rapidfuzz-3.14.5-cp314-cp314-win_arm64.whl", hash = "sha256:67f3f9d2b444268ab53e47d31bab89954888d23c04c6789f2c727e51fe4b1d13", size = 834985, upload-time = "2026-04-07T11:15:49.411Z" }, - { url = "https://files.pythonhosted.org/packages/f7/0d/4a8988cea658fe335048ddef8c876addff1b6daa3c9ca8ad65a5a2196e69/rapidfuzz-3.14.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:77eac0526899b3c3ad1454bb2b03cdb491d67358ec8ef0c9c48bd61b632b431d", size = 1972517, upload-time = "2026-04-07T11:15:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a3/f5cfd9965a9d9a9e32249159797c47b5d6299ea6d1629f9126b25f1c10a3/rapidfuzz-3.14.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b9c6bd754d11f6e78ac54e3d86b4b11dc1ba2f13e5fc958899574532897f5a99", size = 1196056, upload-time = "2026-04-07T11:15:54.292Z" }, - { url = "https://files.pythonhosted.org/packages/64/07/561c2e40cfd10e6630a7b0ac5a2a813aef50d944bcd1f3d260319d659d5b/rapidfuzz-3.14.5-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:738c96944d076deeaff70e92b65696ab4f7ecb8081d7791c5403a3257dfaf8ff", size = 1374732, upload-time = "2026-04-07T11:15:56.584Z" }, - { url = "https://files.pythonhosted.org/packages/c2/39/123bb94fee40e2fb3b7c49b80827c7ef42d838e18def3fc2fef5a3cf817a/rapidfuzz-3.14.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4c1bca487a17fe4226b4ffb2d30e799d2b274d692cffa76bd0746f56235fca3", size = 3166902, upload-time = "2026-04-07T11:15:58.768Z" }, - { url = "https://files.pythonhosted.org/packages/75/0a/45716fafc9fd2e028cf20b5ac5bc704887081cd312f84edb0e325599414b/rapidfuzz-3.14.5-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:af6a90a4ed2a48fa1a2d17e9d824e6c7c950bea5bad0b707c77fd55751e6bfef", size = 1452130, upload-time = "2026-04-07T11:16:01.453Z" }, - { url = "https://files.pythonhosted.org/packages/ca/49/4e96c413114398481c0a5b0086af32c364a18613c9a2ea578d17c4bea4ee/rapidfuzz-3.14.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bf5018938208d4597b2e679a4f8cff9fd252f1df53583130ae56281a21801b64", size = 2396308, upload-time = "2026-04-07T11:16:03.588Z" }, - { url = "https://files.pythonhosted.org/packages/89/b7/49fea9fc6878d59bd259d01dd1972d9b86117992b1c66d9b16f0a65273c3/rapidfuzz-3.14.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c0919d1f89ddf91129906705723118ea09754171e4116f5a5dbc667c7bc9b261", size = 2488210, upload-time = "2026-04-07T11:16:05.871Z" }, - { url = "https://files.pythonhosted.org/packages/0c/44/a1f732b93ffacbdad077b7c801149549b2938e1bece6addb5ad85ed74df8/rapidfuzz-3.14.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:93d8da883a35116d6813432177f35e570db5b0a5e30ecb0cbd7cb39c815735df", size = 4270621, upload-time = "2026-04-07T11:16:08.483Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ce/ff942d19fce5385054650bb71a58495ddda299d94661ccc4e6e7fa44868b/rapidfuzz-3.14.5-cp314-cp314t-win32.whl", hash = "sha256:0f23e37019ec07712d58976b1ab2b889f8649a7f7c2f626a2f34ea9139e79279", size = 1803950, upload-time = "2026-04-07T11:16:10.873Z" }, - { url = "https://files.pythonhosted.org/packages/5c/0f/9aafc63f9661222b819b391c187eed29fc90ad5935f9690e5ecc2d2047a4/rapidfuzz-3.14.5-cp314-cp314t-win_amd64.whl", hash = "sha256:7d5ca9c7832e6879a707296d1463685f7c243a27846227044504741640caec66", size = 1632357, upload-time = "2026-04-07T11:16:13.1Z" }, - { url = "https://files.pythonhosted.org/packages/70/a6/51fc1b0e61e3326e1c68a61cfd0c6b3c34c843681c4b1eefbf0596f59162/rapidfuzz-3.14.5-cp314-cp314t-win_arm64.whl", hash = "sha256:3e91dcd2549b8f8d843f98ba03a17e01f3d8b72ce942adbbb6761bc58ffce813", size = 855409, upload-time = "2026-04-07T11:16:15.787Z" }, - { url = "https://files.pythonhosted.org/packages/d9/ee/e71853bf82846c5c2174b924b71d8e8099fb05ff87c958a720380b434ba3/rapidfuzz-3.14.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:578e6051f6d5e6200c259b47a103cf06bb875ab5814d17333fc0b5c290b22f4c", size = 1888603, upload-time = "2026-04-07T11:16:18.223Z" }, - { url = "https://files.pythonhosted.org/packages/36/82/40f67b730f32be2ebad9f62add1571c754f52249254b2e88af094b907eee/rapidfuzz-3.14.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbf1b8bb2695415b347f3727da1addca2acb82c9b97ac86bebf8b1bead1eb12d", size = 1120599, upload-time = "2026-04-07T11:16:20.682Z" }, - { url = "https://files.pythonhosted.org/packages/ef/9f/a3635cc4ec8fc6e14b46e7db1f7f8763d8c4bef33dcc124eea2e6cb2c8f3/rapidfuzz-3.14.5-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f4a8f5cc84c7ad6bffa0e9947b33eb343ad66e6b53e94fe54378a5508c5ed53", size = 1348524, upload-time = "2026-04-07T11:16:23.451Z" }, - { url = "https://files.pythonhosted.org/packages/cc/1b/2b229520f0b48464cfcd7aa758f74551d12c9bc4ab544022a60210aab064/rapidfuzz-3.14.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c6d85283629646fa87acc22c66b30ea9d4de7f6fdf887daa2e30fa041829b5", size = 3099302, upload-time = "2026-04-07T11:16:25.858Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b5/363906b1064fc6fe611783a61764927bbd91919aaaabe8cba82151ca93ef/rapidfuzz-3.14.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:dfef96543ced67d9513a422755db422ae1dc34dade0a1485e0b43e7342ed3ebf", size = 1509889, upload-time = "2026-04-07T11:16:28.487Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/2c/21/ef6157213316e85790041254259907eb722e00b03480256c0545d98acd33/rapidfuzz-3.14.5.tar.gz", hash = "sha256:ba10ac57884ce82112f7ed910b67e7fb6072d8ef2c06e30dc63c0f604a112e0e", size = 57901753 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/f9/3c41a7be8855803f4f6c713b472226a98d31d41869d98f64f4ca790510d6/rapidfuzz-3.14.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e251126d48615e1f02b4a178f2cd0cd4f0332b8a019c01a2e10480f7552554b4", size = 1952372 }, + { url = "https://files.pythonhosted.org/packages/9e/89/c2557e37531d03465193bff0ab9de70b468420a807d71a26a65100635459/rapidfuzz-3.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ab449c9abd0d4e1f8145dce0798a4c822a1a1933d613c764a641bea88b8bdab", size = 1159782 }, + { url = "https://files.pythonhosted.org/packages/1a/b2/ffeeb7eca1a897d51b998f4c0ef0281696c3b06abcca4f88f9def708ffe1/rapidfuzz-3.14.5-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb2829fedd672dd7107267189dabe2bbe07972801d636014417c6861eb89e358", size = 1383677 }, + { url = "https://files.pythonhosted.org/packages/6b/d0/4539e42a2d596e068f7738f279638a4a74edd1fbb6f8594e2458058979c6/rapidfuzz-3.14.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d50e5861872935fece391351cbb5ba21d1bced277cf5e1143d207a0a35f1925", size = 3168906 }, + { url = "https://files.pythonhosted.org/packages/5e/1c/3ec897eb9d8b05308aa8ef6ae4ed64b088ad521a3f9d8ff469e7e97bc2b0/rapidfuzz-3.14.5-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:7092a216728f80c960bd6b3807275d1ee318b168986bd5dc523349581d4890b8", size = 1478176 }, + { url = "https://files.pythonhosted.org/packages/ab/ba/970c03a12ce20a5399e22afe9f8932fd4cd1265b8a8461d0e63b00eb4eae/rapidfuzz-3.14.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9669753caef7fdc6529f6adcc5883ed98d65976445d9322e7dbdb6b697feee13", size = 2402441 }, + { url = "https://files.pythonhosted.org/packages/81/93/61d351cae60c1d0e21ba5ff1a1015ad045539ed215da9d6e302204ed887a/rapidfuzz-3.14.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:823b1b9d9230809d8edcc18872770764bfe8ef4357995e16744047c8ccf0e489", size = 2511628 }, + { url = "https://files.pythonhosted.org/packages/87/52/374d2d4f60fd98155142a869323aa221e30868cfa1f15171a0f64070c247/rapidfuzz-3.14.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f0b2af76b7e7060c09e1a0dfa9410eb19369cbe6164509bff2ef94094b54d2b6", size = 4275480 }, + { url = "https://files.pythonhosted.org/packages/d8/04/82e7989bc9ec20a15b720a335c5cb6b0724bf6582013898f90a3280cfccd/rapidfuzz-3.14.5-cp311-cp311-win32.whl", hash = "sha256:c5801a89604c65ab4cc9e91b23bc4076d0ca80efd8c976fb63843d7879a85d7f", size = 1725627 }, + { url = "https://files.pythonhosted.org/packages/b9/b5/eca8ac5609bc9bcb02bb6ff87fa5983cc92b8772d66a431556ab8a8c178f/rapidfuzz-3.14.5-cp311-cp311-win_amd64.whl", hash = "sha256:d7ca16637c0ede8243f84074044bd0b2335a0341421f8227c85756de2d18c819", size = 1545977 }, + { url = "https://files.pythonhosted.org/packages/ca/e1/dbf318de28f65fa2cdd0a9dfbdee380f8199eb83b19259bc4f8592551b4e/rapidfuzz-3.14.5-cp311-cp311-win_arm64.whl", hash = "sha256:8c90cdf8516d9057e502aa6003cea71cf5ec27cc44699ca52412b502a04761bb", size = 816827 }, + { url = "https://files.pythonhosted.org/packages/d3/e3/574435c6aafb80254c191ef40d7aca2cb2bb97a095ec9395e9fa59ac307a/rapidfuzz-3.14.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0d3378f471ef440473a396ce2f8e97ee12f89a78b495540e0a5617bbfe895638", size = 1944601 }, + { url = "https://files.pythonhosted.org/packages/d0/1f/fbad3102a255ecc112ce9a7e779bacab7fd14398217be8868dc9082ba363/rapidfuzz-3.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e910eebca9fd0eba245c0555e764597e8a0cccb673a92da2dc2397050725f48", size = 1164293 }, + { url = "https://files.pythonhosted.org/packages/88/37/a3eb7ff6121ed3a5f199a8c38cc86c8e481816f879cb0e0b738b078c9a7e/rapidfuzz-3.14.5-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01550fe5f60fd176aa66b7611289d46dc4aa4b1b904874c7b6d1d54e581c5ec1", size = 1371999 }, + { url = "https://files.pythonhosted.org/packages/79/72/97a9728c711c7c1b06e107d3f0623880fb4ef90e147ed13c551a1730e7cc/rapidfuzz-3.14.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48bee0b91bebfaec41e1081e351000659ab7570cc4598d617aa04d5bf827f9e6", size = 3145715 }, + { url = "https://files.pythonhosted.org/packages/ed/54/d5caabbea233ac90c286c87c260e49d7641467e87438a18d858e41c82e91/rapidfuzz-3.14.5-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:7e580cb04ad849ae9b786fa21383c6b994b6e6c1444ad1cb9f22392759d72741", size = 1456304 }, + { url = "https://files.pythonhosted.org/packages/fc/a7/2d1a81250ac8c01a0100c026018e76f0e7a097ff63e4c553e02a6938c6fb/rapidfuzz-3.14.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:09d6c9ba091854f07817055d795d604179c12a8f308ba4c7d56f3719dfea1646", size = 2389089 }, + { url = "https://files.pythonhosted.org/packages/65/0d/c47c3872203ae88e6506997c0b576ad731f5261daa25d559be09c9756658/rapidfuzz-3.14.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1e989f86113be66574113b9c7bdf4793f3f863d248e47d911b355e05ca6b6b10", size = 2493404 }, + { url = "https://files.pythonhosted.org/packages/8f/2f/71e0a5a3130792146c8a200a2dd1e52aa16f7c1074012e17f2601eea9a90/rapidfuzz-3.14.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ebd1a18e2e47bc0b292a07e6ed9c3642f8aaa672d12253885f599b50807a4f9", size = 4251709 }, + { url = "https://files.pythonhosted.org/packages/86/45/d39874901abacef325adb5b34ae416817c8486dfb4fb87c7a9b74ec5b072/rapidfuzz-3.14.5-cp312-cp312-win32.whl", hash = "sha256:9981d38a703b86f0e315a3cd229fd1906fe1d91c989ed121fb975b3c849f89f5", size = 1710069 }, + { url = "https://files.pythonhosted.org/packages/85/0b/f65572c53de8a1c704bda707f63a447b67bdbe95d7cdc70d18885e191df5/rapidfuzz-3.14.5-cp312-cp312-win_amd64.whl", hash = "sha256:d8375e3da319593389727c3187ccaf3e0e84199accc530866b8e0f2b79af05e9", size = 1540630 }, + { url = "https://files.pythonhosted.org/packages/5e/c3/143be3a578f989758cae516f3270d5cbb49783a7bfdf57cc27a670e00456/rapidfuzz-3.14.5-cp312-cp312-win_arm64.whl", hash = "sha256:478b59bb018a6780d73f33e38d0b3ec5e968a6c1ed42876b993dd456b7aa20e8", size = 813137 }, + { url = "https://files.pythonhosted.org/packages/11/66/252803f2010ba699618cdc048b6e1f7cc1f433c08b4a9a17579b92ab0142/rapidfuzz-3.14.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebd8fd343bf8492a1e60bcb6dc99f90f74f65d98d8241a6b3e1fed225b76ecd6", size = 1940205 }, + { url = "https://files.pythonhosted.org/packages/ea/59/b2afd98e41af9cd54554a4c1c423d84cdd60e6b1c0a09496f033b55f60ec/rapidfuzz-3.14.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6737b35d5af7479c5bf9710f7b17edd9d2c43128d974d25fb4ea653e42c64609", size = 1159639 }, + { url = "https://files.pythonhosted.org/packages/a3/31/7aa7e62c4c516a7af322ed0c4f0774208b72d457d0cfec808bad0df12f4a/rapidfuzz-3.14.5-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b002c7994cc9f2bc9d9856f0fbaee6e8072c983873846c92f25cefba5b2a925f", size = 1367194 }, + { url = "https://files.pythonhosted.org/packages/90/79/2fc252a63bc91d3c3b234d0a3a6ad4ebc460037a23cdcdaf9285f986e6c9/rapidfuzz-3.14.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17a34330cd2a538c1ce5d400b61ba358c5b72c654b928ff87b362e88f8b864c7", size = 3151805 }, + { url = "https://files.pythonhosted.org/packages/17/54/0c83508f2683ea70e2d05f8527eb07328acf7bb1e9d97a3bece5702378e7/rapidfuzz-3.14.5-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:95d937e74c1a7a1287dfb03b62a827be08ede10a155cf1af73bbf47f2b73ee6e", size = 1455667 }, + { url = "https://files.pythonhosted.org/packages/71/1b/070175e873177814d58850a01ebe80e20ae11e93eb4da894d563988660fa/rapidfuzz-3.14.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:46b92a9970dcc34f0096901c792644094cab49554ac3547f35e3aebbdf0a3610", size = 2388246 }, + { url = "https://files.pythonhosted.org/packages/c9/dd/77caf7aaf9c2be050ad1f128d7c24ff0f59079aa62c5f62f9df41c0af45e/rapidfuzz-3.14.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e012177c8e8a8a0754ae0d6027d63042aa5ff036d9f40f07cb3466a6082e21b8", size = 2494333 }, + { url = "https://files.pythonhosted.org/packages/2c/e2/dd7e1f2aa31a8fbbfc16b0610af1d770ffaf1287490f3c8c5b1c52da264f/rapidfuzz-3.14.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a2ae6f53f99c9a0eca7a0afc5b4e45fc73bc1dd4ac74c00509031d76df80ed98", size = 4258579 }, + { url = "https://files.pythonhosted.org/packages/9c/0a/ac99e1ba347ba0e85e0bb60b74231d55fb93c0eff43f2920ccb413d0be08/rapidfuzz-3.14.5-cp313-cp313-win32.whl", hash = "sha256:4a60f0057231188e3bd30216f7b4e0f279b11fa4ec818bb6c1d9f014d1562fbc", size = 1709231 }, + { url = "https://files.pythonhosted.org/packages/cf/cb/0e251d731b3166378644238e8f0cf9e89858c024e19f75ca9f7e3ae83fd5/rapidfuzz-3.14.5-cp313-cp313-win_amd64.whl", hash = "sha256:11bfc2ed8fbe4ab86bd516fadefab126f90e6dcadffa761739fcb304707dfd35", size = 1538519 }, + { url = "https://files.pythonhosted.org/packages/30/6f/4548132acc947db6d5346a248e44a8b3a22d608ef30e770fb578caaf2d00/rapidfuzz-3.14.5-cp313-cp313-win_arm64.whl", hash = "sha256:b486b5218808f6f4dc471b114b1054e63553db69705c97da0271f47bd706aedd", size = 812628 }, + { url = "https://files.pythonhosted.org/packages/00/60/69b177577290c5eab892c6f75fe89c3aff3f9ae80298a78d9372b1cecb9a/rapidfuzz-3.14.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:39ef8658aaf67d51667e7bdaf7096f432333377d8302ac43c70b5df8a4cf89b8", size = 1970231 }, + { url = "https://files.pythonhosted.org/packages/48/38/2fd790052659cc4e2907b63c25433f0987864b445c1aeec1a302ef5ad948/rapidfuzz-3.14.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ad37a0be705b544af6296da8edddc260d10a8ae5462530fc9991f66498bb1f9", size = 1194394 }, + { url = "https://files.pythonhosted.org/packages/80/f4/28430ad8472fc3536e8ebd51a864a226e979cfe924c6e3f83d111373aa74/rapidfuzz-3.14.5-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d45e06f60729e07d9b20c205f7e5cff90b6ef2584e852eecf46e045aea69627d", size = 1377051 }, + { url = "https://files.pythonhosted.org/packages/77/7e/9aeacabcfd1e77397968362e5b98fe14248b8307011136b17daf99752a8e/rapidfuzz-3.14.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e52da10236aa6212de71b9e170bace65b64b129c0dea7fc243d6c9ce976f5074", size = 3160565 }, + { url = "https://files.pythonhosted.org/packages/56/f4/db4dd7be0cd2f2022117ac5407d905f435d60e48baaea313a567ad27e865/rapidfuzz-3.14.5-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:440d30faaf682ca496170a7f0cc5453ec942e3e079f0fd802c9a7f938dfb50a3", size = 1442113 }, + { url = "https://files.pythonhosted.org/packages/a4/99/0e9f6aa57f3e32a767216f797e56dc96b720fcecfb9d8ee907ecc82f8d66/rapidfuzz-3.14.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:56227a61fd3d17b0cd9793132431f3a3d07c8654be96794ba9f89fe0fc8b2d09", size = 2396618 }, + { url = "https://files.pythonhosted.org/packages/60/94/44a78e39ffce17cbdd3e2b53b696acc751d5d153be0f499d052b07a4d904/rapidfuzz-3.14.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:2e83cd2e25bb4edd97b689d9979d9c3acccdaaf26ceac08212ceece202febcfa", size = 2478220 }, + { url = "https://files.pythonhosted.org/packages/dd/df/454311469a09a507e9d784a35796742bec22e4cebe75551e2da4e0e290fd/rapidfuzz-3.14.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:af3b859726cd3374287e405e14b9634563c078c5531a4f62375508addebddad1", size = 4265027 }, + { url = "https://files.pythonhosted.org/packages/fc/01/175465a9ab3e3b70ba669058372f009d1d49c1746e2dcd56b69df188d3a5/rapidfuzz-3.14.5-cp313-cp313t-win32.whl", hash = "sha256:8ce1d850b3c0178440efde9e884d98421b5e87ff925f364d6d79e23910d7593f", size = 1766814 }, + { url = "https://files.pythonhosted.org/packages/1b/a0/a9b84a47af06ebed94a1439eb2f02adebfb8628bcd30af1fe3e02f5ef56c/rapidfuzz-3.14.5-cp313-cp313t-win_amd64.whl", hash = "sha256:c84af70bcf34e99aee894e46a0f1ac77f17d0ef828179c387407642e2466d28a", size = 1582448 }, + { url = "https://files.pythonhosted.org/packages/1e/f1/5937800238b3f8248e70860d79f69ba8f73e764fff47e36bc9e2f26dbcc6/rapidfuzz-3.14.5-cp313-cp313t-win_arm64.whl", hash = "sha256:aac0ad28c686a5e72b81668b906c030ee28050b244544b8af68e12fb32543895", size = 832932 }, + { url = "https://files.pythonhosted.org/packages/81/41/aa3ffb3355e62e1bf91f6599b3092e866bc88487a07c524004943c7676df/rapidfuzz-3.14.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1a31cc6d7d03e7318a0974c038959c59e19c752b81115f2e9138b3331cd64d45", size = 1943327 }, + { url = "https://files.pythonhosted.org/packages/2d/e1/c2141f1840a41e07ad2db6f724945f8f8ff3065463899a22939152dd6e09/rapidfuzz-3.14.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0298d357e2bc59d572da4db0bc631009b6f8f6c9bc8c11e99a12b833f16b6575", size = 1161755 }, + { url = "https://files.pythonhosted.org/packages/ca/07/66e753eeaa353161d1d331b7dd517bb349b0bacfebe8496d7b26be26f81f/rapidfuzz-3.14.5-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59b3dba758661a318995655435c6ab20a04ade79fa51e75bc8dc107cac8df280", size = 1376571 }, + { url = "https://files.pythonhosted.org/packages/c8/85/9535df0b78ba51f478c9ce7eb6d1f85535cc31fe356773b48fd9d3e563ca/rapidfuzz-3.14.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4900143d82071bdda533b00300c40b14b963ff826b3642cc463b6dd0f036585e", size = 3156468 }, + { url = "https://files.pythonhosted.org/packages/81/ee/b667eb93bba6dc4e0de658edd778e1619dc4d6aab68fa5e5c7f075152735/rapidfuzz-3.14.5-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:feedf219672eef83ea6be6f3bb093bba396a8560fc75be85ba225f082903df0a", size = 1458311 }, + { url = "https://files.pythonhosted.org/packages/7d/ce/479074f5624364a48df3403c538797ef22d3ac49c19dc76c3f79fcdcc70c/rapidfuzz-3.14.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:419e4397a36e2665ec992d8d64c20ba4b2a42500c76ecadeca78a4f19cb9cc32", size = 2398228 }, + { url = "https://files.pythonhosted.org/packages/0b/15/a8982f649150fffbdcd6f17565974501f6ab33b2795267bffbd4a7ba905b/rapidfuzz-3.14.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:97131ab2be39043054ee28d99e09efe316e6d53449b7e962dfcf3c2de8b2b246", size = 2497226 }, + { url = "https://files.pythonhosted.org/packages/19/52/5267c03ef6759831b7d4625a0c9c06e87baa2fae084b61ac9c388858317b/rapidfuzz-3.14.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:593c00dac4e30231c35bf3b4f1da8ec0998762e9e94425586a5d636fcd57f9d0", size = 4262283 }, + { url = "https://files.pythonhosted.org/packages/71/c0/2579f343a97f5254c43bb5853baccc01488357dcb64a27bcb869b7888a4a/rapidfuzz-3.14.5-cp314-cp314-win32.whl", hash = "sha256:0084b687b02b4e569b46d8d6d4ad25659528e6081cd6d067ca453a69035f07e4", size = 1744614 }, + { url = "https://files.pythonhosted.org/packages/17/eb/8edfed1e80119dc9c35b11df4bc701eea85622ad681fff0263b6961d3224/rapidfuzz-3.14.5-cp314-cp314-win_amd64.whl", hash = "sha256:5dfa89d78f22cd773054caff44827b846161a29f2dcf7e78b8f90d086621e502", size = 1588971 }, + { url = "https://files.pythonhosted.org/packages/f6/04/5676df93c85cfa57a3045d8047318df9f3cd58c7b8a99340dd95f874795e/rapidfuzz-3.14.5-cp314-cp314-win_arm64.whl", hash = "sha256:67f3f9d2b444268ab53e47d31bab89954888d23c04c6789f2c727e51fe4b1d13", size = 834985 }, + { url = "https://files.pythonhosted.org/packages/f7/0d/4a8988cea658fe335048ddef8c876addff1b6daa3c9ca8ad65a5a2196e69/rapidfuzz-3.14.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:77eac0526899b3c3ad1454bb2b03cdb491d67358ec8ef0c9c48bd61b632b431d", size = 1972517 }, + { url = "https://files.pythonhosted.org/packages/1c/a3/f5cfd9965a9d9a9e32249159797c47b5d6299ea6d1629f9126b25f1c10a3/rapidfuzz-3.14.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b9c6bd754d11f6e78ac54e3d86b4b11dc1ba2f13e5fc958899574532897f5a99", size = 1196056 }, + { url = "https://files.pythonhosted.org/packages/64/07/561c2e40cfd10e6630a7b0ac5a2a813aef50d944bcd1f3d260319d659d5b/rapidfuzz-3.14.5-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:738c96944d076deeaff70e92b65696ab4f7ecb8081d7791c5403a3257dfaf8ff", size = 1374732 }, + { url = "https://files.pythonhosted.org/packages/c2/39/123bb94fee40e2fb3b7c49b80827c7ef42d838e18def3fc2fef5a3cf817a/rapidfuzz-3.14.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4c1bca487a17fe4226b4ffb2d30e799d2b274d692cffa76bd0746f56235fca3", size = 3166902 }, + { url = "https://files.pythonhosted.org/packages/75/0a/45716fafc9fd2e028cf20b5ac5bc704887081cd312f84edb0e325599414b/rapidfuzz-3.14.5-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:af6a90a4ed2a48fa1a2d17e9d824e6c7c950bea5bad0b707c77fd55751e6bfef", size = 1452130 }, + { url = "https://files.pythonhosted.org/packages/ca/49/4e96c413114398481c0a5b0086af32c364a18613c9a2ea578d17c4bea4ee/rapidfuzz-3.14.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bf5018938208d4597b2e679a4f8cff9fd252f1df53583130ae56281a21801b64", size = 2396308 }, + { url = "https://files.pythonhosted.org/packages/89/b7/49fea9fc6878d59bd259d01dd1972d9b86117992b1c66d9b16f0a65273c3/rapidfuzz-3.14.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c0919d1f89ddf91129906705723118ea09754171e4116f5a5dbc667c7bc9b261", size = 2488210 }, + { url = "https://files.pythonhosted.org/packages/0c/44/a1f732b93ffacbdad077b7c801149549b2938e1bece6addb5ad85ed74df8/rapidfuzz-3.14.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:93d8da883a35116d6813432177f35e570db5b0a5e30ecb0cbd7cb39c815735df", size = 4270621 }, + { url = "https://files.pythonhosted.org/packages/bb/ce/ff942d19fce5385054650bb71a58495ddda299d94661ccc4e6e7fa44868b/rapidfuzz-3.14.5-cp314-cp314t-win32.whl", hash = "sha256:0f23e37019ec07712d58976b1ab2b889f8649a7f7c2f626a2f34ea9139e79279", size = 1803950 }, + { url = "https://files.pythonhosted.org/packages/5c/0f/9aafc63f9661222b819b391c187eed29fc90ad5935f9690e5ecc2d2047a4/rapidfuzz-3.14.5-cp314-cp314t-win_amd64.whl", hash = "sha256:7d5ca9c7832e6879a707296d1463685f7c243a27846227044504741640caec66", size = 1632357 }, + { url = "https://files.pythonhosted.org/packages/70/a6/51fc1b0e61e3326e1c68a61cfd0c6b3c34c843681c4b1eefbf0596f59162/rapidfuzz-3.14.5-cp314-cp314t-win_arm64.whl", hash = "sha256:3e91dcd2549b8f8d843f98ba03a17e01f3d8b72ce942adbbb6761bc58ffce813", size = 855409 }, + { url = "https://files.pythonhosted.org/packages/d9/ee/e71853bf82846c5c2174b924b71d8e8099fb05ff87c958a720380b434ba3/rapidfuzz-3.14.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:578e6051f6d5e6200c259b47a103cf06bb875ab5814d17333fc0b5c290b22f4c", size = 1888603 }, + { url = "https://files.pythonhosted.org/packages/36/82/40f67b730f32be2ebad9f62add1571c754f52249254b2e88af094b907eee/rapidfuzz-3.14.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbf1b8bb2695415b347f3727da1addca2acb82c9b97ac86bebf8b1bead1eb12d", size = 1120599 }, + { url = "https://files.pythonhosted.org/packages/ef/9f/a3635cc4ec8fc6e14b46e7db1f7f8763d8c4bef33dcc124eea2e6cb2c8f3/rapidfuzz-3.14.5-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f4a8f5cc84c7ad6bffa0e9947b33eb343ad66e6b53e94fe54378a5508c5ed53", size = 1348524 }, + { url = "https://files.pythonhosted.org/packages/cc/1b/2b229520f0b48464cfcd7aa758f74551d12c9bc4ab544022a60210aab064/rapidfuzz-3.14.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:97c6d85283629646fa87acc22c66b30ea9d4de7f6fdf887daa2e30fa041829b5", size = 3099302 }, + { url = "https://files.pythonhosted.org/packages/aa/b5/363906b1064fc6fe611783a61764927bbd91919aaaabe8cba82151ca93ef/rapidfuzz-3.14.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:dfef96543ced67d9513a422755db422ae1dc34dade0a1485e0b43e7342ed3ebf", size = 1509889 }, ] [[package]] @@ -2343,9 +2345,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232, upload-time = "2026-03-25T15:10:41.586Z" } +sdist = { url = "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", size = 134232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017, upload-time = "2026-03-25T15:10:40.382Z" }, + { url = "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b", size = 65017 }, ] [[package]] @@ -2355,18 +2357,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/32/587625f91f9a0a3d84688bf9cfc4b2480a7e8ec327cefd0ff2ac891fd2cf/requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401", size = 60901, upload-time = "2024-03-29T03:54:29.446Z" } +sdist = { url = "https://files.pythonhosted.org/packages/92/32/587625f91f9a0a3d84688bf9cfc4b2480a7e8ec327cefd0ff2ac891fd2cf/requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401", size = 60901 } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/ec/889fbc557727da0c34a33850950310240f2040f3b1955175fdb2b36a8910/requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", size = 27695, upload-time = "2024-03-29T03:54:27.64Z" }, + { url = "https://files.pythonhosted.org/packages/97/ec/889fbc557727da0c34a33850950310240f2040f3b1955175fdb2b36a8910/requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563", size = 27695 }, ] [[package]] name = "result" version = "0.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/36/4a5099e26c7ba275f8c56c8d72242d62ad6ccbac155114493f451c9981db/result-0.5.0.tar.gz", hash = "sha256:f4563ff615b1147822d13eb363fbda202511fcbf281b3cf7acf0723ca7cb612b", size = 7721, upload-time = "2020-03-03T14:42:14.017Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/36/4a5099e26c7ba275f8c56c8d72242d62ad6ccbac155114493f451c9981db/result-0.5.0.tar.gz", hash = "sha256:f4563ff615b1147822d13eb363fbda202511fcbf281b3cf7acf0723ca7cb612b", size = 7721 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0f/2e100673dcaa9456c3826a048048d877f9bac27eaf864097515eae5d8c66/result-0.5.0-py3-none-any.whl", hash = "sha256:46f039a2d17e47709c13e29af359c3fa91fd5cacddba2a8109fdcb514e6ff471", size = 7345, upload-time = "2020-03-03T14:42:12.327Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0f/2e100673dcaa9456c3826a048048d877f9bac27eaf864097515eae5d8c66/result-0.5.0-py3-none-any.whl", hash = "sha256:46f039a2d17e47709c13e29af359c3fa91fd5cacddba2a8109fdcb514e6ff471", size = 7345 }, ] [[package]] @@ -2377,9 +2379,9 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654 }, ] [[package]] @@ -2389,34 +2391,34 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, ] [[package]] name = "ruff" version = "0.15.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985, upload-time = "2026-05-28T14:16:57.784Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652, upload-time = "2026-05-28T14:16:06.701Z" }, - { url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615, upload-time = "2026-05-28T14:16:23.313Z" }, - { url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683, upload-time = "2026-05-28T14:16:40.974Z" }, - { url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064, upload-time = "2026-05-28T14:16:28.905Z" }, - { url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987, upload-time = "2026-05-28T14:16:43.732Z" }, - { url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100, upload-time = "2026-05-28T14:16:55.244Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903, upload-time = "2026-05-28T14:16:14.368Z" }, - { url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550, upload-time = "2026-05-28T14:16:20.138Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027, upload-time = "2026-05-28T14:16:46.615Z" }, - { url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041, upload-time = "2026-05-28T14:16:26.247Z" }, - { url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795, upload-time = "2026-05-28T14:16:17.11Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117, upload-time = "2026-05-28T14:16:31.767Z" }, - { url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867, upload-time = "2026-05-28T14:16:35.149Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101, upload-time = "2026-05-28T14:16:49.598Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774, upload-time = "2026-05-28T14:16:52.337Z" }, - { url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463, upload-time = "2026-05-28T14:16:11.333Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498, upload-time = "2026-05-28T14:16:38.425Z" }, + { url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652 }, + { url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615 }, + { url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683 }, + { url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064 }, + { url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987 }, + { url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100 }, + { url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903 }, + { url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550 }, + { url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027 }, + { url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041 }, + { url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795 }, + { url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117 }, + { url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867 }, + { url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101 }, + { url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774 }, + { url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463 }, + { url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498 }, ] [[package]] @@ -2436,66 +2438,66 @@ wheels = [ name = "setuptools" version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, ] [[package]] name = "simplejson" version = "3.20.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/f4/a1ac5ed32f7ed9a088d62a59d410d4c204b3b3815722e2ccfb491fa8251b/simplejson-3.20.2.tar.gz", hash = "sha256:5fe7a6ce14d1c300d80d08695b7f7e633de6cd72c80644021874d985b3393649", size = 85784, upload-time = "2025-09-26T16:29:36.64Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/3e/96898c6c66d9dca3f9bd14d7487bf783b4acc77471b42f979babbb68d4ca/simplejson-3.20.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:06190b33cd7849efc413a5738d3da00b90e4a5382fd3d584c841ac20fb828c6f", size = 92633, upload-time = "2025-09-26T16:27:45.028Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a2/cd2e10b880368305d89dd540685b8bdcc136df2b3c76b5ddd72596254539/simplejson-3.20.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4ad4eac7d858947a30d2c404e61f16b84d16be79eb6fb316341885bdde864fa8", size = 75309, upload-time = "2025-09-26T16:27:46.142Z" }, - { url = "https://files.pythonhosted.org/packages/5d/02/290f7282eaa6ebe945d35c47e6534348af97472446951dce0d144e013f4c/simplejson-3.20.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b392e11c6165d4a0fde41754a0e13e1d88a5ad782b245a973dd4b2bdb4e5076a", size = 75308, upload-time = "2025-09-26T16:27:47.542Z" }, - { url = "https://files.pythonhosted.org/packages/43/91/43695f17b69e70c4b0b03247aa47fb3989d338a70c4b726bbdc2da184160/simplejson-3.20.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51eccc4e353eed3c50e0ea2326173acdc05e58f0c110405920b989d481287e51", size = 143733, upload-time = "2025-09-26T16:27:48.673Z" }, - { url = "https://files.pythonhosted.org/packages/9b/4b/fdcaf444ac1c3cbf1c52bf00320c499e1cf05d373a58a3731ae627ba5e2d/simplejson-3.20.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:306e83d7c331ad833d2d43c76a67f476c4b80c4a13334f6e34bb110e6105b3bd", size = 153397, upload-time = "2025-09-26T16:27:49.89Z" }, - { url = "https://files.pythonhosted.org/packages/c4/83/21550f81a50cd03599f048a2d588ffb7f4c4d8064ae091511e8e5848eeaa/simplejson-3.20.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f820a6ac2ef0bc338ae4963f4f82ccebdb0824fe9caf6d660670c578abe01013", size = 141654, upload-time = "2025-09-26T16:27:51.168Z" }, - { url = "https://files.pythonhosted.org/packages/cf/54/d76c0e72ad02450a3e723b65b04f49001d0e73218ef6a220b158a64639cb/simplejson-3.20.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21e7a066528a5451433eb3418184f05682ea0493d14e9aae690499b7e1eb6b81", size = 144913, upload-time = "2025-09-26T16:27:52.331Z" }, - { url = "https://files.pythonhosted.org/packages/3f/49/976f59b42a6956d4aeb075ada16ad64448a985704bc69cd427a2245ce835/simplejson-3.20.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:438680ddde57ea87161a4824e8de04387b328ad51cfdf1eaf723623a3014b7aa", size = 144568, upload-time = "2025-09-26T16:27:53.41Z" }, - { url = "https://files.pythonhosted.org/packages/60/c7/30bae30424ace8cd791ca660fed454ed9479233810fe25c3f3eab3d9dc7b/simplejson-3.20.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cac78470ae68b8d8c41b6fca97f5bf8e024ca80d5878c7724e024540f5cdaadb", size = 146239, upload-time = "2025-09-26T16:27:54.502Z" }, - { url = "https://files.pythonhosted.org/packages/79/3e/7f3b7b97351c53746e7b996fcd106986cda1954ab556fd665314756618d2/simplejson-3.20.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7524e19c2da5ef281860a3d74668050c6986be15c9dd99966034ba47c68828c2", size = 154497, upload-time = "2025-09-26T16:27:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/1d/48/7241daa91d0bf19126589f6a8dcbe8287f4ed3d734e76fd4a092708947be/simplejson-3.20.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e9b6d845a603b2eef3394eb5e21edb8626cd9ae9a8361d14e267eb969dbe413", size = 148069, upload-time = "2025-09-26T16:27:57.039Z" }, - { url = "https://files.pythonhosted.org/packages/e6/f4/ef18d2962fe53e7be5123d3784e623859eec7ed97060c9c8536c69d34836/simplejson-3.20.2-cp311-cp311-win32.whl", hash = "sha256:47d8927e5ac927fdd34c99cc617938abb3624b06ff86e8e219740a86507eb961", size = 74158, upload-time = "2025-09-26T16:27:58.265Z" }, - { url = "https://files.pythonhosted.org/packages/35/fd/3d1158ecdc573fdad81bf3cc78df04522bf3959758bba6597ba4c956c74d/simplejson-3.20.2-cp311-cp311-win_amd64.whl", hash = "sha256:ba4edf3be8e97e4713d06c3d302cba1ff5c49d16e9d24c209884ac1b8455520c", size = 75911, upload-time = "2025-09-26T16:27:59.292Z" }, - { url = "https://files.pythonhosted.org/packages/9d/9e/1a91e7614db0416885eab4136d49b7303de20528860ffdd798ce04d054db/simplejson-3.20.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4376d5acae0d1e91e78baeba4ee3cf22fbf6509d81539d01b94e0951d28ec2b6", size = 93523, upload-time = "2025-09-26T16:28:00.356Z" }, - { url = "https://files.pythonhosted.org/packages/5e/2b/d2413f5218fc25608739e3d63fe321dfa85c5f097aa6648dbe72513a5f12/simplejson-3.20.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f8fe6de652fcddae6dec8f281cc1e77e4e8f3575249e1800090aab48f73b4259", size = 75844, upload-time = "2025-09-26T16:28:01.756Z" }, - { url = "https://files.pythonhosted.org/packages/ad/f1/efd09efcc1e26629e120fef59be059ce7841cc6e1f949a4db94f1ae8a918/simplejson-3.20.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25ca2663d99328d51e5a138f22018e54c9162438d831e26cfc3458688616eca8", size = 75655, upload-time = "2025-09-26T16:28:03.037Z" }, - { url = "https://files.pythonhosted.org/packages/97/ec/5c6db08e42f380f005d03944be1af1a6bd501cc641175429a1cbe7fb23b9/simplejson-3.20.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12a6b2816b6cab6c3fd273d43b1948bc9acf708272074c8858f579c394f4cbc9", size = 150335, upload-time = "2025-09-26T16:28:05.027Z" }, - { url = "https://files.pythonhosted.org/packages/81/f5/808a907485876a9242ec67054da7cbebefe0ee1522ef1c0be3bfc90f96f6/simplejson-3.20.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac20dc3fcdfc7b8415bfc3d7d51beccd8695c3f4acb7f74e3a3b538e76672868", size = 158519, upload-time = "2025-09-26T16:28:06.5Z" }, - { url = "https://files.pythonhosted.org/packages/66/af/b8a158246834645ea890c36136584b0cc1c0e4b83a73b11ebd9c2a12877c/simplejson-3.20.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db0804d04564e70862ef807f3e1ace2cc212ef0e22deb1b3d6f80c45e5882c6b", size = 148571, upload-time = "2025-09-26T16:28:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/20/05/ed9b2571bbf38f1a2425391f18e3ac11cb1e91482c22d644a1640dea9da7/simplejson-3.20.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:979ce23ea663895ae39106946ef3d78527822d918a136dbc77b9e2b7f006237e", size = 152367, upload-time = "2025-09-26T16:28:08.921Z" }, - { url = "https://files.pythonhosted.org/packages/81/2c/bad68b05dd43e93f77994b920505634d31ed239418eb6a88997d06599983/simplejson-3.20.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a2ba921b047bb029805726800819675249ef25d2f65fd0edb90639c5b1c3033c", size = 150205, upload-time = "2025-09-26T16:28:10.086Z" }, - { url = "https://files.pythonhosted.org/packages/69/46/90c7fc878061adafcf298ce60cecdee17a027486e9dce507e87396d68255/simplejson-3.20.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:12d3d4dc33770069b780cc8f5abef909fe4a3f071f18f55f6d896a370fd0f970", size = 151823, upload-time = "2025-09-26T16:28:11.329Z" }, - { url = "https://files.pythonhosted.org/packages/ab/27/b85b03349f825ae0f5d4f780cdde0bbccd4f06c3d8433f6a3882df887481/simplejson-3.20.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:aff032a59a201b3683a34be1169e71ddda683d9c3b43b261599c12055349251e", size = 158997, upload-time = "2025-09-26T16:28:12.917Z" }, - { url = "https://files.pythonhosted.org/packages/71/ad/d7f3c331fb930638420ac6d236db68e9f4c28dab9c03164c3cd0e7967e15/simplejson-3.20.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:30e590e133b06773f0dc9c3f82e567463df40598b660b5adf53eb1c488202544", size = 154367, upload-time = "2025-09-26T16:28:14.393Z" }, - { url = "https://files.pythonhosted.org/packages/f0/46/5c67324addd40fa2966f6e886cacbbe0407c03a500db94fb8bb40333fcdf/simplejson-3.20.2-cp312-cp312-win32.whl", hash = "sha256:8d7be7c99939cc58e7c5bcf6bb52a842a58e6c65e1e9cdd2a94b697b24cddb54", size = 74285, upload-time = "2025-09-26T16:28:15.931Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c9/5cc2189f4acd3a6e30ffa9775bf09b354302dbebab713ca914d7134d0f29/simplejson-3.20.2-cp312-cp312-win_amd64.whl", hash = "sha256:2c0b4a67e75b945489052af6590e7dca0ed473ead5d0f3aad61fa584afe814ab", size = 75969, upload-time = "2025-09-26T16:28:17.017Z" }, - { url = "https://files.pythonhosted.org/packages/5e/9e/f326d43f6bf47f4e7704a4426c36e044c6bedfd24e072fb8e27589a373a5/simplejson-3.20.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90d311ba8fcd733a3677e0be21804827226a57144130ba01c3c6a325e887dd86", size = 93530, upload-time = "2025-09-26T16:28:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/35/28/5a4b8f3483fbfb68f3f460bc002cef3a5735ef30950e7c4adce9c8da15c7/simplejson-3.20.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:feed6806f614bdf7f5cb6d0123cb0c1c5f40407ef103aa935cffaa694e2e0c74", size = 75846, upload-time = "2025-09-26T16:28:19.12Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4d/30dfef83b9ac48afae1cf1ab19c2867e27b8d22b5d9f8ca7ce5a0a157d8c/simplejson-3.20.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6b1d8d7c3e1a205c49e1aee6ba907dcb8ccea83651e6c3e2cb2062f1e52b0726", size = 75661, upload-time = "2025-09-26T16:28:20.219Z" }, - { url = "https://files.pythonhosted.org/packages/09/1d/171009bd35c7099d72ef6afd4bb13527bab469965c968a17d69a203d62a6/simplejson-3.20.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:552f55745044a24c3cb7ec67e54234be56d5d6d0e054f2e4cf4fb3e297429be5", size = 150579, upload-time = "2025-09-26T16:28:21.337Z" }, - { url = "https://files.pythonhosted.org/packages/61/ae/229bbcf90a702adc6bfa476e9f0a37e21d8c58e1059043038797cbe75b8c/simplejson-3.20.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2da97ac65165d66b0570c9e545786f0ac7b5de5854d3711a16cacbcaa8c472d", size = 158797, upload-time = "2025-09-26T16:28:22.53Z" }, - { url = "https://files.pythonhosted.org/packages/90/c5/fefc0ac6b86b9108e302e0af1cf57518f46da0baedd60a12170791d56959/simplejson-3.20.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f59a12966daa356bf68927fca5a67bebac0033cd18b96de9c2d426cd11756cd0", size = 148851, upload-time = "2025-09-26T16:28:23.733Z" }, - { url = "https://files.pythonhosted.org/packages/43/f1/b392952200f3393bb06fbc4dd975fc63a6843261705839355560b7264eb2/simplejson-3.20.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133ae2098a8e162c71da97cdab1f383afdd91373b7ff5fe65169b04167da976b", size = 152598, upload-time = "2025-09-26T16:28:24.962Z" }, - { url = "https://files.pythonhosted.org/packages/f4/b4/d6b7279e52a3e9c0fa8c032ce6164e593e8d9cf390698ee981ed0864291b/simplejson-3.20.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7977640af7b7d5e6a852d26622057d428706a550f7f5083e7c4dd010a84d941f", size = 150498, upload-time = "2025-09-26T16:28:26.114Z" }, - { url = "https://files.pythonhosted.org/packages/62/22/ec2490dd859224326d10c2fac1353e8ad5c84121be4837a6dd6638ba4345/simplejson-3.20.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b530ad6d55e71fa9e93e1109cf8182f427a6355848a4ffa09f69cc44e1512522", size = 152129, upload-time = "2025-09-26T16:28:27.552Z" }, - { url = "https://files.pythonhosted.org/packages/33/ce/b60214d013e93dd9e5a705dcb2b88b6c72bada442a97f79828332217f3eb/simplejson-3.20.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bd96a7d981bf64f0e42345584768da4435c05b24fd3c364663f5fbc8fabf82e3", size = 159359, upload-time = "2025-09-26T16:28:28.667Z" }, - { url = "https://files.pythonhosted.org/packages/99/21/603709455827cdf5b9d83abe726343f542491ca8dc6a2528eb08de0cf034/simplejson-3.20.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f28ee755fadb426ba2e464d6fcf25d3f152a05eb6b38e0b4f790352f5540c769", size = 154717, upload-time = "2025-09-26T16:28:30.288Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f9/dc7f7a4bac16cf7eb55a4df03ad93190e11826d2a8950052949d3dfc11e2/simplejson-3.20.2-cp313-cp313-win32.whl", hash = "sha256:472785b52e48e3eed9b78b95e26a256f59bb1ee38339be3075dad799e2e1e661", size = 74289, upload-time = "2025-09-26T16:28:31.809Z" }, - { url = "https://files.pythonhosted.org/packages/87/10/d42ad61230436735c68af1120622b28a782877146a83d714da7b6a2a1c4e/simplejson-3.20.2-cp313-cp313-win_amd64.whl", hash = "sha256:a1a85013eb33e4820286139540accbe2c98d2da894b2dcefd280209db508e608", size = 75972, upload-time = "2025-09-26T16:28:32.883Z" }, - { url = "https://files.pythonhosted.org/packages/05/5b/83e1ff87eb60ca706972f7e02e15c0b33396e7bdbd080069a5d1b53cf0d8/simplejson-3.20.2-py3-none-any.whl", hash = "sha256:3b6bb7fb96efd673eac2e4235200bfffdc2353ad12c54117e1e4e2fc485ac017", size = 57309, upload-time = "2025-09-26T16:29:35.312Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/41/f4/a1ac5ed32f7ed9a088d62a59d410d4c204b3b3815722e2ccfb491fa8251b/simplejson-3.20.2.tar.gz", hash = "sha256:5fe7a6ce14d1c300d80d08695b7f7e633de6cd72c80644021874d985b3393649", size = 85784 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/3e/96898c6c66d9dca3f9bd14d7487bf783b4acc77471b42f979babbb68d4ca/simplejson-3.20.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:06190b33cd7849efc413a5738d3da00b90e4a5382fd3d584c841ac20fb828c6f", size = 92633 }, + { url = "https://files.pythonhosted.org/packages/6b/a2/cd2e10b880368305d89dd540685b8bdcc136df2b3c76b5ddd72596254539/simplejson-3.20.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4ad4eac7d858947a30d2c404e61f16b84d16be79eb6fb316341885bdde864fa8", size = 75309 }, + { url = "https://files.pythonhosted.org/packages/5d/02/290f7282eaa6ebe945d35c47e6534348af97472446951dce0d144e013f4c/simplejson-3.20.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b392e11c6165d4a0fde41754a0e13e1d88a5ad782b245a973dd4b2bdb4e5076a", size = 75308 }, + { url = "https://files.pythonhosted.org/packages/43/91/43695f17b69e70c4b0b03247aa47fb3989d338a70c4b726bbdc2da184160/simplejson-3.20.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51eccc4e353eed3c50e0ea2326173acdc05e58f0c110405920b989d481287e51", size = 143733 }, + { url = "https://files.pythonhosted.org/packages/9b/4b/fdcaf444ac1c3cbf1c52bf00320c499e1cf05d373a58a3731ae627ba5e2d/simplejson-3.20.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:306e83d7c331ad833d2d43c76a67f476c4b80c4a13334f6e34bb110e6105b3bd", size = 153397 }, + { url = "https://files.pythonhosted.org/packages/c4/83/21550f81a50cd03599f048a2d588ffb7f4c4d8064ae091511e8e5848eeaa/simplejson-3.20.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f820a6ac2ef0bc338ae4963f4f82ccebdb0824fe9caf6d660670c578abe01013", size = 141654 }, + { url = "https://files.pythonhosted.org/packages/cf/54/d76c0e72ad02450a3e723b65b04f49001d0e73218ef6a220b158a64639cb/simplejson-3.20.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21e7a066528a5451433eb3418184f05682ea0493d14e9aae690499b7e1eb6b81", size = 144913 }, + { url = "https://files.pythonhosted.org/packages/3f/49/976f59b42a6956d4aeb075ada16ad64448a985704bc69cd427a2245ce835/simplejson-3.20.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:438680ddde57ea87161a4824e8de04387b328ad51cfdf1eaf723623a3014b7aa", size = 144568 }, + { url = "https://files.pythonhosted.org/packages/60/c7/30bae30424ace8cd791ca660fed454ed9479233810fe25c3f3eab3d9dc7b/simplejson-3.20.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cac78470ae68b8d8c41b6fca97f5bf8e024ca80d5878c7724e024540f5cdaadb", size = 146239 }, + { url = "https://files.pythonhosted.org/packages/79/3e/7f3b7b97351c53746e7b996fcd106986cda1954ab556fd665314756618d2/simplejson-3.20.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7524e19c2da5ef281860a3d74668050c6986be15c9dd99966034ba47c68828c2", size = 154497 }, + { url = "https://files.pythonhosted.org/packages/1d/48/7241daa91d0bf19126589f6a8dcbe8287f4ed3d734e76fd4a092708947be/simplejson-3.20.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e9b6d845a603b2eef3394eb5e21edb8626cd9ae9a8361d14e267eb969dbe413", size = 148069 }, + { url = "https://files.pythonhosted.org/packages/e6/f4/ef18d2962fe53e7be5123d3784e623859eec7ed97060c9c8536c69d34836/simplejson-3.20.2-cp311-cp311-win32.whl", hash = "sha256:47d8927e5ac927fdd34c99cc617938abb3624b06ff86e8e219740a86507eb961", size = 74158 }, + { url = "https://files.pythonhosted.org/packages/35/fd/3d1158ecdc573fdad81bf3cc78df04522bf3959758bba6597ba4c956c74d/simplejson-3.20.2-cp311-cp311-win_amd64.whl", hash = "sha256:ba4edf3be8e97e4713d06c3d302cba1ff5c49d16e9d24c209884ac1b8455520c", size = 75911 }, + { url = "https://files.pythonhosted.org/packages/9d/9e/1a91e7614db0416885eab4136d49b7303de20528860ffdd798ce04d054db/simplejson-3.20.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4376d5acae0d1e91e78baeba4ee3cf22fbf6509d81539d01b94e0951d28ec2b6", size = 93523 }, + { url = "https://files.pythonhosted.org/packages/5e/2b/d2413f5218fc25608739e3d63fe321dfa85c5f097aa6648dbe72513a5f12/simplejson-3.20.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f8fe6de652fcddae6dec8f281cc1e77e4e8f3575249e1800090aab48f73b4259", size = 75844 }, + { url = "https://files.pythonhosted.org/packages/ad/f1/efd09efcc1e26629e120fef59be059ce7841cc6e1f949a4db94f1ae8a918/simplejson-3.20.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25ca2663d99328d51e5a138f22018e54c9162438d831e26cfc3458688616eca8", size = 75655 }, + { url = "https://files.pythonhosted.org/packages/97/ec/5c6db08e42f380f005d03944be1af1a6bd501cc641175429a1cbe7fb23b9/simplejson-3.20.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12a6b2816b6cab6c3fd273d43b1948bc9acf708272074c8858f579c394f4cbc9", size = 150335 }, + { url = "https://files.pythonhosted.org/packages/81/f5/808a907485876a9242ec67054da7cbebefe0ee1522ef1c0be3bfc90f96f6/simplejson-3.20.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac20dc3fcdfc7b8415bfc3d7d51beccd8695c3f4acb7f74e3a3b538e76672868", size = 158519 }, + { url = "https://files.pythonhosted.org/packages/66/af/b8a158246834645ea890c36136584b0cc1c0e4b83a73b11ebd9c2a12877c/simplejson-3.20.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db0804d04564e70862ef807f3e1ace2cc212ef0e22deb1b3d6f80c45e5882c6b", size = 148571 }, + { url = "https://files.pythonhosted.org/packages/20/05/ed9b2571bbf38f1a2425391f18e3ac11cb1e91482c22d644a1640dea9da7/simplejson-3.20.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:979ce23ea663895ae39106946ef3d78527822d918a136dbc77b9e2b7f006237e", size = 152367 }, + { url = "https://files.pythonhosted.org/packages/81/2c/bad68b05dd43e93f77994b920505634d31ed239418eb6a88997d06599983/simplejson-3.20.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a2ba921b047bb029805726800819675249ef25d2f65fd0edb90639c5b1c3033c", size = 150205 }, + { url = "https://files.pythonhosted.org/packages/69/46/90c7fc878061adafcf298ce60cecdee17a027486e9dce507e87396d68255/simplejson-3.20.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:12d3d4dc33770069b780cc8f5abef909fe4a3f071f18f55f6d896a370fd0f970", size = 151823 }, + { url = "https://files.pythonhosted.org/packages/ab/27/b85b03349f825ae0f5d4f780cdde0bbccd4f06c3d8433f6a3882df887481/simplejson-3.20.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:aff032a59a201b3683a34be1169e71ddda683d9c3b43b261599c12055349251e", size = 158997 }, + { url = "https://files.pythonhosted.org/packages/71/ad/d7f3c331fb930638420ac6d236db68e9f4c28dab9c03164c3cd0e7967e15/simplejson-3.20.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:30e590e133b06773f0dc9c3f82e567463df40598b660b5adf53eb1c488202544", size = 154367 }, + { url = "https://files.pythonhosted.org/packages/f0/46/5c67324addd40fa2966f6e886cacbbe0407c03a500db94fb8bb40333fcdf/simplejson-3.20.2-cp312-cp312-win32.whl", hash = "sha256:8d7be7c99939cc58e7c5bcf6bb52a842a58e6c65e1e9cdd2a94b697b24cddb54", size = 74285 }, + { url = "https://files.pythonhosted.org/packages/fa/c9/5cc2189f4acd3a6e30ffa9775bf09b354302dbebab713ca914d7134d0f29/simplejson-3.20.2-cp312-cp312-win_amd64.whl", hash = "sha256:2c0b4a67e75b945489052af6590e7dca0ed473ead5d0f3aad61fa584afe814ab", size = 75969 }, + { url = "https://files.pythonhosted.org/packages/5e/9e/f326d43f6bf47f4e7704a4426c36e044c6bedfd24e072fb8e27589a373a5/simplejson-3.20.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90d311ba8fcd733a3677e0be21804827226a57144130ba01c3c6a325e887dd86", size = 93530 }, + { url = "https://files.pythonhosted.org/packages/35/28/5a4b8f3483fbfb68f3f460bc002cef3a5735ef30950e7c4adce9c8da15c7/simplejson-3.20.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:feed6806f614bdf7f5cb6d0123cb0c1c5f40407ef103aa935cffaa694e2e0c74", size = 75846 }, + { url = "https://files.pythonhosted.org/packages/7a/4d/30dfef83b9ac48afae1cf1ab19c2867e27b8d22b5d9f8ca7ce5a0a157d8c/simplejson-3.20.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6b1d8d7c3e1a205c49e1aee6ba907dcb8ccea83651e6c3e2cb2062f1e52b0726", size = 75661 }, + { url = "https://files.pythonhosted.org/packages/09/1d/171009bd35c7099d72ef6afd4bb13527bab469965c968a17d69a203d62a6/simplejson-3.20.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:552f55745044a24c3cb7ec67e54234be56d5d6d0e054f2e4cf4fb3e297429be5", size = 150579 }, + { url = "https://files.pythonhosted.org/packages/61/ae/229bbcf90a702adc6bfa476e9f0a37e21d8c58e1059043038797cbe75b8c/simplejson-3.20.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2da97ac65165d66b0570c9e545786f0ac7b5de5854d3711a16cacbcaa8c472d", size = 158797 }, + { url = "https://files.pythonhosted.org/packages/90/c5/fefc0ac6b86b9108e302e0af1cf57518f46da0baedd60a12170791d56959/simplejson-3.20.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f59a12966daa356bf68927fca5a67bebac0033cd18b96de9c2d426cd11756cd0", size = 148851 }, + { url = "https://files.pythonhosted.org/packages/43/f1/b392952200f3393bb06fbc4dd975fc63a6843261705839355560b7264eb2/simplejson-3.20.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133ae2098a8e162c71da97cdab1f383afdd91373b7ff5fe65169b04167da976b", size = 152598 }, + { url = "https://files.pythonhosted.org/packages/f4/b4/d6b7279e52a3e9c0fa8c032ce6164e593e8d9cf390698ee981ed0864291b/simplejson-3.20.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7977640af7b7d5e6a852d26622057d428706a550f7f5083e7c4dd010a84d941f", size = 150498 }, + { url = "https://files.pythonhosted.org/packages/62/22/ec2490dd859224326d10c2fac1353e8ad5c84121be4837a6dd6638ba4345/simplejson-3.20.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b530ad6d55e71fa9e93e1109cf8182f427a6355848a4ffa09f69cc44e1512522", size = 152129 }, + { url = "https://files.pythonhosted.org/packages/33/ce/b60214d013e93dd9e5a705dcb2b88b6c72bada442a97f79828332217f3eb/simplejson-3.20.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bd96a7d981bf64f0e42345584768da4435c05b24fd3c364663f5fbc8fabf82e3", size = 159359 }, + { url = "https://files.pythonhosted.org/packages/99/21/603709455827cdf5b9d83abe726343f542491ca8dc6a2528eb08de0cf034/simplejson-3.20.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f28ee755fadb426ba2e464d6fcf25d3f152a05eb6b38e0b4f790352f5540c769", size = 154717 }, + { url = "https://files.pythonhosted.org/packages/3c/f9/dc7f7a4bac16cf7eb55a4df03ad93190e11826d2a8950052949d3dfc11e2/simplejson-3.20.2-cp313-cp313-win32.whl", hash = "sha256:472785b52e48e3eed9b78b95e26a256f59bb1ee38339be3075dad799e2e1e661", size = 74289 }, + { url = "https://files.pythonhosted.org/packages/87/10/d42ad61230436735c68af1120622b28a782877146a83d714da7b6a2a1c4e/simplejson-3.20.2-cp313-cp313-win_amd64.whl", hash = "sha256:a1a85013eb33e4820286139540accbe2c98d2da894b2dcefd280209db508e608", size = 75972 }, + { url = "https://files.pythonhosted.org/packages/05/5b/83e1ff87eb60ca706972f7e02e15c0b33396e7bdbd080069a5d1b53cf0d8/simplejson-3.20.2-py3-none-any.whl", hash = "sha256:3b6bb7fb96efd673eac2e4235200bfffdc2353ad12c54117e1e4e2fc485ac017", size = 57309 }, ] [[package]] name = "six" version = "1.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041, upload-time = "2021-05-05T14:18:18.379Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053, upload-time = "2021-05-05T14:18:17.237Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, ] [[package]] @@ -2505,18 +2507,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ce/af/20290b55d469e873cba9d41c0206ab5461ff49d759989b3fe65010f9d265/sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a", size = 8470350, upload-time = "2024-09-05T15:54:10.398Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/af/20290b55d469e873cba9d41c0206ab5461ff49d759989b3fe65010f9d265/sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a", size = 8470350 } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/49/fb98983b5568e93696a25fd5bec1b789095b79a72d5f57c6effddaa81d0a/SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e", size = 1589301, upload-time = "2024-09-05T19:22:42.197Z" }, - { url = "https://files.pythonhosted.org/packages/03/98/5a81430bbd646991346cb088a2bdc84d1bcd3dbe6b0cfc1aaa898370e5c7/SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936", size = 1629553, upload-time = "2024-09-05T17:49:18.846Z" }, - { url = "https://files.pythonhosted.org/packages/f1/17/14e35db2b0d6deaa27691d014addbb0dd6f7e044f7ee465446a3c0c71404/SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f", size = 1627640, upload-time = "2024-09-05T17:48:01.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/62/335006a8f2c98f704f391e1a0cc01446d1b1b9c198f579f03599f55bd860/SQLAlchemy-1.4.54-cp311-cp311-win32.whl", hash = "sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc", size = 1591723, upload-time = "2024-09-05T17:53:17.486Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/6b4b8c07082920f5445ec65c221fa33baab102aced5dcc2d87a15d3f8db4/SQLAlchemy-1.4.54-cp311-cp311-win_amd64.whl", hash = "sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5", size = 1593511, upload-time = "2024-09-05T17:51:50.947Z" }, - { url = "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d", size = 1589983, upload-time = "2024-09-05T17:39:02.132Z" }, - { url = "https://files.pythonhosted.org/packages/59/47/cb0fc64e5344f0a3d02216796c342525ab283f8f052d1c31a1d487d08aa0/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4", size = 1630158, upload-time = "2024-09-05T17:50:13.255Z" }, - { url = "https://files.pythonhosted.org/packages/c0/8b/f45dd378f6c97e8ff9332ff3d03ecb0b8c491be5bb7a698783b5a2f358ec/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c", size = 1629232, upload-time = "2024-09-05T17:48:15.514Z" }, - { url = "https://files.pythonhosted.org/packages/0d/3c/884fe389f5bec86a310b81e79abaa1e26e5d78dc10a84d544a6822833e47/SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f", size = 1592027, upload-time = "2024-09-05T17:54:02.253Z" }, - { url = "https://files.pythonhosted.org/packages/01/c3/c690d037be57efd3a69cde16a2ef1bd2a905dafe869434d33836de0983d0/SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88", size = 1593827, upload-time = "2024-09-05T17:52:07.454Z" }, + { url = "https://files.pythonhosted.org/packages/da/49/fb98983b5568e93696a25fd5bec1b789095b79a72d5f57c6effddaa81d0a/SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e", size = 1589301 }, + { url = "https://files.pythonhosted.org/packages/03/98/5a81430bbd646991346cb088a2bdc84d1bcd3dbe6b0cfc1aaa898370e5c7/SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936", size = 1629553 }, + { url = "https://files.pythonhosted.org/packages/f1/17/14e35db2b0d6deaa27691d014addbb0dd6f7e044f7ee465446a3c0c71404/SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f", size = 1627640 }, + { url = "https://files.pythonhosted.org/packages/98/62/335006a8f2c98f704f391e1a0cc01446d1b1b9c198f579f03599f55bd860/SQLAlchemy-1.4.54-cp311-cp311-win32.whl", hash = "sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc", size = 1591723 }, + { url = "https://files.pythonhosted.org/packages/e2/a1/6b4b8c07082920f5445ec65c221fa33baab102aced5dcc2d87a15d3f8db4/SQLAlchemy-1.4.54-cp311-cp311-win_amd64.whl", hash = "sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5", size = 1593511 }, + { url = "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d", size = 1589983 }, + { url = "https://files.pythonhosted.org/packages/59/47/cb0fc64e5344f0a3d02216796c342525ab283f8f052d1c31a1d487d08aa0/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4", size = 1630158 }, + { url = "https://files.pythonhosted.org/packages/c0/8b/f45dd378f6c97e8ff9332ff3d03ecb0b8c491be5bb7a698783b5a2f358ec/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c", size = 1629232 }, + { url = "https://files.pythonhosted.org/packages/0d/3c/884fe389f5bec86a310b81e79abaa1e26e5d78dc10a84d544a6822833e47/SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f", size = 1592027 }, + { url = "https://files.pythonhosted.org/packages/01/c3/c690d037be57efd3a69cde16a2ef1bd2a905dafe869434d33836de0983d0/SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88", size = 1593827 }, ] [package.optional-dependencies] @@ -2532,9 +2534,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/e0/6906a8a9b8e9deb82923e02e2c1f750c567d69a34f6e1fe566792494a682/SQLAlchemy-Utils-0.41.1.tar.gz", hash = "sha256:a2181bff01eeb84479e38571d2c0718eb52042f9afd8c194d0d02877e84b7d74", size = 136579, upload-time = "2023-04-27T11:40:14.959Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/e0/6906a8a9b8e9deb82923e02e2c1f750c567d69a34f6e1fe566792494a682/SQLAlchemy-Utils-0.41.1.tar.gz", hash = "sha256:a2181bff01eeb84479e38571d2c0718eb52042f9afd8c194d0d02877e84b7d74", size = 136579 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/d8/3863fdfe6b27f6c0dffc650aaa2929f313b33aea615b102279fd46ab550b/SQLAlchemy_Utils-0.41.1-py3-none-any.whl", hash = "sha256:6c96b0768ea3f15c0dc56b363d386138c562752b84f647fb8d31a2223aaab801", size = 92612, upload-time = "2023-04-27T11:40:12.624Z" }, + { url = "https://files.pythonhosted.org/packages/73/d8/3863fdfe6b27f6c0dffc650aaa2929f313b33aea615b102279fd46ab550b/SQLAlchemy_Utils-0.41.1-py3-none-any.whl", hash = "sha256:6c96b0768ea3f15c0dc56b363d386138c562752b84f647fb8d31a2223aaab801", size = 92612 }, ] [[package]] @@ -2544,9 +2546,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/df/be9e0062f649fd2e9b9b73a98c250f520fa10beaebddb8948dffad23c3b6/sqlalchemy2-stubs-0.0.2a38.tar.gz", hash = "sha256:861d722abeb12f13eacd775a9f09379b11a5a9076f469ccd4099961b95800f9e", size = 123950, upload-time = "2023-12-30T12:15:29.27Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/df/be9e0062f649fd2e9b9b73a98c250f520fa10beaebddb8948dffad23c3b6/sqlalchemy2-stubs-0.0.2a38.tar.gz", hash = "sha256:861d722abeb12f13eacd775a9f09379b11a5a9076f469ccd4099961b95800f9e", size = 123950 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/ea/6eff437d0a26c894da2982429ed2c148ecaf0526349ddc8cda1e7151c171/sqlalchemy2_stubs-0.0.2a38-py3-none-any.whl", hash = "sha256:b62aa46943807287550e2033dafe07564b33b6a815fbaa3c144e396f9cc53bcb", size = 191786, upload-time = "2023-12-30T12:15:27.882Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ea/6eff437d0a26c894da2982429ed2c148ecaf0526349ddc8cda1e7151c171/sqlalchemy2_stubs-0.0.2a38-py3-none-any.whl", hash = "sha256:b62aa46943807287550e2033dafe07564b33b6a815fbaa3c144e396f9cc53bcb", size = 191786 }, ] [[package]] @@ -2558,36 +2560,36 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, ] [[package]] name = "tabulate" version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814 }, ] [[package]] name = "tenacity" version = "8.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/9c/ce67f96abe7c7530173e746b4f16a0bc5b4fa962ea1080d80cc5757dd210/tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445", size = 37658, upload-time = "2022-09-21T12:24:13.07Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/9c/ce67f96abe7c7530173e746b4f16a0bc5b4fa962ea1080d80cc5757dd210/tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445", size = 37658 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/94/933ce16d18450ccf518a6da5bd51418611e8776b992070b9f40b2f9cedff/tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac", size = 23370, upload-time = "2022-09-21T12:24:11.567Z" }, + { url = "https://files.pythonhosted.org/packages/a5/94/933ce16d18450ccf518a6da5bd51418611e8776b992070b9f40b2f9cedff/tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac", size = 23370 }, ] [[package]] name = "text-unidecode" version = "1.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885, upload-time = "2019-08-30T21:36:45.405Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154, upload-time = "2019-08-30T21:37:03.543Z" }, + { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154 }, ] [[package]] @@ -2602,9 +2604,9 @@ dependencies = [ { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9b/7a/c519db0aba5024f86e71e9631810bfdd6866ed2c8695bd7fa34b90e7ef59/textual-8.2.7.tar.gz", hash = "sha256:658f568ff81e30ed43890c3e07520390e5cf1b4763822006e060656b0a88f105", size = 1859249, upload-time = "2026-05-19T10:52:49.531Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/7a/c519db0aba5024f86e71e9631810bfdd6866ed2c8695bd7fa34b90e7ef59/textual-8.2.7.tar.gz", hash = "sha256:658f568ff81e30ed43890c3e07520390e5cf1b4763822006e060656b0a88f105", size = 1859249 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/f5/c1e18bc0707300a0e90204343abbf7d7acd6fb7ebe03a6d4893b99a234b8/textual-8.2.7-py3-none-any.whl", hash = "sha256:4caaa13a90bc4cf9c6c862c067ccd34fe84e9c161710a2a907a8026313b6bd73", size = 731129, upload-time = "2026-05-19T10:52:51.773Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f5/c1e18bc0707300a0e90204343abbf7d7acd6fb7ebe03a6d4893b99a234b8/textual-8.2.7-py3-none-any.whl", hash = "sha256:4caaa13a90bc4cf9c6c862c067ccd34fe84e9c161710a2a907a8026313b6bd73", size = 731129 }, ] [[package]] @@ -2615,53 +2617,53 @@ dependencies = [ { name = "absl-py" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/69/57f1fc1089e1b6b9e950587fd7c0916a9b7b2796d97dcb583f1546afa4cf/tink-1.9.0.tar.gz", hash = "sha256:c34d23af20f41fa027c1f98f7d490429f93462c7dc52516763cf0d5887b94272", size = 203496, upload-time = "2023-11-27T12:14:22.637Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/69/57f1fc1089e1b6b9e950587fd7c0916a9b7b2796d97dcb583f1546afa4cf/tink-1.9.0.tar.gz", hash = "sha256:c34d23af20f41fa027c1f98f7d490429f93462c7dc52516763cf0d5887b94272", size = 203496 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/9a/d1685de372097c92b984d810170acd21599005046d04f3024eaf41274722/tink-1.9.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b0927ccdec82df547440e18a4ff7416f83edc234d3f76646886e3f07af176304", size = 5107105, upload-time = "2023-11-27T12:14:00.557Z" }, - { url = "https://files.pythonhosted.org/packages/11/d4/367acff6bf53c0bf6b7dc463db240b3af7b4d1f8c757ea77524fcc29dcd6/tink-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7023281a6a478161b4dac62d8277a42774e7913198992be240249bbd53520a53", size = 3091357, upload-time = "2023-11-27T12:14:02.551Z" }, - { url = "https://files.pythonhosted.org/packages/fa/9e/f50b9ea0d3f25fb34b3852769491b3cf7c1c2f863e793cf498f9fd3bbc47/tink-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba820ce63ca84cd857aefc4e110a7ca5b9fca401fa2e0ae33f6fc00f4526ae09", size = 3162656, upload-time = "2023-11-27T12:14:04.917Z" }, + { url = "https://files.pythonhosted.org/packages/89/9a/d1685de372097c92b984d810170acd21599005046d04f3024eaf41274722/tink-1.9.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b0927ccdec82df547440e18a4ff7416f83edc234d3f76646886e3f07af176304", size = 5107105 }, + { url = "https://files.pythonhosted.org/packages/11/d4/367acff6bf53c0bf6b7dc463db240b3af7b4d1f8c757ea77524fcc29dcd6/tink-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7023281a6a478161b4dac62d8277a42774e7913198992be240249bbd53520a53", size = 3091357 }, + { url = "https://files.pythonhosted.org/packages/fa/9e/f50b9ea0d3f25fb34b3852769491b3cf7c1c2f863e793cf498f9fd3bbc47/tink-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba820ce63ca84cd857aefc4e110a7ca5b9fca401fa2e0ae33f6fc00f4526ae09", size = 3162656 }, ] [[package]] name = "tld" version = "0.12.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0e/3d/a2d4daa269b583cd16c885cda5bb5ac63012cb4c08f680ea1acc8b6abcab/tld-0.12.7.tar.gz", hash = "sha256:b6f7729e19ce0ebc77ba0a65b70d6213aeb952c01ff605e1299aae5fb7621c5e", size = 740889, upload-time = "2023-02-02T21:38:41.758Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/3d/a2d4daa269b583cd16c885cda5bb5ac63012cb4c08f680ea1acc8b6abcab/tld-0.12.7.tar.gz", hash = "sha256:b6f7729e19ce0ebc77ba0a65b70d6213aeb952c01ff605e1299aae5fb7621c5e", size = 740889 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/b8/c69d24555c1a1b707918da847f6a790b57bef99bc2baf6b3e90416801d36/tld-0.12.7-py310-none-any.whl", hash = "sha256:728083653341819d7c1a76e3aaeb6bfc4bafebfaa3336384762a998320f14d1e", size = 263148, upload-time = "2023-02-02T21:43:55.019Z" }, - { url = "https://files.pythonhosted.org/packages/0b/04/cb1cae08ca627b25b05d7af7229d073d89a88c2362b45d175af1fb75049e/tld-0.12.7-py311-none-any.whl", hash = "sha256:7e3d4c856c0d62484117f527f278bb5583849d71961d4fd062bcac0773b0984c", size = 263147, upload-time = "2023-02-02T21:43:57.364Z" }, - { url = "https://files.pythonhosted.org/packages/4d/06/3cfa4c94f6a6e80e5dc972958a5993a985034c38ba019178cbe5df2b71a9/tld-0.12.7-py35-none-any.whl", hash = "sha256:da090e9a8706fa9107e451162c31f391c082b30c60b3f1afe94811daf559b0ae", size = 262442, upload-time = "2023-02-02T21:40:52.992Z" }, - { url = "https://files.pythonhosted.org/packages/9f/70/4228952550f58f8e50b4df78127c06c121db982afe3e53231c769b33be2e/tld-0.12.7-py36-none-any.whl", hash = "sha256:982e1e35895e32b04777eba704d26d9aeb7cc31d10efc69466a346fac295d7aa", size = 263146, upload-time = "2023-02-02T21:38:31.882Z" }, - { url = "https://files.pythonhosted.org/packages/9e/7f/663bafebe158190ffa95c65e3c07a8ceda3c39be5ef218a56b9d3afa1a57/tld-0.12.7-py37-none-any.whl", hash = "sha256:f8efb8d883398aa9ada8995a5a13f8e8d8e6694696dc7dda3e37dc7170b625e4", size = 263146, upload-time = "2023-02-02T21:38:34.703Z" }, - { url = "https://files.pythonhosted.org/packages/5a/e9/7b3ad23ef14bfcdf8e011e3ea8a2011eaeff07cff9d98393359f92b2e3d4/tld-0.12.7-py38-none-any.whl", hash = "sha256:d16d2475383f0a78bc4faa2fa2c23417fe494d9b73081a0670dc4a1e5a32fba8", size = 263148, upload-time = "2023-02-02T21:38:37.069Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d2/2186bf33a7d2a3436612cacba0f96b5dd67d9317b0d3ac6d8bc8158c3b42/tld-0.12.7-py39-none-any.whl", hash = "sha256:2157f36502c88e538c73e991fffbd2fb905fb8d87bbeef0feb7b24b03335c180", size = 263146, upload-time = "2023-02-02T21:38:39.35Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b8/c69d24555c1a1b707918da847f6a790b57bef99bc2baf6b3e90416801d36/tld-0.12.7-py310-none-any.whl", hash = "sha256:728083653341819d7c1a76e3aaeb6bfc4bafebfaa3336384762a998320f14d1e", size = 263148 }, + { url = "https://files.pythonhosted.org/packages/0b/04/cb1cae08ca627b25b05d7af7229d073d89a88c2362b45d175af1fb75049e/tld-0.12.7-py311-none-any.whl", hash = "sha256:7e3d4c856c0d62484117f527f278bb5583849d71961d4fd062bcac0773b0984c", size = 263147 }, + { url = "https://files.pythonhosted.org/packages/4d/06/3cfa4c94f6a6e80e5dc972958a5993a985034c38ba019178cbe5df2b71a9/tld-0.12.7-py35-none-any.whl", hash = "sha256:da090e9a8706fa9107e451162c31f391c082b30c60b3f1afe94811daf559b0ae", size = 262442 }, + { url = "https://files.pythonhosted.org/packages/9f/70/4228952550f58f8e50b4df78127c06c121db982afe3e53231c769b33be2e/tld-0.12.7-py36-none-any.whl", hash = "sha256:982e1e35895e32b04777eba704d26d9aeb7cc31d10efc69466a346fac295d7aa", size = 263146 }, + { url = "https://files.pythonhosted.org/packages/9e/7f/663bafebe158190ffa95c65e3c07a8ceda3c39be5ef218a56b9d3afa1a57/tld-0.12.7-py37-none-any.whl", hash = "sha256:f8efb8d883398aa9ada8995a5a13f8e8d8e6694696dc7dda3e37dc7170b625e4", size = 263146 }, + { url = "https://files.pythonhosted.org/packages/5a/e9/7b3ad23ef14bfcdf8e011e3ea8a2011eaeff07cff9d98393359f92b2e3d4/tld-0.12.7-py38-none-any.whl", hash = "sha256:d16d2475383f0a78bc4faa2fa2c23417fe494d9b73081a0670dc4a1e5a32fba8", size = 263148 }, + { url = "https://files.pythonhosted.org/packages/bf/d2/2186bf33a7d2a3436612cacba0f96b5dd67d9317b0d3ac6d8bc8158c3b42/tld-0.12.7-py39-none-any.whl", hash = "sha256:2157f36502c88e538c73e991fffbd2fb905fb8d87bbeef0feb7b24b03335c180", size = 263146 }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, ] [[package]] name = "types-cachetools" version = "6.1.0.20250717" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/14/e98ea3b3fda81787659268bbf09dec56961c39db060fdca74cb521df0515/types_cachetools-6.1.0.20250717.tar.gz", hash = "sha256:4acc8e25de9f5f84dd176ea81dcffa7cb24393869bb2e59e692dfd0139a1e66f", size = 9105, upload-time = "2025-07-17T03:20:48.482Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/14/e98ea3b3fda81787659268bbf09dec56961c39db060fdca74cb521df0515/types_cachetools-6.1.0.20250717.tar.gz", hash = "sha256:4acc8e25de9f5f84dd176ea81dcffa7cb24393869bb2e59e692dfd0139a1e66f", size = 9105 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/bb/554208964e901e9e1992a7ea0bcab1590a4b2e94d20a9e6200826110ec89/types_cachetools-6.1.0.20250717-py3-none-any.whl", hash = "sha256:bba4b8d42262460d24e570097d2d9040e60311934603caa642efd971f3658ed0", size = 8940, upload-time = "2025-07-17T03:20:47.375Z" }, + { url = "https://files.pythonhosted.org/packages/61/bb/554208964e901e9e1992a7ea0bcab1590a4b2e94d20a9e6200826110ec89/types_cachetools-6.1.0.20250717-py3-none-any.whl", hash = "sha256:bba4b8d42262460d24e570097d2d9040e60311934603caa642efd971f3658ed0", size = 8940 }, ] [[package]] name = "types-click" version = "7.1.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/ff/0e6a56108d45c80c61cdd4743312d0304d8192482aea4cce96c554aaa90d/types-click-7.1.8.tar.gz", hash = "sha256:b6604968be6401dc516311ca50708a0a28baa7a0cb840efd7412f0dbbff4e092", size = 10015, upload-time = "2021-11-23T12:28:01.701Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/ff/0e6a56108d45c80c61cdd4743312d0304d8192482aea4cce96c554aaa90d/types-click-7.1.8.tar.gz", hash = "sha256:b6604968be6401dc516311ca50708a0a28baa7a0cb840efd7412f0dbbff4e092", size = 10015 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/ad/607454a5f991c5b3e14693a7113926758f889138371058a5f72f567fa131/types_click-7.1.8-py3-none-any.whl", hash = "sha256:8cb030a669e2e927461be9827375f83c16b8178c365852c060a34e24871e7e81", size = 12929, upload-time = "2021-11-23T12:27:59.493Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ad/607454a5f991c5b3e14693a7113926758f889138371058a5f72f567fa131/types_click-7.1.8-py3-none-any.whl", hash = "sha256:8cb030a669e2e927461be9827375f83c16b8178c365852c060a34e24871e7e81", size = 12929 }, ] [[package]] @@ -2673,27 +2675,27 @@ dependencies = [ { name = "types-jinja2" }, { name = "types-werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/65/728a104973133a45fba50f3d1e1ee832287666ac74cfd47004cea8402ea3/types-Flask-1.1.6.tar.gz", hash = "sha256:aac777b3abfff9436e6b01f6d08171cf23ea6e5be71cbf773aaabb1c5763e9cf", size = 9829, upload-time = "2021-11-26T06:21:31.199Z" } +sdist = { url = "https://files.pythonhosted.org/packages/79/65/728a104973133a45fba50f3d1e1ee832287666ac74cfd47004cea8402ea3/types-Flask-1.1.6.tar.gz", hash = "sha256:aac777b3abfff9436e6b01f6d08171cf23ea6e5be71cbf773aaabb1c5763e9cf", size = 9829 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/6c/a98a0c29c39d8a6283ac704f3d36f0d570d8dee931e9d46d6cc60d436bec/types_Flask-1.1.6-py3-none-any.whl", hash = "sha256:6ab8a9a5e258b76539d652f6341408867298550b19b81f0e41e916825fc39087", size = 13733, upload-time = "2021-11-26T06:21:30.365Z" }, + { url = "https://files.pythonhosted.org/packages/60/6c/a98a0c29c39d8a6283ac704f3d36f0d570d8dee931e9d46d6cc60d436bec/types_Flask-1.1.6-py3-none-any.whl", hash = "sha256:6ab8a9a5e258b76539d652f6341408867298550b19b81f0e41e916825fc39087", size = 13733 }, ] [[package]] name = "types-flask-cors" version = "3.0.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/cf/e0ead32db111ffa49c7bdfc9854a4d81f6b5b0f3e05e3d5cb6fb2b849ffb/types-Flask-Cors-3.0.10.tar.gz", hash = "sha256:8d2dad18f3f5d2b3a22bc4235c97629b701b784fd428e671564093ca293ae91d", size = 3779, upload-time = "2022-07-12T15:25:46.787Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/cf/e0ead32db111ffa49c7bdfc9854a4d81f6b5b0f3e05e3d5cb6fb2b849ffb/types-Flask-Cors-3.0.10.tar.gz", hash = "sha256:8d2dad18f3f5d2b3a22bc4235c97629b701b784fd428e671564093ca293ae91d", size = 3779 } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/91/d23d00dc4cae85097cd89c35c6c2caf92e98829e60ae7c0e5a7700aa565b/types_Flask_Cors-3.0.10-py3-none-any.whl", hash = "sha256:17ba57b32a97dde31d136e2b312f06714533d1e828bf5328adde64b49c9cdbd8", size = 4507, upload-time = "2022-07-12T15:25:45.478Z" }, + { url = "https://files.pythonhosted.org/packages/77/91/d23d00dc4cae85097cd89c35c6c2caf92e98829e60ae7c0e5a7700aa565b/types_Flask_Cors-3.0.10-py3-none-any.whl", hash = "sha256:17ba57b32a97dde31d136e2b312f06714533d1e828bf5328adde64b49c9cdbd8", size = 4507 }, ] [[package]] name = "types-ipaddress" version = "1.0.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/4e/1b814342e5586fd4da2e483150b98d86d566922debf10fc4ff815864a729/types-ipaddress-1.0.8.tar.gz", hash = "sha256:a03df3be5935e50ba03fa843daabff539a041a28e73e0fce2c5705bee54d3841", size = 3009, upload-time = "2022-01-30T01:00:16.464Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/4e/1b814342e5586fd4da2e483150b98d86d566922debf10fc4ff815864a729/types-ipaddress-1.0.8.tar.gz", hash = "sha256:a03df3be5935e50ba03fa843daabff539a041a28e73e0fce2c5705bee54d3841", size = 3009 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/f0/77dcbd8ff526b0f9989fb4bc92b5c584679710e0e7e0cc1527ba084ce04a/types_ipaddress-1.0.8-py3-none-any.whl", hash = "sha256:4933b74da157ba877b1a705d64f6fa7742745e9ffd65e51011f370c11ebedb55", size = 3091, upload-time = "2022-01-30T01:00:15.227Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f0/77dcbd8ff526b0f9989fb4bc92b5c584679710e0e7e0cc1527ba084ce04a/types_ipaddress-1.0.8-py3-none-any.whl", hash = "sha256:4933b74da157ba877b1a705d64f6fa7742745e9ffd65e51011f370c11ebedb55", size = 3091 }, ] [[package]] @@ -2703,18 +2705,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/c4/b82309bfed8195de7997672deac301bd6f5bd5cbb6a3e392b7fe780d7852/types-Jinja2-2.11.9.tar.gz", hash = "sha256:dbdc74a40aba7aed520b7e4d89e8f0fe4286518494208b35123bcf084d4b8c81", size = 13302, upload-time = "2021-11-26T06:21:17.496Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/c4/b82309bfed8195de7997672deac301bd6f5bd5cbb6a3e392b7fe780d7852/types-Jinja2-2.11.9.tar.gz", hash = "sha256:dbdc74a40aba7aed520b7e4d89e8f0fe4286518494208b35123bcf084d4b8c81", size = 13302 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b0/e79d84748f1d34304f13191424348a719c3febaa3493835370fe9528e1e6/types_Jinja2-2.11.9-py3-none-any.whl", hash = "sha256:60a1e21e8296979db32f9374d8a239af4cb541ff66447bb915d8ad398f9c63b2", size = 18190, upload-time = "2021-11-26T06:21:16.18Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b0/e79d84748f1d34304f13191424348a719c3febaa3493835370fe9528e1e6/types_Jinja2-2.11.9-py3-none-any.whl", hash = "sha256:60a1e21e8296979db32f9374d8a239af4cb541ff66447bb915d8ad398f9c63b2", size = 18190 }, ] [[package]] name = "types-markupsafe" version = "1.1.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/39/31/b5f059142d058aec41e913d8e0eff0a967e7bc46f9a2ba2f31bc11cff059/types-MarkupSafe-1.1.10.tar.gz", hash = "sha256:85b3a872683d02aea3a5ac2a8ef590193c344092032f58457287fbf8e06711b1", size = 2986, upload-time = "2021-11-27T03:18:07.558Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/31/b5f059142d058aec41e913d8e0eff0a967e7bc46f9a2ba2f31bc11cff059/types-MarkupSafe-1.1.10.tar.gz", hash = "sha256:85b3a872683d02aea3a5ac2a8ef590193c344092032f58457287fbf8e06711b1", size = 2986 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/d6/b8effb1c48539260a5eb4196afc55efac4ea1684a4991977555eb266b2ef/types_MarkupSafe-1.1.10-py3-none-any.whl", hash = "sha256:ca2bee0f4faafc45250602567ef38d533e877d2ddca13003b319c551ff5b3cc5", size = 3998, upload-time = "2021-11-27T03:18:06.398Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d6/b8effb1c48539260a5eb4196afc55efac4ea1684a4991977555eb266b2ef/types_MarkupSafe-1.1.10-py3-none-any.whl", hash = "sha256:ca2bee0f4faafc45250602567ef38d533e877d2ddca13003b319c551ff5b3cc5", size = 3998 }, ] [[package]] @@ -2724,27 +2726,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-ipaddress" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/6e/c24aaa183c9e5e1761b7e1785ae0286b9bdd282157b9ee75fe6cec3441bd/types-maxminddb-1.5.0.tar.gz", hash = "sha256:9146df7098d834d5f584d2393af85ef9294c67a16ace991f1635a2aa331f7854", size = 2800, upload-time = "2021-09-20T15:17:30.993Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/6e/c24aaa183c9e5e1761b7e1785ae0286b9bdd282157b9ee75fe6cec3441bd/types-maxminddb-1.5.0.tar.gz", hash = "sha256:9146df7098d834d5f584d2393af85ef9294c67a16ace991f1635a2aa331f7854", size = 2800 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/3a/7c9f2efd9cb43f0277c32c9b27969b19664c730784165f00a1e3ae6e5530/types_maxminddb-1.5.0-py3-none-any.whl", hash = "sha256:4bdcd434a6f12feefbe1fa569cc202b15556cb5a5aec38f1008446516a36dc36", size = 4303, upload-time = "2021-09-20T15:17:29.554Z" }, + { url = "https://files.pythonhosted.org/packages/54/3a/7c9f2efd9cb43f0277c32c9b27969b19664c730784165f00a1e3ae6e5530/types_maxminddb-1.5.0-py3-none-any.whl", hash = "sha256:4bdcd434a6f12feefbe1fa569cc202b15556cb5a5aec38f1008446516a36dc36", size = 4303 }, ] [[package]] name = "types-protobuf" version = "4.24.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/8c/b8154e316ec3ed3f710207a0fc2de64bf8775f7b744ff34096e2d1ea1448/types-protobuf-4.24.0.1.tar.gz", hash = "sha256:90adea3b693d6a40d8ef075c58fe6b5cc6e01fe1496301a7e6fc70398dcff92e", size = 47648, upload-time = "2023-08-13T21:11:07.079Z" } +sdist = { url = "https://files.pythonhosted.org/packages/84/8c/b8154e316ec3ed3f710207a0fc2de64bf8775f7b744ff34096e2d1ea1448/types-protobuf-4.24.0.1.tar.gz", hash = "sha256:90adea3b693d6a40d8ef075c58fe6b5cc6e01fe1496301a7e6fc70398dcff92e", size = 47648 } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/f4/22c136d9587e693f2eed6ef98074bb4c4b318c5c85ebfed3a033086a6b2e/types_protobuf-4.24.0.1-py3-none-any.whl", hash = "sha256:df203a204e4ae97d4cca4c9cf725262579dd7857a19f9e7fc74871ccfa073c01", size = 61656, upload-time = "2023-08-13T21:11:05.821Z" }, + { url = "https://files.pythonhosted.org/packages/71/f4/22c136d9587e693f2eed6ef98074bb4c4b318c5c85ebfed3a033086a6b2e/types_protobuf-4.24.0.1-py3-none-any.whl", hash = "sha256:df203a204e4ae97d4cca4c9cf725262579dd7857a19f9e7fc74871ccfa073c01", size = 61656 }, ] [[package]] name = "types-psycopg2" version = "2.9.21.20260518" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/46/61f27369bd1426ea718f759249a5160463522ace6325bcfcbb846305646d/types_psycopg2-2.9.21.20260518.tar.gz", hash = "sha256:8b1f80d90d6799a4fcdac12198b382a8feee9ed4340d5f69b56fc5ffa0644143", size = 27241, upload-time = "2026-05-18T06:01:42.167Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/46/61f27369bd1426ea718f759249a5160463522ace6325bcfcbb846305646d/types_psycopg2-2.9.21.20260518.tar.gz", hash = "sha256:8b1f80d90d6799a4fcdac12198b382a8feee9ed4340d5f69b56fc5ffa0644143", size = 27241 } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/87/41f48317ec5fea2cc9e881547600f40bcf9021f2b63183d9b0705d0aa72b/types_psycopg2-2.9.21.20260518-py3-none-any.whl", hash = "sha256:2fd728a4fa3860db0a4a9813e5f49c30ed329b3d2e60e73530d9db01b2b98420", size = 24955, upload-time = "2026-05-18T06:01:40.764Z" }, + { url = "https://files.pythonhosted.org/packages/aa/87/41f48317ec5fea2cc9e881547600f40bcf9021f2b63183d9b0705d0aa72b/types_psycopg2-2.9.21.20260518-py3-none-any.whl", hash = "sha256:2fd728a4fa3860db0a4a9813e5f49c30ed329b3d2e60e73530d9db01b2b98420", size = 24955 }, ] [[package]] @@ -2760,18 +2762,18 @@ wheels = [ name = "types-pytz" version = "2025.2.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/72/b0e711fd90409f5a76c75349055d3eb19992c110f0d2d6aabbd6cfbc14bf/types_pytz-2025.2.0.20250516.tar.gz", hash = "sha256:e1216306f8c0d5da6dafd6492e72eb080c9a166171fa80dd7a1990fd8be7a7b3", size = 10940, upload-time = "2025-05-16T03:07:01.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/72/b0e711fd90409f5a76c75349055d3eb19992c110f0d2d6aabbd6cfbc14bf/types_pytz-2025.2.0.20250516.tar.gz", hash = "sha256:e1216306f8c0d5da6dafd6492e72eb080c9a166171fa80dd7a1990fd8be7a7b3", size = 10940 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ba/e205cd11c1c7183b23c97e4bcd1de7bc0633e2e867601c32ecfc6ad42675/types_pytz-2025.2.0.20250516-py3-none-any.whl", hash = "sha256:e0e0c8a57e2791c19f718ed99ab2ba623856b11620cb6b637e5f62ce285a7451", size = 10136, upload-time = "2025-05-16T03:07:01.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/e205cd11c1c7183b23c97e4bcd1de7bc0633e2e867601c32ecfc6ad42675/types_pytz-2025.2.0.20250516-py3-none-any.whl", hash = "sha256:e0e0c8a57e2791c19f718ed99ab2ba623856b11620cb6b637e5f62ce285a7451", size = 10136 }, ] [[package]] name = "types-pyyaml" version = "6.0.12.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, + { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312 }, ] [[package]] @@ -2781,54 +2783,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/76de4c42bf515069c8d47306539a57f8d46cbed6d0c714b70fe7ec28a10d/types-requests-2.27.7.tar.gz", hash = "sha256:f38bd488528cdcbce5b01dc953972f3cead0d060cfd9ee35b363066c25bab13c", size = 9654, upload-time = "2022-01-13T21:15:51.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/76de4c42bf515069c8d47306539a57f8d46cbed6d0c714b70fe7ec28a10d/types-requests-2.27.7.tar.gz", hash = "sha256:f38bd488528cdcbce5b01dc953972f3cead0d060cfd9ee35b363066c25bab13c", size = 9654 } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/2b348b3b4eaba4cc80ee8365458bbccdf8f911d196fed0f5cfefc38cf678/types_requests-2.27.7-py3-none-any.whl", hash = "sha256:2e0e100dd489f83870d4f61949d3a7eae4821e7bfbf46c57e463c38f92d473d4", size = 11847, upload-time = "2022-01-13T21:15:49.956Z" }, + { url = "https://files.pythonhosted.org/packages/45/58/2b348b3b4eaba4cc80ee8365458bbccdf8f911d196fed0f5cfefc38cf678/types_requests-2.27.7-py3-none-any.whl", hash = "sha256:2e0e100dd489f83870d4f61949d3a7eae4821e7bfbf46c57e463c38f92d473d4", size = 11847 }, ] [[package]] name = "types-simplejson" version = "3.20.0.20250326" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/14/e26fc55e1ea56f9ea470917d3e2f8240e6d043ca914181021d04115ae0f7/types_simplejson-3.20.0.20250326.tar.gz", hash = "sha256:b2689bc91e0e672d7a5a947b4cb546b76ae7ddc2899c6678e72a10bf96cd97d2", size = 10489, upload-time = "2025-03-26T02:53:35.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/14/e26fc55e1ea56f9ea470917d3e2f8240e6d043ca914181021d04115ae0f7/types_simplejson-3.20.0.20250326.tar.gz", hash = "sha256:b2689bc91e0e672d7a5a947b4cb546b76ae7ddc2899c6678e72a10bf96cd97d2", size = 10489 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/bf/d3f3a5ba47fd18115e8446d39f025b85905d2008677c29ee4d03b4cddd57/types_simplejson-3.20.0.20250326-py3-none-any.whl", hash = "sha256:db1ddea7b8f7623b27a137578f22fc6c618db8c83ccfb1828ca0d2f0ec11efa7", size = 10462, upload-time = "2025-03-26T02:53:35.036Z" }, + { url = "https://files.pythonhosted.org/packages/76/bf/d3f3a5ba47fd18115e8446d39f025b85905d2008677c29ee4d03b4cddd57/types_simplejson-3.20.0.20250326-py3-none-any.whl", hash = "sha256:db1ddea7b8f7623b27a137578f22fc6c618db8c83ccfb1828ca0d2f0ec11efa7", size = 10462 }, ] [[package]] name = "types-six" version = "1.17.0.20250515" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/78/344047eeced8d230140aa3d9503aa969acb61c6095e7308bbc1ff1de3865/types_six-1.17.0.20250515.tar.gz", hash = "sha256:f4f7f0398cb79304e88397336e642b15e96fbeacf5b96d7625da366b069d2d18", size = 15598, upload-time = "2025-05-15T03:04:19.806Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/78/344047eeced8d230140aa3d9503aa969acb61c6095e7308bbc1ff1de3865/types_six-1.17.0.20250515.tar.gz", hash = "sha256:f4f7f0398cb79304e88397336e642b15e96fbeacf5b96d7625da366b069d2d18", size = 15598 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/85/5ee1c8e35b33b9c8ea1816d5a4e119c27f8bb1539b73b1f636f07aa64750/types_six-1.17.0.20250515-py3-none-any.whl", hash = "sha256:adfaa9568caf35e03d80ffa4ed765c33b282579c869b40bf4b6009c7d8db3fb1", size = 19987, upload-time = "2025-05-15T03:04:18.556Z" }, + { url = "https://files.pythonhosted.org/packages/d1/85/5ee1c8e35b33b9c8ea1816d5a4e119c27f8bb1539b73b1f636f07aa64750/types_six-1.17.0.20250515-py3-none-any.whl", hash = "sha256:adfaa9568caf35e03d80ffa4ed765c33b282579c869b40bf4b6009c7d8db3fb1", size = 19987 }, ] [[package]] name = "types-urllib3" version = "1.26.25.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" }, + { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377 }, ] [[package]] name = "types-werkzeug" version = "1.0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/43/161261d2ac1fc20e944aa108e48a98ff0d994e19b498d6fb19d6637caf05/types-Werkzeug-1.0.9.tar.gz", hash = "sha256:5cc269604c400133d452a40cee6397655f878fc460e03fde291b9e3a5eaa518c", size = 23909, upload-time = "2021-11-26T06:21:28.33Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/43/161261d2ac1fc20e944aa108e48a98ff0d994e19b498d6fb19d6637caf05/types-Werkzeug-1.0.9.tar.gz", hash = "sha256:5cc269604c400133d452a40cee6397655f878fc460e03fde291b9e3a5eaa518c", size = 23909 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/c1/eaf8426126eafa46d649afb2fddede327043fbc2e84021b8b09a7fa15115/types_Werkzeug-1.0.9-py3-none-any.whl", hash = "sha256:194bd5715a13c598f05c63e8a739328657590943bce941e8a3619a6b5d4a54ec", size = 36186, upload-time = "2021-11-26T06:21:27.37Z" }, + { url = "https://files.pythonhosted.org/packages/4a/c1/eaf8426126eafa46d649afb2fddede327043fbc2e84021b8b09a7fa15115/types_Werkzeug-1.0.9-py3-none-any.whl", hash = "sha256:194bd5715a13c598f05c63e8a739328657590943bce941e8a3619a6b5d4a54ec", size = 36186 }, ] [[package]] name = "typing-extensions" version = "4.12.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] [[package]] @@ -2839,45 +2841,45 @@ dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825 } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827 }, ] [[package]] name = "uc-micro-py" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/78/67/9a363818028526e2d4579334460df777115bdec1bb77c08f9db88f6389f2/uc_micro_py-2.0.0.tar.gz", hash = "sha256:c53691e495c8db60e16ffc4861a35469b0ba0821fe409a8a7a0a71864d33a811", size = 6611, upload-time = "2026-03-01T06:31:27.526Z" } +sdist = { url = "https://files.pythonhosted.org/packages/78/67/9a363818028526e2d4579334460df777115bdec1bb77c08f9db88f6389f2/uc_micro_py-2.0.0.tar.gz", hash = "sha256:c53691e495c8db60e16ffc4861a35469b0ba0821fe409a8a7a0a71864d33a811", size = 6611 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/73/d21edf5b204d1467e06500080a50f79d49ef2b997c79123a536d4a17d97c/uc_micro_py-2.0.0-py3-none-any.whl", hash = "sha256:3603a3859af53e5a39bc7677713c78ea6589ff188d70f4fee165db88e22b242c", size = 6383, upload-time = "2026-03-01T06:31:26.257Z" }, + { url = "https://files.pythonhosted.org/packages/61/73/d21edf5b204d1467e06500080a50f79d49ef2b997c79123a536d4a17d97c/uc_micro_py-2.0.0-py3-none-any.whl", hash = "sha256:3603a3859af53e5a39bc7677713c78ea6589ff188d70f4fee165db88e22b242c", size = 6383 }, ] [[package]] name = "unidecode" version = "1.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701, upload-time = "2024-01-11T11:58:35.609Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494, upload-time = "2024-01-11T11:58:33.012Z" }, + { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 }, ] [[package]] name = "uritemplate" version = "4.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload-time = "2025-06-02T15:12:06.318Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" }, + { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488 }, ] [[package]] name = "urllib3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087 }, ] [[package]] @@ -2890,144 +2892,144 @@ dependencies = [ { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0d/4e93c8e6d1001a75763f87d8f5ecda8ebc7f4aa2153dddfaf4ae8892821a/virtualenv-21.4.2.tar.gz", hash = "sha256:38e6ee0a555615c0ea9da2ac7e9998fe8dc3b911dd33ad8eaad2020957653b0c", size = 7613326, upload-time = "2026-05-31T17:01:22.827Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/0d/4e93c8e6d1001a75763f87d8f5ecda8ebc7f4aa2153dddfaf4ae8892821a/virtualenv-21.4.2.tar.gz", hash = "sha256:38e6ee0a555615c0ea9da2ac7e9998fe8dc3b911dd33ad8eaad2020957653b0c", size = 7613326 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/c4/557dc082be035381b85fdb2b74e21d3d21b57750b74f2b47a32f3a639ff9/virtualenv-21.4.2-py3-none-any.whl", hash = "sha256:854210ca524a1a4d0d744734f4acbc721c3ffe163b85bbf5d56d14d5ae2f0fae", size = 7594079, upload-time = "2026-05-31T17:01:20.735Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c4/557dc082be035381b85fdb2b74e21d3d21b57750b74f2b47a32f3a639ff9/virtualenv-21.4.2-py3-none-any.whl", hash = "sha256:854210ca524a1a4d0d744734f4acbc721c3ffe163b85bbf5d56d14d5ae2f0fae", size = 7594079 }, ] [[package]] name = "wcwidth" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" }, + { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825 }, ] [[package]] name = "werkzeug" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/27/a33329150147594eff0ea4c33c2036c0eadd933141055be0ff911f7f8d04/Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c", size = 904455, upload-time = "2020-03-31T18:03:37.943Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/27/a33329150147594eff0ea4c33c2036c0eadd933141055be0ff911f7f8d04/Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c", size = 904455 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", size = 298631, upload-time = "2020-03-31T18:03:34.839Z" }, + { url = "https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43", size = 298631 }, ] [[package]] name = "wrapt" version = "1.17.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, - { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, - { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, - { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, - { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, - { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, - { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, - { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, - { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, - { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, - { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, - { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, - { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, - { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, - { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, - { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, - { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, - { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003, upload-time = "2025-08-12T05:51:48.627Z" }, - { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025, upload-time = "2025-08-12T05:51:37.156Z" }, - { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108, upload-time = "2025-08-12T05:51:58.425Z" }, - { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072, upload-time = "2025-08-12T05:52:37.53Z" }, - { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214, upload-time = "2025-08-12T05:52:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105, upload-time = "2025-08-12T05:52:17.914Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766, upload-time = "2025-08-12T05:52:39.243Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711, upload-time = "2025-08-12T05:53:10.074Z" }, - { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885, upload-time = "2025-08-12T05:53:08.695Z" }, - { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896, upload-time = "2025-08-12T05:52:55.34Z" }, - { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132, upload-time = "2025-08-12T05:51:49.864Z" }, - { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091, upload-time = "2025-08-12T05:51:38.935Z" }, - { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172, upload-time = "2025-08-12T05:51:59.365Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163, upload-time = "2025-08-12T05:52:40.965Z" }, - { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963, upload-time = "2025-08-12T05:52:20.326Z" }, - { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945, upload-time = "2025-08-12T05:52:21.581Z" }, - { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857, upload-time = "2025-08-12T05:52:43.043Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178, upload-time = "2025-08-12T05:53:12.605Z" }, - { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310, upload-time = "2025-08-12T05:53:11.106Z" }, - { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266, upload-time = "2025-08-12T05:52:56.531Z" }, - { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544, upload-time = "2025-08-12T05:51:51.109Z" }, - { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283, upload-time = "2025-08-12T05:51:39.912Z" }, - { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366, upload-time = "2025-08-12T05:52:00.693Z" }, - { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571, upload-time = "2025-08-12T05:52:44.521Z" }, - { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094, upload-time = "2025-08-12T05:52:22.618Z" }, - { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659, upload-time = "2025-08-12T05:52:24.057Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946, upload-time = "2025-08-12T05:52:45.976Z" }, - { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717, upload-time = "2025-08-12T05:53:15.214Z" }, - { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334, upload-time = "2025-08-12T05:53:14.178Z" }, - { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471, upload-time = "2025-08-12T05:52:57.784Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482 }, + { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674 }, + { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959 }, + { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376 }, + { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604 }, + { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782 }, + { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076 }, + { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457 }, + { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745 }, + { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806 }, + { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998 }, + { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020 }, + { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098 }, + { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036 }, + { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156 }, + { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102 }, + { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732 }, + { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705 }, + { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877 }, + { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885 }, + { url = "https://files.pythonhosted.org/packages/fc/f6/759ece88472157acb55fc195e5b116e06730f1b651b5b314c66291729193/wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0", size = 54003 }, + { url = "https://files.pythonhosted.org/packages/4f/a9/49940b9dc6d47027dc850c116d79b4155f15c08547d04db0f07121499347/wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77", size = 39025 }, + { url = "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7", size = 39108 }, + { url = "https://files.pythonhosted.org/packages/0c/37/6faf15cfa41bf1f3dba80cd3f5ccc6622dfccb660ab26ed79f0178c7497f/wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277", size = 88072 }, + { url = "https://files.pythonhosted.org/packages/78/f2/efe19ada4a38e4e15b6dff39c3e3f3f73f5decf901f66e6f72fe79623a06/wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d", size = 88214 }, + { url = "https://files.pythonhosted.org/packages/40/90/ca86701e9de1622b16e09689fc24b76f69b06bb0150990f6f4e8b0eeb576/wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa", size = 87105 }, + { url = "https://files.pythonhosted.org/packages/fd/e0/d10bd257c9a3e15cbf5523025252cc14d77468e8ed644aafb2d6f54cb95d/wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050", size = 87766 }, + { url = "https://files.pythonhosted.org/packages/e8/cf/7d848740203c7b4b27eb55dbfede11aca974a51c3d894f6cc4b865f42f58/wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8", size = 36711 }, + { url = "https://files.pythonhosted.org/packages/57/54/35a84d0a4d23ea675994104e667ceff49227ce473ba6a59ba2c84f250b74/wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb", size = 38885 }, + { url = "https://files.pythonhosted.org/packages/01/77/66e54407c59d7b02a3c4e0af3783168fff8e5d61def52cda8728439d86bc/wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16", size = 36896 }, + { url = "https://files.pythonhosted.org/packages/02/a2/cd864b2a14f20d14f4c496fab97802001560f9f41554eef6df201cd7f76c/wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39", size = 54132 }, + { url = "https://files.pythonhosted.org/packages/d5/46/d011725b0c89e853dc44cceb738a307cde5d240d023d6d40a82d1b4e1182/wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235", size = 39091 }, + { url = "https://files.pythonhosted.org/packages/2e/9e/3ad852d77c35aae7ddebdbc3b6d35ec8013af7d7dddad0ad911f3d891dae/wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c", size = 39172 }, + { url = "https://files.pythonhosted.org/packages/c3/f7/c983d2762bcce2326c317c26a6a1e7016f7eb039c27cdf5c4e30f4160f31/wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b", size = 87163 }, + { url = "https://files.pythonhosted.org/packages/e4/0f/f673f75d489c7f22d17fe0193e84b41540d962f75fce579cf6873167c29b/wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa", size = 87963 }, + { url = "https://files.pythonhosted.org/packages/df/61/515ad6caca68995da2fac7a6af97faab8f78ebe3bf4f761e1b77efbc47b5/wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7", size = 86945 }, + { url = "https://files.pythonhosted.org/packages/d3/bd/4e70162ce398462a467bc09e768bee112f1412e563620adc353de9055d33/wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4", size = 86857 }, + { url = "https://files.pythonhosted.org/packages/2b/b8/da8560695e9284810b8d3df8a19396a6e40e7518059584a1a394a2b35e0a/wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10", size = 37178 }, + { url = "https://files.pythonhosted.org/packages/db/c8/b71eeb192c440d67a5a0449aaee2310a1a1e8eca41676046f99ed2487e9f/wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6", size = 39310 }, + { url = "https://files.pythonhosted.org/packages/45/20/2cda20fd4865fa40f86f6c46ed37a2a8356a7a2fde0773269311f2af56c7/wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58", size = 37266 }, + { url = "https://files.pythonhosted.org/packages/77/ed/dd5cf21aec36c80443c6f900449260b80e2a65cf963668eaef3b9accce36/wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a", size = 56544 }, + { url = "https://files.pythonhosted.org/packages/8d/96/450c651cc753877ad100c7949ab4d2e2ecc4d97157e00fa8f45df682456a/wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067", size = 40283 }, + { url = "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454", size = 40366 }, + { url = "https://files.pythonhosted.org/packages/64/0e/f4472f2fdde2d4617975144311f8800ef73677a159be7fe61fa50997d6c0/wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e", size = 108571 }, + { url = "https://files.pythonhosted.org/packages/cc/01/9b85a99996b0a97c8a17484684f206cbb6ba73c1ce6890ac668bcf3838fb/wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f", size = 113094 }, + { url = "https://files.pythonhosted.org/packages/25/02/78926c1efddcc7b3aa0bc3d6b33a822f7d898059f7cd9ace8c8318e559ef/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056", size = 110659 }, + { url = "https://files.pythonhosted.org/packages/dc/ee/c414501ad518ac3e6fe184753632fe5e5ecacdcf0effc23f31c1e4f7bfcf/wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804", size = 106946 }, + { url = "https://files.pythonhosted.org/packages/be/44/a1bd64b723d13bb151d6cc91b986146a1952385e0392a78567e12149c7b4/wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977", size = 38717 }, + { url = "https://files.pythonhosted.org/packages/79/d9/7cfd5a312760ac4dd8bf0184a6ee9e43c33e47f3dadc303032ce012b8fa3/wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116", size = 41334 }, + { url = "https://files.pythonhosted.org/packages/46/78/10ad9781128ed2f99dbc474f43283b13fea8ba58723e98844367531c18e9/wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6", size = 38471 }, + { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591 }, ] [[package]] name = "xmltodict" version = "1.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" }, + { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580 }, ] [[package]] name = "zope-event" version = "6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/93/41/faa10af34d48d9cd6fa0249a1162943ad84a9590bd1a06939981e6640416/zope_event-6.2.tar.gz", hash = "sha256:b97d5d6327067ee6b9dfcbdf606ade9ade70991e19c162e808ea39e5fcf0f8d3", size = 18958, upload-time = "2026-04-28T06:24:10.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/93/41/faa10af34d48d9cd6fa0249a1162943ad84a9590bd1a06939981e6640416/zope_event-6.2.tar.gz", hash = "sha256:b97d5d6327067ee6b9dfcbdf606ade9ade70991e19c162e808ea39e5fcf0f8d3", size = 18958 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/33/848922889e946d4befc415c219fe516af75c49555d8e736e183bfd30db42/zope_event-6.2-py3-none-any.whl", hash = "sha256:5e755153ac4faf64c10a4b6dd3307680166a3edf65b38df22df592610f8fa874", size = 6525, upload-time = "2026-04-28T06:24:09.176Z" }, + { url = "https://files.pythonhosted.org/packages/9e/33/848922889e946d4befc415c219fe516af75c49555d8e736e183bfd30db42/zope_event-6.2-py3-none-any.whl", hash = "sha256:5e755153ac4faf64c10a4b6dd3307680166a3edf65b38df22df592610f8fa874", size = 6525 }, ] [[package]] name = "zope-interface" version = "8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/08/dc/50550cfcbb2ea3cbca5f1d7ed05c8aa840f831a0f2d63aec0a953f7c590e/zope_interface-8.5.tar.gz", hash = "sha256:7a3ba1c5877f0f3e3906b02ddf793abed2becc2948116414ce0e1dd820b68d6d", size = 257957, upload-time = "2026-05-26T06:50:14.574Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/f1/83ad110fb847413affe71609bb50e59e1aa082e1236030122227c7c283d3/zope_interface-8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:afc66ccaef2a3c0bef6ca02aad40d29a39276389dad16a8eac36f9f385e4d057", size = 211426, upload-time = "2026-05-26T06:49:12.595Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a7/6b6e0c31ac240cb9fc015ae9ed45ca54be886c18fcf7bfa2377a4d7a8785/zope_interface-8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c28044972187245d7a309e4699319bfdbd2ffcbf7176d1d4ddf5adffb2dea80f", size = 211850, upload-time = "2026-05-26T06:49:14.474Z" }, - { url = "https://files.pythonhosted.org/packages/37/36/7599ecabcf80ce4fef2e1ef3c5ac0d4696b61f03f724cc44022f4d226af9/zope_interface-8.5-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:03bbecc7982af713d7499d4084bc03916413d17ffd45f89009348cc0c1d9e376", size = 260711, upload-time = "2026-05-26T06:49:16.568Z" }, - { url = "https://files.pythonhosted.org/packages/03/3e/1774b0ee46ccbb5498ee3c33ece40315b6ef58bc71957be94bd345340bc1/zope_interface-8.5-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf917009a4a7457c7290225a019f4a0aa706d96accd2cfdba2418d3bc1fcde2f", size = 265277, upload-time = "2026-05-26T06:49:18.656Z" }, - { url = "https://files.pythonhosted.org/packages/b6/09/e533b2ffabaae4e5d5730d6768a591cf335defe8e37bec2ad905d09be656/zope_interface-8.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31cff25b2aaedb5267e6e77b1e9be6b0ec4f622032de8a069202b8ffacda7dc2", size = 266369, upload-time = "2026-05-26T06:49:20.174Z" }, - { url = "https://files.pythonhosted.org/packages/49/4a/3ebe6a4c122b2d5340db45cbe7e490663d3228b172710ec71060cd5d541e/zope_interface-8.5-cp311-cp311-win_amd64.whl", hash = "sha256:17a3114bbdddb5e75e5784cdf318944636190cbbc72d357ef9fb1a8b0351f955", size = 215161, upload-time = "2026-05-26T06:49:21.799Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/056ad97af5b16db1975ee98ec7ab03d2ce3f3355efad904ced1dbce0e39f/zope_interface-8.5-cp311-cp311-win_arm64.whl", hash = "sha256:aab6bb5bee10f38ea688b95ba054396b67f613552d2c8378be7fcb2d2fba7646", size = 213481, upload-time = "2026-05-26T06:49:25.085Z" }, - { url = "https://files.pythonhosted.org/packages/97/cc/b84123a948f3162a34623e188922827cd845244fdd043ed20f8d02228caa/zope_interface-8.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8e6ee90c2e6de7c37058d5fa41f123c8b13a312db8d1e0fb5840d7f4bcdff9c9", size = 212165, upload-time = "2026-05-26T06:49:26.566Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/cbceec44f1b27208a76c1a688c131302685852406a23df5aab68324109cc/zope_interface-8.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c1adc90d3576b3b4c4de4953e6002c37bef28b78d7fa54c1bbfd0c50f022fe7c", size = 212341, upload-time = "2026-05-26T06:49:28.182Z" }, - { url = "https://files.pythonhosted.org/packages/e1/c3/005032195ff3b210c139b7c560ed5c534e844b0907d8e44d2b3d8919305e/zope_interface-8.5-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:e6347b8d8d12c5eca6502450a92be30079b7acfade2c4f693efa0deb8871b06e", size = 265296, upload-time = "2026-05-26T06:49:29.741Z" }, - { url = "https://files.pythonhosted.org/packages/c5/66/1036543d6a66bc04c19df3cf650f3ad938a002ab0a443c24e23e8de5e8b9/zope_interface-8.5-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5e970dabea777a24b0b0bbf9dae3ab75ce8b2d8e948edf4875627034b21f3560", size = 270689, upload-time = "2026-05-26T06:49:31.767Z" }, - { url = "https://files.pythonhosted.org/packages/30/4c/8b56259558cace4414e753ca6740396a1f59d4a95ddb55b4658600408670/zope_interface-8.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f0b48ccadaa9839e09ff81e969703cecb3f402c813bfe8b958652e699bea69f5", size = 270280, upload-time = "2026-05-26T06:49:33.489Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ea/649908c83aa8fdb7faf2ddca4d3cf6fb8f2157121267dc56e8f72681e26c/zope_interface-8.5-cp312-cp312-win_amd64.whl", hash = "sha256:e0e311f1277468c08fd59a2b41f71b43d25dff639789d364747acd1705c0df6e", size = 215019, upload-time = "2026-05-26T06:49:35.607Z" }, - { url = "https://files.pythonhosted.org/packages/9f/97/da13037b4c563e4df32eedbc819f8c00b754af494f68211e3dffd48d52da/zope_interface-8.5-cp312-cp312-win_arm64.whl", hash = "sha256:652b73107a04159ec6c020db6c1543d4f1e8f4d069bd2aac88a947820923517b", size = 213569, upload-time = "2026-05-26T06:49:37.317Z" }, - { url = "https://files.pythonhosted.org/packages/f4/8c/4c15755d701f2ec0e80d64a18e1ebaf5be2c584c0ec153fd516f5d13eada/zope_interface-8.5-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:28e80457c134d1fa57a7d758004dece348654e1b1467ac22dcdc20fc1d127c52", size = 212512, upload-time = "2026-05-26T06:49:38.996Z" }, - { url = "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:09495ce9d559c06b70f2d4855b3e4f48a822a9ddc8be1d30c5b4e5be14ae1ace", size = 212541, upload-time = "2026-05-26T06:49:41.186Z" }, - { url = "https://files.pythonhosted.org/packages/aa/a5/692a2b8d70f78e848793231d5fae5fecbf8d0cccd73430fdc34802a6d3c1/zope_interface-8.5-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:7849ad8fa90763cc1087f4dda78ca3a233e950b3e08fac7079297c9cafbbd7bb", size = 265191, upload-time = "2026-05-26T06:49:43.449Z" }, - { url = "https://files.pythonhosted.org/packages/70/8d/454a9cfc7a050c394ab4f11b3371f7897828b7415e096afff724637e65e0/zope_interface-8.5-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5578c9421ca409a1f39f153d6f7803e4cde01da592ec75a9ac5e1b777d18d33b", size = 270626, upload-time = "2026-05-26T06:49:45.425Z" }, - { url = "https://files.pythonhosted.org/packages/51/8c/db8409cfa3575b8e9b4800babd7d49f8228433cd1f0c56814bd0ada49c33/zope_interface-8.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e1bd7d96b4ca5fa311f54c9eac16dce4886b428c1531dbe06067763ccdf123b4", size = 270444, upload-time = "2026-05-26T06:49:47.025Z" }, - { url = "https://files.pythonhosted.org/packages/4a/df/a386940e41469ef615e100a216d8b386521e9e598817147f87932ca203c4/zope_interface-8.5-cp313-cp313-win_amd64.whl", hash = "sha256:0c8123d2a4dfde2a613c7cb772605477724782c20bc2e0ad1d9435376a6a44a3", size = 215021, upload-time = "2026-05-26T06:49:48.478Z" }, - { url = "https://files.pythonhosted.org/packages/89/75/477eb5669b6b2a7a843decd1a075e9b1971a8720017654143a7183abd3d9/zope_interface-8.5-cp313-cp313-win_arm64.whl", hash = "sha256:6d02be14f3173c6c7288bc2fdf530090c01c3cf8764ad46c68024686f364278e", size = 213610, upload-time = "2026-05-26T06:49:50.01Z" }, - { url = "https://files.pythonhosted.org/packages/d4/19/5032e954827fdf02db2d2f49737ac4378bb9cfc2cd95a8f2e2a5ae2ec01a/zope_interface-8.5-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:ffaecf013251a89d0de6feb49a46eba48ad8cbbf8a40aeb6045e459e7bec6784", size = 212597, upload-time = "2026-05-26T06:49:51.63Z" }, - { url = "https://files.pythonhosted.org/packages/f1/53/3ef644012cf8a6a234a2d6134aab5a5c65ac5467c86296865501d4fbc406/zope_interface-8.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:126fa9d1c52295ae076d4cf968634f0a1826afa408a20808b57ff72877b8f69f", size = 212626, upload-time = "2026-05-26T06:49:53.236Z" }, - { url = "https://files.pythonhosted.org/packages/32/67/bc8b4f465d388039255003e230c284a175cedf1203c692f23cb7bff64efe/zope_interface-8.5-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:3090e3a663d20194756a59a272e0c8508b889341e31d5894223331fe6b4f9b21", size = 266827, upload-time = "2026-05-26T06:49:54.873Z" }, - { url = "https://files.pythonhosted.org/packages/a7/eb/37d05b935ede53d79690fecc8d201440084418e590bcfc05f384451c7593/zope_interface-8.5-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9342fb74e2afefdb081bf1df727d209ea56995c6e13f5a0540e6d7aff4beafb8", size = 270139, upload-time = "2026-05-26T06:49:57.116Z" }, - { url = "https://files.pythonhosted.org/packages/8b/0b/fd0c54579e2ce8dc6cf1a757903f3374bc6fbda929a46af9e0f53cb0e5f0/zope_interface-8.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6c54725d818f1b57a7efb8b16528326e1f3c257b602b32393fd255c45af8799d", size = 270338, upload-time = "2026-05-26T06:49:58.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/1d/c420dcd777bb761067ea92879ac766694a5ca78608185f1aecea64cbfc11/zope_interface-8.5-cp314-cp314-win_amd64.whl", hash = "sha256:29d74febbae1afeb6834c4ccbf42e242a673c860060f09e53142825270456140", size = 215789, upload-time = "2026-05-26T06:50:00.405Z" }, - { url = "https://files.pythonhosted.org/packages/62/94/50b5eb8f94e527edceac14f9955e58917424ea79bb572ddc18548561cbc2/zope_interface-8.5-cp314-cp314-win_arm64.whl", hash = "sha256:633c8c49396f38df030340797c533e9fe460d1b5d1e42d88e55e938e525f548c", size = 213757, upload-time = "2026-05-26T06:50:01.973Z" }, - { url = "https://files.pythonhosted.org/packages/17/6f/5d5f32c4dfcdb16ce2ec5363da686840f13c13e1a1214cb70b49e1cd6d9f/zope_interface-8.5-cp314-cp314t-macosx_10_9_x86_64.whl", hash = "sha256:133999820fdbae513c36c03d6f29ef87317aaa3edef39112222b155083664714", size = 213591, upload-time = "2026-05-26T06:50:03.529Z" }, - { url = "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8bd75c96966e573232f0599deaff717564828031c7f05563ccc1ac35c5ee0304", size = 213733, upload-time = "2026-05-26T06:50:05.101Z" }, - { url = "https://files.pythonhosted.org/packages/c2/95/d97430abd5ae9677e8b9295b58720c0064a5b557dbb6b8bf5928484cf0d8/zope_interface-8.5-cp314-cp314t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:14b0e9799351d4c34fe99afd67f0cdd76e55ba15c66a98699d5fc22ea8241e08", size = 294905, upload-time = "2026-05-26T06:50:07.384Z" }, - { url = "https://files.pythonhosted.org/packages/41/ec/a0f8f3dad6e74992f4654bdd94802be0929eabca7b871cac3b6fbb5e961b/zope_interface-8.5-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0cd6a732ac84b94eb1ef9222a117347a27efd294ee16810ffdf7ecd307677ed5", size = 300885, upload-time = "2026-05-26T06:50:08.997Z" }, - { url = "https://files.pythonhosted.org/packages/0f/da/6881b48803a0ee8d23eb5efa30fce3ed218a2bd9de5758ce489d224fee81/zope_interface-8.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:798b7c87d0e59a7d5d086d642208d0d8700ff0d55c4029134b3c479c3bfb110f", size = 304672, upload-time = "2026-05-26T06:50:10.563Z" }, - { url = "https://files.pythonhosted.org/packages/2e/0e/b4c01320859ff1d585438bc231fd60bd258d096359bccf6654fecdf0cffb/zope_interface-8.5-cp314-cp314t-win_amd64.whl", hash = "sha256:0fc3a9d45f114d27eaa1e53beeb144533689edca8a9f66505b1e8e8b3f075e42", size = 217241, upload-time = "2026-05-26T06:50:12.171Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/08/dc/50550cfcbb2ea3cbca5f1d7ed05c8aa840f831a0f2d63aec0a953f7c590e/zope_interface-8.5.tar.gz", hash = "sha256:7a3ba1c5877f0f3e3906b02ddf793abed2becc2948116414ce0e1dd820b68d6d", size = 257957 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/f1/83ad110fb847413affe71609bb50e59e1aa082e1236030122227c7c283d3/zope_interface-8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:afc66ccaef2a3c0bef6ca02aad40d29a39276389dad16a8eac36f9f385e4d057", size = 211426 }, + { url = "https://files.pythonhosted.org/packages/bb/a7/6b6e0c31ac240cb9fc015ae9ed45ca54be886c18fcf7bfa2377a4d7a8785/zope_interface-8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c28044972187245d7a309e4699319bfdbd2ffcbf7176d1d4ddf5adffb2dea80f", size = 211850 }, + { url = "https://files.pythonhosted.org/packages/37/36/7599ecabcf80ce4fef2e1ef3c5ac0d4696b61f03f724cc44022f4d226af9/zope_interface-8.5-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:03bbecc7982af713d7499d4084bc03916413d17ffd45f89009348cc0c1d9e376", size = 260711 }, + { url = "https://files.pythonhosted.org/packages/03/3e/1774b0ee46ccbb5498ee3c33ece40315b6ef58bc71957be94bd345340bc1/zope_interface-8.5-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf917009a4a7457c7290225a019f4a0aa706d96accd2cfdba2418d3bc1fcde2f", size = 265277 }, + { url = "https://files.pythonhosted.org/packages/b6/09/e533b2ffabaae4e5d5730d6768a591cf335defe8e37bec2ad905d09be656/zope_interface-8.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31cff25b2aaedb5267e6e77b1e9be6b0ec4f622032de8a069202b8ffacda7dc2", size = 266369 }, + { url = "https://files.pythonhosted.org/packages/49/4a/3ebe6a4c122b2d5340db45cbe7e490663d3228b172710ec71060cd5d541e/zope_interface-8.5-cp311-cp311-win_amd64.whl", hash = "sha256:17a3114bbdddb5e75e5784cdf318944636190cbbc72d357ef9fb1a8b0351f955", size = 215161 }, + { url = "https://files.pythonhosted.org/packages/d2/59/056ad97af5b16db1975ee98ec7ab03d2ce3f3355efad904ced1dbce0e39f/zope_interface-8.5-cp311-cp311-win_arm64.whl", hash = "sha256:aab6bb5bee10f38ea688b95ba054396b67f613552d2c8378be7fcb2d2fba7646", size = 213481 }, + { url = "https://files.pythonhosted.org/packages/97/cc/b84123a948f3162a34623e188922827cd845244fdd043ed20f8d02228caa/zope_interface-8.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8e6ee90c2e6de7c37058d5fa41f123c8b13a312db8d1e0fb5840d7f4bcdff9c9", size = 212165 }, + { url = "https://files.pythonhosted.org/packages/4e/78/cbceec44f1b27208a76c1a688c131302685852406a23df5aab68324109cc/zope_interface-8.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c1adc90d3576b3b4c4de4953e6002c37bef28b78d7fa54c1bbfd0c50f022fe7c", size = 212341 }, + { url = "https://files.pythonhosted.org/packages/e1/c3/005032195ff3b210c139b7c560ed5c534e844b0907d8e44d2b3d8919305e/zope_interface-8.5-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:e6347b8d8d12c5eca6502450a92be30079b7acfade2c4f693efa0deb8871b06e", size = 265296 }, + { url = "https://files.pythonhosted.org/packages/c5/66/1036543d6a66bc04c19df3cf650f3ad938a002ab0a443c24e23e8de5e8b9/zope_interface-8.5-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5e970dabea777a24b0b0bbf9dae3ab75ce8b2d8e948edf4875627034b21f3560", size = 270689 }, + { url = "https://files.pythonhosted.org/packages/30/4c/8b56259558cace4414e753ca6740396a1f59d4a95ddb55b4658600408670/zope_interface-8.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f0b48ccadaa9839e09ff81e969703cecb3f402c813bfe8b958652e699bea69f5", size = 270280 }, + { url = "https://files.pythonhosted.org/packages/f9/ea/649908c83aa8fdb7faf2ddca4d3cf6fb8f2157121267dc56e8f72681e26c/zope_interface-8.5-cp312-cp312-win_amd64.whl", hash = "sha256:e0e311f1277468c08fd59a2b41f71b43d25dff639789d364747acd1705c0df6e", size = 215019 }, + { url = "https://files.pythonhosted.org/packages/9f/97/da13037b4c563e4df32eedbc819f8c00b754af494f68211e3dffd48d52da/zope_interface-8.5-cp312-cp312-win_arm64.whl", hash = "sha256:652b73107a04159ec6c020db6c1543d4f1e8f4d069bd2aac88a947820923517b", size = 213569 }, + { url = "https://files.pythonhosted.org/packages/f4/8c/4c15755d701f2ec0e80d64a18e1ebaf5be2c584c0ec153fd516f5d13eada/zope_interface-8.5-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:28e80457c134d1fa57a7d758004dece348654e1b1467ac22dcdc20fc1d127c52", size = 212512 }, + { url = "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:09495ce9d559c06b70f2d4855b3e4f48a822a9ddc8be1d30c5b4e5be14ae1ace", size = 212541 }, + { url = "https://files.pythonhosted.org/packages/aa/a5/692a2b8d70f78e848793231d5fae5fecbf8d0cccd73430fdc34802a6d3c1/zope_interface-8.5-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:7849ad8fa90763cc1087f4dda78ca3a233e950b3e08fac7079297c9cafbbd7bb", size = 265191 }, + { url = "https://files.pythonhosted.org/packages/70/8d/454a9cfc7a050c394ab4f11b3371f7897828b7415e096afff724637e65e0/zope_interface-8.5-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5578c9421ca409a1f39f153d6f7803e4cde01da592ec75a9ac5e1b777d18d33b", size = 270626 }, + { url = "https://files.pythonhosted.org/packages/51/8c/db8409cfa3575b8e9b4800babd7d49f8228433cd1f0c56814bd0ada49c33/zope_interface-8.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e1bd7d96b4ca5fa311f54c9eac16dce4886b428c1531dbe06067763ccdf123b4", size = 270444 }, + { url = "https://files.pythonhosted.org/packages/4a/df/a386940e41469ef615e100a216d8b386521e9e598817147f87932ca203c4/zope_interface-8.5-cp313-cp313-win_amd64.whl", hash = "sha256:0c8123d2a4dfde2a613c7cb772605477724782c20bc2e0ad1d9435376a6a44a3", size = 215021 }, + { url = "https://files.pythonhosted.org/packages/89/75/477eb5669b6b2a7a843decd1a075e9b1971a8720017654143a7183abd3d9/zope_interface-8.5-cp313-cp313-win_arm64.whl", hash = "sha256:6d02be14f3173c6c7288bc2fdf530090c01c3cf8764ad46c68024686f364278e", size = 213610 }, + { url = "https://files.pythonhosted.org/packages/d4/19/5032e954827fdf02db2d2f49737ac4378bb9cfc2cd95a8f2e2a5ae2ec01a/zope_interface-8.5-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:ffaecf013251a89d0de6feb49a46eba48ad8cbbf8a40aeb6045e459e7bec6784", size = 212597 }, + { url = "https://files.pythonhosted.org/packages/f1/53/3ef644012cf8a6a234a2d6134aab5a5c65ac5467c86296865501d4fbc406/zope_interface-8.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:126fa9d1c52295ae076d4cf968634f0a1826afa408a20808b57ff72877b8f69f", size = 212626 }, + { url = "https://files.pythonhosted.org/packages/32/67/bc8b4f465d388039255003e230c284a175cedf1203c692f23cb7bff64efe/zope_interface-8.5-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:3090e3a663d20194756a59a272e0c8508b889341e31d5894223331fe6b4f9b21", size = 266827 }, + { url = "https://files.pythonhosted.org/packages/a7/eb/37d05b935ede53d79690fecc8d201440084418e590bcfc05f384451c7593/zope_interface-8.5-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9342fb74e2afefdb081bf1df727d209ea56995c6e13f5a0540e6d7aff4beafb8", size = 270139 }, + { url = "https://files.pythonhosted.org/packages/8b/0b/fd0c54579e2ce8dc6cf1a757903f3374bc6fbda929a46af9e0f53cb0e5f0/zope_interface-8.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6c54725d818f1b57a7efb8b16528326e1f3c257b602b32393fd255c45af8799d", size = 270338 }, + { url = "https://files.pythonhosted.org/packages/c1/1d/c420dcd777bb761067ea92879ac766694a5ca78608185f1aecea64cbfc11/zope_interface-8.5-cp314-cp314-win_amd64.whl", hash = "sha256:29d74febbae1afeb6834c4ccbf42e242a673c860060f09e53142825270456140", size = 215789 }, + { url = "https://files.pythonhosted.org/packages/62/94/50b5eb8f94e527edceac14f9955e58917424ea79bb572ddc18548561cbc2/zope_interface-8.5-cp314-cp314-win_arm64.whl", hash = "sha256:633c8c49396f38df030340797c533e9fe460d1b5d1e42d88e55e938e525f548c", size = 213757 }, + { url = "https://files.pythonhosted.org/packages/17/6f/5d5f32c4dfcdb16ce2ec5363da686840f13c13e1a1214cb70b49e1cd6d9f/zope_interface-8.5-cp314-cp314t-macosx_10_9_x86_64.whl", hash = "sha256:133999820fdbae513c36c03d6f29ef87317aaa3edef39112222b155083664714", size = 213591 }, + { url = "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8bd75c96966e573232f0599deaff717564828031c7f05563ccc1ac35c5ee0304", size = 213733 }, + { url = "https://files.pythonhosted.org/packages/c2/95/d97430abd5ae9677e8b9295b58720c0064a5b557dbb6b8bf5928484cf0d8/zope_interface-8.5-cp314-cp314t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:14b0e9799351d4c34fe99afd67f0cdd76e55ba15c66a98699d5fc22ea8241e08", size = 294905 }, + { url = "https://files.pythonhosted.org/packages/41/ec/a0f8f3dad6e74992f4654bdd94802be0929eabca7b871cac3b6fbb5e961b/zope_interface-8.5-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0cd6a732ac84b94eb1ef9222a117347a27efd294ee16810ffdf7ecd307677ed5", size = 300885 }, + { url = "https://files.pythonhosted.org/packages/0f/da/6881b48803a0ee8d23eb5efa30fce3ed218a2bd9de5758ce489d224fee81/zope_interface-8.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:798b7c87d0e59a7d5d086d642208d0d8700ff0d55c4029134b3c479c3bfb110f", size = 304672 }, + { url = "https://files.pythonhosted.org/packages/2e/0e/b4c01320859ff1d585438bc231fd60bd258d096359bccf6654fecdf0cffb/zope_interface-8.5-cp314-cp314t-win_amd64.whl", hash = "sha256:0fc3a9d45f114d27eaa1e53beeb144533689edca8a9f66505b1e8e8b3f075e42", size = 217241 }, ]