From 14606e7ccb03777362075b12adc85fd821b8d400 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 29 Apr 2025 15:16:02 +0200 Subject: [PATCH 01/15] Added streaming support for writer palmyra models --- libs/aws/langchain_aws/chat_models/bedrock_converse.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/aws/langchain_aws/chat_models/bedrock_converse.py b/libs/aws/langchain_aws/chat_models/bedrock_converse.py index 70d22a4c..634613f4 100644 --- a/libs/aws/langchain_aws/chat_models/bedrock_converse.py +++ b/libs/aws/langchain_aws/chat_models/bedrock_converse.py @@ -532,6 +532,9 @@ def set_disable_streaming(cls, values: Dict) -> Any: or # Cohere Command R models (provider == "cohere" and "command-r" in model_id_lower) + or + # Writer Palmyra models + (provider == "writer" and "palmyra" in model_id_lower) ): streaming_support = True elif ( From e5a6da712f5ebb7a5a7689251f3014c76bccbe26 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Fri, 2 May 2025 20:04:48 +0200 Subject: [PATCH 02/15] first commit for async session saver --- .../langgraph_checkpoint_aws/async_saver.py | 569 ++++++++++++++++++ .../langgraph_checkpoint_aws/async_session.py | 0 2 files changed, 569 insertions(+) create mode 100644 libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py create mode 100644 libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py new file mode 100644 index 00000000..73a248e0 --- /dev/null +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py @@ -0,0 +1,569 @@ +import datetime +import json +from collections.abc import AsyncIterator, Sequence +from typing import Any, Optional + +from botocore.config import Config +from botocore.exceptions import ClientError +from langchain_core.runnables import RunnableConfig +from langgraph.checkpoint.base import ( + BaseCheckpointSaver, + ChannelVersions, + Checkpoint, + CheckpointMetadata, + CheckpointTuple, + get_checkpoint_id, +) +from pydantic import SecretStr + +from langgraph_checkpoint_aws.constants import CHECKPOINT_PREFIX +from langgraph_checkpoint_aws.models import ( + BedrockSessionContentBlock, + CreateInvocationRequest, + GetInvocationStepRequest, + InvocationStep, + InvocationStepPayload, + ListInvocationStepsRequest, + PutInvocationStepRequest, + SessionCheckpoint, + SessionPendingWrite, +) +from langgraph_checkpoint_aws.async_session import AsyncBedrockAgentRuntimeSessionClient +from langgraph_checkpoint_aws.utils import ( + construct_checkpoint_tuple, + create_session_checkpoint, + deserialize_data, + generate_checkpoint_id, + generate_write_id, + process_write_operations, + process_writes_invocation_content_blocks, + transform_pending_task_writes, +) + + +class AsyncBedrockSessionSaver(BaseCheckpointSaver): + """Asynchronously saves and retrieves checkpoints using Amazon Bedrock Agent Runtime sessions. + + This class provides async functionality to persist checkpoint data and writes to Bedrock Agent Runtime sessions. + It handles creating invocations, managing checkpoint data, and tracking pending writes. + + Args: + region_name: AWS region name + credentials_profile_name: AWS credentials profile name + aws_access_key_id: AWS access key ID + aws_secret_access_key: AWS secret access key + aws_session_token: AWS session token + endpoint_url: Custom endpoint URL for the Bedrock service + config: Botocore config object + """ + + def __init__( + self, + region_name: Optional[str] = None, + credentials_profile_name: Optional[str] = None, + aws_access_key_id: Optional[SecretStr] = None, + aws_secret_access_key: Optional[SecretStr] = None, + aws_session_token: Optional[SecretStr] = None, + endpoint_url: Optional[str] = None, + config: Optional[Config] = None, + ) -> None: + super().__init__() + self.session_client = AsyncBedrockAgentRuntimeSessionClient( + region_name=region_name, + credentials_profile_name=credentials_profile_name, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + aws_session_token=aws_session_token, + endpoint_url=endpoint_url, + config=config, + ) + + async def _create_session_invocation(self, thread_id: str, invocation_id: str): + """Asynchronously create a new invocation if one doesn't already exist. + + Args: + thread_id: The session identifier + invocation_id: The unique invocation identifier + + Raises: + ClientError: If creation fails for reasons other than the invocation already existing + """ + try: + await self.session_client.create_invocation( + CreateInvocationRequest( + session_identifier=thread_id, + invocation_id=invocation_id, + ) + ) + except ClientError as e: + if e.response["Error"]["Code"] != "ConflictException": + raise e + + async def _get_checkpoint_pending_writes( + self, thread_id: str, checkpoint_ns: str, checkpoint_id: str + ) -> list[SessionPendingWrite]: + """Asynchronously retrieve pending write operations for a given checkpoint from the Bedrock session. + + This method retrieves any pending write operations that were stored for a specific checkpoint. + It first gets the most recent invocation step, then retrieves the full details of that step, + and finally parses the content blocks to reconstruct the PendingWrite objects. + + Args: + thread_id: Session thread identifier used to locate the checkpoint data + checkpoint_ns: Namespace that groups related checkpoints together + checkpoint_id: Unique identifier for the specific checkpoint to retrieve + + Returns: + List of PendingWrite objects containing task_id, channel, value, task_path and write_idx. + Returns empty list if no pending writes are found. + """ + # Generate unique ID for the write operation + writes_id = generate_write_id(checkpoint_ns, checkpoint_id) + + try: + # Retrieve most recent invocation step (limit 1) for this writes_id + invocation_steps = await self.session_client.list_invocation_steps( + ListInvocationStepsRequest( + session_identifier=thread_id, + invocation_identifier=writes_id, + max_results=1, + ) + ) + invocation_step_summaries = invocation_steps.invocation_step_summaries + + # Return empty list if no steps found + if len(invocation_step_summaries) == 0: + return [] + + # Get complete details for the most recent step + invocation_step = await self.session_client.get_invocation_step( + GetInvocationStepRequest( + session_identifier=thread_id, + invocation_identifier=writes_id, + invocation_step_id=invocation_step_summaries[0].invocation_step_id, + ) + ) + + return process_writes_invocation_content_blocks( + invocation_step.invocation_step.payload.content_blocks, self.serde + ) + + except ClientError as e: + # Return empty list if resource not found, otherwise re-raise error + if e.response["Error"]["Code"] == "ResourceNotFoundException": + return [] + raise e + + async def _save_invocation_step( + self, + thread_id: str, + invocation_identifier: str, + invocation_step_id: Optional[str], + payload: InvocationStepPayload, + ) -> None: + """Asynchronously persist an invocation step and its payload to the Bedrock session store. + + This method stores a single invocation step along with its associated payload data + in the Bedrock session. The step is timestamped with the current UTC time. + + Args: + thread_id: Unique identifier for the session thread + invocation_identifier: Identifier for the specific invocation + invocation_step_id: Unique identifier for this step within the invocation + payload: InvocationStepPayload object containing the content blocks to store + + Returns: + None + """ + await self.session_client.put_invocation_step( + PutInvocationStepRequest( + session_identifier=thread_id, + invocation_identifier=invocation_identifier, + invocation_step_id=invocation_step_id, + invocation_step_time=datetime.datetime.now(datetime.timezone.utc), + payload=payload, + ) + ) + + async def _find_most_recent_checkpoint_step( + self, thread_id: str, invocation_id: str + ) -> Optional[InvocationStep]: + """Asynchronously retrieve the most recent checkpoint step from a session's invocation history. + + Iterates through all invocation steps in reverse chronological order until it finds + a step with a checkpoint payload type. Uses pagination to handle large result sets. + + Args: + thread_id: The unique identifier for the session thread + invocation_id: The identifier for the specific invocation to search + + Returns: + InvocationStep object if a checkpoint is found, None otherwise + """ + next_token = None + while True: + # Get batch of invocation steps using pagination token if available + invocation_steps = await self.session_client.list_invocation_steps( + ListInvocationStepsRequest( + session_identifier=thread_id, + invocation_identifier=invocation_id, + next_token=next_token, + ) + ) + + # Return None if no steps found in this batch + if len(invocation_steps.invocation_step_summaries) == 0: + return None + + # Check each step in the batch for checkpoint type + for invocation_step_summary in invocation_steps.invocation_step_summaries: + invocation_step = await self.session_client.get_invocation_step( + GetInvocationStepRequest( + session_identifier=thread_id, + invocation_identifier=invocation_id, + invocation_step_id=invocation_step_summary.invocation_step_id, + ) + ) + + # Parse the step payload and check if it's a checkpoint + step_payload = json.loads( + invocation_step.invocation_step.payload.content_blocks[0].text + ) + if step_payload["step_type"] == CHECKPOINT_PREFIX: + return invocation_step.invocation_step + + # Get token for next batch of results + next_token = invocation_steps.next_token + if next_token is None: + return None + + async def _get_checkpoint_step( + self, thread_id: str, invocation_id: str, checkpoint_id: Optional[str] = None + ) -> Optional[InvocationStep]: + """Asynchronously retrieve checkpoint step data. + + Args: + thread_id: Session thread identifier + invocation_id: Invocation identifier + checkpoint_id: Optional checkpoint identifier + + Returns: + InvocationStep if found, None otherwise + """ + if checkpoint_id is None: + step = await self._find_most_recent_checkpoint_step(thread_id, invocation_id) + if step is None: + return None + return step + + response = await self.session_client.get_invocation_step( + GetInvocationStepRequest( + session_identifier=thread_id, + invocation_identifier=invocation_id, + invocation_step_id=checkpoint_id, + ) + ) + return response.invocation_step + + async def _get_task_sends( + self, thread_id: str, checkpoint_ns: str, parent_checkpoint_id: Optional[str] + ) -> list: + """Asynchronously get sorted task sends for parent checkpoint. + + Args: + thread_id: Session thread identifier + checkpoint_ns: Checkpoint namespace + parent_checkpoint_id: Parent checkpoint identifier + + Returns: + Sorted list of task sends + """ + if not parent_checkpoint_id: + return [] + + pending_writes = await self._get_checkpoint_pending_writes( + thread_id, checkpoint_ns, parent_checkpoint_id + ) + return transform_pending_task_writes(pending_writes) + + async def aget_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]: + """Asynchronously retrieve a checkpoint tuple from the Bedrock session. + + This function retrieves checkpoint data from the session, processes it and returns + a structured CheckpointTuple containing the checkpoint state and metadata. + + Args: + config (RunnableConfig): Configuration containing thread_id and optional checkpoint_ns. + + Returns: + Optional[CheckpointTuple]: Structured checkpoint data if found, None otherwise. + """ + session_thread_id = config["configurable"]["thread_id"] + checkpoint_namespace = config["configurable"].get("checkpoint_ns", "") + checkpoint_identifier = get_checkpoint_id(config) + + invocation_id = generate_checkpoint_id(checkpoint_namespace) + + try: + invocation_step = await self._get_checkpoint_step( + session_thread_id, invocation_id, checkpoint_identifier + ) + if invocation_step is None: + return None + + session_checkpoint = SessionCheckpoint( + **json.loads(invocation_step.payload.content_blocks[0].text) + ) + + pending_write_ops = await self._get_checkpoint_pending_writes( + session_thread_id, + checkpoint_namespace, + invocation_step.invocation_step_id, + ) + + task_sends = await self._get_task_sends( + session_thread_id, + checkpoint_namespace, + session_checkpoint.parent_checkpoint_id, + ) + + return construct_checkpoint_tuple( + session_thread_id, + checkpoint_namespace, + session_checkpoint, + pending_write_ops, + task_sends, + self.serde, + ) + + except ClientError as err: + if err.response["Error"]["Code"] != "ResourceNotFoundException": + raise err + return None + + async def aput( + self, + config: RunnableConfig, + checkpoint: Checkpoint, + metadata: CheckpointMetadata, + new_versions: ChannelVersions, + ) -> RunnableConfig: + """Asynchronously store a new checkpoint in the Bedrock session. + + This method persists checkpoint data and metadata to a Bedrock Agent Runtime session. + It serializes the checkpoint data, creates a session invocation, and saves an invocation + step containing the checkpoint information. + + Args: + config (RunnableConfig): Configuration containing thread_id and checkpoint namespace + checkpoint (Checkpoint): The checkpoint data to store, containing state and channel values + metadata (CheckpointMetadata): Metadata associated with the checkpoint like timestamps + new_versions (ChannelVersions): Version information for communication channels + + Returns: + RunnableConfig: Updated configuration with thread_id, checkpoint_ns and checkpoint_id + """ + session_checkpoint = create_session_checkpoint( + checkpoint, config, metadata, self.serde, new_versions + ) + + # Create session invocation to store checkpoint + checkpoint_invocation_identifier = generate_checkpoint_id( + session_checkpoint.checkpoint_ns + ) + await self._create_session_invocation( + session_checkpoint.thread_id, checkpoint_invocation_identifier + ) + await self._save_invocation_step( + session_checkpoint.thread_id, + checkpoint_invocation_identifier, + session_checkpoint.checkpoint_id, + InvocationStepPayload( + content_blocks=[ + BedrockSessionContentBlock( + text=session_checkpoint.model_dump_json() + ), + ] + ), + ) + + return RunnableConfig( + configurable={ + "thread_id": session_checkpoint.thread_id, + "checkpoint_ns": session_checkpoint.checkpoint_ns, + "checkpoint_id": checkpoint["id"], + } + ) + + async def aput_writes( + self, + config: RunnableConfig, + writes: Sequence[tuple[str, Any]], + task_id: str, + task_path: str = "", + ) -> None: + """Asynchronously store write operations in the Bedrock session. + + This method handles storing write operations by: + 1. Creating a new invocation for the writes + 2. Retrieving existing pending writes + 3. Building new content blocks for writes that don't exist + 4. Preserving existing writes that aren't being updated + 5. Saving all content blocks in a new invocation step + + Args: + config (RunnableConfig): Configuration containing thread_id, checkpoint_ns and checkpoint_id + writes (Sequence[tuple[str, Any]]): Sequence of (channel, value) tuples to write + task_id (str): Identifier for the task performing the writes + task_path (str, optional): Path information for the task. Defaults to empty string. + + Returns: + None + """ + thread_id = config["configurable"]["thread_id"] + checkpoint_ns = config["configurable"].get("checkpoint_ns", "") + checkpoint_id = config["configurable"]["checkpoint_id"] + + # Generate unique identifier for this write operation + writes_invocation_identifier = generate_write_id(checkpoint_ns, checkpoint_id) + + # Create new session invocation + await self._create_session_invocation(thread_id, writes_invocation_identifier) + + # Get existing pending writes for this checkpoint + current_pending_writes = await self._get_checkpoint_pending_writes( + thread_id, checkpoint_ns, checkpoint_id + ) + + content_blocks, new_writes = process_write_operations( + writes, + task_id, + current_pending_writes, + thread_id, + checkpoint_ns, + checkpoint_id, + task_path, + self.serde, + ) + + # Save content blocks if any exist + if content_blocks and new_writes: + await self._save_invocation_step( + thread_id, + writes_invocation_identifier, + None, # Let service generate the step id + InvocationStepPayload(content_blocks=content_blocks), + ) + + async def alist( + self, + config: Optional[RunnableConfig], + *, + filter: Optional[dict[str, Any]] = None, + before: Optional[RunnableConfig] = None, + limit: Optional[int] = None, + ) -> AsyncIterator[CheckpointTuple]: + """Asynchronously list checkpoints matching the given criteria. + + Args: + config: Optional configuration to filter by + filter: Optional dictionary of filter criteria + before: Optional configuration to get checkpoints before + limit: Optional maximum number of checkpoints to return + + Returns: + AsyncIterator of matching CheckpointTuple objects + """ + thread_id = config["configurable"]["thread_id"] + checkpoint_ns = config["configurable"].get("checkpoint_ns") + + invocation_identifier = None + + # Get invocation ID only if checkpoint_ns is provided + if checkpoint_ns is not None: + invocation_identifier = generate_checkpoint_id(checkpoint_ns) + + # List all invocation steps with pagination + matching_checkpoints = [] + next_token = None + + while True: + try: + response = await self.session_client.list_invocation_steps( + ListInvocationStepsRequest( + session_identifier=thread_id, + invocation_identifier=invocation_identifier, + next_token=next_token, + ) + ) + except ClientError as e: + if e.response["Error"]["Code"] == "ResourceNotFoundException": + return + else: + raise e + + # Check if there are more pages + next_token = response.next_token + + # Process current page + for step in response.invocation_step_summaries: + if before and step.invocation_step_id >= get_checkpoint_id(before): + continue + + # Get full step details to access metadata + step_detail = await self.session_client.get_invocation_step( + GetInvocationStepRequest( + session_identifier=thread_id, + invocation_identifier=step.invocation_id, + invocation_step_id=step.invocation_step_id, + ) + ) + + payload = json.loads(step_detail.invocation_step.payload.content_blocks[0].text) + + # Append checkpoints and ignore writes + if payload["step_type"] != CHECKPOINT_PREFIX: + continue + + session_checkpoint = SessionCheckpoint(**payload) + + # Apply metadata filter + if filter: + metadata = ( + deserialize_data(self.serde, session_checkpoint.metadata) + if session_checkpoint.metadata + else {} + ) + if not all(metadata.get(k) == v for k, v in filter.items()): + continue + + # Append checkpoints + matching_checkpoints.append(session_checkpoint) + + if limit and len(matching_checkpoints) >= limit: + next_token = None + break + + if next_token is None: + break + + # Yield checkpoint tuples + for checkpoint in matching_checkpoints: + pending_write_ops = await self._get_checkpoint_pending_writes( + thread_id, + checkpoint.checkpoint_ns, + checkpoint.checkpoint_id, + ) + + task_sends = await self._get_task_sends( + thread_id, checkpoint.checkpoint_ns, checkpoint.parent_checkpoint_id + ) + + yield construct_checkpoint_tuple( + thread_id, + checkpoint.checkpoint_ns, + checkpoint, + pending_write_ops, + task_sends, + self.serde, + ) \ No newline at end of file diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py new file mode 100644 index 00000000..e69de29b From 7f549620d1b6d6ec772ed28e9a42f845ad1666d1 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Fri, 2 May 2025 21:09:42 +0200 Subject: [PATCH 03/15] added async session --- .../langgraph_checkpoint_aws/async_session.py | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index e69de29b..89953441 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -0,0 +1,222 @@ +from typing import Optional + +import aioboto3 +from botocore.config import Config +from pydantic import SecretStr + +from langgraph_checkpoint_aws.models import ( + CreateInvocationRequest, + CreateInvocationResponse, + CreateSessionRequest, + CreateSessionResponse, + DeleteSessionRequest, + EndSessionRequest, + EndSessionResponse, + GetInvocationStepRequest, + GetInvocationStepResponse, + GetSessionRequest, + GetSessionResponse, + ListInvocationsRequest, + ListInvocationsResponse, + ListInvocationStepsRequest, + ListInvocationStepsResponse, + PutInvocationStepRequest, + PutInvocationStepResponse, +) +from langgraph_checkpoint_aws.utils import process_aws_client_args, to_boto_params + + +class AsyncBedrockAgentRuntimeSessionClient: + """ + Asynchronous client for AWS Bedrock Agent Runtime API + + This class provides an asynchronous interface to interact with AWS Bedrock Agent Runtime service. + It handles session management, invocations and invocation steps through the Bedrock Agent Runtime API. + + The client supports operations like: + - Session management (create, get, end, delete) + - Invocation management (create, list) + - Invocation step management (put, get, list) + + Attributes: + session: Aioboto3 session for bedrock-agent-runtime service + _client_kwargs: Arguments for client creation + """ + + def __init__( + self, + region_name: Optional[str] = None, + credentials_profile_name: Optional[str] = None, + aws_access_key_id: Optional[SecretStr] = None, + aws_secret_access_key: Optional[SecretStr] = None, + aws_session_token: Optional[SecretStr] = None, + endpoint_url: Optional[str] = None, + config: Optional[Config] = None, + ): + """ + Initialize AsyncBedrockAgentRuntime with AWS configuration + + Args: + region_name: AWS region (e.g., us-west-2) + credentials_profile_name: AWS credentials profile name + aws_access_key_id: AWS access key ID + aws_secret_access_key: AWS secret access key + aws_session_token: AWS session token + endpoint_url: Custom endpoint URL + config: Boto3 config object + """ + _session_kwargs, self._client_kwargs = process_aws_client_args( + region_name, + credentials_profile_name, + aws_access_key_id, + aws_secret_access_key, + aws_session_token, + endpoint_url, + config, + ) + self.session = aioboto3.Session(**_session_kwargs) + + async def _get_client(self): + """ + Get an async bedrock-agent-runtime client + + Returns: + Async client for bedrock-agent-runtime + """ + return self.session.client("bedrock-agent-runtime", **self._client_kwargs) + + async def create_session( + self, request: Optional[CreateSessionRequest] = None + ) -> CreateSessionResponse: + """ + Create a new session asynchronously + + Args: + request (CreateSessionRequest): Optional object containing session creation details + + Returns: + CreateSessionResponse: Response object containing session identifier and metadata + """ + async with await self._get_client() as client: + response = await client.create_session( + **to_boto_params(request) if request else {} + ) + return CreateSessionResponse(**response) + + async def get_session(self, request: GetSessionRequest) -> GetSessionResponse: + """ + Get details of an existing session asynchronously + + Args: + request (GetSessionRequest): Object containing session identifier + + Returns: + GetSessionResponse: Response object containing session details and metadata + """ + async with await self._get_client() as client: + response = await client.get_session(**to_boto_params(request)) + return GetSessionResponse(**response) + + async def end_session(self, request: EndSessionRequest) -> EndSessionResponse: + """ + End an existing session asynchronously + + Args: + request (EndSessionRequest): Object containing session identifier + + Returns: + EndSessionResponse: Response object containing the ended session details + """ + async with await self._get_client() as client: + response = await client.end_session(**to_boto_params(request)) + return EndSessionResponse(**response) + + async def delete_session(self, request: DeleteSessionRequest) -> None: + """ + Delete an existing session asynchronously + + Args: + request (DeleteSessionRequest): Object containing session identifier + """ + async with await self._get_client() as client: + await client.delete_session(**to_boto_params(request)) + + async def create_invocation( + self, request: CreateInvocationRequest + ) -> CreateInvocationResponse: + """ + Create a new invocation asynchronously + + Args: + request (CreateInvocationRequest): Object containing invocation details + + Returns: + CreateInvocationResponse: Response object containing invocation identifier and metadata + """ + async with await self._get_client() as client: + response = await client.create_invocation(**to_boto_params(request)) + return CreateInvocationResponse(**response) + + async def list_invocations( + self, request: ListInvocationsRequest + ) -> ListInvocationsResponse: + """ + List invocations for a session asynchronously + + Args: + request (ListInvocationsRequest): Object containing session identifier + + Returns: + ListInvocationsResponse: Response object containing list of invocations and pagination token + """ + async with await self._get_client() as client: + response = await client.list_invocations(**to_boto_params(request)) + return ListInvocationsResponse(**response) + + async def put_invocation_step( + self, request: PutInvocationStepRequest + ) -> PutInvocationStepResponse: + """ + Put a step in an invocation asynchronously + + Args: + request (PutInvocationStepRequest): Object containing invocation identifier and step payload + + Returns: + PutInvocationStepResponse: Response object containing invocation step identifier + """ + async with await self._get_client() as client: + response = await client.put_invocation_step(**to_boto_params(request)) + return PutInvocationStepResponse(**response) + + async def get_invocation_step( + self, request: GetInvocationStepRequest + ) -> GetInvocationStepResponse: + """ + Get a step in an invocation asynchronously + + Args: + request (GetInvocationStepRequest): Object containing invocation and step identifiers + + Returns: + GetInvocationStepResponse: Response object containing invocation step identifier and payload + """ + async with await self._get_client() as client: + response = await client.get_invocation_step(**to_boto_params(request)) + return GetInvocationStepResponse(**response) + + async def list_invocation_steps( + self, request: ListInvocationStepsRequest + ) -> ListInvocationStepsResponse: + """ + List steps in an invocation asynchronously + + Args: + request (ListInvocationStepsRequest): Object containing invocation step id and pagination token + + Returns: + ListInvocationStepsResponse: Response object containing list of invocation steps and pagination token + """ + async with await self._get_client() as client: + response = await client.list_invocation_steps(**to_boto_params(request)) + return ListInvocationStepsResponse(**response) \ No newline at end of file From 971c41da0a1037bf391ccab0820919b14419050d Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Mon, 5 May 2025 20:24:58 +0200 Subject: [PATCH 04/15] added unit tests --- libs/langgraph-checkpoint-aws/poetry.lock | 831 ++++++++++++++- libs/langgraph-checkpoint-aws/pyproject.toml | 7 +- .../tests/unit_tests/conftest.py | 24 +- .../tests/unit_tests/test_async_saver.py | 978 ++++++++++++++++++ .../tests/unit_tests/test_async_session.py | 302 ++++++ 5 files changed, 2127 insertions(+), 15 deletions(-) create mode 100644 libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py create mode 100644 libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py diff --git a/libs/langgraph-checkpoint-aws/poetry.lock b/libs/langgraph-checkpoint-aws/poetry.lock index c78b5cb5..7531a327 100644 --- a/libs/langgraph-checkpoint-aws/poetry.lock +++ b/libs/langgraph-checkpoint-aws/poetry.lock @@ -1,4 +1,212 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. + +[[package]] +name = "aioboto3" +version = "14.1.0" +description = "Async boto3 wrapper" +optional = false +python-versions = "<4.0,>=3.8" +groups = ["main"] +files = [ + {file = "aioboto3-14.1.0-py3-none-any.whl", hash = "sha256:f8547032bc4f90966b22869c1295d890c161549f4e8919f32853571ceb6fd0c6"}, + {file = "aioboto3-14.1.0.tar.gz", hash = "sha256:9d59b536ae8a951b9413ce151bf77df9c7cfe2cbaa2c4c240c066f384305c932"}, +] + +[package.dependencies] +aiobotocore = {version = "2.21.1", extras = ["boto3"]} +aiofiles = ">=23.2.1" + +[package.extras] +chalice = ["chalice (>=1.24.0)"] +s3cse = ["cryptography (>=44.0.1)"] + +[[package]] +name = "aiobotocore" +version = "2.21.1" +description = "Async client for aws services using botocore and aiohttp" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "aiobotocore-2.21.1-py3-none-any.whl", hash = "sha256:bd7c49a6d6f8a3d9444b0a94417c8da13813b5c7eec1c4f0ec2db7e8ce8f23e7"}, + {file = "aiobotocore-2.21.1.tar.gz", hash = "sha256:010357f43004413e92a9d066bb0db1f241aeb29ffed306e9197061ffc94e6577"}, +] + +[package.dependencies] +aiohttp = ">=3.9.2,<4.0.0" +aioitertools = ">=0.5.1,<1.0.0" +boto3 = {version = ">=1.37.0,<1.37.2", optional = true, markers = "extra == \"boto3\""} +botocore = ">=1.37.0,<1.37.2" +jmespath = ">=0.7.1,<2.0.0" +multidict = ">=6.0.0,<7.0.0" +python-dateutil = ">=2.1,<3.0.0" +wrapt = ">=1.10.10,<2.0.0" + +[package.extras] +awscli = ["awscli (>=1.38.0,<1.38.2)"] +boto3 = ["boto3 (>=1.37.0,<1.37.2)"] + +[[package]] +name = "aiofiles" +version = "24.1.0" +description = "File support for asyncio." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, + {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, +] + +[[package]] +name = "aiohttp" +version = "3.11.18" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:96264854fedbea933a9ca4b7e0c745728f01380691687b7365d18d9e977179c4"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9602044ff047043430452bc3a2089743fa85da829e6fc9ee0025351d66c332b6"}, + {file = "aiohttp-3.11.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5691dc38750fcb96a33ceef89642f139aa315c8a193bbd42a0c33476fd4a1609"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554c918ec43f8480b47a5ca758e10e793bd7410b83701676a4782672d670da55"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a4076a2b3ba5b004b8cffca6afe18a3b2c5c9ef679b4d1e9859cf76295f8d4f"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:767a97e6900edd11c762be96d82d13a1d7c4fc4b329f054e88b57cdc21fded94"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ddc9337a0fb0e727785ad4f41163cc314376e82b31846d3835673786420ef1"}, + {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f414f37b244f2a97e79b98d48c5ff0789a0b4b4609b17d64fa81771ad780e415"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fdb239f47328581e2ec7744ab5911f97afb10752332a6dd3d98e14e429e1a9e7"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f2c50bad73ed629cc326cc0f75aed8ecfb013f88c5af116f33df556ed47143eb"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a8d8f20c39d3fa84d1c28cdb97f3111387e48209e224408e75f29c6f8e0861d"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:106032eaf9e62fd6bc6578c8b9e6dc4f5ed9a5c1c7fb2231010a1b4304393421"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b491e42183e8fcc9901d8dcd8ae644ff785590f1727f76ca86e731c61bfe6643"}, + {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad8c745ff9460a16b710e58e06a9dec11ebc0d8f4dd82091cefb579844d69868"}, + {file = "aiohttp-3.11.18-cp310-cp310-win32.whl", hash = "sha256:8e57da93e24303a883146510a434f0faf2f1e7e659f3041abc4e3fb3f6702a9f"}, + {file = "aiohttp-3.11.18-cp310-cp310-win_amd64.whl", hash = "sha256:cc93a4121d87d9f12739fc8fab0a95f78444e571ed63e40bfc78cd5abe700ac9"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:427fdc56ccb6901ff8088544bde47084845ea81591deb16f957897f0f0ba1be9"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c828b6d23b984255b85b9b04a5b963a74278b7356a7de84fda5e3b76866597b"}, + {file = "aiohttp-3.11.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c2eaa145bb36b33af1ff2860820ba0589e165be4ab63a49aebfd0981c173b66"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d518ce32179f7e2096bf4e3e8438cf445f05fedd597f252de9f54c728574756"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0700055a6e05c2f4711011a44364020d7a10fbbcd02fbf3e30e8f7e7fddc8717"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8bd1cde83e4684324e6ee19adfc25fd649d04078179890be7b29f76b501de8e4"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73b8870fe1c9a201b8c0d12c94fe781b918664766728783241a79e0468427e4f"}, + {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25557982dd36b9e32c0a3357f30804e80790ec2c4d20ac6bcc598533e04c6361"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e889c9df381a2433802991288a61e5a19ceb4f61bd14f5c9fa165655dcb1fd1"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9ea345fda05bae217b6cce2acf3682ce3b13d0d16dd47d0de7080e5e21362421"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9f26545b9940c4b46f0a9388fd04ee3ad7064c4017b5a334dd450f616396590e"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3a621d85e85dccabd700294494d7179ed1590b6d07a35709bb9bd608c7f5dd1d"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9c23fd8d08eb9c2af3faeedc8c56e134acdaf36e2117ee059d7defa655130e5f"}, + {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9e6b0e519067caa4fd7fb72e3e8002d16a68e84e62e7291092a5433763dc0dd"}, + {file = "aiohttp-3.11.18-cp311-cp311-win32.whl", hash = "sha256:122f3e739f6607e5e4c6a2f8562a6f476192a682a52bda8b4c6d4254e1138f4d"}, + {file = "aiohttp-3.11.18-cp311-cp311-win_amd64.whl", hash = "sha256:e6f3c0a3a1e73e88af384b2e8a0b9f4fb73245afd47589df2afcab6b638fa0e6"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:63d71eceb9cad35d47d71f78edac41fcd01ff10cacaa64e473d1aec13fa02df2"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d1929da615840969929e8878d7951b31afe0bac883d84418f92e5755d7b49508"}, + {file = "aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d0aebeb2392f19b184e3fdd9e651b0e39cd0f195cdb93328bd124a1d455cd0e"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3849ead845e8444f7331c284132ab314b4dac43bfae1e3cf350906d4fff4620f"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e8452ad6b2863709f8b3d615955aa0807bc093c34b8e25b3b52097fe421cb7f"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b8d2b42073611c860a37f718b3d61ae8b4c2b124b2e776e2c10619d920350ec"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fbf91f6a0ac317c0a07eb328a1384941872f6761f2e6f7208b63c4cc0a7ff6"}, + {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ff5625413fec55216da5eaa011cf6b0a2ed67a565914a212a51aa3755b0009"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f33a92a2fde08e8c6b0c61815521324fc1612f397abf96eed86b8e31618fdb4"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:11d5391946605f445ddafda5eab11caf310f90cdda1fd99865564e3164f5cff9"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3cc314245deb311364884e44242e00c18b5896e4fe6d5f942e7ad7e4cb640adb"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f421843b0f70740772228b9e8093289924359d306530bcd3926f39acbe1adda"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e220e7562467dc8d589e31c1acd13438d82c03d7f385c9cd41a3f6d1d15807c1"}, + {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab2ef72f8605046115bc9aa8e9d14fd49086d405855f40b79ed9e5c1f9f4faea"}, + {file = "aiohttp-3.11.18-cp312-cp312-win32.whl", hash = "sha256:12a62691eb5aac58d65200c7ae94d73e8a65c331c3a86a2e9670927e94339ee8"}, + {file = "aiohttp-3.11.18-cp312-cp312-win_amd64.whl", hash = "sha256:364329f319c499128fd5cd2d1c31c44f234c58f9b96cc57f743d16ec4f3238c8"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:474215ec618974054cf5dc465497ae9708543cbfc312c65212325d4212525811"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ced70adf03920d4e67c373fd692123e34d3ac81dfa1c27e45904a628567d804"}, + {file = "aiohttp-3.11.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d9f6c0152f8d71361905aaf9ed979259537981f47ad099c8b3d81e0319814bd"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a35197013ed929c0aed5c9096de1fc5a9d336914d73ab3f9df14741668c0616c"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:540b8a1f3a424f1af63e0af2d2853a759242a1769f9f1ab053996a392bd70118"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9e6710ebebfce2ba21cee6d91e7452d1125100f41b906fb5af3da8c78b764c1"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8af2ef3b4b652ff109f98087242e2ab974b2b2b496304063585e3d78de0b000"}, + {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28c3f975e5ae3dbcbe95b7e3dcd30e51da561a0a0f2cfbcdea30fc1308d72137"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c28875e316c7b4c3e745172d882d8a5c835b11018e33432d281211af35794a93"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:13cd38515568ae230e1ef6919e2e33da5d0f46862943fcda74e7e915096815f3"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0e2a92101efb9f4c2942252c69c63ddb26d20f46f540c239ccfa5af865197bb8"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e6d3e32b8753c8d45ac550b11a1090dd66d110d4ef805ffe60fa61495360b3b2"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ea4cf2488156e0f281f93cc2fd365025efcba3e2d217cbe3df2840f8c73db261"}, + {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d4df95ad522c53f2b9ebc07f12ccd2cb15550941e11a5bbc5ddca2ca56316d7"}, + {file = "aiohttp-3.11.18-cp313-cp313-win32.whl", hash = "sha256:cdd1bbaf1e61f0d94aced116d6e95fe25942f7a5f42382195fd9501089db5d78"}, + {file = "aiohttp-3.11.18-cp313-cp313-win_amd64.whl", hash = "sha256:bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:469ac32375d9a716da49817cd26f1916ec787fc82b151c1c832f58420e6d3533"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cec21dd68924179258ae14af9f5418c1ebdbba60b98c667815891293902e5e0"}, + {file = "aiohttp-3.11.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b426495fb9140e75719b3ae70a5e8dd3a79def0ae3c6c27e012fc59f16544a4a"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2f41203e2808616292db5d7170cccf0c9f9c982d02544443c7eb0296e8b0c7"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc0ae0a5e9939e423e065a3e5b00b24b8379f1db46046d7ab71753dfc7dd0e1"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7cdd3f7d1df43200e1c80f1aed86bb36033bf65e3c7cf46a2b97a253ef8798"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5199be2a2f01ffdfa8c3a6f5981205242986b9e63eb8ae03fd18f736e4840721"}, + {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ccec9e72660b10f8e283e91aa0295975c7bd85c204011d9f5eb69310555cf30"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1596ebf17e42e293cbacc7a24c3e0dc0f8f755b40aff0402cb74c1ff6baec1d3"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:eab7b040a8a873020113ba814b7db7fa935235e4cbaf8f3da17671baa1024863"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5d61df4a05476ff891cff0030329fee4088d40e4dc9b013fac01bc3c745542c2"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:46533e6792e1410f9801d09fd40cbbff3f3518d1b501d6c3c5b218f427f6ff08"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c1b90407ced992331dd6d4f1355819ea1c274cc1ee4d5b7046c6761f9ec11829"}, + {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a2fd04ae4971b914e54fe459dd7edbbd3f2ba875d69e057d5e3c8e8cac094935"}, + {file = "aiohttp-3.11.18-cp39-cp39-win32.whl", hash = "sha256:b2f317d1678002eee6fe85670039fb34a757972284614638f82b903a03feacdc"}, + {file = "aiohttp-3.11.18-cp39-cp39-win_amd64.whl", hash = "sha256:5e7007b8d1d09bce37b54111f593d173691c530b80f27c6493b928dabed9e6ef"}, + {file = "aiohttp-3.11.18.tar.gz", hash = "sha256:ae856e1138612b7e412db63b7708735cff4d38d0399f6a5435d3dac2669f558a"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.3.0" +aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""] + +[[package]] +name = "aioitertools" +version = "0.12.0" +description = "itertools and builtins for AsyncIO and mixed iterables" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "aioitertools-0.12.0-py3-none-any.whl", hash = "sha256:fc1f5fac3d737354de8831cbba3eb04f79dd649d8f3afb4c5b114925e662a796"}, + {file = "aioitertools-0.12.0.tar.gz", hash = "sha256:c2a9055b4fbb7705f561b9d86053e8af5d10cc845d22c32008c43490b2d8dd6b"}, +] + +[package.dependencies] +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.10\""} + +[package.extras] +dev = ["attribution (==1.8.0)", "black (==24.8.0)", "build (>=1.2)", "coverage (==7.6.1)", "flake8 (==7.1.1)", "flit (==3.9.0)", "mypy (==1.11.2)", "ufmt (==2.7.1)", "usort (==1.0.8.post1)"] +docs = ["sphinx (==8.0.2)", "sphinx-mdinclude (==0.6.2)"] + +[[package]] +name = "aiosignal" +version = "1.3.2" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, + {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" [[package]] name = "annotated-types" @@ -35,20 +243,53 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[[package]] +name = "attrs" +version = "25.3.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, +] + +[package.extras] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] + [[package]] name = "boto3" -version = "1.37.3" +version = "1.37.1" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" groups = ["main", "test_integration"] files = [ - {file = "boto3-1.37.3-py3-none-any.whl", hash = "sha256:2063b40af99fd02f6228ff52397b552ff3353831edaf8d25cc04801827ab9794"}, - {file = "boto3-1.37.3.tar.gz", hash = "sha256:21f3ce0ef111297e63a6eb998a25197b8c10982970c320d4c6e8db08be2157be"}, + {file = "boto3-1.37.1-py3-none-any.whl", hash = "sha256:4320441f904435a1b85e6ecb81793192e522c737cc9ed6566014e29f0a11cb22"}, + {file = "boto3-1.37.1.tar.gz", hash = "sha256:96d18f7feb0c1fcb95f8837b74b6c8880e1b4e35ce5f8a8f8cb243a090c278ed"}, ] [package.dependencies] -botocore = ">=1.37.3,<1.38.0" +botocore = ">=1.37.1,<1.38.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.11.0,<0.12.0" @@ -57,14 +298,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.37.3" +version = "1.37.1" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" groups = ["main", "test_integration"] files = [ - {file = "botocore-1.37.3-py3-none-any.whl", hash = "sha256:d01bd3bf4c80e61fa88d636ad9f5c9f60a551d71549b481386c6b4efe0bb2b2e"}, - {file = "botocore-1.37.3.tar.gz", hash = "sha256:fe8403eb55a88faf9b0f9da6615e5bee7be056d75e17af66c3c8f0a3b0648da4"}, + {file = "botocore-1.37.1-py3-none-any.whl", hash = "sha256:c1db1bfc5d8c6b3b6d1ca6794f605294b4264e82a7e727b88e0fef9c2b9fbb9c"}, + {file = "botocore-1.37.1.tar.gz", hash = "sha256:b194db8fb2a0ffba53568c364ae26166e7eec0445496b2ac86a6e142f3dd982f"}, ] [package.dependencies] @@ -399,6 +640,120 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "frozenlist" +version = "1.6.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e6e558ea1e47fd6fa8ac9ccdad403e5dd5ecc6ed8dda94343056fa4277d5c65e"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4b3cd7334a4bbc0c472164f3744562cb72d05002cc6fcf58adb104630bbc352"}, + {file = "frozenlist-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9799257237d0479736e2b4c01ff26b5c7f7694ac9692a426cb717f3dc02fff9b"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a7bb0fe1f7a70fb5c6f497dc32619db7d2cdd53164af30ade2f34673f8b1fc"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:36d2fc099229f1e4237f563b2a3e0ff7ccebc3999f729067ce4e64a97a7f2869"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f27a9f9a86dcf00708be82359db8de86b80d029814e6693259befe82bb58a106"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75ecee69073312951244f11b8627e3700ec2bfe07ed24e3a685a5979f0412d24"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2c7d5aa19714b1b01a0f515d078a629e445e667b9da869a3cd0e6fe7dec78bd"}, + {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69bbd454f0fb23b51cadc9bdba616c9678e4114b6f9fa372d462ff2ed9323ec8"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7daa508e75613809c7a57136dec4871a21bca3080b3a8fc347c50b187df4f00c"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:89ffdb799154fd4d7b85c56d5fa9d9ad48946619e0eb95755723fffa11022d75"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:920b6bd77d209931e4c263223381d63f76828bec574440f29eb497cf3394c249"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d3ceb265249fb401702fce3792e6b44c1166b9319737d21495d3611028d95769"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52021b528f1571f98a7d4258c58aa8d4b1a96d4f01d00d51f1089f2e0323cb02"}, + {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0f2ca7810b809ed0f1917293050163c7654cefc57a49f337d5cd9de717b8fad3"}, + {file = "frozenlist-1.6.0-cp310-cp310-win32.whl", hash = "sha256:0e6f8653acb82e15e5443dba415fb62a8732b68fe09936bb6d388c725b57f812"}, + {file = "frozenlist-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1a39819a5a3e84304cd286e3dc62a549fe60985415851b3337b6f5cc91907f1"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae8337990e7a45683548ffb2fee1af2f1ed08169284cd829cdd9a7fa7470530d"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c952f69dd524558694818a461855f35d36cc7f5c0adddce37e962c85d06eac0"}, + {file = "frozenlist-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f5fef13136c4e2dee91bfb9a44e236fff78fc2cd9f838eddfc470c3d7d90afe"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:716bbba09611b4663ecbb7cd022f640759af8259e12a6ca939c0a6acd49eedba"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7b8c4dc422c1a3ffc550b465090e53b0bf4839047f3e436a34172ac67c45d595"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b11534872256e1666116f6587a1592ef395a98b54476addb5e8d352925cb5d4a"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c6eceb88aaf7221f75be6ab498dc622a151f5f88d536661af3ffc486245a626"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62c828a5b195570eb4b37369fcbbd58e96c905768d53a44d13044355647838ff"}, + {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1c6bd2c6399920c9622362ce95a7d74e7f9af9bfec05fff91b8ce4b9647845a"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49ba23817781e22fcbd45fd9ff2b9b8cdb7b16a42a4851ab8025cae7b22e96d0"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:431ef6937ae0f853143e2ca67d6da76c083e8b1fe3df0e96f3802fd37626e606"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9d124b38b3c299ca68433597ee26b7819209cb8a3a9ea761dfe9db3a04bba584"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:118e97556306402e2b010da1ef21ea70cb6d6122e580da64c056b96f524fbd6a"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fb3b309f1d4086b5533cf7bbcf3f956f0ae6469664522f1bde4feed26fba60f1"}, + {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54dece0d21dce4fdb188a1ffc555926adf1d1c516e493c2914d7c370e454bc9e"}, + {file = "frozenlist-1.6.0-cp311-cp311-win32.whl", hash = "sha256:654e4ba1d0b2154ca2f096bed27461cf6160bc7f504a7f9a9ef447c293caf860"}, + {file = "frozenlist-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e911391bffdb806001002c1f860787542f45916c3baf764264a52765d5a5603"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c5b9e42ace7d95bf41e19b87cec8f262c41d3510d8ad7514ab3862ea2197bfb1"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ca9973735ce9f770d24d5484dcb42f68f135351c2fc81a7a9369e48cf2998a29"}, + {file = "frozenlist-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ac40ec76041c67b928ca8aaffba15c2b2ee3f5ae8d0cb0617b5e63ec119ca25"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b7a8a3180dfb280eb044fdec562f9b461614c0ef21669aea6f1d3dac6ee576"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c444d824e22da6c9291886d80c7d00c444981a72686e2b59d38b285617cb52c8"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb52c8166499a8150bfd38478248572c924c003cbb45fe3bcd348e5ac7c000f9"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b35298b2db9c2468106278537ee529719228950a5fdda686582f68f247d1dc6e"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d108e2d070034f9d57210f22fefd22ea0d04609fc97c5f7f5a686b3471028590"}, + {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1be9111cb6756868ac242b3c2bd1f09d9aea09846e4f5c23715e7afb647103"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:94bb451c664415f02f07eef4ece976a2c65dcbab9c2f1705b7031a3a75349d8c"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d1a686d0b0949182b8faddea596f3fc11f44768d1f74d4cad70213b2e139d821"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea8e59105d802c5a38bdbe7362822c522230b3faba2aa35c0fa1765239b7dd70"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:abc4e880a9b920bc5020bf6a431a6bb40589d9bca3975c980495f63632e8382f"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a79713adfe28830f27a3c62f6b5406c37376c892b05ae070906f07ae4487046"}, + {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0318c2068e217a8f5e3b85e35899f5a19e97141a45bb925bb357cfe1daf770"}, + {file = "frozenlist-1.6.0-cp312-cp312-win32.whl", hash = "sha256:853ac025092a24bb3bf09ae87f9127de9fe6e0c345614ac92536577cf956dfcc"}, + {file = "frozenlist-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bdfe2d7e6c9281c6e55523acd6c2bf77963cb422fdc7d142fb0cb6621b66878"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1d7fb014fe0fbfee3efd6a94fc635aeaa68e5e1720fe9e57357f2e2c6e1a647e"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01bcaa305a0fdad12745502bfd16a1c75b14558dabae226852f9159364573117"}, + {file = "frozenlist-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b314faa3051a6d45da196a2c495e922f987dc848e967d8cfeaee8a0328b1cd4"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da62fecac21a3ee10463d153549d8db87549a5e77eefb8c91ac84bb42bb1e4e3"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1eb89bf3454e2132e046f9599fbcf0a4483ed43b40f545551a39316d0201cd1"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18689b40cb3936acd971f663ccb8e2589c45db5e2c5f07e0ec6207664029a9c"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e67ddb0749ed066b1a03fba812e2dcae791dd50e5da03be50b6a14d0c1a9ee45"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc5e64626e6682638d6e44398c9baf1d6ce6bc236d40b4b57255c9d3f9761f1f"}, + {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:437cfd39564744ae32ad5929e55b18ebd88817f9180e4cc05e7d53b75f79ce85"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62dd7df78e74d924952e2feb7357d826af8d2f307557a779d14ddf94d7311be8"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a66781d7e4cddcbbcfd64de3d41a61d6bdde370fc2e38623f30b2bd539e84a9f"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:482fe06e9a3fffbcd41950f9d890034b4a54395c60b5e61fae875d37a699813f"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e4f9373c500dfc02feea39f7a56e4f543e670212102cc2eeb51d3a99c7ffbde6"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e69bb81de06827147b7bfbaeb284d85219fa92d9f097e32cc73675f279d70188"}, + {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7613d9977d2ab4a9141dde4a149f4357e4065949674c5649f920fec86ecb393e"}, + {file = "frozenlist-1.6.0-cp313-cp313-win32.whl", hash = "sha256:4def87ef6d90429f777c9d9de3961679abf938cb6b7b63d4a7eb8a268babfce4"}, + {file = "frozenlist-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:37a8a52c3dfff01515e9bbbee0e6063181362f9de3db2ccf9bc96189b557cbfd"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:46138f5a0773d064ff663d273b309b696293d7a7c00a0994c5c13a5078134b64"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f88bc0a2b9c2a835cb888b32246c27cdab5740059fb3688852bf91e915399b91"}, + {file = "frozenlist-1.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:777704c1d7655b802c7850255639672e90e81ad6fa42b99ce5ed3fbf45e338dd"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ef8d41764c7de0dcdaf64f733a27352248493a85a80661f3c678acd27e31f2"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:da5cb36623f2b846fb25009d9d9215322318ff1c63403075f812b3b2876c8506"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbb56587a16cf0fb8acd19e90ff9924979ac1431baea8681712716a8337577b0"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6154c3ba59cda3f954c6333025369e42c3acd0c6e8b6ce31eb5c5b8116c07e0"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e8246877afa3f1ae5c979fe85f567d220f86a50dc6c493b9b7d8191181ae01e"}, + {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0f6cce16306d2e117cf9db71ab3a9e8878a28176aeaf0dbe35248d97b28d0c"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1b8e8cd8032ba266f91136d7105706ad57770f3522eac4a111d77ac126a25a9b"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e2ada1d8515d3ea5378c018a5f6d14b4994d4036591a52ceaf1a1549dec8e1ad"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:cdb2c7f071e4026c19a3e32b93a09e59b12000751fc9b0b7758da899e657d215"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:03572933a1969a6d6ab509d509e5af82ef80d4a5d4e1e9f2e1cdd22c77a3f4d2"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:77effc978947548b676c54bbd6a08992759ea6f410d4987d69feea9cd0919911"}, + {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a2bda8be77660ad4089caf2223fdbd6db1858462c4b85b67fbfa22102021e497"}, + {file = "frozenlist-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:a4d96dc5bcdbd834ec6b0f91027817214216b5b30316494d2b1aebffb87c534f"}, + {file = "frozenlist-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e18036cb4caa17ea151fd5f3d70be9d354c99eb8cf817a3ccde8a7873b074348"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:536a1236065c29980c15c7229fbb830dedf809708c10e159b8136534233545f0"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ed5e3a4462ff25ca84fb09e0fada8ea267df98a450340ead4c91b44857267d70"}, + {file = "frozenlist-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e19c0fc9f4f030fcae43b4cdec9e8ab83ffe30ec10c79a4a43a04d1af6c5e1ad"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c608f833897501dac548585312d73a7dca028bf3b8688f0d712b7acfaf7fb3"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0dbae96c225d584f834b8d3cc688825911960f003a85cb0fd20b6e5512468c42"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:625170a91dd7261a1d1c2a0c1a353c9e55d21cd67d0852185a5fef86587e6f5f"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1db8b2fc7ee8a940b547a14c10e56560ad3ea6499dc6875c354e2335812f739d"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4da6fc43048b648275a220e3a61c33b7fff65d11bdd6dcb9d9c145ff708b804c"}, + {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef8e7e8f2f3820c5f175d70fdd199b79e417acf6c72c5d0aa8f63c9f721646f"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa733d123cc78245e9bb15f29b44ed9e5780dc6867cfc4e544717b91f980af3b"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ba7f8d97152b61f22d7f59491a781ba9b177dd9f318486c5fbc52cde2db12189"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:56a0b8dd6d0d3d971c91f1df75e824986667ccce91e20dca2023683814344791"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5c9e89bf19ca148efcc9e3c44fd4c09d5af85c8a7dd3dbd0da1cb83425ef4983"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1330f0a4376587face7637dfd245380a57fe21ae8f9d360c1c2ef8746c4195fa"}, + {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2187248203b59625566cac53572ec8c2647a140ee2738b4e36772930377a533c"}, + {file = "frozenlist-1.6.0-cp39-cp39-win32.whl", hash = "sha256:2b8cf4cfea847d6c12af06091561a89740f1f67f331c3fa8623391905e878530"}, + {file = "frozenlist-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:1255d5d64328c5a0d066ecb0f02034d086537925f1f04b50b1ae60d37afbf572"}, + {file = "frozenlist-1.6.0-py3-none-any.whl", hash = "sha256:535eec9987adb04701266b92745d6cdcef2e77669299359c3009c3404dd5d191"}, + {file = "frozenlist-1.6.0.tar.gz", hash = "sha256:b99655c32c1c8e06d111e7f41c06c29a5318cb1835df23a45518e02a47c63b68"}, +] + [[package]] name = "h11" version = "0.14.0" @@ -737,6 +1092,123 @@ files = [ {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] +[[package]] +name = "multidict" +version = "6.4.3" +description = "multidict implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32a998bd8a64ca48616eac5a8c1cc4fa38fb244a3facf2eeb14abe186e0f6cc5"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a54ec568f1fc7f3c313c2f3b16e5db346bf3660e1309746e7fccbbfded856188"}, + {file = "multidict-6.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a7be07e5df178430621c716a63151165684d3e9958f2bbfcb644246162007ab7"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b128dbf1c939674a50dd0b28f12c244d90e5015e751a4f339a96c54f7275e291"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9cb19dfd83d35b6ff24a4022376ea6e45a2beba8ef3f0836b8a4b288b6ad685"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3cf62f8e447ea2c1395afa289b332e49e13d07435369b6f4e41f887db65b40bf"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:909f7d43ff8f13d1adccb6a397094adc369d4da794407f8dd592c51cf0eae4b1"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bb8f8302fbc7122033df959e25777b0b7659b1fd6bcb9cb6bed76b5de67afef"}, + {file = "multidict-6.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:224b79471b4f21169ea25ebc37ed6f058040c578e50ade532e2066562597b8a9"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a7bd27f7ab3204f16967a6f899b3e8e9eb3362c0ab91f2ee659e0345445e0078"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:99592bd3162e9c664671fd14e578a33bfdba487ea64bcb41d281286d3c870ad7"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a62d78a1c9072949018cdb05d3c533924ef8ac9bcb06cbf96f6d14772c5cd451"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ccdde001578347e877ca4f629450973c510e88e8865d5aefbcb89b852ccc666"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:eccb67b0e78aa2e38a04c5ecc13bab325a43e5159a181a9d1a6723db913cbb3c"}, + {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b6fcf6054fc4114a27aa865f8840ef3d675f9316e81868e0ad5866184a6cba5"}, + {file = "multidict-6.4.3-cp310-cp310-win32.whl", hash = "sha256:f92c7f62d59373cd93bc9969d2da9b4b21f78283b1379ba012f7ee8127b3152e"}, + {file = "multidict-6.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:b57e28dbc031d13916b946719f213c494a517b442d7b48b29443e79610acd887"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6f19170197cc29baccd33ccc5b5d6a331058796485857cf34f7635aa25fb0cd"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2882bf27037eb687e49591690e5d491e677272964f9ec7bc2abbe09108bdfb8"}, + {file = "multidict-6.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbf226ac85f7d6b6b9ba77db4ec0704fde88463dc17717aec78ec3c8546c70ad"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e329114f82ad4b9dd291bef614ea8971ec119ecd0f54795109976de75c9a852"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1f4e0334d7a555c63f5c8952c57ab6f1c7b4f8c7f3442df689fc9f03df315c08"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:740915eb776617b57142ce0bb13b7596933496e2f798d3d15a20614adf30d229"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255dac25134d2b141c944b59a0d2f7211ca12a6d4779f7586a98b4b03ea80508"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e8535bd4d741039b5aad4285ecd9b902ef9e224711f0b6afda6e38d7ac02c7"}, + {file = "multidict-6.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c433a33be000dd968f5750722eaa0991037be0be4a9d453eba121774985bc8"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4eb33b0bdc50acd538f45041f5f19945a1f32b909b76d7b117c0c25d8063df56"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:75482f43465edefd8a5d72724887ccdcd0c83778ded8f0cb1e0594bf71736cc0"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce5b3082e86aee80b3925ab4928198450d8e5b6466e11501fe03ad2191c6d777"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e413152e3212c4d39f82cf83c6f91be44bec9ddea950ce17af87fbf4e32ca6b2"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8aac2eeff69b71f229a405c0a4b61b54bade8e10163bc7b44fcd257949620618"}, + {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab583ac203af1d09034be41458feeab7863c0635c650a16f15771e1386abf2d7"}, + {file = "multidict-6.4.3-cp311-cp311-win32.whl", hash = "sha256:1b2019317726f41e81154df636a897de1bfe9228c3724a433894e44cd2512378"}, + {file = "multidict-6.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:43173924fa93c7486402217fab99b60baf78d33806af299c56133a3755f69589"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f1c2f58f08b36f8475f3ec6f5aeb95270921d418bf18f90dffd6be5c7b0e676"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:26ae9ad364fc61b936fb7bf4c9d8bd53f3a5b4417142cd0be5c509d6f767e2f1"}, + {file = "multidict-6.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:659318c6c8a85f6ecfc06b4e57529e5a78dfdd697260cc81f683492ad7e9435a"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1eb72c741fd24d5a28242ce72bb61bc91f8451877131fa3fe930edb195f7054"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3cd06d88cb7398252284ee75c8db8e680aa0d321451132d0dba12bc995f0adcc"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4543d8dc6470a82fde92b035a92529317191ce993533c3c0c68f56811164ed07"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30a3ebdc068c27e9d6081fca0e2c33fdf132ecea703a72ea216b81a66860adde"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b038f10e23f277153f86f95c777ba1958bcd5993194fda26a1d06fae98b2f00c"}, + {file = "multidict-6.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c605a2b2dc14282b580454b9b5d14ebe0668381a3a26d0ac39daa0ca115eb2ae"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8bd2b875f4ca2bb527fe23e318ddd509b7df163407b0fb717df229041c6df5d3"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c2e98c840c9c8e65c0e04b40c6c5066c8632678cd50c8721fdbcd2e09f21a507"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66eb80dd0ab36dbd559635e62fba3083a48a252633164857a1d1684f14326427"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c23831bdee0a2a3cf21be057b5e5326292f60472fb6c6f86392bbf0de70ba731"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1535cec6443bfd80d028052e9d17ba6ff8a5a3534c51d285ba56c18af97e9713"}, + {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b73e7227681f85d19dec46e5b881827cd354aabe46049e1a61d2f9aaa4e285a"}, + {file = "multidict-6.4.3-cp312-cp312-win32.whl", hash = "sha256:8eac0c49df91b88bf91f818e0a24c1c46f3622978e2c27035bfdca98e0e18124"}, + {file = "multidict-6.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:11990b5c757d956cd1db7cb140be50a63216af32cd6506329c2c59d732d802db"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a76534263d03ae0cfa721fea40fd2b5b9d17a6f85e98025931d41dc49504474"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:805031c2f599eee62ac579843555ed1ce389ae00c7e9f74c2a1b45e0564a88dd"}, + {file = "multidict-6.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c56c179839d5dcf51d565132185409d1d5dd8e614ba501eb79023a6cab25576b"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c64f4ddb3886dd8ab71b68a7431ad4aa01a8fa5be5b11543b29674f29ca0ba3"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3002a856367c0b41cad6784f5b8d3ab008eda194ed7864aaa58f65312e2abcac"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d75e621e7d887d539d6e1d789f0c64271c250276c333480a9e1de089611f790"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:995015cf4a3c0d72cbf453b10a999b92c5629eaf3a0c3e1efb4b5c1f602253bb"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b0fabae7939d09d7d16a711468c385272fa1b9b7fb0d37e51143585d8e72e0"}, + {file = "multidict-6.4.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61ed4d82f8a1e67eb9eb04f8587970d78fe7cddb4e4d6230b77eda23d27938f9"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:062428944a8dc69df9fdc5d5fc6279421e5f9c75a9ee3f586f274ba7b05ab3c8"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b90e27b4674e6c405ad6c64e515a505c6d113b832df52fdacb6b1ffd1fa9a1d1"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7d50d4abf6729921e9613d98344b74241572b751c6b37feed75fb0c37bd5a817"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:43fe10524fb0a0514be3954be53258e61d87341008ce4914f8e8b92bee6f875d"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:236966ca6c472ea4e2d3f02f6673ebfd36ba3f23159c323f5a496869bc8e47c9"}, + {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:422a5ec315018e606473ba1f5431e064cf8b2a7468019233dcf8082fabad64c8"}, + {file = "multidict-6.4.3-cp313-cp313-win32.whl", hash = "sha256:f901a5aace8e8c25d78960dcc24c870c8d356660d3b49b93a78bf38eb682aac3"}, + {file = "multidict-6.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:1c152c49e42277bc9a2f7b78bd5fa10b13e88d1b0328221e7aef89d5c60a99a5"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:be8751869e28b9c0d368d94f5afcb4234db66fe8496144547b4b6d6a0645cfc6"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d4b31f8a68dccbcd2c0ea04f0e014f1defc6b78f0eb8b35f2265e8716a6df0c"}, + {file = "multidict-6.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:032efeab3049e37eef2ff91271884303becc9e54d740b492a93b7e7266e23756"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e78006af1a7c8a8007e4f56629d7252668344442f66982368ac06522445e375"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:daeac9dd30cda8703c417e4fddccd7c4dc0c73421a0b54a7da2713be125846be"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f6f90700881438953eae443a9c6f8a509808bc3b185246992c4233ccee37fea"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f84627997008390dd15762128dcf73c3365f4ec0106739cde6c20a07ed198ec8"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3307b48cd156153b117c0ea54890a3bdbf858a5b296ddd40dc3852e5f16e9b02"}, + {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead46b0fa1dcf5af503a46e9f1c2e80b5d95c6011526352fa5f42ea201526124"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1748cb2743bedc339d63eb1bca314061568793acd603a6e37b09a326334c9f44"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:acc9fa606f76fc111b4569348cc23a771cb52c61516dcc6bcef46d612edb483b"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:31469d5832b5885adeb70982e531ce86f8c992334edd2f2254a10fa3182ac504"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ba46b51b6e51b4ef7bfb84b82f5db0dc5e300fb222a8a13b8cd4111898a869cf"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:389cfefb599edf3fcfd5f64c0410da686f90f5f5e2c4d84e14f6797a5a337af4"}, + {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:64bc2bbc5fba7b9db5c2c8d750824f41c6994e3882e6d73c903c2afa78d091e4"}, + {file = "multidict-6.4.3-cp313-cp313t-win32.whl", hash = "sha256:0ecdc12ea44bab2807d6b4a7e5eef25109ab1c82a8240d86d3c1fc9f3b72efd5"}, + {file = "multidict-6.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7146a8742ea71b5d7d955bffcef58a9e6e04efba704b52a460134fefd10a8208"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5427a2679e95a642b7f8b0f761e660c845c8e6fe3141cddd6b62005bd133fc21"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:24a8caa26521b9ad09732972927d7b45b66453e6ebd91a3c6a46d811eeb7349b"}, + {file = "multidict-6.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6b5a272bc7c36a2cd1b56ddc6bff02e9ce499f9f14ee4a45c45434ef083f2459"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf74dc5e212b8c75165b435c43eb0d5e81b6b300a938a4eb82827119115e840"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9f35de41aec4b323c71f54b0ca461ebf694fb48bec62f65221f52e0017955b39"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae93e0ff43b6f6892999af64097b18561691ffd835e21a8348a441e256592e1f"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e3929269e9d7eff905d6971d8b8c85e7dbc72c18fb99c8eae6fe0a152f2e343"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6214fe1750adc2a1b801a199d64b5a67671bf76ebf24c730b157846d0e90d2"}, + {file = "multidict-6.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d79cf5c0c6284e90f72123f4a3e4add52d6c6ebb4a9054e88df15b8d08444c6"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2427370f4a255262928cd14533a70d9738dfacadb7563bc3b7f704cc2360fc4e"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:fbd8d737867912b6c5f99f56782b8cb81f978a97b4437a1c476de90a3e41c9a1"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0ee1bf613c448997f73fc4efb4ecebebb1c02268028dd4f11f011f02300cf1e8"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:578568c4ba5f2b8abd956baf8b23790dbfdc953e87d5b110bce343b4a54fc9e7"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a059ad6b80de5b84b9fa02a39400319e62edd39d210b4e4f8c4f1243bdac4752"}, + {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dd53893675b729a965088aaadd6a1f326a72b83742b056c1065bdd2e2a42b4df"}, + {file = "multidict-6.4.3-cp39-cp39-win32.whl", hash = "sha256:abcfed2c4c139f25c2355e180bcc077a7cae91eefbb8b3927bb3f836c9586f1f"}, + {file = "multidict-6.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:b1b389ae17296dd739015d5ddb222ee99fd66adeae910de21ac950e00979d897"}, + {file = "multidict-6.4.3-py3-none-any.whl", hash = "sha256:59fe01ee8e2a1e8ceb3f6dbb216b09c8d9f4ef1c22c4fc825d045a147fa2ebc9"}, + {file = "multidict-6.4.3.tar.gz", hash = "sha256:3ada0b058c9f213c5f95ba301f922d402ac234f1111a7d8fd70f1b99f3c281ec"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "mypy" version = "1.15.0" @@ -1034,6 +1506,114 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "propcache" +version = "0.3.1" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136"}, + {file = "propcache-0.3.1-cp310-cp310-win32.whl", hash = "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42"}, + {file = "propcache-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9"}, + {file = "propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005"}, + {file = "propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7"}, + {file = "propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b"}, + {file = "propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef"}, + {file = "propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24"}, + {file = "propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a"}, + {file = "propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d"}, + {file = "propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe"}, + {file = "propcache-0.3.1-cp39-cp39-win32.whl", hash = "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64"}, + {file = "propcache-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566"}, + {file = "propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40"}, + {file = "propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf"}, +] + [[package]] name = "pycparser" version = "2.22" @@ -1204,6 +1784,26 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "0.26.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.9" +groups = ["test"] +files = [ + {file = "pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0"}, + {file = "pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f"}, +] + +[package.dependencies] +pytest = ">=8.2,<9" +typing-extensions = {version = ">=4.12", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + [[package]] name = "pytest-cov" version = "6.0.0" @@ -1473,11 +2073,12 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main", "dev", "test_integration", "typing"] +groups = ["main", "dev", "test", "test_integration", "typing"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +markers = {test = "python_version == \"3.9\""} [[package]] name = "urllib3" @@ -1486,7 +2087,7 @@ description = "HTTP library with thread-safe connection pooling, file post, and optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" groups = ["main", "test_integration"] -markers = "python_version < \"3.10\"" +markers = "python_version == \"3.9\"" files = [ {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, @@ -1516,6 +2117,214 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "wrapt" +version = "1.17.2" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"}, + {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"}, + {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, + {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, + {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, + {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, + {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, + {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, + {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, + {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, + {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"}, + {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"}, + {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"}, + {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"}, + {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"}, + {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, + {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, +] + +[[package]] +name = "yarl" +version = "1.20.0" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f1f6670b9ae3daedb325fa55fbe31c22c8228f6e0b513772c2e1c623caa6ab22"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85a231fa250dfa3308f3c7896cc007a47bc76e9e8e8595c20b7426cac4884c62"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a06701b647c9939d7019acdfa7ebbfbb78ba6aa05985bb195ad716ea759a569"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7595498d085becc8fb9203aa314b136ab0516c7abd97e7d74f7bb4eb95042abe"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af5607159085dcdb055d5678fc2d34949bd75ae6ea6b4381e784bbab1c3aa195"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95b50910e496567434cb77a577493c26bce0f31c8a305135f3bda6a2483b8e10"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b594113a301ad537766b4e16a5a6750fcbb1497dcc1bc8a4daae889e6402a634"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:083ce0393ea173cd37834eb84df15b6853b555d20c52703e21fbababa8c129d2"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f1a350a652bbbe12f666109fbddfdf049b3ff43696d18c9ab1531fbba1c977a"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fb0caeac4a164aadce342f1597297ec0ce261ec4532bbc5a9ca8da5622f53867"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d88cc43e923f324203f6ec14434fa33b85c06d18d59c167a0637164863b8e995"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e52d6ed9ea8fd3abf4031325dc714aed5afcbfa19ee4a89898d663c9976eb487"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ce360ae48a5e9961d0c730cf891d40698a82804e85f6e74658fb175207a77cb2"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:06d06c9d5b5bc3eb56542ceeba6658d31f54cf401e8468512447834856fb0e61"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c27d98f4e5c4060582f44e58309c1e55134880558f1add7a87c1bc36ecfade19"}, + {file = "yarl-1.20.0-cp310-cp310-win32.whl", hash = "sha256:f4d3fa9b9f013f7050326e165c3279e22850d02ae544ace285674cb6174b5d6d"}, + {file = "yarl-1.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc906b636239631d42eb8a07df8359905da02704a868983265603887ed68c076"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdb5204d17cb32b2de2d1e21c7461cabfacf17f3645e4b9039f210c5d3378bf3"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eaddd7804d8e77d67c28d154ae5fab203163bd0998769569861258e525039d2a"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:634b7ba6b4a85cf67e9df7c13a7fb2e44fa37b5d34501038d174a63eaac25ee2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d409e321e4addf7d97ee84162538c7258e53792eb7c6defd0c33647d754172e"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ea52f7328a36960ba3231c6677380fa67811b414798a6e071c7085c57b6d20a9"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8703517b924463994c344dcdf99a2d5ce9eca2b6882bb640aa555fb5efc706a"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:077989b09ffd2f48fb2d8f6a86c5fef02f63ffe6b1dd4824c76de7bb01e4f2e2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0acfaf1da020253f3533526e8b7dd212838fdc4109959a2c53cafc6db611bff2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4230ac0b97ec5eeb91d96b324d66060a43fd0d2a9b603e3327ed65f084e41f8"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6a1e6ae21cdd84011c24c78d7a126425148b24d437b5702328e4ba640a8902"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:86de313371ec04dd2531f30bc41a5a1a96f25a02823558ee0f2af0beaa7ca791"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dd59c9dd58ae16eaa0f48c3d0cbe6be8ab4dc7247c3ff7db678edecbaf59327f"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a0bc5e05f457b7c1994cc29e83b58f540b76234ba6b9648a4971ddc7f6aa52da"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c9471ca18e6aeb0e03276b5e9b27b14a54c052d370a9c0c04a68cefbd1455eb4"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40ed574b4df723583a26c04b298b283ff171bcc387bc34c2683235e2487a65a5"}, + {file = "yarl-1.20.0-cp311-cp311-win32.whl", hash = "sha256:db243357c6c2bf3cd7e17080034ade668d54ce304d820c2a58514a4e51d0cfd6"}, + {file = "yarl-1.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c12cd754d9dbd14204c328915e23b0c361b88f3cffd124129955e60a4fbfcfb"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b"}, + {file = "yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64"}, + {file = "yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2137810a20b933b1b1b7e5cf06a64c3ed3b4747b0e5d79c9447c00db0e2f752f"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:447c5eadd750db8389804030d15f43d30435ed47af1313303ed82a62388176d3"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42fbe577272c203528d402eec8bf4b2d14fd49ecfec92272334270b850e9cd7d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18e321617de4ab170226cd15006a565d0fa0d908f11f724a2c9142d6b2812ab0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4345f58719825bba29895011e8e3b545e6e00257abb984f9f27fe923afca2501"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d9b980d7234614bc4674468ab173ed77d678349c860c3af83b1fffb6a837ddc"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af4baa8a445977831cbaa91a9a84cc09debb10bc8391f128da2f7bd070fc351d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123393db7420e71d6ce40d24885a9e65eb1edefc7a5228db2d62bcab3386a5c0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab47acc9332f3de1b39e9b702d9c916af7f02656b2a86a474d9db4e53ef8fd7a"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4a34c52ed158f89876cba9c600b2c964dfc1ca52ba7b3ab6deb722d1d8be6df2"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:04d8cfb12714158abf2618f792c77bc5c3d8c5f37353e79509608be4f18705c9"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7dc63ad0d541c38b6ae2255aaa794434293964677d5c1ec5d0116b0e308031f5"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d02b591a64e4e6ca18c5e3d925f11b559c763b950184a64cf47d74d7e41877"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95fc9876f917cac7f757df80a5dda9de59d423568460fe75d128c813b9af558e"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb769ae5760cd1c6a712135ee7915f9d43f11d9ef769cb3f75a23e398a92d384"}, + {file = "yarl-1.20.0-cp313-cp313-win32.whl", hash = "sha256:70e0c580a0292c7414a1cead1e076c9786f685c1fc4757573d2967689b370e62"}, + {file = "yarl-1.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:4c43030e4b0af775a85be1fa0433119b1565673266a70bf87ef68a9d5ba3174c"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b6c4c3d0d6a0ae9b281e492b1465c72de433b782e6b5001c8e7249e085b69051"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8681700f4e4df891eafa4f69a439a6e7d480d64e52bf460918f58e443bd3da7d"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:84aeb556cb06c00652dbf87c17838eb6d92cfd317799a8092cee0e570ee11229"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f166eafa78810ddb383e930d62e623d288fb04ec566d1b4790099ae0f31485f1"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5d3d6d14754aefc7a458261027a562f024d4f6b8a798adb472277f675857b1eb"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a8f64df8ed5d04c51260dbae3cc82e5649834eebea9eadfd829837b8093eb00"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9949eaf05b4d30e93e4034a7790634bbb41b8be2d07edd26754f2e38e491de"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c366b254082d21cc4f08f522ac201d0d83a8b8447ab562732931d31d80eb2a5"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91bc450c80a2e9685b10e34e41aef3d44ddf99b3a498717938926d05ca493f6a"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c2aa4387de4bc3a5fe158080757748d16567119bef215bec643716b4fbf53f9"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d2cbca6760a541189cf87ee54ff891e1d9ea6406079c66341008f7ef6ab61145"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:798a5074e656f06b9fad1a162be5a32da45237ce19d07884d0b67a0aa9d5fdda"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f106e75c454288472dbe615accef8248c686958c2e7dd3b8d8ee2669770d020f"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3b60a86551669c23dc5445010534d2c5d8a4e012163218fc9114e857c0586fdd"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e429857e341d5e8e15806118e0294f8073ba9c4580637e59ab7b238afca836f"}, + {file = "yarl-1.20.0-cp313-cp313t-win32.whl", hash = "sha256:65a4053580fe88a63e8e4056b427224cd01edfb5f951498bfefca4052f0ce0ac"}, + {file = "yarl-1.20.0-cp313-cp313t-win_amd64.whl", hash = "sha256:53b2da3a6ca0a541c1ae799c349788d480e5144cac47dba0266c7cb6c76151fe"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:119bca25e63a7725b0c9d20ac67ca6d98fa40e5a894bd5d4686010ff73397914"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35d20fb919546995f1d8c9e41f485febd266f60e55383090010f272aca93edcc"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:484e7a08f72683c0f160270566b4395ea5412b4359772b98659921411d32ad26"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d8a3d54a090e0fff5837cd3cc305dd8a07d3435a088ddb1f65e33b322f66a94"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f0cf05ae2d3d87a8c9022f3885ac6dea2b751aefd66a4f200e408a61ae9b7f0d"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a884b8974729e3899d9287df46f015ce53f7282d8d3340fa0ed57536b440621c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8d8aa8dd89ffb9a831fedbcb27d00ffd9f4842107d52dc9d57e64cb34073d5c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4e88d6c3c8672f45a30867817e4537df1bbc6f882a91581faf1f6d9f0f1b5a"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdb77efde644d6f1ad27be8a5d67c10b7f769804fff7a966ccb1da5a4de4b656"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4ba5e59f14bfe8d261a654278a0f6364feef64a794bd456a8c9e823071e5061c"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d0bf955b96ea44ad914bc792c26a0edcd71b4668b93cbcd60f5b0aeaaed06c64"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:27359776bc359ee6eaefe40cb19060238f31228799e43ebd3884e9c589e63b20"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:04d9c7a1dc0a26efb33e1acb56c8849bd57a693b85f44774356c92d610369efa"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:faa709b66ae0e24c8e5134033187a972d849d87ed0a12a0366bedcc6b5dc14a5"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:44869ee8538208fe5d9342ed62c11cc6a7a1af1b3d0bb79bb795101b6e77f6e0"}, + {file = "yarl-1.20.0-cp39-cp39-win32.whl", hash = "sha256:b7fa0cb9fd27ffb1211cde944b41f5c67ab1c13a13ebafe470b1e206b8459da8"}, + {file = "yarl-1.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4fad6e5189c847820288286732075f213eabf81be4d08d6cc309912e62be5b7"}, + {file = "yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124"}, + {file = "yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.1" + [[package]] name = "zstandard" version = "0.23.0" @@ -1632,4 +2441,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "ec4602a5086ce90702d1b44800851a755d5ecd64973d1d4d0164c1d50f030967" +content-hash = "c71d3617ac685ee537e292ebe100992eb8d6bf0ac62bb3dbf340ddc95728abb6" diff --git a/libs/langgraph-checkpoint-aws/pyproject.toml b/libs/langgraph-checkpoint-aws/pyproject.toml index 8faefe6f..bc1dd1a3 100644 --- a/libs/langgraph-checkpoint-aws/pyproject.toml +++ b/libs/langgraph-checkpoint-aws/pyproject.toml @@ -19,7 +19,8 @@ keywords = ["aws", "bedrock", "langchain", "langgraph", "checkpointer"] python = ">=3.9,<4.0" langgraph-checkpoint = ">=2.0.0" langgraph = ">=0.2.55" -boto3 = ">=1.37.3" +boto3 = ">=1.37.0,<1.37.2" +aioboto3 = ">=14.1.0" [tool.poetry.group.dev] optional = true @@ -35,10 +36,14 @@ optional = true [tool.poetry.group.test.dependencies] pytest = ">=7.4.3" pytest-cov = ">=4.1.0" +pytest-asyncio = ">=0.26.0" [tool.poetry.group.test_integration] optional = true +[tool.pytest.ini_options] +asyncio_default_fixture_loop_scope = "function" + [tool.poetry.group.test_integration.dependencies] langchain-aws = ">=0.2.14" diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py index f3980e28..2fb189af 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py @@ -1,11 +1,12 @@ import base64 import datetime import json -from unittest.mock import MagicMock, Mock +from unittest.mock import MagicMock, Mock, AsyncMock from uuid import uuid4 import pytest from botocore.client import BaseClient +from aiobotocore.client import AioBaseClient from langgraph.checkpoint.base import Checkpoint, CheckpointMetadata from langgraph.constants import TASKS @@ -17,7 +18,6 @@ SessionPendingWrite, ) - @pytest.fixture def mock_boto_client(): mock_client = Mock(spec=BaseClient) @@ -35,6 +35,24 @@ def mock_boto_client(): mock_client.list_invocation_steps = MagicMock() return mock_client +@pytest.fixture +def mock_aioboto_client(): + mock_client = AsyncMock(spec=AioBaseClient) + + mock_client.__aenter__ = AsyncMock(return_value=mock_client) + mock_client.__aexit__ = AsyncMock(return_value=None) + + mock_client.create_session = AsyncMock() + mock_client.get_session = AsyncMock() + mock_client.end_session = AsyncMock() + mock_client.delete_session = AsyncMock() + mock_client.create_invocation = AsyncMock() + mock_client.list_invocations = AsyncMock() + mock_client.put_invocation_step = AsyncMock() + mock_client.get_invocation_step = AsyncMock() + mock_client.list_invocation_steps = AsyncMock() + + return mock_client @pytest.fixture def sample_session_id(): @@ -228,7 +246,7 @@ def sample_session_checkpoint(sample_invocation_step_summary): thread_id=sample_invocation_step_summary["sessionId"], checkpoint_ns=sample_invocation_step_summary["invocationId"], checkpoint_id=sample_invocation_step_summary["invocationStepId"], - checkpoint={}, + checkpoint=('json', b'e30='), metadata=json.dumps({"key": "value"}), parent_checkpoint_id=None, channel_values={}, diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py new file mode 100644 index 00000000..27e4cb0f --- /dev/null +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py @@ -0,0 +1,978 @@ +import datetime +import json +from unittest.mock import ANY, Mock, patch, AsyncMock + +import pytest +from botocore.config import Config +from botocore.exceptions import ClientError +from langchain_core.runnables import RunnableConfig +from langgraph.checkpoint.base import CheckpointTuple +from langgraph.constants import ERROR +from pydantic import SecretStr + +from langgraph_checkpoint_aws.models import ( + GetInvocationStepResponse, + InvocationStep, + ListInvocationStepsResponse, +) +from langgraph_checkpoint_aws.async_saver import ( + AsyncBedrockAgentRuntimeSessionClient, + AsyncBedrockSessionSaver, +) + + +class TestAsyncBedrockSessionSaver: + @pytest.fixture + def session_saver(self, mock_aioboto_client): + with patch("aioboto3.Session") as mock_aioboto_session: + mock_aioboto_session.return_value.client.return_value = mock_aioboto_client + yield AsyncBedrockSessionSaver() + + @pytest.fixture + def runnable_config(self): + return RunnableConfig( + configurable={ + "thread_id": "test_thread_id", + "checkpoint_ns": "test_namespace", + } + ) + + @pytest.mark.asyncio + async def test_init_with_default_client(self, session_saver, mock_aioboto_client): + # Assert type of session_client + assert isinstance(session_saver.session_client, AsyncBedrockAgentRuntimeSessionClient) + + # Assert that the session is set correctly + assert session_saver.session_client.session.client.return_value == mock_aioboto_client + + # test _get_client logic + client = await session_saver.session_client._get_client() + assert client == mock_aioboto_client + + + @pytest.mark.asyncio + async def test_init_with_all_parameters(self, mock_aioboto_client): + # Mock both the Session and the AsyncBedrockAgentRuntimeSessionClient + with patch("aioboto3.Session") as mock_aioboto_session: + + # Configure the mock to return our mock client + mock_aioboto_session.return_value.client.return_value = mock_aioboto_client + + # Set up test parameters + config = Config(retries=dict(max_attempts=5)) + endpoint_url = "https://custom-endpoint.amazonaws.com" + + # Create the AsyncBedrockSessionSaver instance + saver = AsyncBedrockSessionSaver( + region_name="us-west-2", + credentials_profile_name="test-profile", + aws_access_key_id=SecretStr("test-access-key"), + aws_secret_access_key=SecretStr("test-secret-key"), + aws_session_token=SecretStr("test-session-token"), + endpoint_url=endpoint_url, + config=config, + ) + + # Assert that AsyncBedrockAgentRuntimeSessionClient was initialized with the correct parameters + assert isinstance(saver.session_client, AsyncBedrockAgentRuntimeSessionClient) + + @pytest.mark.asyncio + async def test__create_session_invocation_success( + self, mock_aioboto_client, session_saver, sample_create_invocation_response + ): + # Arrange + thread_id = "test_thread_id" + invocation_id = "test_invocation_id" + mock_aioboto_client.create_invocation.return_value = ( + sample_create_invocation_response + ) + + # Act + await session_saver._create_session_invocation(thread_id, invocation_id) + + # Assert + mock_aioboto_client.create_invocation.assert_called_once() + + @pytest.mark.asyncio + async def test__create_session_invocation_conflict(self, mock_aioboto_client, session_saver): + # Arrange + error_response = {"Error": {"Code": "ConflictException", "Message": "Conflict"}} + mock_aioboto_client.create_invocation.side_effect = ClientError( + error_response=error_response, + operation_name="CreateInvocation", + ) + thread_id = "test_thread_id" + invocation_id = "test_invocation_id" + + # Act - should not raise an exception + await session_saver._create_session_invocation(thread_id, invocation_id) + + # Assert + mock_aioboto_client.create_invocation.assert_called_once() + + @pytest.mark.asyncio + async def test__create_session_invocation_raises_error( + self, mock_aioboto_client, session_saver + ): + # Arrange + thread_id = "test_thread_id" + invocation_id = "test_invocation_id" + + error_response = {"Error": {"Code": "SomeOtherError", "Message": "Other error"}} + mock_aioboto_client.create_invocation.side_effect = ClientError( + error_response=error_response, + operation_name="CreateInvocation", + ) + + # Act & Assert + with pytest.raises(ClientError) as exc_info: + await session_saver._create_session_invocation(thread_id, invocation_id) + + assert exc_info.value.response["Error"]["Code"] == "SomeOtherError" + mock_aioboto_client.create_invocation.assert_called_once() + + @pytest.mark.asyncio + async def test__get_checkpoint_pending_writes_success( + self, + mock_aioboto_client, + session_saver, + sample_session_pending_write, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + thread_id = "test_thread" + checkpoint_ns = "test_namespace" + checkpoint_id = "test_checkpoint" + + # serialize payload + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_pending_write.model_dump_json() + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + mock_aioboto_client.get_invocation_step.return_value = ( + sample_get_invocation_step_response + ) + + # Act + result = await session_saver._get_checkpoint_pending_writes( + thread_id, checkpoint_ns, checkpoint_id + ) + + # Assert + assert len(result) == 1 + mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_aioboto_client.get_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test__get_checkpoint_pending_writes_no_invocation_steps( + self, + mock_aioboto_client, + session_saver, + sample_list_invocation_steps_response, + ): + # Arrange + sample_list_invocation_steps_response["invocationStepSummaries"] = [] + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + + # Act + result = await session_saver._get_checkpoint_pending_writes( + "thread_id", "ns", "checkpoint_id" + ) + + # Assert + assert result == [] + mock_aioboto_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test__get_checkpoint_pending_writes_resource_not_found( + self, mock_aioboto_client, session_saver + ): + # Arrange + error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} + mock_aioboto_client.list_invocation_steps.side_effect = ClientError( + error_response=error_response, + operation_name="ListInvocationSteps", + ) + + # Act + result = await session_saver._get_checkpoint_pending_writes( + "thread_id", "ns", "checkpoint_id" + ) + + # Assert + assert result == [] + mock_aioboto_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test__get_checkpoint_pending_writes_client_error( + self, mock_aioboto_client, session_saver, sample_invocation_step_payload + ): + # Arrange + error_response = {"Error": {"Code": "SomeError", "Message": "Error occurred"}} + mock_aioboto_client.list_invocation_steps.side_effect = ClientError( + error_response=error_response, + operation_name="ListInvocationSteps", + ) + + # Act & Assert + with pytest.raises(ClientError): + await session_saver._get_checkpoint_pending_writes( + "thread_id", "ns", "checkpoint_id" + ) + + mock_aioboto_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test__save_invocation_step_success( + self, + mock_aioboto_client, + session_saver, + sample_invocation_step_payload, + sample_put_invocation_step_response, + ): + # Arrange + thread_id = "test_thread_id" + invocation_identifier = "test_invocation_identifier" + invocation_step_id = "test_invocation_step_id" + mock_aioboto_client.put_invocation_step.return_value = ( + sample_put_invocation_step_response + ) + + # Act + with patch("datetime.datetime") as mock_datetime: + invocation_step_time = datetime.datetime.now(datetime.timezone.utc) + mock_datetime.now.return_value = invocation_step_time + await session_saver._save_invocation_step( + thread_id, + invocation_identifier, + invocation_step_id, + sample_invocation_step_payload, + ) + + # Assert + mock_aioboto_client.put_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test__save_invocation_step_client_error( + self, mock_aioboto_client, session_saver, sample_invocation_step_payload + ): + # Arrange + error_response = {"Error": {"Code": "SomeError", "Message": "Error occurred"}} + mock_aioboto_client.put_invocation_step.side_effect = ClientError( + error_response=error_response, + operation_name="PutInvocationStep", + ) + + # Act & Assert + with pytest.raises(ClientError): + await session_saver._save_invocation_step( + "thread_id", "inv_id", "step_id", sample_invocation_step_payload + ) + + mock_aioboto_client.put_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test__find_most_recent_checkpoint_step_success( + self, + mock_aioboto_client, + session_saver, + sample_session_checkpoint, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + + # serialize payload + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_checkpoint.model_dump_json() + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + mock_aioboto_client.get_invocation_step.return_value = ( + sample_get_invocation_step_response + ) + + # Act + result = await session_saver._find_most_recent_checkpoint_step( + thread_id, checkpoint_ns + ) + + # Assert + assert result is not None + mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_aioboto_client.get_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test__find_most_recent_checkpoint_step_skips_writes( + self, + mock_aioboto_client, + session_saver, + sample_session_pending_write, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + + # serialize payload + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_pending_write.model_dump_json() + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + mock_aioboto_client.get_invocation_step.return_value = ( + sample_get_invocation_step_response + ) + + # Act + result = await session_saver._find_most_recent_checkpoint_step( + thread_id, checkpoint_ns + ) + + # Assert + assert result is None + mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_aioboto_client.get_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test__find_most_recent_checkpoint_step_no_invocation_steps( + self, + mock_aioboto_client, + session_saver, + sample_list_invocation_steps_response, + ): + # Arrange + sample_list_invocation_steps_response["invocationStepSummaries"] = [] + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + + # Act + result = await session_saver._find_most_recent_checkpoint_step("thread_id", "ns") + + # Assert + assert result is None + mock_aioboto_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test__get_checkpoint_step_with_checkpoint_id( + self, + mock_aioboto_client, + session_saver, + sample_get_invocation_step_response, + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + checkpoint_id = "test_checkpoint_id" + session_saver._find_most_recent_checkpoint_step = Mock() + mock_aioboto_client.get_invocation_step.return_value = ( + sample_get_invocation_step_response + ) + + # Act + await session_saver._get_checkpoint_step(thread_id, checkpoint_ns, checkpoint_id) + + # Assert + session_saver._find_most_recent_checkpoint_step.assert_not_called() + mock_aioboto_client.get_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test__get_checkpoint_step_without_checkpoint_id( + self, + mock_aioboto_client, + session_saver, + sample_invocation_step_payload, + sample_get_invocation_step_response, + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + session_saver._find_most_recent_checkpoint_step = AsyncMock( + return_value=sample_invocation_step_payload + ) + + # Act + result = await session_saver._get_checkpoint_step(thread_id, checkpoint_ns) + + # Assert + assert result == sample_invocation_step_payload + session_saver._find_most_recent_checkpoint_step.assert_called_once_with( + thread_id, + checkpoint_ns, + ) + mock_aioboto_client.get_invocation_step.assert_not_called() + + @pytest.mark.asyncio + async def test__get_checkpoint_step_empty_without_checkpoint_id( + self, + mock_aioboto_client, + session_saver, + sample_invocation_step_payload, + sample_get_invocation_step_response, + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + session_saver._find_most_recent_checkpoint_step = AsyncMock(return_value=None) + + # Act + result = await session_saver._get_checkpoint_step(thread_id, checkpoint_ns) + + # Assert + assert result is None + session_saver._find_most_recent_checkpoint_step.assert_called_once_with( + thread_id, + checkpoint_ns, + ) + mock_aioboto_client.get_invocation_step.assert_not_called() + + @pytest.mark.asyncio + async def test__get_task_sends_without_parent_checkpoint_id( + self, session_saver, sample_session_checkpoint + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + + # Act + result = await session_saver._get_task_sends(thread_id, checkpoint_ns, None) + + # Assert + assert result == [] + + @pytest.mark.asyncio + async def test__get_task_sends( + self, session_saver, sample_session_pending_write_with_sends + ): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + parent_checkpoint_id = "test_parent_checkpoint_id" + + session_saver._get_checkpoint_pending_writes = AsyncMock( + return_value=sample_session_pending_write_with_sends + ) + + # Act + result = await session_saver._get_task_sends( + thread_id, checkpoint_ns, parent_checkpoint_id + ) + + # Assert + assert result == [ + ["2", "__pregel_tasks", ["json", b"eyJrMiI6ICJ2MiJ9"], "/test2/path2", 1], + ["3", "__pregel_tasks", ["json", b"eyJrMyI6ICJ2MyJ9"], "/test3/path3", 1], + ] + session_saver._get_checkpoint_pending_writes.assert_called_once_with( + thread_id, checkpoint_ns, parent_checkpoint_id + ) + + @pytest.mark.asyncio + async def test__get_task_sends_empty(self, session_saver): + # Arrange + thread_id = "test_thread_id" + checkpoint_ns = "test_namespace" + parent_checkpoint_id = "test_parent_checkpoint_id" + + session_saver._get_checkpoint_pending_writes = AsyncMock(return_value=[]) + + # Act + result = await session_saver._get_task_sends( + thread_id, checkpoint_ns, parent_checkpoint_id + ) + + # Assert + assert result == [] + session_saver._get_checkpoint_pending_writes.assert_called_once_with( + thread_id, checkpoint_ns, parent_checkpoint_id + ) + + @pytest.mark.asyncio + @patch("langgraph_checkpoint_aws.async_saver.construct_checkpoint_tuple") + async def test_aget_tuple_success( + self, + mock_construct_checkpoint, + session_saver, + runnable_config, + sample_get_invocation_step_response, + sample_session_pending_write_with_sends, + sample_session_checkpoint, + ): + # Arrange + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_checkpoint.model_dump_json() + + # Mock all required internal methods + session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._get_checkpoint_step = AsyncMock( + return_value=InvocationStep( + **sample_get_invocation_step_response["invocationStep"] + ) + ) + session_saver._get_checkpoint_pending_writes = AsyncMock( + return_value=sample_session_pending_write_with_sends + ) + session_saver._get_task_sends = AsyncMock(return_value=[]) + mock_construct_checkpoint.return_value = AsyncMock(spec=CheckpointTuple) + + # Act + result = await session_saver.aget_tuple(runnable_config) + + # Assert + assert isinstance(result, CheckpointTuple) + + + @pytest.mark.asyncio + async def test_aget_tuple_success_empty(self, session_saver, runnable_config): + # Arrange + session_saver._get_checkpoint_step = AsyncMock(return_value=None) + + # Act + result = await session_saver.aget_tuple(runnable_config) + + # Assert + assert result is None + session_saver._get_checkpoint_step.assert_called_once() + + @pytest.mark.asyncio + async def test_aget_tuple_resource_not_found_error(self, session_saver, runnable_config): + # Arrange + error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} + session_saver._get_checkpoint_step = AsyncMock( + side_effect=ClientError( + error_response=error_response, + operation_name="ListInvocationSteps", + ) + ) + + # Act + result = await session_saver.aget_tuple(runnable_config) + + # Assert + assert result is None + session_saver._get_checkpoint_step.assert_called_once() + + @pytest.mark.asyncio + async def test_aget_tuple_error(self, session_saver, runnable_config): + # Arrange + error_response = {"Error": {"Code": "SomeOtherError", "Message": "Some other error"}} + session_saver._get_checkpoint_step = AsyncMock( + side_effect=ClientError( + error_response=error_response, + operation_name="ListInvocationSteps", + ) + ) + + # Act and Assert + with pytest.raises(ClientError): + await session_saver.aget_tuple(runnable_config) + + session_saver._get_checkpoint_step.assert_called_once() + + @pytest.mark.asyncio + async def test_aput_success( + self, + session_saver, + runnable_config, + sample_checkpoint, + sample_checkpoint_metadata, + ): + # Arrange + session_saver._create_session_invocation = AsyncMock() + session_saver._save_invocation_step = AsyncMock() + + # Act + await session_saver.aput( + runnable_config, sample_checkpoint, sample_checkpoint_metadata, {} + ) + + # Assert + session_saver._create_session_invocation.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "72f4457f-e6bb-e1db-49ee-06cd9901904f", + ) + session_saver._save_invocation_step.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "72f4457f-e6bb-e1db-49ee-06cd9901904f", + "checkpoint_123", + ANY, + ) + + @pytest.mark.asyncio + async def test_aput_writes_success( + self, + session_saver, + runnable_config, + sample_checkpoint, + sample_checkpoint_metadata, + ): + # Arrange + task_id = "test_task_id" + task_path = "test_task_path" + writes = [("__pregel_pull", "__start__"), ("__pregel_pull", "add_one")] + runnable_config["configurable"]["checkpoint_id"] = "test_checkpoint_id" + + session_saver._create_session_invocation = AsyncMock() + session_saver._save_invocation_step = AsyncMock() + session_saver._get_checkpoint_pending_writes = AsyncMock(return_value=[]) + + # Act + await session_saver.aput_writes(runnable_config, writes, task_id, task_path) + + # Assert + session_saver._create_session_invocation.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "ea473b95-7b9c-fe52-df2c-3a7353d3148b", + ) + session_saver._save_invocation_step.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "ea473b95-7b9c-fe52-df2c-3a7353d3148b", + None, + ANY, + ) + + @pytest.mark.asyncio + async def test_aput_writes_skip_existing_writes( + self, + session_saver, + runnable_config, + sample_checkpoint, + sample_checkpoint_metadata, + sample_session_pending_write, + ): + # Arrange + task_id = "test_task_id" + task_path = "test_task_path" + writes = [("__pregel_pull", "__start__")] + runnable_config["configurable"]["checkpoint_id"] = "test_checkpoint_id" + + session_saver._create_session_invocation = AsyncMock() + session_saver._save_invocation_step = AsyncMock() + + sample_session_pending_write.task_id = task_id + sample_session_pending_write.write_idx = 0 + + session_saver._get_checkpoint_pending_writes = AsyncMock( + return_value=[sample_session_pending_write] + ) + + # Act + await session_saver.aput_writes(runnable_config, writes, task_id, task_path) + + # Assert + session_saver._create_session_invocation.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "ea473b95-7b9c-fe52-df2c-3a7353d3148b", + ) + session_saver._save_invocation_step.assert_not_called() + + @pytest.mark.asyncio + async def test_aput_writes_override_existing_writes( + self, + session_saver, + runnable_config, + sample_checkpoint, + sample_checkpoint_metadata, + sample_session_pending_write, + ): + # Arrange + task_id = "test_task_id" + task_path = "test_task_path" + writes = [(ERROR, "__start__")] + runnable_config["configurable"]["checkpoint_id"] = "test_checkpoint_id" + + session_saver._create_session_invocation = AsyncMock() + session_saver._save_invocation_step = AsyncMock() + + sample_session_pending_write.task_id = task_id + sample_session_pending_write.write_idx = 0 + + session_saver._get_checkpoint_pending_writes = AsyncMock( + return_value=[sample_session_pending_write] + ) + + # Act + await session_saver.aput_writes(runnable_config, writes, task_id, task_path) + + # Assert + session_saver._create_session_invocation.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "ea473b95-7b9c-fe52-df2c-3a7353d3148b", + ) + session_saver._save_invocation_step.assert_called_once_with( + runnable_config["configurable"]["thread_id"], + "ea473b95-7b9c-fe52-df2c-3a7353d3148b", + None, + ANY, + ) + + @pytest.mark.asyncio + @patch("langgraph_checkpoint_aws.async_saver.construct_checkpoint_tuple") + async def test_alist_success( + self, + mock_construct_checkpoint, + session_saver, + runnable_config, + sample_session_checkpoint, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_checkpoint.model_dump_json() + + # Mock all required internal methods + session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver.session_client.get_invocation_step = AsyncMock( + return_value=GetInvocationStepResponse( + **sample_get_invocation_step_response + ) + ) + session_saver.session_client.list_invocation_steps = AsyncMock( + return_value=ListInvocationStepsResponse( + **sample_list_invocation_steps_response + ) + ) + session_saver._get_checkpoint_pending_writes = AsyncMock(return_value=[]) + session_saver._get_task_sends = AsyncMock(return_value=[]) + mock_construct_checkpoint.return_value = AsyncMock(spec=CheckpointTuple) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + + # Assert + assert len(list(result)) == 1 + + @pytest.mark.asyncio + async def test_alist_skips_writes( + self, + session_saver, + runnable_config, + sample_session_pending_write, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_pending_write.model_dump_json() + + # Mock all required internal methods + session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver.session_client.get_invocation_step = AsyncMock( + return_value=GetInvocationStepResponse( + **sample_get_invocation_step_response + ) + ) + session_saver.session_client.list_invocation_steps = AsyncMock( + return_value=ListInvocationStepsResponse( + **sample_list_invocation_steps_response + ) + ) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + + # Assert + assert len(list(result)) == 0 + + + + @pytest.mark.asyncio + @patch("langgraph_checkpoint_aws.async_saver.construct_checkpoint_tuple") + async def test_alist_with_limit( + self, + mock_construct_checkpoint, + session_saver, + runnable_config, + sample_session_checkpoint, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_checkpoint.model_dump_json() + + # Mock all required internal methods + session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver.session_client.get_invocation_step = AsyncMock( + return_value=GetInvocationStepResponse( + **sample_get_invocation_step_response + ) + ) + # Duplicate list response + sample_list_invocation_steps_response["invocationStepSummaries"] *= 10 + session_saver.session_client.list_invocation_steps = AsyncMock( + return_value=ListInvocationStepsResponse( + **sample_list_invocation_steps_response + ) + ) + session_saver._get_checkpoint_pending_writes = AsyncMock(return_value=[]) + session_saver._get_task_sends = AsyncMock(return_value=[]) + mock_construct_checkpoint.return_value = AsyncMock(spec=CheckpointTuple) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config, limit=3)] + + # Assert + assert len(list(result)) == 3 + + @pytest.mark.asyncio + async def test_alist_with_filter( + self, + session_saver, + runnable_config, + sample_session_checkpoint, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_checkpoint.model_dump_json() + + # Mock all required internal methods + session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver.session_client.get_invocation_step = AsyncMock( + return_value=GetInvocationStepResponse( + **sample_get_invocation_step_response + ) + ) + session_saver.session_client.list_invocation_steps = AsyncMock( + return_value=ListInvocationStepsResponse( + **sample_list_invocation_steps_response + ) + ) + session_saver._get_checkpoint_pending_writes = AsyncMock(return_value=[]) + session_saver._get_task_sends = AsyncMock(return_value=[]) + session_saver._construct_checkpoint_tuple = AsyncMock( + return_value=AsyncMock(spec=CheckpointTuple) + ) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config, filter={"key": "value1"})] + + + # Assert + assert len(list(result)) == 0 + + @pytest.mark.asyncio + async def test_alist_with_before( + self, + session_saver, + runnable_config, + sample_session_checkpoint, + sample_list_invocation_steps_response, + sample_get_invocation_step_response, + ): + # Arrange + before = RunnableConfig( + configurable={ + "checkpoint_id": sample_get_invocation_step_response["invocationStep"][ + "invocationStepId" + ] + } + ) + sample_session_checkpoint.metadata = json.dumps( + sample_session_checkpoint.metadata + ) + sample_get_invocation_step_response["invocationStep"]["payload"][ + "contentBlocks" + ][0]["text"] = sample_session_checkpoint.model_dump_json() + + # Mock all required internal methods + session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver.session_client.get_invocation_step = AsyncMock( + return_value=GetInvocationStepResponse( + **sample_get_invocation_step_response + ) + ) + session_saver.session_client.list_invocation_steps = AsyncMock( + return_value=ListInvocationStepsResponse( + **sample_list_invocation_steps_response + ) + ) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config, before=before)] + + # Assert + assert len(list(result)) == 0 + + @pytest.mark.asyncio + async def test_alist_empty_response( + self, + session_saver, + runnable_config, + ): + # Arrange + session_saver.session_client.list_invocation_steps = AsyncMock( + return_value=ListInvocationStepsResponse(invocation_step_summaries=[]) + ) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + + # Assert + assert len(result) == 0 + session_saver.session_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test_alist_returns_empty_on_resource_not_found( + self, + session_saver, + runnable_config, + ): + # Arrange + error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} + session_saver.session_client.list_invocation_steps = AsyncMock( + side_effect=ClientError( + error_response=error_response, + operation_name="ListInvocationSteps", + ) + ) + + # Act + result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + + # Assert + assert len(result) == 0 + session_saver.session_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test_alist_error( + self, + session_saver, + runnable_config, + ): + # Arrange + error_response = {"Error": {"Code": "SomeOtherError", "Message": "Some other error"}} + session_saver.session_client.list_invocation_steps = AsyncMock( + side_effect=ClientError( + error_response=error_response, + operation_name="ListInvocationSteps", + ) + ) + + # Act and Assert + with pytest.raises(ClientError): + async for _ in session_saver.alist(runnable_config): + pass + + session_saver.session_client.list_invocation_steps.assert_called_once() + + diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py new file mode 100644 index 00000000..cb243298 --- /dev/null +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py @@ -0,0 +1,302 @@ +from unittest.mock import patch + +import pytest + +from langgraph_checkpoint_aws.models import ( + CreateInvocationRequest, + CreateInvocationResponse, + CreateSessionRequest, + CreateSessionResponse, + DeleteSessionRequest, + EndSessionRequest, + EndSessionResponse, + GetInvocationStepRequest, + GetInvocationStepResponse, + GetSessionRequest, + GetSessionResponse, + ListInvocationsRequest, + ListInvocationsResponse, + ListInvocationStepsRequest, + ListInvocationStepsResponse, + PutInvocationStepRequest, + PutInvocationStepResponse, +) +from langgraph_checkpoint_aws.async_saver import AsyncBedrockAgentRuntimeSessionClient + + +class TestAsyncBedrockAgentRuntimeSessionClient: + @pytest.fixture + def mock_session_client(self, mock_aioboto_client): + with patch("aioboto3.Session") as mock_aioboto_session: + mock_aioboto_session.return_value.client.return_value = mock_aioboto_client + yield AsyncBedrockAgentRuntimeSessionClient() + + class TestSession: + @pytest.mark.asyncio + async def test_create_async_session( + self, mock_session_client, mock_aioboto_client, sample_create_session_response + ): + # Arrange + mock_aioboto_client.create_session.return_value = ( + sample_create_session_response + ) + request = CreateSessionRequest() + + # Act + response = await mock_session_client.create_session(request) + + # Assert + assert isinstance(response, CreateSessionResponse) + mock_aioboto_client.create_session.assert_called_once() + + @pytest.mark.asyncio + async def test_create_session_with_user_attr( + self, mock_session_client, mock_aioboto_client, sample_create_session_response + ): + # Arrange + mock_aioboto_client.create_session.return_value = ( + sample_create_session_response + ) + request = CreateSessionRequest( + session_metadata={"key": "value"}, + encryption_key_arn="test-arn", + tags={"tag1": "value1"}, + ) + + # Act + response = await mock_session_client.create_session(request) + + # Assert + assert isinstance(response, CreateSessionResponse) + mock_aioboto_client.create_session.assert_called_once() + + @pytest.mark.asyncio + async def test_get_session( + self, + mock_session_client, + mock_aioboto_client, + sample_get_session_response, + sample_session_id, + ): + # Arrange + mock_aioboto_client.get_session.return_value = sample_get_session_response + request = GetSessionRequest(session_identifier=sample_session_id) + + # Act + response = await mock_session_client.get_session(request) + + # Assert + assert isinstance(response, GetSessionResponse) + mock_aioboto_client.get_session.assert_called_once() + + @pytest.mark.asyncio + async def test_end_session( + self, + mock_session_client, + mock_aioboto_client, + sample_get_session_response, + sample_session_id, + ): + # Arrange + mock_aioboto_client.end_session.return_value = sample_get_session_response + request = EndSessionRequest(session_identifier=sample_session_id) + + # Act + response = await mock_session_client.end_session(request) + + # Assert + assert isinstance(response, EndSessionResponse) + mock_aioboto_client.end_session.assert_called_once() + + @pytest.mark.asyncio + async def test_delete_session( + self, mock_session_client, mock_aioboto_client, sample_session_id + ): + # Arrange + request = DeleteSessionRequest(session_identifier=sample_session_id) + + # Act + await mock_session_client.delete_session(request) + + # Assert + mock_aioboto_client.delete_session.assert_called_once() + + class TestInvocation: + @pytest.mark.asyncio + async def test_create_invocation( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_create_invocation_response, + ): + # Arrange + mock_aioboto_client.create_invocation.return_value = ( + sample_create_invocation_response + ) + request = CreateInvocationRequest(session_identifier=sample_session_id) + + # Act + response = await mock_session_client.create_invocation(request) + + # Assert + assert isinstance(response, CreateInvocationResponse) + mock_aioboto_client.create_invocation.assert_called_once() + + @pytest.mark.asyncio + async def test_create_invocation_with_user_attr( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_invocation_id, + sample_create_invocation_response, + ): + # Arrange + mock_aioboto_client.create_invocation.return_value = ( + sample_create_invocation_response + ) + request = CreateInvocationRequest( + session_identifier=sample_session_id, + invocation_id=sample_invocation_id, + description="Test invocation description", + ) + + # Act + response = await mock_session_client.create_invocation(request) + + # Assert + assert isinstance(response, CreateInvocationResponse) + mock_aioboto_client.create_invocation.assert_called_once() + + @pytest.mark.asyncio + async def test_list_invocation( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_list_invocation_response, + ): + # Arrange + mock_aioboto_client.list_invocations.return_value = ( + sample_list_invocation_response + ) + request = ListInvocationsRequest( + session_identifier=sample_session_id, max_results=1 + ) + + # Act + response = await mock_session_client.list_invocations(request) + + # Assert + assert isinstance(response, ListInvocationsResponse) + mock_aioboto_client.list_invocations.assert_called_once() + + class TestInvocationStep: + @pytest.mark.asyncio + async def test_put_invocation_step( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_invocation_id, + sample_invocation_step_id, + sample_timestamp, + sample_invocation_step_payload, + sample_put_invocation_step_response, + ): + # Arrange + mock_aioboto_client.put_invocation_step.return_value = ( + sample_put_invocation_step_response + ) + request = PutInvocationStepRequest( + session_identifier=sample_session_id, + invocation_identifier=sample_invocation_id, + invocation_step_id=sample_invocation_step_id, + invocation_step_time=sample_timestamp, + payload=sample_invocation_step_payload, + ) + + # Act + response = await mock_session_client.put_invocation_step(request) + + # Assert + assert isinstance(response, PutInvocationStepResponse) + mock_aioboto_client.put_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test_get_invocation_step( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_invocation_id, + sample_invocation_step_id, + sample_get_invocation_step_response, + ): + # Arrange + mock_aioboto_client.get_invocation_step.return_value = ( + sample_get_invocation_step_response + ) + request = GetInvocationStepRequest( + session_identifier=sample_session_id, + invocation_identifier=sample_invocation_id, + invocation_step_id=sample_invocation_step_id, + ) + + # Act + response = await mock_session_client.get_invocation_step(request) + + # Assert + assert isinstance(response, GetInvocationStepResponse) + mock_aioboto_client.get_invocation_step.assert_called_once() + + @pytest.mark.asyncio + async def test_list_invocation_steps( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_list_invocation_steps_response, + ): + # Arrange + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + request = ListInvocationStepsRequest( + session_identifier=sample_session_id, + max_results=1, + ) + + # Act + response = await mock_session_client.list_invocation_steps(request) + + # Assert + assert isinstance(response, ListInvocationStepsResponse) + mock_aioboto_client.list_invocation_steps.assert_called_once() + + @pytest.mark.asyncio + async def test_list_invocation_steps_by_invocation( + self, + mock_session_client, + mock_aioboto_client, + sample_session_id, + sample_invocation_id, + sample_list_invocation_steps_response, + ): + # Arrange + mock_aioboto_client.list_invocation_steps.return_value = ( + sample_list_invocation_steps_response + ) + request = ListInvocationStepsRequest( + session_identifier=sample_session_id, + invocation_identifier=sample_invocation_id, + max_results=1, + ) + + # Act + response = await mock_session_client.list_invocation_steps(request) + + # Assert + assert isinstance(response, ListInvocationStepsResponse) + mock_aioboto_client.list_invocation_steps.assert_called_once() From 01392a623b68222f20a39d50d0b0a02c971459ef Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Mon, 5 May 2025 20:54:48 +0200 Subject: [PATCH 05/15] updated aioboto3 version --- libs/langgraph-checkpoint-aws/poetry.lock | 38 ++++++++++---------- libs/langgraph-checkpoint-aws/pyproject.toml | 4 +-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/poetry.lock b/libs/langgraph-checkpoint-aws/poetry.lock index 7531a327..865b84ca 100644 --- a/libs/langgraph-checkpoint-aws/poetry.lock +++ b/libs/langgraph-checkpoint-aws/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "aioboto3" -version = "14.1.0" +version = "14.2.0" description = "Async boto3 wrapper" optional = false python-versions = "<4.0,>=3.8" groups = ["main"] files = [ - {file = "aioboto3-14.1.0-py3-none-any.whl", hash = "sha256:f8547032bc4f90966b22869c1295d890c161549f4e8919f32853571ceb6fd0c6"}, - {file = "aioboto3-14.1.0.tar.gz", hash = "sha256:9d59b536ae8a951b9413ce151bf77df9c7cfe2cbaa2c4c240c066f384305c932"}, + {file = "aioboto3-14.2.0-py3-none-any.whl", hash = "sha256:0bf0663fd4f8ad814207ef77fcbdfca51be1daf81108eeba598b9d48654e1da4"}, + {file = "aioboto3-14.2.0.tar.gz", hash = "sha256:80cee479dfe9686f2823bed2ac616d3c0bc977255b2c3f997da612fd8179ffe4"}, ] [package.dependencies] -aiobotocore = {version = "2.21.1", extras = ["boto3"]} +aiobotocore = {version = "2.22.0", extras = ["boto3"]} aiofiles = ">=23.2.1" [package.extras] @@ -22,29 +22,29 @@ s3cse = ["cryptography (>=44.0.1)"] [[package]] name = "aiobotocore" -version = "2.21.1" +version = "2.22.0" description = "Async client for aws services using botocore and aiohttp" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "aiobotocore-2.21.1-py3-none-any.whl", hash = "sha256:bd7c49a6d6f8a3d9444b0a94417c8da13813b5c7eec1c4f0ec2db7e8ce8f23e7"}, - {file = "aiobotocore-2.21.1.tar.gz", hash = "sha256:010357f43004413e92a9d066bb0db1f241aeb29ffed306e9197061ffc94e6577"}, + {file = "aiobotocore-2.22.0-py3-none-any.whl", hash = "sha256:b4e6306f79df9d81daff1f9d63189a2dbee4b77ce3ab937304834e35eaaeeccf"}, + {file = "aiobotocore-2.22.0.tar.gz", hash = "sha256:11091477266b75c2b5d28421c1f2bc9a87d175d0b8619cb830805e7a113a170b"}, ] [package.dependencies] aiohttp = ">=3.9.2,<4.0.0" aioitertools = ">=0.5.1,<1.0.0" -boto3 = {version = ">=1.37.0,<1.37.2", optional = true, markers = "extra == \"boto3\""} -botocore = ">=1.37.0,<1.37.2" +boto3 = {version = ">=1.37.2,<1.37.4", optional = true, markers = "extra == \"boto3\""} +botocore = ">=1.37.2,<1.37.4" jmespath = ">=0.7.1,<2.0.0" multidict = ">=6.0.0,<7.0.0" python-dateutil = ">=2.1,<3.0.0" wrapt = ">=1.10.10,<2.0.0" [package.extras] -awscli = ["awscli (>=1.38.0,<1.38.2)"] -boto3 = ["boto3 (>=1.37.0,<1.37.2)"] +awscli = ["awscli (>=1.38.2,<1.38.4)"] +boto3 = ["boto3 (>=1.37.2,<1.37.4)"] [[package]] name = "aiofiles" @@ -278,18 +278,18 @@ tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" a [[package]] name = "boto3" -version = "1.37.1" +version = "1.37.3" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" groups = ["main", "test_integration"] files = [ - {file = "boto3-1.37.1-py3-none-any.whl", hash = "sha256:4320441f904435a1b85e6ecb81793192e522c737cc9ed6566014e29f0a11cb22"}, - {file = "boto3-1.37.1.tar.gz", hash = "sha256:96d18f7feb0c1fcb95f8837b74b6c8880e1b4e35ce5f8a8f8cb243a090c278ed"}, + {file = "boto3-1.37.3-py3-none-any.whl", hash = "sha256:2063b40af99fd02f6228ff52397b552ff3353831edaf8d25cc04801827ab9794"}, + {file = "boto3-1.37.3.tar.gz", hash = "sha256:21f3ce0ef111297e63a6eb998a25197b8c10982970c320d4c6e8db08be2157be"}, ] [package.dependencies] -botocore = ">=1.37.1,<1.38.0" +botocore = ">=1.37.3,<1.38.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.11.0,<0.12.0" @@ -298,14 +298,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.37.1" +version = "1.37.3" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" groups = ["main", "test_integration"] files = [ - {file = "botocore-1.37.1-py3-none-any.whl", hash = "sha256:c1db1bfc5d8c6b3b6d1ca6794f605294b4264e82a7e727b88e0fef9c2b9fbb9c"}, - {file = "botocore-1.37.1.tar.gz", hash = "sha256:b194db8fb2a0ffba53568c364ae26166e7eec0445496b2ac86a6e142f3dd982f"}, + {file = "botocore-1.37.3-py3-none-any.whl", hash = "sha256:d01bd3bf4c80e61fa88d636ad9f5c9f60a551d71549b481386c6b4efe0bb2b2e"}, + {file = "botocore-1.37.3.tar.gz", hash = "sha256:fe8403eb55a88faf9b0f9da6615e5bee7be056d75e17af66c3c8f0a3b0648da4"}, ] [package.dependencies] @@ -2441,4 +2441,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "c71d3617ac685ee537e292ebe100992eb8d6bf0ac62bb3dbf340ddc95728abb6" +content-hash = "af4e2ef43ff3c5d73f3a85fadc0112def4ec7fa5ad7e7b1799e44cfe8e30dfbc" diff --git a/libs/langgraph-checkpoint-aws/pyproject.toml b/libs/langgraph-checkpoint-aws/pyproject.toml index bc1dd1a3..d3fbb669 100644 --- a/libs/langgraph-checkpoint-aws/pyproject.toml +++ b/libs/langgraph-checkpoint-aws/pyproject.toml @@ -19,8 +19,8 @@ keywords = ["aws", "bedrock", "langchain", "langgraph", "checkpointer"] python = ">=3.9,<4.0" langgraph-checkpoint = ">=2.0.0" langgraph = ">=0.2.55" -boto3 = ">=1.37.0,<1.37.2" -aioboto3 = ">=14.1.0" +boto3 = ">=1.37.3" +aioboto3 = ">=14.2.0" [tool.poetry.group.dev] optional = true From a725e4e58876a012261d0b0306b1b4b2c1bbd57d Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Mon, 5 May 2025 21:44:25 +0200 Subject: [PATCH 06/15] added async --- .../langgraph_checkpoint_aws/async_session.py | 224 +++++++----------- 1 file changed, 85 insertions(+), 139 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index 89953441..24498466 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -1,6 +1,10 @@ -from typing import Optional +import asyncio +from concurrent.futures import ThreadPoolExecutor +from functools import partial +from contextvars import copy_context +from typing import Any, Callable, Optional, TypeVar, Union, cast -import aioboto3 +import boto3 from botocore.config import Config from pydantic import SecretStr @@ -25,22 +29,30 @@ ) from langgraph_checkpoint_aws.utils import process_aws_client_args, to_boto_params +T = TypeVar('T') -class AsyncBedrockAgentRuntimeSessionClient: - """ - Asynchronous client for AWS Bedrock Agent Runtime API +async def run_boto3_in_executor( + func: Callable[..., T], + *args: Any, + **kwargs: Any +) -> T: + """Run a boto3 function in an executor to prevent blocking the event loop.""" + def wrapper() -> T: + try: + return func(*args, **kwargs) + except StopIteration as exc: + raise RuntimeError from exc - This class provides an asynchronous interface to interact with AWS Bedrock Agent Runtime service. - It handles session management, invocations and invocation steps through the Bedrock Agent Runtime API. + # Use copy_context to preserve context vars across thread boundaries + return await asyncio.get_running_loop().run_in_executor( + None, + cast("Callable[..., T]", partial(copy_context().run, wrapper)) + ) - The client supports operations like: - - Session management (create, get, end, delete) - - Invocation management (create, list) - - Invocation step management (put, get, list) - Attributes: - session: Aioboto3 session for bedrock-agent-runtime service - _client_kwargs: Arguments for client creation +class AsyncBedrockAgentRuntimeSessionClient: + """ + Asynchronous client for AWS Bedrock Agent Runtime API using standard boto3 with async executor. """ def __init__( @@ -55,15 +67,6 @@ def __init__( ): """ Initialize AsyncBedrockAgentRuntime with AWS configuration - - Args: - region_name: AWS region (e.g., us-west-2) - credentials_profile_name: AWS credentials profile name - aws_access_key_id: AWS access key ID - aws_secret_access_key: AWS secret access key - aws_session_token: AWS session token - endpoint_url: Custom endpoint URL - config: Boto3 config object """ _session_kwargs, self._client_kwargs = process_aws_client_args( region_name, @@ -74,149 +77,92 @@ def __init__( endpoint_url, config, ) - self.session = aioboto3.Session(**_session_kwargs) - - async def _get_client(self): - """ - Get an async bedrock-agent-runtime client - Returns: - Async client for bedrock-agent-runtime - """ - return self.session.client("bedrock-agent-runtime", **self._client_kwargs) - + # Create a standard boto3 session instead of aioboto3 + self.session = boto3.Session(**_session_kwargs) + # Pre-create the client to avoid creating it for each operation + self.client = self.session.client("bedrock-agent-runtime", **self._client_kwargs) + async def create_session( self, request: Optional[CreateSessionRequest] = None ) -> CreateSessionResponse: - """ - Create a new session asynchronously - - Args: - request (CreateSessionRequest): Optional object containing session creation details - - Returns: - CreateSessionResponse: Response object containing session identifier and metadata - """ - async with await self._get_client() as client: - response = await client.create_session( - **to_boto_params(request) if request else {} - ) - return CreateSessionResponse(**response) + """Create a new session asynchronously""" + params = to_boto_params(request) if request else {} + response = await run_boto3_in_executor( + self.client.create_session, + **params + ) + return CreateSessionResponse(**response) async def get_session(self, request: GetSessionRequest) -> GetSessionResponse: - """ - Get details of an existing session asynchronously - - Args: - request (GetSessionRequest): Object containing session identifier - - Returns: - GetSessionResponse: Response object containing session details and metadata - """ - async with await self._get_client() as client: - response = await client.get_session(**to_boto_params(request)) - return GetSessionResponse(**response) + """Get details of an existing session asynchronously""" + response = await run_boto3_in_executor( + self.client.get_session, + **to_boto_params(request) + ) + return GetSessionResponse(**response) async def end_session(self, request: EndSessionRequest) -> EndSessionResponse: - """ - End an existing session asynchronously - - Args: - request (EndSessionRequest): Object containing session identifier - - Returns: - EndSessionResponse: Response object containing the ended session details - """ - async with await self._get_client() as client: - response = await client.end_session(**to_boto_params(request)) - return EndSessionResponse(**response) + """End an existing session asynchronously""" + response = await run_boto3_in_executor( + self.client.end_session, + **to_boto_params(request) + ) + return EndSessionResponse(**response) async def delete_session(self, request: DeleteSessionRequest) -> None: - """ - Delete an existing session asynchronously - - Args: - request (DeleteSessionRequest): Object containing session identifier - """ - async with await self._get_client() as client: - await client.delete_session(**to_boto_params(request)) + """Delete an existing session asynchronously""" + await run_boto3_in_executor( + self.client.delete_session, + **to_boto_params(request) + ) async def create_invocation( self, request: CreateInvocationRequest ) -> CreateInvocationResponse: - """ - Create a new invocation asynchronously - - Args: - request (CreateInvocationRequest): Object containing invocation details - - Returns: - CreateInvocationResponse: Response object containing invocation identifier and metadata - """ - async with await self._get_client() as client: - response = await client.create_invocation(**to_boto_params(request)) - return CreateInvocationResponse(**response) + """Create a new invocation asynchronously""" + response = await run_boto3_in_executor( + self.client.create_invocation, + **to_boto_params(request) + ) + return CreateInvocationResponse(**response) async def list_invocations( self, request: ListInvocationsRequest ) -> ListInvocationsResponse: - """ - List invocations for a session asynchronously - - Args: - request (ListInvocationsRequest): Object containing session identifier - - Returns: - ListInvocationsResponse: Response object containing list of invocations and pagination token - """ - async with await self._get_client() as client: - response = await client.list_invocations(**to_boto_params(request)) - return ListInvocationsResponse(**response) + """List invocations for a session asynchronously""" + response = await run_boto3_in_executor( + self.client.list_invocations, + **to_boto_params(request) + ) + return ListInvocationsResponse(**response) async def put_invocation_step( self, request: PutInvocationStepRequest ) -> PutInvocationStepResponse: - """ - Put a step in an invocation asynchronously - - Args: - request (PutInvocationStepRequest): Object containing invocation identifier and step payload - - Returns: - PutInvocationStepResponse: Response object containing invocation step identifier - """ - async with await self._get_client() as client: - response = await client.put_invocation_step(**to_boto_params(request)) - return PutInvocationStepResponse(**response) + """Put a step in an invocation asynchronously""" + response = await run_boto3_in_executor( + self.client.put_invocation_step, + **to_boto_params(request) + ) + return PutInvocationStepResponse(**response) async def get_invocation_step( self, request: GetInvocationStepRequest ) -> GetInvocationStepResponse: - """ - Get a step in an invocation asynchronously - - Args: - request (GetInvocationStepRequest): Object containing invocation and step identifiers - - Returns: - GetInvocationStepResponse: Response object containing invocation step identifier and payload - """ - async with await self._get_client() as client: - response = await client.get_invocation_step(**to_boto_params(request)) - return GetInvocationStepResponse(**response) + """Get a step in an invocation asynchronously""" + response = await run_boto3_in_executor( + self.client.get_invocation_step, + **to_boto_params(request) + ) + return GetInvocationStepResponse(**response) async def list_invocation_steps( self, request: ListInvocationStepsRequest ) -> ListInvocationStepsResponse: - """ - List steps in an invocation asynchronously - - Args: - request (ListInvocationStepsRequest): Object containing invocation step id and pagination token - - Returns: - ListInvocationStepsResponse: Response object containing list of invocation steps and pagination token - """ - async with await self._get_client() as client: - response = await client.list_invocation_steps(**to_boto_params(request)) - return ListInvocationStepsResponse(**response) \ No newline at end of file + """List steps in an invocation asynchronously""" + response = await run_boto3_in_executor( + self.client.list_invocation_steps, + **to_boto_params(request) + ) + return ListInvocationStepsResponse(**response) \ No newline at end of file From c096152990b57861933accf70c244da06e4f11c3 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Mon, 5 May 2025 21:46:15 +0200 Subject: [PATCH 07/15] added async --- libs/langgraph-checkpoint-aws/pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/langgraph-checkpoint-aws/pyproject.toml b/libs/langgraph-checkpoint-aws/pyproject.toml index d3fbb669..60cc0f66 100644 --- a/libs/langgraph-checkpoint-aws/pyproject.toml +++ b/libs/langgraph-checkpoint-aws/pyproject.toml @@ -20,7 +20,6 @@ python = ">=3.9,<4.0" langgraph-checkpoint = ">=2.0.0" langgraph = ">=0.2.55" boto3 = ">=1.37.3" -aioboto3 = ">=14.2.0" [tool.poetry.group.dev] optional = true From 7eaa12f0f9f18027d05d9c6ddb2ba33d5ae867bf Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Mon, 5 May 2025 22:08:01 +0200 Subject: [PATCH 08/15] added unit tests --- .../langgraph_checkpoint_aws/async_session.py | 16 +- libs/langgraph-checkpoint-aws/poetry.lock | 790 +----------------- .../tests/unit_tests/conftest.py | 18 - .../tests/unit_tests/test_async_saver.py | 143 ++-- .../tests/unit_tests/test_async_session.py | 76 +- 5 files changed, 99 insertions(+), 944 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index 24498466..abb8db3a 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -2,7 +2,7 @@ from concurrent.futures import ThreadPoolExecutor from functools import partial from contextvars import copy_context -from typing import Any, Callable, Optional, TypeVar, Union, cast +from typing import Any, Callable, Optional, TypeVar, cast import boto3 from botocore.config import Config @@ -37,17 +37,17 @@ async def run_boto3_in_executor( **kwargs: Any ) -> T: """Run a boto3 function in an executor to prevent blocking the event loop.""" - def wrapper() -> T: + loop = asyncio.get_running_loop() + ctx = copy_context() + + def wrapper(): try: + # Execute the actual boto3 call with parameters inside the executor return func(*args, **kwargs) except StopIteration as exc: raise RuntimeError from exc - # Use copy_context to preserve context vars across thread boundaries - return await asyncio.get_running_loop().run_in_executor( - None, - cast("Callable[..., T]", partial(copy_context().run, wrapper)) - ) + return await loop.run_in_executor(None, ctx.run, wrapper) class AsyncBedrockAgentRuntimeSessionClient: @@ -78,7 +78,7 @@ def __init__( config, ) - # Create a standard boto3 session instead of aioboto3 + # Create a standard boto3 session self.session = boto3.Session(**_session_kwargs) # Pre-create the client to avoid creating it for each operation self.client = self.session.client("bedrock-agent-runtime", **self._client_kwargs) diff --git a/libs/langgraph-checkpoint-aws/poetry.lock b/libs/langgraph-checkpoint-aws/poetry.lock index 865b84ca..3c136fcf 100644 --- a/libs/langgraph-checkpoint-aws/poetry.lock +++ b/libs/langgraph-checkpoint-aws/poetry.lock @@ -1,213 +1,5 @@ # This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. -[[package]] -name = "aioboto3" -version = "14.2.0" -description = "Async boto3 wrapper" -optional = false -python-versions = "<4.0,>=3.8" -groups = ["main"] -files = [ - {file = "aioboto3-14.2.0-py3-none-any.whl", hash = "sha256:0bf0663fd4f8ad814207ef77fcbdfca51be1daf81108eeba598b9d48654e1da4"}, - {file = "aioboto3-14.2.0.tar.gz", hash = "sha256:80cee479dfe9686f2823bed2ac616d3c0bc977255b2c3f997da612fd8179ffe4"}, -] - -[package.dependencies] -aiobotocore = {version = "2.22.0", extras = ["boto3"]} -aiofiles = ">=23.2.1" - -[package.extras] -chalice = ["chalice (>=1.24.0)"] -s3cse = ["cryptography (>=44.0.1)"] - -[[package]] -name = "aiobotocore" -version = "2.22.0" -description = "Async client for aws services using botocore and aiohttp" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "aiobotocore-2.22.0-py3-none-any.whl", hash = "sha256:b4e6306f79df9d81daff1f9d63189a2dbee4b77ce3ab937304834e35eaaeeccf"}, - {file = "aiobotocore-2.22.0.tar.gz", hash = "sha256:11091477266b75c2b5d28421c1f2bc9a87d175d0b8619cb830805e7a113a170b"}, -] - -[package.dependencies] -aiohttp = ">=3.9.2,<4.0.0" -aioitertools = ">=0.5.1,<1.0.0" -boto3 = {version = ">=1.37.2,<1.37.4", optional = true, markers = "extra == \"boto3\""} -botocore = ">=1.37.2,<1.37.4" -jmespath = ">=0.7.1,<2.0.0" -multidict = ">=6.0.0,<7.0.0" -python-dateutil = ">=2.1,<3.0.0" -wrapt = ">=1.10.10,<2.0.0" - -[package.extras] -awscli = ["awscli (>=1.38.2,<1.38.4)"] -boto3 = ["boto3 (>=1.37.2,<1.37.4)"] - -[[package]] -name = "aiofiles" -version = "24.1.0" -description = "File support for asyncio." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"}, - {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, -] - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -description = "Happy Eyeballs for asyncio" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, - {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, -] - -[[package]] -name = "aiohttp" -version = "3.11.18" -description = "Async http client/server framework (asyncio)" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:96264854fedbea933a9ca4b7e0c745728f01380691687b7365d18d9e977179c4"}, - {file = "aiohttp-3.11.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9602044ff047043430452bc3a2089743fa85da829e6fc9ee0025351d66c332b6"}, - {file = "aiohttp-3.11.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5691dc38750fcb96a33ceef89642f139aa315c8a193bbd42a0c33476fd4a1609"}, - {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554c918ec43f8480b47a5ca758e10e793bd7410b83701676a4782672d670da55"}, - {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a4076a2b3ba5b004b8cffca6afe18a3b2c5c9ef679b4d1e9859cf76295f8d4f"}, - {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:767a97e6900edd11c762be96d82d13a1d7c4fc4b329f054e88b57cdc21fded94"}, - {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ddc9337a0fb0e727785ad4f41163cc314376e82b31846d3835673786420ef1"}, - {file = "aiohttp-3.11.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f414f37b244f2a97e79b98d48c5ff0789a0b4b4609b17d64fa81771ad780e415"}, - {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fdb239f47328581e2ec7744ab5911f97afb10752332a6dd3d98e14e429e1a9e7"}, - {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f2c50bad73ed629cc326cc0f75aed8ecfb013f88c5af116f33df556ed47143eb"}, - {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a8d8f20c39d3fa84d1c28cdb97f3111387e48209e224408e75f29c6f8e0861d"}, - {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:106032eaf9e62fd6bc6578c8b9e6dc4f5ed9a5c1c7fb2231010a1b4304393421"}, - {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b491e42183e8fcc9901d8dcd8ae644ff785590f1727f76ca86e731c61bfe6643"}, - {file = "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad8c745ff9460a16b710e58e06a9dec11ebc0d8f4dd82091cefb579844d69868"}, - {file = "aiohttp-3.11.18-cp310-cp310-win32.whl", hash = "sha256:8e57da93e24303a883146510a434f0faf2f1e7e659f3041abc4e3fb3f6702a9f"}, - {file = "aiohttp-3.11.18-cp310-cp310-win_amd64.whl", hash = "sha256:cc93a4121d87d9f12739fc8fab0a95f78444e571ed63e40bfc78cd5abe700ac9"}, - {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:427fdc56ccb6901ff8088544bde47084845ea81591deb16f957897f0f0ba1be9"}, - {file = "aiohttp-3.11.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c828b6d23b984255b85b9b04a5b963a74278b7356a7de84fda5e3b76866597b"}, - {file = "aiohttp-3.11.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c2eaa145bb36b33af1ff2860820ba0589e165be4ab63a49aebfd0981c173b66"}, - {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d518ce32179f7e2096bf4e3e8438cf445f05fedd597f252de9f54c728574756"}, - {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0700055a6e05c2f4711011a44364020d7a10fbbcd02fbf3e30e8f7e7fddc8717"}, - {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8bd1cde83e4684324e6ee19adfc25fd649d04078179890be7b29f76b501de8e4"}, - {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73b8870fe1c9a201b8c0d12c94fe781b918664766728783241a79e0468427e4f"}, - {file = "aiohttp-3.11.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25557982dd36b9e32c0a3357f30804e80790ec2c4d20ac6bcc598533e04c6361"}, - {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e889c9df381a2433802991288a61e5a19ceb4f61bd14f5c9fa165655dcb1fd1"}, - {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9ea345fda05bae217b6cce2acf3682ce3b13d0d16dd47d0de7080e5e21362421"}, - {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9f26545b9940c4b46f0a9388fd04ee3ad7064c4017b5a334dd450f616396590e"}, - {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3a621d85e85dccabd700294494d7179ed1590b6d07a35709bb9bd608c7f5dd1d"}, - {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9c23fd8d08eb9c2af3faeedc8c56e134acdaf36e2117ee059d7defa655130e5f"}, - {file = "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9e6b0e519067caa4fd7fb72e3e8002d16a68e84e62e7291092a5433763dc0dd"}, - {file = "aiohttp-3.11.18-cp311-cp311-win32.whl", hash = "sha256:122f3e739f6607e5e4c6a2f8562a6f476192a682a52bda8b4c6d4254e1138f4d"}, - {file = "aiohttp-3.11.18-cp311-cp311-win_amd64.whl", hash = "sha256:e6f3c0a3a1e73e88af384b2e8a0b9f4fb73245afd47589df2afcab6b638fa0e6"}, - {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:63d71eceb9cad35d47d71f78edac41fcd01ff10cacaa64e473d1aec13fa02df2"}, - {file = "aiohttp-3.11.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d1929da615840969929e8878d7951b31afe0bac883d84418f92e5755d7b49508"}, - {file = "aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d0aebeb2392f19b184e3fdd9e651b0e39cd0f195cdb93328bd124a1d455cd0e"}, - {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3849ead845e8444f7331c284132ab314b4dac43bfae1e3cf350906d4fff4620f"}, - {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e8452ad6b2863709f8b3d615955aa0807bc093c34b8e25b3b52097fe421cb7f"}, - {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b8d2b42073611c860a37f718b3d61ae8b4c2b124b2e776e2c10619d920350ec"}, - {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fbf91f6a0ac317c0a07eb328a1384941872f6761f2e6f7208b63c4cc0a7ff6"}, - {file = "aiohttp-3.11.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ff5625413fec55216da5eaa011cf6b0a2ed67a565914a212a51aa3755b0009"}, - {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f33a92a2fde08e8c6b0c61815521324fc1612f397abf96eed86b8e31618fdb4"}, - {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:11d5391946605f445ddafda5eab11caf310f90cdda1fd99865564e3164f5cff9"}, - {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3cc314245deb311364884e44242e00c18b5896e4fe6d5f942e7ad7e4cb640adb"}, - {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f421843b0f70740772228b9e8093289924359d306530bcd3926f39acbe1adda"}, - {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e220e7562467dc8d589e31c1acd13438d82c03d7f385c9cd41a3f6d1d15807c1"}, - {file = "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab2ef72f8605046115bc9aa8e9d14fd49086d405855f40b79ed9e5c1f9f4faea"}, - {file = "aiohttp-3.11.18-cp312-cp312-win32.whl", hash = "sha256:12a62691eb5aac58d65200c7ae94d73e8a65c331c3a86a2e9670927e94339ee8"}, - {file = "aiohttp-3.11.18-cp312-cp312-win_amd64.whl", hash = "sha256:364329f319c499128fd5cd2d1c31c44f234c58f9b96cc57f743d16ec4f3238c8"}, - {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:474215ec618974054cf5dc465497ae9708543cbfc312c65212325d4212525811"}, - {file = "aiohttp-3.11.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ced70adf03920d4e67c373fd692123e34d3ac81dfa1c27e45904a628567d804"}, - {file = "aiohttp-3.11.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d9f6c0152f8d71361905aaf9ed979259537981f47ad099c8b3d81e0319814bd"}, - {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a35197013ed929c0aed5c9096de1fc5a9d336914d73ab3f9df14741668c0616c"}, - {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:540b8a1f3a424f1af63e0af2d2853a759242a1769f9f1ab053996a392bd70118"}, - {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9e6710ebebfce2ba21cee6d91e7452d1125100f41b906fb5af3da8c78b764c1"}, - {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8af2ef3b4b652ff109f98087242e2ab974b2b2b496304063585e3d78de0b000"}, - {file = "aiohttp-3.11.18-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28c3f975e5ae3dbcbe95b7e3dcd30e51da561a0a0f2cfbcdea30fc1308d72137"}, - {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c28875e316c7b4c3e745172d882d8a5c835b11018e33432d281211af35794a93"}, - {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:13cd38515568ae230e1ef6919e2e33da5d0f46862943fcda74e7e915096815f3"}, - {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0e2a92101efb9f4c2942252c69c63ddb26d20f46f540c239ccfa5af865197bb8"}, - {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e6d3e32b8753c8d45ac550b11a1090dd66d110d4ef805ffe60fa61495360b3b2"}, - {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ea4cf2488156e0f281f93cc2fd365025efcba3e2d217cbe3df2840f8c73db261"}, - {file = "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d4df95ad522c53f2b9ebc07f12ccd2cb15550941e11a5bbc5ddca2ca56316d7"}, - {file = "aiohttp-3.11.18-cp313-cp313-win32.whl", hash = "sha256:cdd1bbaf1e61f0d94aced116d6e95fe25942f7a5f42382195fd9501089db5d78"}, - {file = "aiohttp-3.11.18-cp313-cp313-win_amd64.whl", hash = "sha256:bdd619c27e44382cf642223f11cfd4d795161362a5a1fc1fa3940397bc89db01"}, - {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:469ac32375d9a716da49817cd26f1916ec787fc82b151c1c832f58420e6d3533"}, - {file = "aiohttp-3.11.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cec21dd68924179258ae14af9f5418c1ebdbba60b98c667815891293902e5e0"}, - {file = "aiohttp-3.11.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b426495fb9140e75719b3ae70a5e8dd3a79def0ae3c6c27e012fc59f16544a4a"}, - {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad2f41203e2808616292db5d7170cccf0c9f9c982d02544443c7eb0296e8b0c7"}, - {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc0ae0a5e9939e423e065a3e5b00b24b8379f1db46046d7ab71753dfc7dd0e1"}, - {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7cdd3f7d1df43200e1c80f1aed86bb36033bf65e3c7cf46a2b97a253ef8798"}, - {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5199be2a2f01ffdfa8c3a6f5981205242986b9e63eb8ae03fd18f736e4840721"}, - {file = "aiohttp-3.11.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ccec9e72660b10f8e283e91aa0295975c7bd85c204011d9f5eb69310555cf30"}, - {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1596ebf17e42e293cbacc7a24c3e0dc0f8f755b40aff0402cb74c1ff6baec1d3"}, - {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:eab7b040a8a873020113ba814b7db7fa935235e4cbaf8f3da17671baa1024863"}, - {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5d61df4a05476ff891cff0030329fee4088d40e4dc9b013fac01bc3c745542c2"}, - {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:46533e6792e1410f9801d09fd40cbbff3f3518d1b501d6c3c5b218f427f6ff08"}, - {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c1b90407ced992331dd6d4f1355819ea1c274cc1ee4d5b7046c6761f9ec11829"}, - {file = "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a2fd04ae4971b914e54fe459dd7edbbd3f2ba875d69e057d5e3c8e8cac094935"}, - {file = "aiohttp-3.11.18-cp39-cp39-win32.whl", hash = "sha256:b2f317d1678002eee6fe85670039fb34a757972284614638f82b903a03feacdc"}, - {file = "aiohttp-3.11.18-cp39-cp39-win_amd64.whl", hash = "sha256:5e7007b8d1d09bce37b54111f593d173691c530b80f27c6493b928dabed9e6ef"}, - {file = "aiohttp-3.11.18.tar.gz", hash = "sha256:ae856e1138612b7e412db63b7708735cff4d38d0399f6a5435d3dac2669f558a"}, -] - -[package.dependencies] -aiohappyeyeballs = ">=2.3.0" -aiosignal = ">=1.1.2" -async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} -attrs = ">=17.3.0" -frozenlist = ">=1.1.1" -multidict = ">=4.5,<7.0" -propcache = ">=0.2.0" -yarl = ">=1.17.0,<2.0" - -[package.extras] -speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""] - -[[package]] -name = "aioitertools" -version = "0.12.0" -description = "itertools and builtins for AsyncIO and mixed iterables" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "aioitertools-0.12.0-py3-none-any.whl", hash = "sha256:fc1f5fac3d737354de8831cbba3eb04f79dd649d8f3afb4c5b114925e662a796"}, - {file = "aioitertools-0.12.0.tar.gz", hash = "sha256:c2a9055b4fbb7705f561b9d86053e8af5d10cc845d22c32008c43490b2d8dd6b"}, -] - -[package.dependencies] -typing_extensions = {version = ">=4.0", markers = "python_version < \"3.10\""} - -[package.extras] -dev = ["attribution (==1.8.0)", "black (==24.8.0)", "build (>=1.2)", "coverage (==7.6.1)", "flake8 (==7.1.1)", "flit (==3.9.0)", "mypy (==1.11.2)", "ufmt (==2.7.1)", "usort (==1.0.8.post1)"] -docs = ["sphinx (==8.0.2)", "sphinx-mdinclude (==0.6.2)"] - -[[package]] -name = "aiosignal" -version = "1.3.2" -description = "aiosignal: a list of registered asynchronous callbacks" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, - {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, -] - -[package.dependencies] -frozenlist = ">=1.1.0" - [[package]] name = "annotated-types" version = "0.7.0" @@ -243,39 +35,6 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] -[[package]] -name = "async-timeout" -version = "5.0.1" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.8" -groups = ["main"] -markers = "python_version < \"3.11\"" -files = [ - {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, - {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, -] - -[[package]] -name = "attrs" -version = "25.3.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, - {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, -] - -[package.extras] -benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] - [[package]] name = "boto3" version = "1.37.3" @@ -640,120 +399,6 @@ files = [ [package.extras] test = ["pytest (>=6)"] -[[package]] -name = "frozenlist" -version = "1.6.0" -description = "A list-like structure which implements collections.abc.MutableSequence" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e6e558ea1e47fd6fa8ac9ccdad403e5dd5ecc6ed8dda94343056fa4277d5c65e"}, - {file = "frozenlist-1.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4b3cd7334a4bbc0c472164f3744562cb72d05002cc6fcf58adb104630bbc352"}, - {file = "frozenlist-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9799257237d0479736e2b4c01ff26b5c7f7694ac9692a426cb717f3dc02fff9b"}, - {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a7bb0fe1f7a70fb5c6f497dc32619db7d2cdd53164af30ade2f34673f8b1fc"}, - {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:36d2fc099229f1e4237f563b2a3e0ff7ccebc3999f729067ce4e64a97a7f2869"}, - {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f27a9f9a86dcf00708be82359db8de86b80d029814e6693259befe82bb58a106"}, - {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75ecee69073312951244f11b8627e3700ec2bfe07ed24e3a685a5979f0412d24"}, - {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2c7d5aa19714b1b01a0f515d078a629e445e667b9da869a3cd0e6fe7dec78bd"}, - {file = "frozenlist-1.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69bbd454f0fb23b51cadc9bdba616c9678e4114b6f9fa372d462ff2ed9323ec8"}, - {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7daa508e75613809c7a57136dec4871a21bca3080b3a8fc347c50b187df4f00c"}, - {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:89ffdb799154fd4d7b85c56d5fa9d9ad48946619e0eb95755723fffa11022d75"}, - {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:920b6bd77d209931e4c263223381d63f76828bec574440f29eb497cf3394c249"}, - {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d3ceb265249fb401702fce3792e6b44c1166b9319737d21495d3611028d95769"}, - {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52021b528f1571f98a7d4258c58aa8d4b1a96d4f01d00d51f1089f2e0323cb02"}, - {file = "frozenlist-1.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0f2ca7810b809ed0f1917293050163c7654cefc57a49f337d5cd9de717b8fad3"}, - {file = "frozenlist-1.6.0-cp310-cp310-win32.whl", hash = "sha256:0e6f8653acb82e15e5443dba415fb62a8732b68fe09936bb6d388c725b57f812"}, - {file = "frozenlist-1.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1a39819a5a3e84304cd286e3dc62a549fe60985415851b3337b6f5cc91907f1"}, - {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae8337990e7a45683548ffb2fee1af2f1ed08169284cd829cdd9a7fa7470530d"}, - {file = "frozenlist-1.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c952f69dd524558694818a461855f35d36cc7f5c0adddce37e962c85d06eac0"}, - {file = "frozenlist-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f5fef13136c4e2dee91bfb9a44e236fff78fc2cd9f838eddfc470c3d7d90afe"}, - {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:716bbba09611b4663ecbb7cd022f640759af8259e12a6ca939c0a6acd49eedba"}, - {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7b8c4dc422c1a3ffc550b465090e53b0bf4839047f3e436a34172ac67c45d595"}, - {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b11534872256e1666116f6587a1592ef395a98b54476addb5e8d352925cb5d4a"}, - {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c6eceb88aaf7221f75be6ab498dc622a151f5f88d536661af3ffc486245a626"}, - {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62c828a5b195570eb4b37369fcbbd58e96c905768d53a44d13044355647838ff"}, - {file = "frozenlist-1.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1c6bd2c6399920c9622362ce95a7d74e7f9af9bfec05fff91b8ce4b9647845a"}, - {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:49ba23817781e22fcbd45fd9ff2b9b8cdb7b16a42a4851ab8025cae7b22e96d0"}, - {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:431ef6937ae0f853143e2ca67d6da76c083e8b1fe3df0e96f3802fd37626e606"}, - {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9d124b38b3c299ca68433597ee26b7819209cb8a3a9ea761dfe9db3a04bba584"}, - {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:118e97556306402e2b010da1ef21ea70cb6d6122e580da64c056b96f524fbd6a"}, - {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fb3b309f1d4086b5533cf7bbcf3f956f0ae6469664522f1bde4feed26fba60f1"}, - {file = "frozenlist-1.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54dece0d21dce4fdb188a1ffc555926adf1d1c516e493c2914d7c370e454bc9e"}, - {file = "frozenlist-1.6.0-cp311-cp311-win32.whl", hash = "sha256:654e4ba1d0b2154ca2f096bed27461cf6160bc7f504a7f9a9ef447c293caf860"}, - {file = "frozenlist-1.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e911391bffdb806001002c1f860787542f45916c3baf764264a52765d5a5603"}, - {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c5b9e42ace7d95bf41e19b87cec8f262c41d3510d8ad7514ab3862ea2197bfb1"}, - {file = "frozenlist-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ca9973735ce9f770d24d5484dcb42f68f135351c2fc81a7a9369e48cf2998a29"}, - {file = "frozenlist-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ac40ec76041c67b928ca8aaffba15c2b2ee3f5ae8d0cb0617b5e63ec119ca25"}, - {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b7a8a3180dfb280eb044fdec562f9b461614c0ef21669aea6f1d3dac6ee576"}, - {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c444d824e22da6c9291886d80c7d00c444981a72686e2b59d38b285617cb52c8"}, - {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb52c8166499a8150bfd38478248572c924c003cbb45fe3bcd348e5ac7c000f9"}, - {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b35298b2db9c2468106278537ee529719228950a5fdda686582f68f247d1dc6e"}, - {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d108e2d070034f9d57210f22fefd22ea0d04609fc97c5f7f5a686b3471028590"}, - {file = "frozenlist-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1be9111cb6756868ac242b3c2bd1f09d9aea09846e4f5c23715e7afb647103"}, - {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:94bb451c664415f02f07eef4ece976a2c65dcbab9c2f1705b7031a3a75349d8c"}, - {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d1a686d0b0949182b8faddea596f3fc11f44768d1f74d4cad70213b2e139d821"}, - {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea8e59105d802c5a38bdbe7362822c522230b3faba2aa35c0fa1765239b7dd70"}, - {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:abc4e880a9b920bc5020bf6a431a6bb40589d9bca3975c980495f63632e8382f"}, - {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a79713adfe28830f27a3c62f6b5406c37376c892b05ae070906f07ae4487046"}, - {file = "frozenlist-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0318c2068e217a8f5e3b85e35899f5a19e97141a45bb925bb357cfe1daf770"}, - {file = "frozenlist-1.6.0-cp312-cp312-win32.whl", hash = "sha256:853ac025092a24bb3bf09ae87f9127de9fe6e0c345614ac92536577cf956dfcc"}, - {file = "frozenlist-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bdfe2d7e6c9281c6e55523acd6c2bf77963cb422fdc7d142fb0cb6621b66878"}, - {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1d7fb014fe0fbfee3efd6a94fc635aeaa68e5e1720fe9e57357f2e2c6e1a647e"}, - {file = "frozenlist-1.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01bcaa305a0fdad12745502bfd16a1c75b14558dabae226852f9159364573117"}, - {file = "frozenlist-1.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b314faa3051a6d45da196a2c495e922f987dc848e967d8cfeaee8a0328b1cd4"}, - {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da62fecac21a3ee10463d153549d8db87549a5e77eefb8c91ac84bb42bb1e4e3"}, - {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1eb89bf3454e2132e046f9599fbcf0a4483ed43b40f545551a39316d0201cd1"}, - {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18689b40cb3936acd971f663ccb8e2589c45db5e2c5f07e0ec6207664029a9c"}, - {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e67ddb0749ed066b1a03fba812e2dcae791dd50e5da03be50b6a14d0c1a9ee45"}, - {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc5e64626e6682638d6e44398c9baf1d6ce6bc236d40b4b57255c9d3f9761f1f"}, - {file = "frozenlist-1.6.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:437cfd39564744ae32ad5929e55b18ebd88817f9180e4cc05e7d53b75f79ce85"}, - {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62dd7df78e74d924952e2feb7357d826af8d2f307557a779d14ddf94d7311be8"}, - {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a66781d7e4cddcbbcfd64de3d41a61d6bdde370fc2e38623f30b2bd539e84a9f"}, - {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:482fe06e9a3fffbcd41950f9d890034b4a54395c60b5e61fae875d37a699813f"}, - {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e4f9373c500dfc02feea39f7a56e4f543e670212102cc2eeb51d3a99c7ffbde6"}, - {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e69bb81de06827147b7bfbaeb284d85219fa92d9f097e32cc73675f279d70188"}, - {file = "frozenlist-1.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7613d9977d2ab4a9141dde4a149f4357e4065949674c5649f920fec86ecb393e"}, - {file = "frozenlist-1.6.0-cp313-cp313-win32.whl", hash = "sha256:4def87ef6d90429f777c9d9de3961679abf938cb6b7b63d4a7eb8a268babfce4"}, - {file = "frozenlist-1.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:37a8a52c3dfff01515e9bbbee0e6063181362f9de3db2ccf9bc96189b557cbfd"}, - {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:46138f5a0773d064ff663d273b309b696293d7a7c00a0994c5c13a5078134b64"}, - {file = "frozenlist-1.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f88bc0a2b9c2a835cb888b32246c27cdab5740059fb3688852bf91e915399b91"}, - {file = "frozenlist-1.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:777704c1d7655b802c7850255639672e90e81ad6fa42b99ce5ed3fbf45e338dd"}, - {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ef8d41764c7de0dcdaf64f733a27352248493a85a80661f3c678acd27e31f2"}, - {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:da5cb36623f2b846fb25009d9d9215322318ff1c63403075f812b3b2876c8506"}, - {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbb56587a16cf0fb8acd19e90ff9924979ac1431baea8681712716a8337577b0"}, - {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6154c3ba59cda3f954c6333025369e42c3acd0c6e8b6ce31eb5c5b8116c07e0"}, - {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e8246877afa3f1ae5c979fe85f567d220f86a50dc6c493b9b7d8191181ae01e"}, - {file = "frozenlist-1.6.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b0f6cce16306d2e117cf9db71ab3a9e8878a28176aeaf0dbe35248d97b28d0c"}, - {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1b8e8cd8032ba266f91136d7105706ad57770f3522eac4a111d77ac126a25a9b"}, - {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e2ada1d8515d3ea5378c018a5f6d14b4994d4036591a52ceaf1a1549dec8e1ad"}, - {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:cdb2c7f071e4026c19a3e32b93a09e59b12000751fc9b0b7758da899e657d215"}, - {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:03572933a1969a6d6ab509d509e5af82ef80d4a5d4e1e9f2e1cdd22c77a3f4d2"}, - {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:77effc978947548b676c54bbd6a08992759ea6f410d4987d69feea9cd0919911"}, - {file = "frozenlist-1.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a2bda8be77660ad4089caf2223fdbd6db1858462c4b85b67fbfa22102021e497"}, - {file = "frozenlist-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:a4d96dc5bcdbd834ec6b0f91027817214216b5b30316494d2b1aebffb87c534f"}, - {file = "frozenlist-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e18036cb4caa17ea151fd5f3d70be9d354c99eb8cf817a3ccde8a7873b074348"}, - {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:536a1236065c29980c15c7229fbb830dedf809708c10e159b8136534233545f0"}, - {file = "frozenlist-1.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ed5e3a4462ff25ca84fb09e0fada8ea267df98a450340ead4c91b44857267d70"}, - {file = "frozenlist-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e19c0fc9f4f030fcae43b4cdec9e8ab83ffe30ec10c79a4a43a04d1af6c5e1ad"}, - {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c608f833897501dac548585312d73a7dca028bf3b8688f0d712b7acfaf7fb3"}, - {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0dbae96c225d584f834b8d3cc688825911960f003a85cb0fd20b6e5512468c42"}, - {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:625170a91dd7261a1d1c2a0c1a353c9e55d21cd67d0852185a5fef86587e6f5f"}, - {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1db8b2fc7ee8a940b547a14c10e56560ad3ea6499dc6875c354e2335812f739d"}, - {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4da6fc43048b648275a220e3a61c33b7fff65d11bdd6dcb9d9c145ff708b804c"}, - {file = "frozenlist-1.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef8e7e8f2f3820c5f175d70fdd199b79e417acf6c72c5d0aa8f63c9f721646f"}, - {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa733d123cc78245e9bb15f29b44ed9e5780dc6867cfc4e544717b91f980af3b"}, - {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ba7f8d97152b61f22d7f59491a781ba9b177dd9f318486c5fbc52cde2db12189"}, - {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:56a0b8dd6d0d3d971c91f1df75e824986667ccce91e20dca2023683814344791"}, - {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5c9e89bf19ca148efcc9e3c44fd4c09d5af85c8a7dd3dbd0da1cb83425ef4983"}, - {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1330f0a4376587face7637dfd245380a57fe21ae8f9d360c1c2ef8746c4195fa"}, - {file = "frozenlist-1.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2187248203b59625566cac53572ec8c2647a140ee2738b4e36772930377a533c"}, - {file = "frozenlist-1.6.0-cp39-cp39-win32.whl", hash = "sha256:2b8cf4cfea847d6c12af06091561a89740f1f67f331c3fa8623391905e878530"}, - {file = "frozenlist-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:1255d5d64328c5a0d066ecb0f02034d086537925f1f04b50b1ae60d37afbf572"}, - {file = "frozenlist-1.6.0-py3-none-any.whl", hash = "sha256:535eec9987adb04701266b92745d6cdcef2e77669299359c3009c3404dd5d191"}, - {file = "frozenlist-1.6.0.tar.gz", hash = "sha256:b99655c32c1c8e06d111e7f41c06c29a5318cb1835df23a45518e02a47c63b68"}, -] - [[package]] name = "h11" version = "0.14.0" @@ -1092,123 +737,6 @@ files = [ {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] -[[package]] -name = "multidict" -version = "6.4.3" -description = "multidict implementation" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32a998bd8a64ca48616eac5a8c1cc4fa38fb244a3facf2eeb14abe186e0f6cc5"}, - {file = "multidict-6.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a54ec568f1fc7f3c313c2f3b16e5db346bf3660e1309746e7fccbbfded856188"}, - {file = "multidict-6.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a7be07e5df178430621c716a63151165684d3e9958f2bbfcb644246162007ab7"}, - {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b128dbf1c939674a50dd0b28f12c244d90e5015e751a4f339a96c54f7275e291"}, - {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9cb19dfd83d35b6ff24a4022376ea6e45a2beba8ef3f0836b8a4b288b6ad685"}, - {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3cf62f8e447ea2c1395afa289b332e49e13d07435369b6f4e41f887db65b40bf"}, - {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:909f7d43ff8f13d1adccb6a397094adc369d4da794407f8dd592c51cf0eae4b1"}, - {file = "multidict-6.4.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0bb8f8302fbc7122033df959e25777b0b7659b1fd6bcb9cb6bed76b5de67afef"}, - {file = "multidict-6.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:224b79471b4f21169ea25ebc37ed6f058040c578e50ade532e2066562597b8a9"}, - {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a7bd27f7ab3204f16967a6f899b3e8e9eb3362c0ab91f2ee659e0345445e0078"}, - {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:99592bd3162e9c664671fd14e578a33bfdba487ea64bcb41d281286d3c870ad7"}, - {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a62d78a1c9072949018cdb05d3c533924ef8ac9bcb06cbf96f6d14772c5cd451"}, - {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ccdde001578347e877ca4f629450973c510e88e8865d5aefbcb89b852ccc666"}, - {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:eccb67b0e78aa2e38a04c5ecc13bab325a43e5159a181a9d1a6723db913cbb3c"}, - {file = "multidict-6.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8b6fcf6054fc4114a27aa865f8840ef3d675f9316e81868e0ad5866184a6cba5"}, - {file = "multidict-6.4.3-cp310-cp310-win32.whl", hash = "sha256:f92c7f62d59373cd93bc9969d2da9b4b21f78283b1379ba012f7ee8127b3152e"}, - {file = "multidict-6.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:b57e28dbc031d13916b946719f213c494a517b442d7b48b29443e79610acd887"}, - {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6f19170197cc29baccd33ccc5b5d6a331058796485857cf34f7635aa25fb0cd"}, - {file = "multidict-6.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2882bf27037eb687e49591690e5d491e677272964f9ec7bc2abbe09108bdfb8"}, - {file = "multidict-6.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbf226ac85f7d6b6b9ba77db4ec0704fde88463dc17717aec78ec3c8546c70ad"}, - {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e329114f82ad4b9dd291bef614ea8971ec119ecd0f54795109976de75c9a852"}, - {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1f4e0334d7a555c63f5c8952c57ab6f1c7b4f8c7f3442df689fc9f03df315c08"}, - {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:740915eb776617b57142ce0bb13b7596933496e2f798d3d15a20614adf30d229"}, - {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255dac25134d2b141c944b59a0d2f7211ca12a6d4779f7586a98b4b03ea80508"}, - {file = "multidict-6.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e8535bd4d741039b5aad4285ecd9b902ef9e224711f0b6afda6e38d7ac02c7"}, - {file = "multidict-6.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c433a33be000dd968f5750722eaa0991037be0be4a9d453eba121774985bc8"}, - {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4eb33b0bdc50acd538f45041f5f19945a1f32b909b76d7b117c0c25d8063df56"}, - {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:75482f43465edefd8a5d72724887ccdcd0c83778ded8f0cb1e0594bf71736cc0"}, - {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce5b3082e86aee80b3925ab4928198450d8e5b6466e11501fe03ad2191c6d777"}, - {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e413152e3212c4d39f82cf83c6f91be44bec9ddea950ce17af87fbf4e32ca6b2"}, - {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8aac2eeff69b71f229a405c0a4b61b54bade8e10163bc7b44fcd257949620618"}, - {file = "multidict-6.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab583ac203af1d09034be41458feeab7863c0635c650a16f15771e1386abf2d7"}, - {file = "multidict-6.4.3-cp311-cp311-win32.whl", hash = "sha256:1b2019317726f41e81154df636a897de1bfe9228c3724a433894e44cd2512378"}, - {file = "multidict-6.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:43173924fa93c7486402217fab99b60baf78d33806af299c56133a3755f69589"}, - {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f1c2f58f08b36f8475f3ec6f5aeb95270921d418bf18f90dffd6be5c7b0e676"}, - {file = "multidict-6.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:26ae9ad364fc61b936fb7bf4c9d8bd53f3a5b4417142cd0be5c509d6f767e2f1"}, - {file = "multidict-6.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:659318c6c8a85f6ecfc06b4e57529e5a78dfdd697260cc81f683492ad7e9435a"}, - {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1eb72c741fd24d5a28242ce72bb61bc91f8451877131fa3fe930edb195f7054"}, - {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3cd06d88cb7398252284ee75c8db8e680aa0d321451132d0dba12bc995f0adcc"}, - {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4543d8dc6470a82fde92b035a92529317191ce993533c3c0c68f56811164ed07"}, - {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30a3ebdc068c27e9d6081fca0e2c33fdf132ecea703a72ea216b81a66860adde"}, - {file = "multidict-6.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b038f10e23f277153f86f95c777ba1958bcd5993194fda26a1d06fae98b2f00c"}, - {file = "multidict-6.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c605a2b2dc14282b580454b9b5d14ebe0668381a3a26d0ac39daa0ca115eb2ae"}, - {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8bd2b875f4ca2bb527fe23e318ddd509b7df163407b0fb717df229041c6df5d3"}, - {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c2e98c840c9c8e65c0e04b40c6c5066c8632678cd50c8721fdbcd2e09f21a507"}, - {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66eb80dd0ab36dbd559635e62fba3083a48a252633164857a1d1684f14326427"}, - {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c23831bdee0a2a3cf21be057b5e5326292f60472fb6c6f86392bbf0de70ba731"}, - {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1535cec6443bfd80d028052e9d17ba6ff8a5a3534c51d285ba56c18af97e9713"}, - {file = "multidict-6.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b73e7227681f85d19dec46e5b881827cd354aabe46049e1a61d2f9aaa4e285a"}, - {file = "multidict-6.4.3-cp312-cp312-win32.whl", hash = "sha256:8eac0c49df91b88bf91f818e0a24c1c46f3622978e2c27035bfdca98e0e18124"}, - {file = "multidict-6.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:11990b5c757d956cd1db7cb140be50a63216af32cd6506329c2c59d732d802db"}, - {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a76534263d03ae0cfa721fea40fd2b5b9d17a6f85e98025931d41dc49504474"}, - {file = "multidict-6.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:805031c2f599eee62ac579843555ed1ce389ae00c7e9f74c2a1b45e0564a88dd"}, - {file = "multidict-6.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c56c179839d5dcf51d565132185409d1d5dd8e614ba501eb79023a6cab25576b"}, - {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c64f4ddb3886dd8ab71b68a7431ad4aa01a8fa5be5b11543b29674f29ca0ba3"}, - {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3002a856367c0b41cad6784f5b8d3ab008eda194ed7864aaa58f65312e2abcac"}, - {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d75e621e7d887d539d6e1d789f0c64271c250276c333480a9e1de089611f790"}, - {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:995015cf4a3c0d72cbf453b10a999b92c5629eaf3a0c3e1efb4b5c1f602253bb"}, - {file = "multidict-6.4.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b0fabae7939d09d7d16a711468c385272fa1b9b7fb0d37e51143585d8e72e0"}, - {file = "multidict-6.4.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61ed4d82f8a1e67eb9eb04f8587970d78fe7cddb4e4d6230b77eda23d27938f9"}, - {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:062428944a8dc69df9fdc5d5fc6279421e5f9c75a9ee3f586f274ba7b05ab3c8"}, - {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b90e27b4674e6c405ad6c64e515a505c6d113b832df52fdacb6b1ffd1fa9a1d1"}, - {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7d50d4abf6729921e9613d98344b74241572b751c6b37feed75fb0c37bd5a817"}, - {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:43fe10524fb0a0514be3954be53258e61d87341008ce4914f8e8b92bee6f875d"}, - {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:236966ca6c472ea4e2d3f02f6673ebfd36ba3f23159c323f5a496869bc8e47c9"}, - {file = "multidict-6.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:422a5ec315018e606473ba1f5431e064cf8b2a7468019233dcf8082fabad64c8"}, - {file = "multidict-6.4.3-cp313-cp313-win32.whl", hash = "sha256:f901a5aace8e8c25d78960dcc24c870c8d356660d3b49b93a78bf38eb682aac3"}, - {file = "multidict-6.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:1c152c49e42277bc9a2f7b78bd5fa10b13e88d1b0328221e7aef89d5c60a99a5"}, - {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:be8751869e28b9c0d368d94f5afcb4234db66fe8496144547b4b6d6a0645cfc6"}, - {file = "multidict-6.4.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d4b31f8a68dccbcd2c0ea04f0e014f1defc6b78f0eb8b35f2265e8716a6df0c"}, - {file = "multidict-6.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:032efeab3049e37eef2ff91271884303becc9e54d740b492a93b7e7266e23756"}, - {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e78006af1a7c8a8007e4f56629d7252668344442f66982368ac06522445e375"}, - {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:daeac9dd30cda8703c417e4fddccd7c4dc0c73421a0b54a7da2713be125846be"}, - {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f6f90700881438953eae443a9c6f8a509808bc3b185246992c4233ccee37fea"}, - {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f84627997008390dd15762128dcf73c3365f4ec0106739cde6c20a07ed198ec8"}, - {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3307b48cd156153b117c0ea54890a3bdbf858a5b296ddd40dc3852e5f16e9b02"}, - {file = "multidict-6.4.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead46b0fa1dcf5af503a46e9f1c2e80b5d95c6011526352fa5f42ea201526124"}, - {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1748cb2743bedc339d63eb1bca314061568793acd603a6e37b09a326334c9f44"}, - {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:acc9fa606f76fc111b4569348cc23a771cb52c61516dcc6bcef46d612edb483b"}, - {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:31469d5832b5885adeb70982e531ce86f8c992334edd2f2254a10fa3182ac504"}, - {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ba46b51b6e51b4ef7bfb84b82f5db0dc5e300fb222a8a13b8cd4111898a869cf"}, - {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:389cfefb599edf3fcfd5f64c0410da686f90f5f5e2c4d84e14f6797a5a337af4"}, - {file = "multidict-6.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:64bc2bbc5fba7b9db5c2c8d750824f41c6994e3882e6d73c903c2afa78d091e4"}, - {file = "multidict-6.4.3-cp313-cp313t-win32.whl", hash = "sha256:0ecdc12ea44bab2807d6b4a7e5eef25109ab1c82a8240d86d3c1fc9f3b72efd5"}, - {file = "multidict-6.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7146a8742ea71b5d7d955bffcef58a9e6e04efba704b52a460134fefd10a8208"}, - {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5427a2679e95a642b7f8b0f761e660c845c8e6fe3141cddd6b62005bd133fc21"}, - {file = "multidict-6.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:24a8caa26521b9ad09732972927d7b45b66453e6ebd91a3c6a46d811eeb7349b"}, - {file = "multidict-6.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6b5a272bc7c36a2cd1b56ddc6bff02e9ce499f9f14ee4a45c45434ef083f2459"}, - {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf74dc5e212b8c75165b435c43eb0d5e81b6b300a938a4eb82827119115e840"}, - {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9f35de41aec4b323c71f54b0ca461ebf694fb48bec62f65221f52e0017955b39"}, - {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae93e0ff43b6f6892999af64097b18561691ffd835e21a8348a441e256592e1f"}, - {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e3929269e9d7eff905d6971d8b8c85e7dbc72c18fb99c8eae6fe0a152f2e343"}, - {file = "multidict-6.4.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6214fe1750adc2a1b801a199d64b5a67671bf76ebf24c730b157846d0e90d2"}, - {file = "multidict-6.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d79cf5c0c6284e90f72123f4a3e4add52d6c6ebb4a9054e88df15b8d08444c6"}, - {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2427370f4a255262928cd14533a70d9738dfacadb7563bc3b7f704cc2360fc4e"}, - {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:fbd8d737867912b6c5f99f56782b8cb81f978a97b4437a1c476de90a3e41c9a1"}, - {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0ee1bf613c448997f73fc4efb4ecebebb1c02268028dd4f11f011f02300cf1e8"}, - {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:578568c4ba5f2b8abd956baf8b23790dbfdc953e87d5b110bce343b4a54fc9e7"}, - {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a059ad6b80de5b84b9fa02a39400319e62edd39d210b4e4f8c4f1243bdac4752"}, - {file = "multidict-6.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dd53893675b729a965088aaadd6a1f326a72b83742b056c1065bdd2e2a42b4df"}, - {file = "multidict-6.4.3-cp39-cp39-win32.whl", hash = "sha256:abcfed2c4c139f25c2355e180bcc077a7cae91eefbb8b3927bb3f836c9586f1f"}, - {file = "multidict-6.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:b1b389ae17296dd739015d5ddb222ee99fd66adeae910de21ac950e00979d897"}, - {file = "multidict-6.4.3-py3-none-any.whl", hash = "sha256:59fe01ee8e2a1e8ceb3f6dbb216b09c8d9f4ef1c22c4fc825d045a147fa2ebc9"}, - {file = "multidict-6.4.3.tar.gz", hash = "sha256:3ada0b058c9f213c5f95ba301f922d402ac234f1111a7d8fd70f1b99f3c281ec"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} - [[package]] name = "mypy" version = "1.15.0" @@ -1506,114 +1034,6 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "propcache" -version = "0.3.1" -description = "Accelerated property cache" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98"}, - {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180"}, - {file = "propcache-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71"}, - {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649"}, - {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f"}, - {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229"}, - {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46"}, - {file = "propcache-0.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7"}, - {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0"}, - {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519"}, - {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd"}, - {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259"}, - {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e"}, - {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136"}, - {file = "propcache-0.3.1-cp310-cp310-win32.whl", hash = "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42"}, - {file = "propcache-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833"}, - {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5"}, - {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371"}, - {file = "propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da"}, - {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744"}, - {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0"}, - {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5"}, - {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256"}, - {file = "propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073"}, - {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d"}, - {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f"}, - {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0"}, - {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a"}, - {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a"}, - {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9"}, - {file = "propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005"}, - {file = "propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7"}, - {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723"}, - {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976"}, - {file = "propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b"}, - {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f"}, - {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70"}, - {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7"}, - {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25"}, - {file = "propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277"}, - {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8"}, - {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e"}, - {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee"}, - {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815"}, - {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5"}, - {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7"}, - {file = "propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b"}, - {file = "propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3"}, - {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8"}, - {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f"}, - {file = "propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111"}, - {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5"}, - {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb"}, - {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7"}, - {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120"}, - {file = "propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654"}, - {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e"}, - {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b"}, - {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53"}, - {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5"}, - {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7"}, - {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef"}, - {file = "propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24"}, - {file = "propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"}, - {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f"}, - {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c"}, - {file = "propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc"}, - {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de"}, - {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6"}, - {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7"}, - {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458"}, - {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11"}, - {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c"}, - {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf"}, - {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27"}, - {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757"}, - {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18"}, - {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a"}, - {file = "propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d"}, - {file = "propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e"}, - {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6"}, - {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf"}, - {file = "propcache-0.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c"}, - {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894"}, - {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035"}, - {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908"}, - {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5"}, - {file = "propcache-0.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5"}, - {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7"}, - {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641"}, - {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294"}, - {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf"}, - {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c"}, - {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe"}, - {file = "propcache-0.3.1-cp39-cp39-win32.whl", hash = "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64"}, - {file = "propcache-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566"}, - {file = "propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40"}, - {file = "propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf"}, -] - [[package]] name = "pycparser" version = "2.22" @@ -2117,214 +1537,6 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] -[[package]] -name = "wrapt" -version = "1.17.2" -description = "Module for decorators, wrappers and monkey patching." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, - {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, - {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"}, - {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"}, - {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"}, - {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"}, - {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"}, - {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"}, - {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"}, - {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"}, - {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"}, - {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, - {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, - {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, - {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, - {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, - {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, - {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, - {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, - {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, - {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, - {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, - {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, - {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, - {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, - {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, - {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, - {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"}, - {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, - {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, - {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, - {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, - {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, - {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, - {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, - {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, - {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, - {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, - {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, - {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, - {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, - {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, - {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, - {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, - {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, - {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, - {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, - {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, - {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, - {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, - {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, - {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, - {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, - {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, - {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, - {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"}, - {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"}, - {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"}, - {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"}, - {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"}, - {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"}, - {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"}, - {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"}, - {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"}, - {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"}, - {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"}, - {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"}, - {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"}, - {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"}, - {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"}, - {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"}, - {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"}, - {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"}, - {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"}, - {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"}, - {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"}, - {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"}, - {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, - {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, -] - -[[package]] -name = "yarl" -version = "1.20.0" -description = "Yet another URL library" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f1f6670b9ae3daedb325fa55fbe31c22c8228f6e0b513772c2e1c623caa6ab22"}, - {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85a231fa250dfa3308f3c7896cc007a47bc76e9e8e8595c20b7426cac4884c62"}, - {file = "yarl-1.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a06701b647c9939d7019acdfa7ebbfbb78ba6aa05985bb195ad716ea759a569"}, - {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7595498d085becc8fb9203aa314b136ab0516c7abd97e7d74f7bb4eb95042abe"}, - {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af5607159085dcdb055d5678fc2d34949bd75ae6ea6b4381e784bbab1c3aa195"}, - {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95b50910e496567434cb77a577493c26bce0f31c8a305135f3bda6a2483b8e10"}, - {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b594113a301ad537766b4e16a5a6750fcbb1497dcc1bc8a4daae889e6402a634"}, - {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:083ce0393ea173cd37834eb84df15b6853b555d20c52703e21fbababa8c129d2"}, - {file = "yarl-1.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f1a350a652bbbe12f666109fbddfdf049b3ff43696d18c9ab1531fbba1c977a"}, - {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fb0caeac4a164aadce342f1597297ec0ce261ec4532bbc5a9ca8da5622f53867"}, - {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d88cc43e923f324203f6ec14434fa33b85c06d18d59c167a0637164863b8e995"}, - {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e52d6ed9ea8fd3abf4031325dc714aed5afcbfa19ee4a89898d663c9976eb487"}, - {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ce360ae48a5e9961d0c730cf891d40698a82804e85f6e74658fb175207a77cb2"}, - {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:06d06c9d5b5bc3eb56542ceeba6658d31f54cf401e8468512447834856fb0e61"}, - {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c27d98f4e5c4060582f44e58309c1e55134880558f1add7a87c1bc36ecfade19"}, - {file = "yarl-1.20.0-cp310-cp310-win32.whl", hash = "sha256:f4d3fa9b9f013f7050326e165c3279e22850d02ae544ace285674cb6174b5d6d"}, - {file = "yarl-1.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc906b636239631d42eb8a07df8359905da02704a868983265603887ed68c076"}, - {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdb5204d17cb32b2de2d1e21c7461cabfacf17f3645e4b9039f210c5d3378bf3"}, - {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eaddd7804d8e77d67c28d154ae5fab203163bd0998769569861258e525039d2a"}, - {file = "yarl-1.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:634b7ba6b4a85cf67e9df7c13a7fb2e44fa37b5d34501038d174a63eaac25ee2"}, - {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d409e321e4addf7d97ee84162538c7258e53792eb7c6defd0c33647d754172e"}, - {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ea52f7328a36960ba3231c6677380fa67811b414798a6e071c7085c57b6d20a9"}, - {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8703517b924463994c344dcdf99a2d5ce9eca2b6882bb640aa555fb5efc706a"}, - {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:077989b09ffd2f48fb2d8f6a86c5fef02f63ffe6b1dd4824c76de7bb01e4f2e2"}, - {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0acfaf1da020253f3533526e8b7dd212838fdc4109959a2c53cafc6db611bff2"}, - {file = "yarl-1.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4230ac0b97ec5eeb91d96b324d66060a43fd0d2a9b603e3327ed65f084e41f8"}, - {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6a1e6ae21cdd84011c24c78d7a126425148b24d437b5702328e4ba640a8902"}, - {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:86de313371ec04dd2531f30bc41a5a1a96f25a02823558ee0f2af0beaa7ca791"}, - {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dd59c9dd58ae16eaa0f48c3d0cbe6be8ab4dc7247c3ff7db678edecbaf59327f"}, - {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a0bc5e05f457b7c1994cc29e83b58f540b76234ba6b9648a4971ddc7f6aa52da"}, - {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c9471ca18e6aeb0e03276b5e9b27b14a54c052d370a9c0c04a68cefbd1455eb4"}, - {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40ed574b4df723583a26c04b298b283ff171bcc387bc34c2683235e2487a65a5"}, - {file = "yarl-1.20.0-cp311-cp311-win32.whl", hash = "sha256:db243357c6c2bf3cd7e17080034ade668d54ce304d820c2a58514a4e51d0cfd6"}, - {file = "yarl-1.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c12cd754d9dbd14204c328915e23b0c361b88f3cffd124129955e60a4fbfcfb"}, - {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f"}, - {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e"}, - {file = "yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e"}, - {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33"}, - {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58"}, - {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f"}, - {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae"}, - {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018"}, - {file = "yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672"}, - {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8"}, - {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7"}, - {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594"}, - {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6"}, - {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1"}, - {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b"}, - {file = "yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64"}, - {file = "yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c"}, - {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2137810a20b933b1b1b7e5cf06a64c3ed3b4747b0e5d79c9447c00db0e2f752f"}, - {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:447c5eadd750db8389804030d15f43d30435ed47af1313303ed82a62388176d3"}, - {file = "yarl-1.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42fbe577272c203528d402eec8bf4b2d14fd49ecfec92272334270b850e9cd7d"}, - {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18e321617de4ab170226cd15006a565d0fa0d908f11f724a2c9142d6b2812ab0"}, - {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4345f58719825bba29895011e8e3b545e6e00257abb984f9f27fe923afca2501"}, - {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d9b980d7234614bc4674468ab173ed77d678349c860c3af83b1fffb6a837ddc"}, - {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af4baa8a445977831cbaa91a9a84cc09debb10bc8391f128da2f7bd070fc351d"}, - {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123393db7420e71d6ce40d24885a9e65eb1edefc7a5228db2d62bcab3386a5c0"}, - {file = "yarl-1.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab47acc9332f3de1b39e9b702d9c916af7f02656b2a86a474d9db4e53ef8fd7a"}, - {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4a34c52ed158f89876cba9c600b2c964dfc1ca52ba7b3ab6deb722d1d8be6df2"}, - {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:04d8cfb12714158abf2618f792c77bc5c3d8c5f37353e79509608be4f18705c9"}, - {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7dc63ad0d541c38b6ae2255aaa794434293964677d5c1ec5d0116b0e308031f5"}, - {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d02b591a64e4e6ca18c5e3d925f11b559c763b950184a64cf47d74d7e41877"}, - {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95fc9876f917cac7f757df80a5dda9de59d423568460fe75d128c813b9af558e"}, - {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb769ae5760cd1c6a712135ee7915f9d43f11d9ef769cb3f75a23e398a92d384"}, - {file = "yarl-1.20.0-cp313-cp313-win32.whl", hash = "sha256:70e0c580a0292c7414a1cead1e076c9786f685c1fc4757573d2967689b370e62"}, - {file = "yarl-1.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:4c43030e4b0af775a85be1fa0433119b1565673266a70bf87ef68a9d5ba3174c"}, - {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b6c4c3d0d6a0ae9b281e492b1465c72de433b782e6b5001c8e7249e085b69051"}, - {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8681700f4e4df891eafa4f69a439a6e7d480d64e52bf460918f58e443bd3da7d"}, - {file = "yarl-1.20.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:84aeb556cb06c00652dbf87c17838eb6d92cfd317799a8092cee0e570ee11229"}, - {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f166eafa78810ddb383e930d62e623d288fb04ec566d1b4790099ae0f31485f1"}, - {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5d3d6d14754aefc7a458261027a562f024d4f6b8a798adb472277f675857b1eb"}, - {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a8f64df8ed5d04c51260dbae3cc82e5649834eebea9eadfd829837b8093eb00"}, - {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9949eaf05b4d30e93e4034a7790634bbb41b8be2d07edd26754f2e38e491de"}, - {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c366b254082d21cc4f08f522ac201d0d83a8b8447ab562732931d31d80eb2a5"}, - {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91bc450c80a2e9685b10e34e41aef3d44ddf99b3a498717938926d05ca493f6a"}, - {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c2aa4387de4bc3a5fe158080757748d16567119bef215bec643716b4fbf53f9"}, - {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d2cbca6760a541189cf87ee54ff891e1d9ea6406079c66341008f7ef6ab61145"}, - {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:798a5074e656f06b9fad1a162be5a32da45237ce19d07884d0b67a0aa9d5fdda"}, - {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f106e75c454288472dbe615accef8248c686958c2e7dd3b8d8ee2669770d020f"}, - {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3b60a86551669c23dc5445010534d2c5d8a4e012163218fc9114e857c0586fdd"}, - {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e429857e341d5e8e15806118e0294f8073ba9c4580637e59ab7b238afca836f"}, - {file = "yarl-1.20.0-cp313-cp313t-win32.whl", hash = "sha256:65a4053580fe88a63e8e4056b427224cd01edfb5f951498bfefca4052f0ce0ac"}, - {file = "yarl-1.20.0-cp313-cp313t-win_amd64.whl", hash = "sha256:53b2da3a6ca0a541c1ae799c349788d480e5144cac47dba0266c7cb6c76151fe"}, - {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:119bca25e63a7725b0c9d20ac67ca6d98fa40e5a894bd5d4686010ff73397914"}, - {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35d20fb919546995f1d8c9e41f485febd266f60e55383090010f272aca93edcc"}, - {file = "yarl-1.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:484e7a08f72683c0f160270566b4395ea5412b4359772b98659921411d32ad26"}, - {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d8a3d54a090e0fff5837cd3cc305dd8a07d3435a088ddb1f65e33b322f66a94"}, - {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f0cf05ae2d3d87a8c9022f3885ac6dea2b751aefd66a4f200e408a61ae9b7f0d"}, - {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a884b8974729e3899d9287df46f015ce53f7282d8d3340fa0ed57536b440621c"}, - {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8d8aa8dd89ffb9a831fedbcb27d00ffd9f4842107d52dc9d57e64cb34073d5c"}, - {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4e88d6c3c8672f45a30867817e4537df1bbc6f882a91581faf1f6d9f0f1b5a"}, - {file = "yarl-1.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdb77efde644d6f1ad27be8a5d67c10b7f769804fff7a966ccb1da5a4de4b656"}, - {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4ba5e59f14bfe8d261a654278a0f6364feef64a794bd456a8c9e823071e5061c"}, - {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d0bf955b96ea44ad914bc792c26a0edcd71b4668b93cbcd60f5b0aeaaed06c64"}, - {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:27359776bc359ee6eaefe40cb19060238f31228799e43ebd3884e9c589e63b20"}, - {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:04d9c7a1dc0a26efb33e1acb56c8849bd57a693b85f44774356c92d610369efa"}, - {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:faa709b66ae0e24c8e5134033187a972d849d87ed0a12a0366bedcc6b5dc14a5"}, - {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:44869ee8538208fe5d9342ed62c11cc6a7a1af1b3d0bb79bb795101b6e77f6e0"}, - {file = "yarl-1.20.0-cp39-cp39-win32.whl", hash = "sha256:b7fa0cb9fd27ffb1211cde944b41f5c67ab1c13a13ebafe470b1e206b8459da8"}, - {file = "yarl-1.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4fad6e5189c847820288286732075f213eabf81be4d08d6cc309912e62be5b7"}, - {file = "yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124"}, - {file = "yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307"}, -] - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" -propcache = ">=0.2.1" - [[package]] name = "zstandard" version = "0.23.0" @@ -2441,4 +1653,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "af4e2ef43ff3c5d73f3a85fadc0112def4ec7fa5ad7e7b1799e44cfe8e30dfbc" +content-hash = "fd83ddf3fafbbf9e0a2380ed8a60b4e87425e9973f41c0f0151e6e778fa58a5e" diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py index 2fb189af..1e22ba88 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py @@ -35,24 +35,6 @@ def mock_boto_client(): mock_client.list_invocation_steps = MagicMock() return mock_client -@pytest.fixture -def mock_aioboto_client(): - mock_client = AsyncMock(spec=AioBaseClient) - - mock_client.__aenter__ = AsyncMock(return_value=mock_client) - mock_client.__aexit__ = AsyncMock(return_value=None) - - mock_client.create_session = AsyncMock() - mock_client.get_session = AsyncMock() - mock_client.end_session = AsyncMock() - mock_client.delete_session = AsyncMock() - mock_client.create_invocation = AsyncMock() - mock_client.list_invocations = AsyncMock() - mock_client.put_invocation_step = AsyncMock() - mock_client.get_invocation_step = AsyncMock() - mock_client.list_invocation_steps = AsyncMock() - - return mock_client @pytest.fixture def sample_session_id(): diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py index 27e4cb0f..6385ae1f 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py @@ -23,9 +23,9 @@ class TestAsyncBedrockSessionSaver: @pytest.fixture - def session_saver(self, mock_aioboto_client): - with patch("aioboto3.Session") as mock_aioboto_session: - mock_aioboto_session.return_value.client.return_value = mock_aioboto_client + def session_saver(self, mock_boto_client): + with patch("boto3.Session") as mock_aioboto_session: + mock_aioboto_session.return_value.client.return_value = mock_boto_client yield AsyncBedrockSessionSaver() @pytest.fixture @@ -37,53 +37,14 @@ def runnable_config(self): } ) - @pytest.mark.asyncio - async def test_init_with_default_client(self, session_saver, mock_aioboto_client): - # Assert type of session_client - assert isinstance(session_saver.session_client, AsyncBedrockAgentRuntimeSessionClient) - - # Assert that the session is set correctly - assert session_saver.session_client.session.client.return_value == mock_aioboto_client - - # test _get_client logic - client = await session_saver.session_client._get_client() - assert client == mock_aioboto_client - - - @pytest.mark.asyncio - async def test_init_with_all_parameters(self, mock_aioboto_client): - # Mock both the Session and the AsyncBedrockAgentRuntimeSessionClient - with patch("aioboto3.Session") as mock_aioboto_session: - - # Configure the mock to return our mock client - mock_aioboto_session.return_value.client.return_value = mock_aioboto_client - - # Set up test parameters - config = Config(retries=dict(max_attempts=5)) - endpoint_url = "https://custom-endpoint.amazonaws.com" - - # Create the AsyncBedrockSessionSaver instance - saver = AsyncBedrockSessionSaver( - region_name="us-west-2", - credentials_profile_name="test-profile", - aws_access_key_id=SecretStr("test-access-key"), - aws_secret_access_key=SecretStr("test-secret-key"), - aws_session_token=SecretStr("test-session-token"), - endpoint_url=endpoint_url, - config=config, - ) - - # Assert that AsyncBedrockAgentRuntimeSessionClient was initialized with the correct parameters - assert isinstance(saver.session_client, AsyncBedrockAgentRuntimeSessionClient) - @pytest.mark.asyncio async def test__create_session_invocation_success( - self, mock_aioboto_client, session_saver, sample_create_invocation_response + self, mock_boto_client, session_saver, sample_create_invocation_response ): # Arrange thread_id = "test_thread_id" invocation_id = "test_invocation_id" - mock_aioboto_client.create_invocation.return_value = ( + mock_boto_client.create_invocation.return_value = ( sample_create_invocation_response ) @@ -91,13 +52,13 @@ async def test__create_session_invocation_success( await session_saver._create_session_invocation(thread_id, invocation_id) # Assert - mock_aioboto_client.create_invocation.assert_called_once() + mock_boto_client.create_invocation.assert_called_once() @pytest.mark.asyncio - async def test__create_session_invocation_conflict(self, mock_aioboto_client, session_saver): + async def test__create_session_invocation_conflict(self, mock_boto_client, session_saver): # Arrange error_response = {"Error": {"Code": "ConflictException", "Message": "Conflict"}} - mock_aioboto_client.create_invocation.side_effect = ClientError( + mock_boto_client.create_invocation.side_effect = ClientError( error_response=error_response, operation_name="CreateInvocation", ) @@ -108,18 +69,18 @@ async def test__create_session_invocation_conflict(self, mock_aioboto_client, se await session_saver._create_session_invocation(thread_id, invocation_id) # Assert - mock_aioboto_client.create_invocation.assert_called_once() + mock_boto_client.create_invocation.assert_called_once() @pytest.mark.asyncio async def test__create_session_invocation_raises_error( - self, mock_aioboto_client, session_saver + self, mock_boto_client, session_saver ): # Arrange thread_id = "test_thread_id" invocation_id = "test_invocation_id" error_response = {"Error": {"Code": "SomeOtherError", "Message": "Other error"}} - mock_aioboto_client.create_invocation.side_effect = ClientError( + mock_boto_client.create_invocation.side_effect = ClientError( error_response=error_response, operation_name="CreateInvocation", ) @@ -129,12 +90,12 @@ async def test__create_session_invocation_raises_error( await session_saver._create_session_invocation(thread_id, invocation_id) assert exc_info.value.response["Error"]["Code"] == "SomeOtherError" - mock_aioboto_client.create_invocation.assert_called_once() + mock_boto_client.create_invocation.assert_called_once() @pytest.mark.asyncio async def test__get_checkpoint_pending_writes_success( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_session_pending_write, sample_list_invocation_steps_response, @@ -149,10 +110,10 @@ async def test__get_checkpoint_pending_writes_success( sample_get_invocation_step_response["invocationStep"]["payload"][ "contentBlocks" ][0]["text"] = sample_session_pending_write.model_dump_json() - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) - mock_aioboto_client.get_invocation_step.return_value = ( + mock_boto_client.get_invocation_step.return_value = ( sample_get_invocation_step_response ) @@ -163,19 +124,19 @@ async def test__get_checkpoint_pending_writes_success( # Assert assert len(result) == 1 - mock_aioboto_client.list_invocation_steps.assert_called_once() - mock_aioboto_client.get_invocation_step.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() + mock_boto_client.get_invocation_step.assert_called_once() @pytest.mark.asyncio async def test__get_checkpoint_pending_writes_no_invocation_steps( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_list_invocation_steps_response, ): # Arrange sample_list_invocation_steps_response["invocationStepSummaries"] = [] - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) @@ -186,15 +147,15 @@ async def test__get_checkpoint_pending_writes_no_invocation_steps( # Assert assert result == [] - mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() @pytest.mark.asyncio async def test__get_checkpoint_pending_writes_resource_not_found( - self, mock_aioboto_client, session_saver + self, mock_boto_client, session_saver ): # Arrange error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} - mock_aioboto_client.list_invocation_steps.side_effect = ClientError( + mock_boto_client.list_invocation_steps.side_effect = ClientError( error_response=error_response, operation_name="ListInvocationSteps", ) @@ -206,15 +167,15 @@ async def test__get_checkpoint_pending_writes_resource_not_found( # Assert assert result == [] - mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() @pytest.mark.asyncio async def test__get_checkpoint_pending_writes_client_error( - self, mock_aioboto_client, session_saver, sample_invocation_step_payload + self, mock_boto_client, session_saver, sample_invocation_step_payload ): # Arrange error_response = {"Error": {"Code": "SomeError", "Message": "Error occurred"}} - mock_aioboto_client.list_invocation_steps.side_effect = ClientError( + mock_boto_client.list_invocation_steps.side_effect = ClientError( error_response=error_response, operation_name="ListInvocationSteps", ) @@ -225,12 +186,12 @@ async def test__get_checkpoint_pending_writes_client_error( "thread_id", "ns", "checkpoint_id" ) - mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() @pytest.mark.asyncio async def test__save_invocation_step_success( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_invocation_step_payload, sample_put_invocation_step_response, @@ -239,7 +200,7 @@ async def test__save_invocation_step_success( thread_id = "test_thread_id" invocation_identifier = "test_invocation_identifier" invocation_step_id = "test_invocation_step_id" - mock_aioboto_client.put_invocation_step.return_value = ( + mock_boto_client.put_invocation_step.return_value = ( sample_put_invocation_step_response ) @@ -255,15 +216,15 @@ async def test__save_invocation_step_success( ) # Assert - mock_aioboto_client.put_invocation_step.assert_called_once() + mock_boto_client.put_invocation_step.assert_called_once() @pytest.mark.asyncio async def test__save_invocation_step_client_error( - self, mock_aioboto_client, session_saver, sample_invocation_step_payload + self, mock_boto_client, session_saver, sample_invocation_step_payload ): # Arrange error_response = {"Error": {"Code": "SomeError", "Message": "Error occurred"}} - mock_aioboto_client.put_invocation_step.side_effect = ClientError( + mock_boto_client.put_invocation_step.side_effect = ClientError( error_response=error_response, operation_name="PutInvocationStep", ) @@ -274,12 +235,12 @@ async def test__save_invocation_step_client_error( "thread_id", "inv_id", "step_id", sample_invocation_step_payload ) - mock_aioboto_client.put_invocation_step.assert_called_once() + mock_boto_client.put_invocation_step.assert_called_once() @pytest.mark.asyncio async def test__find_most_recent_checkpoint_step_success( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_session_checkpoint, sample_list_invocation_steps_response, @@ -293,10 +254,10 @@ async def test__find_most_recent_checkpoint_step_success( sample_get_invocation_step_response["invocationStep"]["payload"][ "contentBlocks" ][0]["text"] = sample_session_checkpoint.model_dump_json() - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) - mock_aioboto_client.get_invocation_step.return_value = ( + mock_boto_client.get_invocation_step.return_value = ( sample_get_invocation_step_response ) @@ -307,13 +268,13 @@ async def test__find_most_recent_checkpoint_step_success( # Assert assert result is not None - mock_aioboto_client.list_invocation_steps.assert_called_once() - mock_aioboto_client.get_invocation_step.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() + mock_boto_client.get_invocation_step.assert_called_once() @pytest.mark.asyncio async def test__find_most_recent_checkpoint_step_skips_writes( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_session_pending_write, sample_list_invocation_steps_response, @@ -327,10 +288,10 @@ async def test__find_most_recent_checkpoint_step_skips_writes( sample_get_invocation_step_response["invocationStep"]["payload"][ "contentBlocks" ][0]["text"] = sample_session_pending_write.model_dump_json() - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) - mock_aioboto_client.get_invocation_step.return_value = ( + mock_boto_client.get_invocation_step.return_value = ( sample_get_invocation_step_response ) @@ -341,19 +302,19 @@ async def test__find_most_recent_checkpoint_step_skips_writes( # Assert assert result is None - mock_aioboto_client.list_invocation_steps.assert_called_once() - mock_aioboto_client.get_invocation_step.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() + mock_boto_client.get_invocation_step.assert_called_once() @pytest.mark.asyncio async def test__find_most_recent_checkpoint_step_no_invocation_steps( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_list_invocation_steps_response, ): # Arrange sample_list_invocation_steps_response["invocationStepSummaries"] = [] - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) @@ -362,12 +323,12 @@ async def test__find_most_recent_checkpoint_step_no_invocation_steps( # Assert assert result is None - mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() @pytest.mark.asyncio async def test__get_checkpoint_step_with_checkpoint_id( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_get_invocation_step_response, ): @@ -376,7 +337,7 @@ async def test__get_checkpoint_step_with_checkpoint_id( checkpoint_ns = "test_namespace" checkpoint_id = "test_checkpoint_id" session_saver._find_most_recent_checkpoint_step = Mock() - mock_aioboto_client.get_invocation_step.return_value = ( + mock_boto_client.get_invocation_step.return_value = ( sample_get_invocation_step_response ) @@ -385,12 +346,12 @@ async def test__get_checkpoint_step_with_checkpoint_id( # Assert session_saver._find_most_recent_checkpoint_step.assert_not_called() - mock_aioboto_client.get_invocation_step.assert_called_once() + mock_boto_client.get_invocation_step.assert_called_once() @pytest.mark.asyncio async def test__get_checkpoint_step_without_checkpoint_id( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_invocation_step_payload, sample_get_invocation_step_response, @@ -411,12 +372,12 @@ async def test__get_checkpoint_step_without_checkpoint_id( thread_id, checkpoint_ns, ) - mock_aioboto_client.get_invocation_step.assert_not_called() + mock_boto_client.get_invocation_step.assert_not_called() @pytest.mark.asyncio async def test__get_checkpoint_step_empty_without_checkpoint_id( self, - mock_aioboto_client, + mock_boto_client, session_saver, sample_invocation_step_payload, sample_get_invocation_step_response, @@ -435,7 +396,7 @@ async def test__get_checkpoint_step_empty_without_checkpoint_id( thread_id, checkpoint_ns, ) - mock_aioboto_client.get_invocation_step.assert_not_called() + mock_boto_client.get_invocation_step.assert_not_called() @pytest.mark.asyncio async def test__get_task_sends_without_parent_checkpoint_id( diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py index cb243298..c255f729 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py @@ -26,18 +26,18 @@ class TestAsyncBedrockAgentRuntimeSessionClient: @pytest.fixture - def mock_session_client(self, mock_aioboto_client): - with patch("aioboto3.Session") as mock_aioboto_session: - mock_aioboto_session.return_value.client.return_value = mock_aioboto_client + def mock_session_client(self, mock_boto_client): + with patch("boto3.Session") as mock_aioboto_session: + mock_aioboto_session.return_value.client.return_value = mock_boto_client yield AsyncBedrockAgentRuntimeSessionClient() class TestSession: @pytest.mark.asyncio async def test_create_async_session( - self, mock_session_client, mock_aioboto_client, sample_create_session_response + self, mock_session_client, mock_boto_client, sample_create_session_response ): # Arrange - mock_aioboto_client.create_session.return_value = ( + mock_boto_client.create_session.return_value = ( sample_create_session_response ) request = CreateSessionRequest() @@ -47,14 +47,14 @@ async def test_create_async_session( # Assert assert isinstance(response, CreateSessionResponse) - mock_aioboto_client.create_session.assert_called_once() + mock_boto_client.create_session.assert_called_once() @pytest.mark.asyncio async def test_create_session_with_user_attr( - self, mock_session_client, mock_aioboto_client, sample_create_session_response + self, mock_session_client, mock_boto_client, sample_create_session_response ): # Arrange - mock_aioboto_client.create_session.return_value = ( + mock_boto_client.create_session.return_value = ( sample_create_session_response ) request = CreateSessionRequest( @@ -68,18 +68,18 @@ async def test_create_session_with_user_attr( # Assert assert isinstance(response, CreateSessionResponse) - mock_aioboto_client.create_session.assert_called_once() + mock_boto_client.create_session.assert_called_once() @pytest.mark.asyncio async def test_get_session( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_get_session_response, sample_session_id, ): # Arrange - mock_aioboto_client.get_session.return_value = sample_get_session_response + mock_boto_client.get_session.return_value = sample_get_session_response request = GetSessionRequest(session_identifier=sample_session_id) # Act @@ -87,18 +87,18 @@ async def test_get_session( # Assert assert isinstance(response, GetSessionResponse) - mock_aioboto_client.get_session.assert_called_once() + mock_boto_client.get_session.assert_called_once() @pytest.mark.asyncio async def test_end_session( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_get_session_response, sample_session_id, ): # Arrange - mock_aioboto_client.end_session.return_value = sample_get_session_response + mock_boto_client.end_session.return_value = sample_get_session_response request = EndSessionRequest(session_identifier=sample_session_id) # Act @@ -106,11 +106,11 @@ async def test_end_session( # Assert assert isinstance(response, EndSessionResponse) - mock_aioboto_client.end_session.assert_called_once() + mock_boto_client.end_session.assert_called_once() @pytest.mark.asyncio async def test_delete_session( - self, mock_session_client, mock_aioboto_client, sample_session_id + self, mock_session_client, mock_boto_client, sample_session_id ): # Arrange request = DeleteSessionRequest(session_identifier=sample_session_id) @@ -119,19 +119,19 @@ async def test_delete_session( await mock_session_client.delete_session(request) # Assert - mock_aioboto_client.delete_session.assert_called_once() + mock_boto_client.delete_session.assert_called_once() class TestInvocation: @pytest.mark.asyncio async def test_create_invocation( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_create_invocation_response, ): # Arrange - mock_aioboto_client.create_invocation.return_value = ( + mock_boto_client.create_invocation.return_value = ( sample_create_invocation_response ) request = CreateInvocationRequest(session_identifier=sample_session_id) @@ -141,19 +141,19 @@ async def test_create_invocation( # Assert assert isinstance(response, CreateInvocationResponse) - mock_aioboto_client.create_invocation.assert_called_once() + mock_boto_client.create_invocation.assert_called_once() @pytest.mark.asyncio async def test_create_invocation_with_user_attr( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_invocation_id, sample_create_invocation_response, ): # Arrange - mock_aioboto_client.create_invocation.return_value = ( + mock_boto_client.create_invocation.return_value = ( sample_create_invocation_response ) request = CreateInvocationRequest( @@ -167,18 +167,18 @@ async def test_create_invocation_with_user_attr( # Assert assert isinstance(response, CreateInvocationResponse) - mock_aioboto_client.create_invocation.assert_called_once() + mock_boto_client.create_invocation.assert_called_once() @pytest.mark.asyncio async def test_list_invocation( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_list_invocation_response, ): # Arrange - mock_aioboto_client.list_invocations.return_value = ( + mock_boto_client.list_invocations.return_value = ( sample_list_invocation_response ) request = ListInvocationsRequest( @@ -190,14 +190,14 @@ async def test_list_invocation( # Assert assert isinstance(response, ListInvocationsResponse) - mock_aioboto_client.list_invocations.assert_called_once() + mock_boto_client.list_invocations.assert_called_once() class TestInvocationStep: @pytest.mark.asyncio async def test_put_invocation_step( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_invocation_id, sample_invocation_step_id, @@ -206,7 +206,7 @@ async def test_put_invocation_step( sample_put_invocation_step_response, ): # Arrange - mock_aioboto_client.put_invocation_step.return_value = ( + mock_boto_client.put_invocation_step.return_value = ( sample_put_invocation_step_response ) request = PutInvocationStepRequest( @@ -222,20 +222,20 @@ async def test_put_invocation_step( # Assert assert isinstance(response, PutInvocationStepResponse) - mock_aioboto_client.put_invocation_step.assert_called_once() + mock_boto_client.put_invocation_step.assert_called_once() @pytest.mark.asyncio async def test_get_invocation_step( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_invocation_id, sample_invocation_step_id, sample_get_invocation_step_response, ): # Arrange - mock_aioboto_client.get_invocation_step.return_value = ( + mock_boto_client.get_invocation_step.return_value = ( sample_get_invocation_step_response ) request = GetInvocationStepRequest( @@ -249,18 +249,18 @@ async def test_get_invocation_step( # Assert assert isinstance(response, GetInvocationStepResponse) - mock_aioboto_client.get_invocation_step.assert_called_once() + mock_boto_client.get_invocation_step.assert_called_once() @pytest.mark.asyncio async def test_list_invocation_steps( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_list_invocation_steps_response, ): # Arrange - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) request = ListInvocationStepsRequest( @@ -273,19 +273,19 @@ async def test_list_invocation_steps( # Assert assert isinstance(response, ListInvocationStepsResponse) - mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() @pytest.mark.asyncio async def test_list_invocation_steps_by_invocation( self, mock_session_client, - mock_aioboto_client, + mock_boto_client, sample_session_id, sample_invocation_id, sample_list_invocation_steps_response, ): # Arrange - mock_aioboto_client.list_invocation_steps.return_value = ( + mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) request = ListInvocationStepsRequest( @@ -299,4 +299,4 @@ async def test_list_invocation_steps_by_invocation( # Assert assert isinstance(response, ListInvocationStepsResponse) - mock_aioboto_client.list_invocation_steps.assert_called_once() + mock_boto_client.list_invocation_steps.assert_called_once() From 6ab07506c0f4bb6576590d4995f1d64f6b979a5e Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Mon, 5 May 2025 22:24:44 +0200 Subject: [PATCH 09/15] added unit tests --- .../langgraph_checkpoint_aws/async_session.py | 28 ++----------------- .../langgraph_checkpoint_aws/utils.py | 18 +++++++++++- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index abb8db3a..de6bc823 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -1,8 +1,4 @@ -import asyncio -from concurrent.futures import ThreadPoolExecutor -from functools import partial -from contextvars import copy_context -from typing import Any, Callable, Optional, TypeVar, cast +from typing import Any, Optional import boto3 from botocore.config import Config @@ -27,27 +23,7 @@ PutInvocationStepRequest, PutInvocationStepResponse, ) -from langgraph_checkpoint_aws.utils import process_aws_client_args, to_boto_params - -T = TypeVar('T') - -async def run_boto3_in_executor( - func: Callable[..., T], - *args: Any, - **kwargs: Any -) -> T: - """Run a boto3 function in an executor to prevent blocking the event loop.""" - loop = asyncio.get_running_loop() - ctx = copy_context() - - def wrapper(): - try: - # Execute the actual boto3 call with parameters inside the executor - return func(*args, **kwargs) - except StopIteration as exc: - raise RuntimeError from exc - - return await loop.run_in_executor(None, ctx.run, wrapper) +from langgraph_checkpoint_aws.utils import process_aws_client_args, to_boto_params, run_boto3_in_executor class AsyncBedrockAgentRuntimeSessionClient: diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py index e09d9d5c..4c947f3c 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py @@ -2,8 +2,11 @@ import hashlib import json import uuid +import asyncio +from functools import partial +from contextvars import copy_context from collections.abc import Sequence -from typing import Any, Optional, Tuple, Union, cast +from typing import Any, Optional, Tuple, Union, Callable, TypeVar, cast from botocore.config import Config from langchain_core.runnables import RunnableConfig @@ -26,6 +29,7 @@ SessionPendingWrite, ) +T = TypeVar('T') def to_boto_params(model: BaseModel) -> dict: """ @@ -444,3 +448,15 @@ def create_client_config(config: Optional[Config] = None) -> Config: new_user_agent = f"{existing_user_agent} md/sdk_user_agent/{SDK_USER_AGENT}".strip() return Config(user_agent_extra=new_user_agent, **config_kwargs) + +async def run_boto3_in_executor( + func: Callable[..., T], + *args: Any, + **kwargs: Any +) -> T: + """Run a boto3 function in an executor to prevent blocking the event loop.""" + + return await asyncio.get_running_loop().run_in_executor( + None, + cast("Callable[..., T]", partial(copy_context().run, lambda: func(*args, **kwargs))), + ) \ No newline at end of file From 8d97f830f0dd45748780bf0faae662c082496d83 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 6 May 2025 15:12:00 +0200 Subject: [PATCH 10/15] added integration tests --- .../saver/test_async_saver.py | 130 ++++++++++++++++++ .../tests/unit_tests/conftest.py | 1 - 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py diff --git a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py new file mode 100644 index 00000000..766418a6 --- /dev/null +++ b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py @@ -0,0 +1,130 @@ +import datetime +from typing import Literal + +import pytest +from langchain_aws import ChatBedrock +from langchain_core.tools import tool +from langgraph.checkpoint.base import Checkpoint, uuid6 +from langgraph.prebuilt import create_react_agent + +from langgraph_checkpoint_aws.async_saver import AsyncBedrockSessionSaver +from langgraph_checkpoint_aws.models import EndSessionRequest, DeleteSessionRequest + + +@tool +def get_weather(city: Literal["nyc", "sf"]): + """Use this to get weather information.""" + if city == "nyc": + return "It might be cloudy in nyc" + elif city == "sf": + return "It's always sunny in sf" + else: + raise AssertionError("Unknown city") + + +class TestAsyncBedrockMemorySaver: + @pytest.fixture + def tools(self): + # Setup tools + return [get_weather] + + @pytest.fixture + def model(self): + # Setup model + return ChatBedrock( + model="anthropic.claude-3-sonnet-20240229-v1:0", region="us-west-2" + ) + + @pytest.fixture + def session_saver(self): + # Return the instantiated object + return AsyncBedrockSessionSaver(region_name="us-west-2") + + @pytest.fixture + def boto_session_client(self, session_saver): + # Return the async client wrapper + return session_saver.session_client + + @pytest.mark.asyncio + async def test_weather_tool_responses(self): + # Test weather tool directly + assert get_weather.invoke("sf") == "It's always sunny in sf" + assert get_weather.invoke("nyc") == "It might be cloudy in nyc" + + @pytest.mark.asyncio + async def test_checkpoint_save_and_retrieve(self, boto_session_client, session_saver): + # Create session + session_response = await boto_session_client.create_session() + session_id = session_response.session_id + assert session_id, "Session ID should not be empty" + + config = {"configurable": {"thread_id": session_id, "checkpoint_ns": ""}} + checkpoint = Checkpoint( + v=1, + id=str(uuid6(clock_seq=-2)), + ts=datetime.datetime.now(datetime.timezone.utc).isoformat(), + channel_values={"key": "value"}, + channel_versions={}, + versions_seen={}, + pending_sends=[], + ) + checkpoint_metadata = {"source": "input", "step": 1, "writes": {"key": "value"}} + + try: + saved_config = await session_saver.aput( + config, + checkpoint, + checkpoint_metadata, + {}, + ) + assert saved_config == { + "configurable": { + "checkpoint_id": checkpoint["id"], + "checkpoint_ns": "", + "thread_id": session_id, + } + } + + checkpoint_tuple = await session_saver.aget_tuple(saved_config) + assert checkpoint_tuple.checkpoint == checkpoint + assert checkpoint_tuple.metadata == checkpoint_metadata + assert checkpoint_tuple.config == saved_config + + finally: + # Create proper request objects + await boto_session_client.end_session(EndSessionRequest(session_identifier=session_id)) + await boto_session_client.delete_session(DeleteSessionRequest(session_identifier=session_id)) + + @pytest.mark.asyncio + async def test_weather_query_and_checkpointing( + self, boto_session_client, tools, model, session_saver + ): + # Create session + session_response = await boto_session_client.create_session() + session_id = session_response.session_id + assert session_id, "Session ID should not be empty" + try: + # Create graph and config + graph = create_react_agent(model, tools=tools, checkpointer=session_saver) + config = {"configurable": {"thread_id": session_id}} + + # Test weather query + response = await graph.ainvoke( + {"messages": [("human", "what's the weather in sf")]}, config + ) + assert response, "Response should not be empty" + + # Test checkpoint retrieval + checkpoint = await session_saver.aget(config) + assert checkpoint, "Checkpoint should not be empty" + + # Test checkpoint listing + checkpoint_tuples = [tup async for tup in session_saver.alist(config)] + assert checkpoint_tuples, "Checkpoint tuples should not be empty" + assert isinstance( + checkpoint_tuples, list + ), "Checkpoint tuples should be a list" + finally: + # Create proper request objects + await boto_session_client.end_session(EndSessionRequest(session_identifier=session_id)) + await boto_session_client.delete_session(DeleteSessionRequest(session_identifier=session_id)) \ No newline at end of file diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py index 1e22ba88..1aa57437 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py @@ -6,7 +6,6 @@ import pytest from botocore.client import BaseClient -from aiobotocore.client import AioBaseClient from langgraph.checkpoint.base import Checkpoint, CheckpointMetadata from langgraph.constants import TASKS From 021fa68fba4c22a89f2662f17278c2cfa040f0b4 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 6 May 2025 15:15:28 +0200 Subject: [PATCH 11/15] added integration tests --- libs/aws/langchain_aws/chat_models/bedrock_converse.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/aws/langchain_aws/chat_models/bedrock_converse.py b/libs/aws/langchain_aws/chat_models/bedrock_converse.py index 634613f4..70d22a4c 100644 --- a/libs/aws/langchain_aws/chat_models/bedrock_converse.py +++ b/libs/aws/langchain_aws/chat_models/bedrock_converse.py @@ -532,9 +532,6 @@ def set_disable_streaming(cls, values: Dict) -> Any: or # Cohere Command R models (provider == "cohere" and "command-r" in model_id_lower) - or - # Writer Palmyra models - (provider == "writer" and "palmyra" in model_id_lower) ): streaming_support = True elif ( From d12c2519f3f9114f06922f0a536e886591ad6cfe Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 6 May 2025 16:13:16 +0200 Subject: [PATCH 12/15] Added async checkpointer class: AsyncBedrockSessionSaver --- .../langgraph_checkpoint_aws/async_saver.py | 10 +- .../langgraph_checkpoint_aws/async_session.py | 45 +++--- .../langgraph_checkpoint_aws/utils.py | 19 +-- .../saver/test_async_saver.py | 26 ++-- .../integration_tests/saver/test_saver.py | 6 +- .../tests/unit_tests/conftest.py | 3 +- .../tests/unit_tests/test_async_saver.py | 134 ++++++++++++------ 7 files changed, 153 insertions(+), 90 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py index 73a248e0..8feaf3b6 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py @@ -251,7 +251,9 @@ async def _get_checkpoint_step( InvocationStep if found, None otherwise """ if checkpoint_id is None: - step = await self._find_most_recent_checkpoint_step(thread_id, invocation_id) + step = await self._find_most_recent_checkpoint_step( + thread_id, invocation_id + ) if step is None: return None return step @@ -519,7 +521,9 @@ async def alist( ) ) - payload = json.loads(step_detail.invocation_step.payload.content_blocks[0].text) + payload = json.loads( + step_detail.invocation_step.payload.content_blocks[0].text + ) # Append checkpoints and ignore writes if payload["step_type"] != CHECKPOINT_PREFIX: @@ -566,4 +570,4 @@ async def alist( pending_write_ops, task_sends, self.serde, - ) \ No newline at end of file + ) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index de6bc823..67f08c08 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -23,7 +23,11 @@ PutInvocationStepRequest, PutInvocationStepResponse, ) -from langgraph_checkpoint_aws.utils import process_aws_client_args, to_boto_params, run_boto3_in_executor +from langgraph_checkpoint_aws.utils import ( + process_aws_client_args, + to_boto_params, + run_boto3_in_executor, +) class AsyncBedrockAgentRuntimeSessionClient: @@ -53,44 +57,40 @@ def __init__( endpoint_url, config, ) - + # Create a standard boto3 session self.session = boto3.Session(**_session_kwargs) # Pre-create the client to avoid creating it for each operation - self.client = self.session.client("bedrock-agent-runtime", **self._client_kwargs) - + self.client = self.session.client( + "bedrock-agent-runtime", **self._client_kwargs + ) + async def create_session( self, request: Optional[CreateSessionRequest] = None ) -> CreateSessionResponse: """Create a new session asynchronously""" params = to_boto_params(request) if request else {} - response = await run_boto3_in_executor( - self.client.create_session, - **params - ) + response = await run_boto3_in_executor(self.client.create_session, **params) return CreateSessionResponse(**response) async def get_session(self, request: GetSessionRequest) -> GetSessionResponse: """Get details of an existing session asynchronously""" response = await run_boto3_in_executor( - self.client.get_session, - **to_boto_params(request) + self.client.get_session, **to_boto_params(request) ) return GetSessionResponse(**response) async def end_session(self, request: EndSessionRequest) -> EndSessionResponse: """End an existing session asynchronously""" response = await run_boto3_in_executor( - self.client.end_session, - **to_boto_params(request) + self.client.end_session, **to_boto_params(request) ) return EndSessionResponse(**response) async def delete_session(self, request: DeleteSessionRequest) -> None: """Delete an existing session asynchronously""" await run_boto3_in_executor( - self.client.delete_session, - **to_boto_params(request) + self.client.delete_session, **to_boto_params(request) ) async def create_invocation( @@ -98,8 +98,7 @@ async def create_invocation( ) -> CreateInvocationResponse: """Create a new invocation asynchronously""" response = await run_boto3_in_executor( - self.client.create_invocation, - **to_boto_params(request) + self.client.create_invocation, **to_boto_params(request) ) return CreateInvocationResponse(**response) @@ -108,8 +107,7 @@ async def list_invocations( ) -> ListInvocationsResponse: """List invocations for a session asynchronously""" response = await run_boto3_in_executor( - self.client.list_invocations, - **to_boto_params(request) + self.client.list_invocations, **to_boto_params(request) ) return ListInvocationsResponse(**response) @@ -118,8 +116,7 @@ async def put_invocation_step( ) -> PutInvocationStepResponse: """Put a step in an invocation asynchronously""" response = await run_boto3_in_executor( - self.client.put_invocation_step, - **to_boto_params(request) + self.client.put_invocation_step, **to_boto_params(request) ) return PutInvocationStepResponse(**response) @@ -128,8 +125,7 @@ async def get_invocation_step( ) -> GetInvocationStepResponse: """Get a step in an invocation asynchronously""" response = await run_boto3_in_executor( - self.client.get_invocation_step, - **to_boto_params(request) + self.client.get_invocation_step, **to_boto_params(request) ) return GetInvocationStepResponse(**response) @@ -138,7 +134,6 @@ async def list_invocation_steps( ) -> ListInvocationStepsResponse: """List steps in an invocation asynchronously""" response = await run_boto3_in_executor( - self.client.list_invocation_steps, - **to_boto_params(request) + self.client.list_invocation_steps, **to_boto_params(request) ) - return ListInvocationStepsResponse(**response) \ No newline at end of file + return ListInvocationStepsResponse(**response) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py index 4c947f3c..e8bb7412 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py @@ -29,7 +29,8 @@ SessionPendingWrite, ) -T = TypeVar('T') +T = TypeVar("T") + def to_boto_params(model: BaseModel) -> dict: """ @@ -449,14 +450,14 @@ def create_client_config(config: Optional[Config] = None) -> Config: return Config(user_agent_extra=new_user_agent, **config_kwargs) -async def run_boto3_in_executor( - func: Callable[..., T], - *args: Any, - **kwargs: Any -) -> T: + +async def run_boto3_in_executor(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: """Run a boto3 function in an executor to prevent blocking the event loop.""" return await asyncio.get_running_loop().run_in_executor( - None, - cast("Callable[..., T]", partial(copy_context().run, lambda: func(*args, **kwargs))), - ) \ No newline at end of file + None, + cast( + "Callable[..., T]", + partial(copy_context().run, lambda: func(*args, **kwargs)), + ), + ) diff --git a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py index 766418a6..3391d277 100644 --- a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py +++ b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py @@ -52,7 +52,9 @@ async def test_weather_tool_responses(self): assert get_weather.invoke("nyc") == "It might be cloudy in nyc" @pytest.mark.asyncio - async def test_checkpoint_save_and_retrieve(self, boto_session_client, session_saver): + async def test_checkpoint_save_and_retrieve( + self, boto_session_client, session_saver + ): # Create session session_response = await boto_session_client.create_session() session_id = session_response.session_id @@ -92,8 +94,12 @@ async def test_checkpoint_save_and_retrieve(self, boto_session_client, session_s finally: # Create proper request objects - await boto_session_client.end_session(EndSessionRequest(session_identifier=session_id)) - await boto_session_client.delete_session(DeleteSessionRequest(session_identifier=session_id)) + await boto_session_client.end_session( + EndSessionRequest(session_identifier=session_id) + ) + await boto_session_client.delete_session( + DeleteSessionRequest(session_identifier=session_id) + ) @pytest.mark.asyncio async def test_weather_query_and_checkpointing( @@ -121,10 +127,14 @@ async def test_weather_query_and_checkpointing( # Test checkpoint listing checkpoint_tuples = [tup async for tup in session_saver.alist(config)] assert checkpoint_tuples, "Checkpoint tuples should not be empty" - assert isinstance( - checkpoint_tuples, list - ), "Checkpoint tuples should be a list" + assert isinstance(checkpoint_tuples, list), ( + "Checkpoint tuples should be a list" + ) finally: # Create proper request objects - await boto_session_client.end_session(EndSessionRequest(session_identifier=session_id)) - await boto_session_client.delete_session(DeleteSessionRequest(session_identifier=session_id)) \ No newline at end of file + await boto_session_client.end_session( + EndSessionRequest(session_identifier=session_id) + ) + await boto_session_client.delete_session( + DeleteSessionRequest(session_identifier=session_id) + ) diff --git a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_saver.py b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_saver.py index 8f54ff00..e2dab0d7 100644 --- a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_saver.py +++ b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_saver.py @@ -113,9 +113,9 @@ def test_weather_query_and_checkpointing( # Test checkpoint listing checkpoint_tuples = list(session_saver.list(config)) assert checkpoint_tuples, "Checkpoint tuples should not be empty" - assert isinstance( - checkpoint_tuples, list - ), "Checkpoint tuples should be a list" + assert isinstance(checkpoint_tuples, list), ( + "Checkpoint tuples should be a list" + ) finally: boto_session_client.end_session(sessionIdentifier=session_id) boto_session_client.delete_session(sessionIdentifier=session_id) diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py index 1aa57437..02b4bf83 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py @@ -17,6 +17,7 @@ SessionPendingWrite, ) + @pytest.fixture def mock_boto_client(): mock_client = Mock(spec=BaseClient) @@ -227,7 +228,7 @@ def sample_session_checkpoint(sample_invocation_step_summary): thread_id=sample_invocation_step_summary["sessionId"], checkpoint_ns=sample_invocation_step_summary["invocationId"], checkpoint_id=sample_invocation_step_summary["invocationStepId"], - checkpoint=('json', b'e30='), + checkpoint=("json", b"e30="), metadata=json.dumps({"key": "value"}), parent_checkpoint_id=None, channel_values={}, diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py index 6385ae1f..ac802431 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py @@ -55,7 +55,9 @@ async def test__create_session_invocation_success( mock_boto_client.create_invocation.assert_called_once() @pytest.mark.asyncio - async def test__create_session_invocation_conflict(self, mock_boto_client, session_saver): + async def test__create_session_invocation_conflict( + self, mock_boto_client, session_saver + ): # Arrange error_response = {"Error": {"Code": "ConflictException", "Message": "Conflict"}} mock_boto_client.create_invocation.side_effect = ClientError( @@ -139,12 +141,12 @@ async def test__get_checkpoint_pending_writes_no_invocation_steps( mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) - + # Act result = await session_saver._get_checkpoint_pending_writes( "thread_id", "ns", "checkpoint_id" ) - + # Assert assert result == [] mock_boto_client.list_invocation_steps.assert_called_once() @@ -154,17 +156,22 @@ async def test__get_checkpoint_pending_writes_resource_not_found( self, mock_boto_client, session_saver ): # Arrange - error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} + error_response = { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Resource not found", + } + } mock_boto_client.list_invocation_steps.side_effect = ClientError( error_response=error_response, operation_name="ListInvocationSteps", ) - + # Act result = await session_saver._get_checkpoint_pending_writes( "thread_id", "ns", "checkpoint_id" ) - + # Assert assert result == [] mock_boto_client.list_invocation_steps.assert_called_once() @@ -185,7 +192,7 @@ async def test__get_checkpoint_pending_writes_client_error( await session_saver._get_checkpoint_pending_writes( "thread_id", "ns", "checkpoint_id" ) - + mock_boto_client.list_invocation_steps.assert_called_once() @pytest.mark.asyncio @@ -234,7 +241,7 @@ async def test__save_invocation_step_client_error( await session_saver._save_invocation_step( "thread_id", "inv_id", "step_id", sample_invocation_step_payload ) - + mock_boto_client.put_invocation_step.assert_called_once() @pytest.mark.asyncio @@ -317,10 +324,12 @@ async def test__find_most_recent_checkpoint_step_no_invocation_steps( mock_boto_client.list_invocation_steps.return_value = ( sample_list_invocation_steps_response ) - + # Act - result = await session_saver._find_most_recent_checkpoint_step("thread_id", "ns") - + result = await session_saver._find_most_recent_checkpoint_step( + "thread_id", "ns" + ) + # Assert assert result is None mock_boto_client.list_invocation_steps.assert_called_once() @@ -342,7 +351,9 @@ async def test__get_checkpoint_step_with_checkpoint_id( ) # Act - await session_saver._get_checkpoint_step(thread_id, checkpoint_ns, checkpoint_id) + await session_saver._get_checkpoint_step( + thread_id, checkpoint_ns, checkpoint_id + ) # Assert session_saver._find_most_recent_checkpoint_step.assert_not_called() @@ -476,7 +487,9 @@ async def test_aget_tuple_success( ][0]["text"] = sample_session_checkpoint.model_dump_json() # Mock all required internal methods - session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._generate_checkpoint_id = AsyncMock( + return_value="test_checkpoint_id" + ) session_saver._get_checkpoint_step = AsyncMock( return_value=InvocationStep( **sample_get_invocation_step_response["invocationStep"] @@ -494,7 +507,6 @@ async def test_aget_tuple_success( # Assert assert isinstance(result, CheckpointTuple) - @pytest.mark.asyncio async def test_aget_tuple_success_empty(self, session_saver, runnable_config): # Arrange @@ -508,9 +520,16 @@ async def test_aget_tuple_success_empty(self, session_saver, runnable_config): session_saver._get_checkpoint_step.assert_called_once() @pytest.mark.asyncio - async def test_aget_tuple_resource_not_found_error(self, session_saver, runnable_config): + async def test_aget_tuple_resource_not_found_error( + self, session_saver, runnable_config + ): # Arrange - error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} + error_response = { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Resource not found", + } + } session_saver._get_checkpoint_step = AsyncMock( side_effect=ClientError( error_response=error_response, @@ -528,7 +547,9 @@ async def test_aget_tuple_resource_not_found_error(self, session_saver, runnable @pytest.mark.asyncio async def test_aget_tuple_error(self, session_saver, runnable_config): # Arrange - error_response = {"Error": {"Code": "SomeOtherError", "Message": "Some other error"}} + error_response = { + "Error": {"Code": "SomeOtherError", "Message": "Some other error"} + } session_saver._get_checkpoint_step = AsyncMock( side_effect=ClientError( error_response=error_response, @@ -539,7 +560,7 @@ async def test_aget_tuple_error(self, session_saver, runnable_config): # Act and Assert with pytest.raises(ClientError): await session_saver.aget_tuple(runnable_config) - + session_saver._get_checkpoint_step.assert_called_once() @pytest.mark.asyncio @@ -556,8 +577,8 @@ async def test_aput_success( # Act await session_saver.aput( - runnable_config, sample_checkpoint, sample_checkpoint_metadata, {} - ) + runnable_config, sample_checkpoint, sample_checkpoint_metadata, {} + ) # Assert session_saver._create_session_invocation.assert_called_once_with( @@ -678,7 +699,7 @@ async def test_aput_writes_override_existing_writes( None, ANY, ) - + @pytest.mark.asyncio @patch("langgraph_checkpoint_aws.async_saver.construct_checkpoint_tuple") async def test_alist_success( @@ -696,7 +717,9 @@ async def test_alist_success( ][0]["text"] = sample_session_checkpoint.model_dump_json() # Mock all required internal methods - session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._generate_checkpoint_id = AsyncMock( + return_value="test_checkpoint_id" + ) session_saver.session_client.get_invocation_step = AsyncMock( return_value=GetInvocationStepResponse( **sample_get_invocation_step_response @@ -712,7 +735,9 @@ async def test_alist_success( mock_construct_checkpoint.return_value = AsyncMock(spec=CheckpointTuple) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + result = [ + checkpoint async for checkpoint in session_saver.alist(runnable_config) + ] # Assert assert len(list(result)) == 1 @@ -732,7 +757,9 @@ async def test_alist_skips_writes( ][0]["text"] = sample_session_pending_write.model_dump_json() # Mock all required internal methods - session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._generate_checkpoint_id = AsyncMock( + return_value="test_checkpoint_id" + ) session_saver.session_client.get_invocation_step = AsyncMock( return_value=GetInvocationStepResponse( **sample_get_invocation_step_response @@ -745,13 +772,13 @@ async def test_alist_skips_writes( ) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + result = [ + checkpoint async for checkpoint in session_saver.alist(runnable_config) + ] # Assert assert len(list(result)) == 0 - - @pytest.mark.asyncio @patch("langgraph_checkpoint_aws.async_saver.construct_checkpoint_tuple") async def test_alist_with_limit( @@ -769,7 +796,9 @@ async def test_alist_with_limit( ][0]["text"] = sample_session_checkpoint.model_dump_json() # Mock all required internal methods - session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._generate_checkpoint_id = AsyncMock( + return_value="test_checkpoint_id" + ) session_saver.session_client.get_invocation_step = AsyncMock( return_value=GetInvocationStepResponse( **sample_get_invocation_step_response @@ -787,7 +816,10 @@ async def test_alist_with_limit( mock_construct_checkpoint.return_value = AsyncMock(spec=CheckpointTuple) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config, limit=3)] + result = [ + checkpoint + async for checkpoint in session_saver.alist(runnable_config, limit=3) + ] # Assert assert len(list(result)) == 3 @@ -807,7 +839,9 @@ async def test_alist_with_filter( ][0]["text"] = sample_session_checkpoint.model_dump_json() # Mock all required internal methods - session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._generate_checkpoint_id = AsyncMock( + return_value="test_checkpoint_id" + ) session_saver.session_client.get_invocation_step = AsyncMock( return_value=GetInvocationStepResponse( **sample_get_invocation_step_response @@ -825,8 +859,12 @@ async def test_alist_with_filter( ) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config, filter={"key": "value1"})] - + result = [ + checkpoint + async for checkpoint in session_saver.alist( + runnable_config, filter={"key": "value1"} + ) + ] # Assert assert len(list(result)) == 0 @@ -856,7 +894,9 @@ async def test_alist_with_before( ][0]["text"] = sample_session_checkpoint.model_dump_json() # Mock all required internal methods - session_saver._generate_checkpoint_id = AsyncMock(return_value="test_checkpoint_id") + session_saver._generate_checkpoint_id = AsyncMock( + return_value="test_checkpoint_id" + ) session_saver.session_client.get_invocation_step = AsyncMock( return_value=GetInvocationStepResponse( **sample_get_invocation_step_response @@ -869,7 +909,10 @@ async def test_alist_with_before( ) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config, before=before)] + result = [ + checkpoint + async for checkpoint in session_saver.alist(runnable_config, before=before) + ] # Assert assert len(list(result)) == 0 @@ -886,7 +929,9 @@ async def test_alist_empty_response( ) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + result = [ + checkpoint async for checkpoint in session_saver.alist(runnable_config) + ] # Assert assert len(result) == 0 @@ -899,7 +944,12 @@ async def test_alist_returns_empty_on_resource_not_found( runnable_config, ): # Arrange - error_response = {"Error": {"Code": "ResourceNotFoundException", "Message": "Resource not found"}} + error_response = { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Resource not found", + } + } session_saver.session_client.list_invocation_steps = AsyncMock( side_effect=ClientError( error_response=error_response, @@ -908,7 +958,9 @@ async def test_alist_returns_empty_on_resource_not_found( ) # Act - result = [checkpoint async for checkpoint in session_saver.alist(runnable_config)] + result = [ + checkpoint async for checkpoint in session_saver.alist(runnable_config) + ] # Assert assert len(result) == 0 @@ -921,7 +973,9 @@ async def test_alist_error( runnable_config, ): # Arrange - error_response = {"Error": {"Code": "SomeOtherError", "Message": "Some other error"}} + error_response = { + "Error": {"Code": "SomeOtherError", "Message": "Some other error"} + } session_saver.session_client.list_invocation_steps = AsyncMock( side_effect=ClientError( error_response=error_response, @@ -933,7 +987,5 @@ async def test_alist_error( with pytest.raises(ClientError): async for _ in session_saver.alist(runnable_config): pass - - session_saver.session_client.list_invocation_steps.assert_called_once() - + session_saver.session_client.list_invocation_steps.assert_called_once() From 97eb01114770ef6895da673de0c586480f9365c3 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 6 May 2025 16:28:05 +0200 Subject: [PATCH 13/15] Added usage example in the readme --- libs/langgraph-checkpoint-aws/README.md | 30 ++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/libs/langgraph-checkpoint-aws/README.md b/libs/langgraph-checkpoint-aws/README.md index 56ea921d..878a7b85 100644 --- a/libs/langgraph-checkpoint-aws/README.md +++ b/libs/langgraph-checkpoint-aws/README.md @@ -53,9 +53,37 @@ config = {"configurable": {"thread_id": session_id}} graph.invoke(1, config) ``` + +when invoking the graph asynchronously + +```python +from langgraph.graph import StateGraph +from langgraph_checkpoint_aws.async_saver import AsyncBedrockSessionSaver + +# Initialize the saver +session_saver = AsyncBedrockSessionSaver( + region_name="us-west-2", # Your AWS region + credentials_profile_name="default", # Optional: AWS credentials profile +) + +# Create a session +session_create_response = await session_saver.session_client.create_session() +session_id = session_response.session_id + +# Use with LangGraph +builder = StateGraph(int) +builder.add_node("add_one", lambda x: x + 1) +builder.set_entry_point("add_one") +builder.set_finish_point("add_one") + +graph = builder.compile(checkpointer=session_saver) +config = {"configurable": {"thread_id": session_id}} +graph.ainvoke(1, config) +``` + ## Configuration Options -`BedrockSessionSaver` accepts the following parameters: +`BedrockSessionSaver` and `AsyncBedrockSessionSaver` accepts the following parameters: ```python def __init__( From f4b44d520757457effe4dea4d90b68ee24d2fcf3 Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 6 May 2025 20:28:07 +0200 Subject: [PATCH 14/15] fixed linting issues --- .../langgraph_checkpoint_aws/async_saver.py | 49 +++++++------------ .../langgraph_checkpoint_aws/async_session.py | 45 ++++++++--------- .../langgraph_checkpoint_aws/utils.py | 29 +++++------ 3 files changed, 49 insertions(+), 74 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py index 8feaf3b6..8039778b 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py @@ -6,39 +6,26 @@ from botocore.config import Config from botocore.exceptions import ClientError from langchain_core.runnables import RunnableConfig -from langgraph.checkpoint.base import ( - BaseCheckpointSaver, - ChannelVersions, - Checkpoint, - CheckpointMetadata, - CheckpointTuple, - get_checkpoint_id, -) -from pydantic import SecretStr - +from langgraph.checkpoint.base import (BaseCheckpointSaver, ChannelVersions, + Checkpoint, CheckpointMetadata, + CheckpointTuple, get_checkpoint_id) +from langgraph_checkpoint_aws.async_session import \ + AsyncBedrockAgentRuntimeSessionClient from langgraph_checkpoint_aws.constants import CHECKPOINT_PREFIX -from langgraph_checkpoint_aws.models import ( - BedrockSessionContentBlock, - CreateInvocationRequest, - GetInvocationStepRequest, - InvocationStep, - InvocationStepPayload, - ListInvocationStepsRequest, - PutInvocationStepRequest, - SessionCheckpoint, - SessionPendingWrite, -) -from langgraph_checkpoint_aws.async_session import AsyncBedrockAgentRuntimeSessionClient +from langgraph_checkpoint_aws.models import (BedrockSessionContentBlock, + CreateInvocationRequest, + GetInvocationStepRequest, + InvocationStep, + InvocationStepPayload, + ListInvocationStepsRequest, + PutInvocationStepRequest, + SessionCheckpoint, + SessionPendingWrite) from langgraph_checkpoint_aws.utils import ( - construct_checkpoint_tuple, - create_session_checkpoint, - deserialize_data, - generate_checkpoint_id, - generate_write_id, - process_write_operations, - process_writes_invocation_content_blocks, - transform_pending_task_writes, -) + construct_checkpoint_tuple, create_session_checkpoint, deserialize_data, + generate_checkpoint_id, generate_write_id, process_write_operations, + process_writes_invocation_content_blocks, transform_pending_task_writes) +from pydantic import SecretStr class AsyncBedrockSessionSaver(BaseCheckpointSaver): diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index 67f08c08..b572ff21 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -2,33 +2,28 @@ import boto3 from botocore.config import Config +from langgraph_checkpoint_aws.models import (CreateInvocationRequest, + CreateInvocationResponse, + CreateSessionRequest, + CreateSessionResponse, + DeleteSessionRequest, + EndSessionRequest, + EndSessionResponse, + GetInvocationStepRequest, + GetInvocationStepResponse, + GetSessionRequest, + GetSessionResponse, + ListInvocationsRequest, + ListInvocationsResponse, + ListInvocationStepsRequest, + ListInvocationStepsResponse, + PutInvocationStepRequest, + PutInvocationStepResponse) +from langgraph_checkpoint_aws.utils import (process_aws_client_args, + run_boto3_in_executor, + to_boto_params) from pydantic import SecretStr -from langgraph_checkpoint_aws.models import ( - CreateInvocationRequest, - CreateInvocationResponse, - CreateSessionRequest, - CreateSessionResponse, - DeleteSessionRequest, - EndSessionRequest, - EndSessionResponse, - GetInvocationStepRequest, - GetInvocationStepResponse, - GetSessionRequest, - GetSessionResponse, - ListInvocationsRequest, - ListInvocationsResponse, - ListInvocationStepsRequest, - ListInvocationStepsResponse, - PutInvocationStepRequest, - PutInvocationStepResponse, -) -from langgraph_checkpoint_aws.utils import ( - process_aws_client_args, - to_boto_params, - run_boto3_in_executor, -) - class AsyncBedrockAgentRuntimeSessionClient: """ diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py index e8bb7412..5d845459 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py @@ -1,33 +1,26 @@ +import asyncio import base64 import hashlib import json import uuid -import asyncio -from functools import partial -from contextvars import copy_context from collections.abc import Sequence -from typing import Any, Optional, Tuple, Union, Callable, TypeVar, cast +from contextvars import copy_context +from functools import partial +from typing import Any, Callable, Optional, Tuple, TypeVar, Union, cast from botocore.config import Config from langchain_core.runnables import RunnableConfig -from langgraph.checkpoint.base import ( - WRITES_IDX_MAP, - ChannelVersions, - Checkpoint, - CheckpointMetadata, - CheckpointTuple, -) +from langgraph.checkpoint.base import (WRITES_IDX_MAP, ChannelVersions, + Checkpoint, CheckpointMetadata, + CheckpointTuple) from langgraph.checkpoint.serde.base import SerializerProtocol from langgraph.constants import TASKS -from pydantic import BaseModel - from langgraph_checkpoint_aws import SDK_USER_AGENT from langgraph_checkpoint_aws.constants import CHECKPOINT_PREFIX, WRITES_PREFIX -from langgraph_checkpoint_aws.models import ( - BedrockSessionContentBlock, - SessionCheckpoint, - SessionPendingWrite, -) +from langgraph_checkpoint_aws.models import (BedrockSessionContentBlock, + SessionCheckpoint, + SessionPendingWrite) +from pydantic import BaseModel T = TypeVar("T") From b531dd678a64f8788e90a8cdced5719392438e7a Mon Sep 17 00:00:00 2001 From: Edvin Hallvaxhiu Date: Tue, 6 May 2025 20:37:54 +0200 Subject: [PATCH 15/15] fixed linting issues --- .../langgraph_checkpoint_aws/async_saver.py | 49 ++++++++++++------- .../langgraph_checkpoint_aws/async_session.py | 45 +++++++++-------- .../langgraph_checkpoint_aws/utils.py | 21 +++++--- .../saver/test_async_saver.py | 2 +- .../tests/unit_tests/conftest.py | 2 +- .../tests/unit_tests/test_async_saver.py | 10 ++-- .../tests/unit_tests/test_async_session.py | 2 +- 7 files changed, 78 insertions(+), 53 deletions(-) diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py index 8039778b..2235724f 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_saver.py @@ -6,26 +6,39 @@ from botocore.config import Config from botocore.exceptions import ClientError from langchain_core.runnables import RunnableConfig -from langgraph.checkpoint.base import (BaseCheckpointSaver, ChannelVersions, - Checkpoint, CheckpointMetadata, - CheckpointTuple, get_checkpoint_id) -from langgraph_checkpoint_aws.async_session import \ - AsyncBedrockAgentRuntimeSessionClient +from langgraph.checkpoint.base import ( + BaseCheckpointSaver, + ChannelVersions, + Checkpoint, + CheckpointMetadata, + CheckpointTuple, + get_checkpoint_id, +) +from pydantic import SecretStr + +from langgraph_checkpoint_aws.async_session import AsyncBedrockAgentRuntimeSessionClient from langgraph_checkpoint_aws.constants import CHECKPOINT_PREFIX -from langgraph_checkpoint_aws.models import (BedrockSessionContentBlock, - CreateInvocationRequest, - GetInvocationStepRequest, - InvocationStep, - InvocationStepPayload, - ListInvocationStepsRequest, - PutInvocationStepRequest, - SessionCheckpoint, - SessionPendingWrite) +from langgraph_checkpoint_aws.models import ( + BedrockSessionContentBlock, + CreateInvocationRequest, + GetInvocationStepRequest, + InvocationStep, + InvocationStepPayload, + ListInvocationStepsRequest, + PutInvocationStepRequest, + SessionCheckpoint, + SessionPendingWrite, +) from langgraph_checkpoint_aws.utils import ( - construct_checkpoint_tuple, create_session_checkpoint, deserialize_data, - generate_checkpoint_id, generate_write_id, process_write_operations, - process_writes_invocation_content_blocks, transform_pending_task_writes) -from pydantic import SecretStr + construct_checkpoint_tuple, + create_session_checkpoint, + deserialize_data, + generate_checkpoint_id, + generate_write_id, + process_write_operations, + process_writes_invocation_content_blocks, + transform_pending_task_writes, +) class AsyncBedrockSessionSaver(BaseCheckpointSaver): diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py index b572ff21..44dcfd70 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/async_session.py @@ -2,28 +2,33 @@ import boto3 from botocore.config import Config -from langgraph_checkpoint_aws.models import (CreateInvocationRequest, - CreateInvocationResponse, - CreateSessionRequest, - CreateSessionResponse, - DeleteSessionRequest, - EndSessionRequest, - EndSessionResponse, - GetInvocationStepRequest, - GetInvocationStepResponse, - GetSessionRequest, - GetSessionResponse, - ListInvocationsRequest, - ListInvocationsResponse, - ListInvocationStepsRequest, - ListInvocationStepsResponse, - PutInvocationStepRequest, - PutInvocationStepResponse) -from langgraph_checkpoint_aws.utils import (process_aws_client_args, - run_boto3_in_executor, - to_boto_params) from pydantic import SecretStr +from langgraph_checkpoint_aws.models import ( + CreateInvocationRequest, + CreateInvocationResponse, + CreateSessionRequest, + CreateSessionResponse, + DeleteSessionRequest, + EndSessionRequest, + EndSessionResponse, + GetInvocationStepRequest, + GetInvocationStepResponse, + GetSessionRequest, + GetSessionResponse, + ListInvocationsRequest, + ListInvocationsResponse, + ListInvocationStepsRequest, + ListInvocationStepsResponse, + PutInvocationStepRequest, + PutInvocationStepResponse, +) +from langgraph_checkpoint_aws.utils import ( + process_aws_client_args, + run_boto3_in_executor, + to_boto_params, +) + class AsyncBedrockAgentRuntimeSessionClient: """ diff --git a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py index 5d845459..44028d99 100644 --- a/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py +++ b/libs/langgraph-checkpoint-aws/langgraph_checkpoint_aws/utils.py @@ -10,17 +10,24 @@ from botocore.config import Config from langchain_core.runnables import RunnableConfig -from langgraph.checkpoint.base import (WRITES_IDX_MAP, ChannelVersions, - Checkpoint, CheckpointMetadata, - CheckpointTuple) +from langgraph.checkpoint.base import ( + WRITES_IDX_MAP, + ChannelVersions, + Checkpoint, + CheckpointMetadata, + CheckpointTuple, +) from langgraph.checkpoint.serde.base import SerializerProtocol from langgraph.constants import TASKS +from pydantic import BaseModel + from langgraph_checkpoint_aws import SDK_USER_AGENT from langgraph_checkpoint_aws.constants import CHECKPOINT_PREFIX, WRITES_PREFIX -from langgraph_checkpoint_aws.models import (BedrockSessionContentBlock, - SessionCheckpoint, - SessionPendingWrite) -from pydantic import BaseModel +from langgraph_checkpoint_aws.models import ( + BedrockSessionContentBlock, + SessionCheckpoint, + SessionPendingWrite, +) T = TypeVar("T") diff --git a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py index 3391d277..faef590f 100644 --- a/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py +++ b/libs/langgraph-checkpoint-aws/tests/integration_tests/saver/test_async_saver.py @@ -8,7 +8,7 @@ from langgraph.prebuilt import create_react_agent from langgraph_checkpoint_aws.async_saver import AsyncBedrockSessionSaver -from langgraph_checkpoint_aws.models import EndSessionRequest, DeleteSessionRequest +from langgraph_checkpoint_aws.models import DeleteSessionRequest, EndSessionRequest @tool diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py index 02b4bf83..a0f1ed34 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/conftest.py @@ -1,7 +1,7 @@ import base64 import datetime import json -from unittest.mock import MagicMock, Mock, AsyncMock +from unittest.mock import AsyncMock, MagicMock, Mock from uuid import uuid4 import pytest diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py index ac802431..3e77bd0c 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_saver.py @@ -1,6 +1,6 @@ import datetime import json -from unittest.mock import ANY, Mock, patch, AsyncMock +from unittest.mock import ANY, AsyncMock, Mock, patch import pytest from botocore.config import Config @@ -10,15 +10,15 @@ from langgraph.constants import ERROR from pydantic import SecretStr +from langgraph_checkpoint_aws.async_saver import ( + AsyncBedrockAgentRuntimeSessionClient, + AsyncBedrockSessionSaver, +) from langgraph_checkpoint_aws.models import ( GetInvocationStepResponse, InvocationStep, ListInvocationStepsResponse, ) -from langgraph_checkpoint_aws.async_saver import ( - AsyncBedrockAgentRuntimeSessionClient, - AsyncBedrockSessionSaver, -) class TestAsyncBedrockSessionSaver: diff --git a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py index c255f729..b7e98d0a 100644 --- a/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py +++ b/libs/langgraph-checkpoint-aws/tests/unit_tests/test_async_session.py @@ -2,6 +2,7 @@ import pytest +from langgraph_checkpoint_aws.async_saver import AsyncBedrockAgentRuntimeSessionClient from langgraph_checkpoint_aws.models import ( CreateInvocationRequest, CreateInvocationResponse, @@ -21,7 +22,6 @@ PutInvocationStepRequest, PutInvocationStepResponse, ) -from langgraph_checkpoint_aws.async_saver import AsyncBedrockAgentRuntimeSessionClient class TestAsyncBedrockAgentRuntimeSessionClient: