From 5b8439285fda9f3877644c711a26bd603445e06d Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Wed, 30 Oct 2024 14:55:44 -0400 Subject: [PATCH 01/16] wip dapr runtime for processes --- python/pyproject.toml | 3 + .../chat_gpt_api_function_calling.py | 69 +++- .../processes/dapr_runtime/__init__.py | 0 .../processes/dapr_runtime/actors/__init__.py | 0 .../dapr_runtime/actors/actor_state_key.py | 27 ++ .../dapr_runtime/actors/event_buffer_actor.py | 61 +++ .../actors/external_event_buffer_actor.py | 62 +++ .../actors/message_buffer_actor.py | 59 +++ .../dapr_runtime/actors/process_actor.py | 228 +++++++++++ .../dapr_runtime/actors/step_actor.py | 370 ++++++++++++++++++ .../dapr_runtime/dapr_kernel_process.py | 40 ++ .../dapr_kernel_process_context.py | 47 +++ .../dapr_runtime/dapr_process_info.py | 57 +++ .../processes/dapr_runtime/dapr_step_info.py | 50 +++ .../processes/dapr_runtime/event_buffer.py | 31 ++ .../dapr_runtime/external_event_buffer.py | 31 ++ .../processes/dapr_runtime/message_buffer.py | 30 ++ .../processes/dapr_runtime/process.py | 57 +++ .../processes/dapr_runtime/step.py | 41 ++ .../processes/local_runtime/local_step.py | 25 +- .../processes/process_event.py | 36 ++ .../processes/process_message.py | 17 + .../processes/process_message_factory.py | 27 ++ .../semantic_kernel/processes/step_utils.py | 29 ++ python/uv.lock | 308 ++------------- 25 files changed, 1379 insertions(+), 326 deletions(-) create mode 100644 python/semantic_kernel/processes/dapr_runtime/__init__.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/__init__.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/event_buffer.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/message_buffer.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/process.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/step.py create mode 100644 python/semantic_kernel/processes/process_event.py create mode 100644 python/semantic_kernel/processes/process_message.py create mode 100644 python/semantic_kernel/processes/process_message_factory.py create mode 100644 python/semantic_kernel/processes/step_utils.py diff --git a/python/pyproject.toml b/python/pyproject.toml index e816bc6b85bc..cf88a64eabe0 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -116,6 +116,9 @@ pandas = [ aws = [ "boto3>=1.28.57", ] +dapr = [ + "dapr>=1.14.0", +] [tool.uv] prerelease = "if-necessary-or-explicit" diff --git a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py index f0381c1048ac..137f9eec0d85 100644 --- a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py +++ b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py @@ -2,8 +2,9 @@ import asyncio import os +from enum import Enum from functools import reduce -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated from semantic_kernel import Kernel from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior @@ -12,30 +13,63 @@ from semantic_kernel.contents.chat_message_content import ChatMessageContent from semantic_kernel.contents.function_call_content import FunctionCallContent from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent -from semantic_kernel.core_plugins.math_plugin import MathPlugin -from semantic_kernel.core_plugins.time_plugin import TimePlugin from semantic_kernel.functions import KernelArguments +from semantic_kernel.functions.kernel_function_decorator import kernel_function if TYPE_CHECKING: from semantic_kernel.functions import KernelFunction +class Coordinates: + lat: float + lon: float + + def __init__(self, lat: float, lon: float): + self.lat = lat + self.lon = lon + + +class Status(Enum): + HOTELS = "hotels" + ATTRACTIONS = "attractions" + RESTAURANTS = "restaurants" + GEOS = "geos" + + +class Location: + name: str + coordinates: Coordinates + status: list[Status] + + def __init__(self, name: str, coordinates: Coordinates, status: list[Status]): + self.name = name + self.coordinates = coordinates + self.status = status + + +class TravelPlugin: + @kernel_function(name="search", description="Provides the coordinates for locations using fuzzy search.") + def search( + self, + query: Annotated[str, "the name of the location to search for"], + coordinates: Annotated[Coordinates, "lat/lon coordinates to search around"], + radius: Annotated[int | None, "the radius to search within in meters"] = 1, + categories: Annotated[list[Status] | None, "categories to search for"] = None, + ) -> list[Location]: + return [ + Location( + name="Space Needle", coordinates=Coordinates(lat=47.6205, lon=-122.3493), status=[Status.ATTRACTIONS] + ), + ] + + system_message = """ -You are a chat bot. Your name is Mosscap and -you have one goal: figure out what people need. -Your full name, should you need to know it, is -Splendid Speckled Mosscap. You communicate -effectively, but you tend to answer with long -flowery prose. You are also a math wizard, -especially for adding and subtracting. -You also excel at joke telling, where your tone is often sarcastic. -Once you have the answer I am looking for, -you will return a full answer to me as soon as possible. +You are a chat bot who helps users find information about travel destinations. """ # This concept example shows how to handle both streaming and non-streaming responses # To toggle the behavior, set the following flag accordingly: -stream = True +stream = False kernel = Kernel() @@ -44,8 +78,9 @@ plugins_directory = os.path.join(__file__, "../../../../../prompt_template_samples/") # adding plugins to the kernel -kernel.add_plugin(MathPlugin(), plugin_name="math") -kernel.add_plugin(TimePlugin(), plugin_name="time") +# kernel.add_plugin(MathPlugin(), plugin_name="math") +# kernel.add_plugin(TimePlugin(), plugin_name="time") +kernel.add_plugin(TravelPlugin(), plugin_name="travel") chat_function = kernel.add_function( prompt="{{$chat_history}}{{$user_input}}", @@ -83,7 +118,7 @@ max_tokens=2000, temperature=0.7, top_p=0.8, - function_choice_behavior=FunctionChoiceBehavior.Auto(auto_invoke=True), + function_choice_behavior=FunctionChoiceBehavior.Auto(filters={"included_plugins": ["travel"]}), ) history = ChatHistory() diff --git a/python/semantic_kernel/processes/dapr_runtime/__init__.py b/python/semantic_kernel/processes/dapr_runtime/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/__init__.py b/python/semantic_kernel/processes/dapr_runtime/actors/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py b/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py new file mode 100644 index 000000000000..86ee082daa91 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft. All rights reserved. + +from enum import Enum + + +class ActorStateKeys(Enum): + """Keys used to store actor state in Dapr.""" + + # StepActor Keys + StepParentProcessId = "parentProcessId" + StepInfoState = "DaprStepInfo" + StepStateJson = "kernelStepStateJson" + StepStateType = "kernelStepStateType" + StepIncomingMessagesState = "incomingMessagesState" + + # ProcessActor Keys + ProcessInfoState = "DaprProcessInfo" + StepActivatedState = "kernelStepActivated" + + # MessageBufferActor Keys + MessageQueueState = "DaprMessageBufferState" + + # ExternalEventBufferActor Keys + ExternalEventQueueState = "DaprExternalEventBufferState" + + # EventBufferActor Keys + EventQueueState = "DaprEventBufferState" diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py new file mode 100644 index 000000000000..e816e35f27f8 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py @@ -0,0 +1,61 @@ +# Copyright (c) Microsoft. All rights reserved. + +from queue import Queue +from typing import TYPE_CHECKING + +from dapr.actor import Actor, ActorId +from dapr.actor.runtime.context import ActorRuntimeContext +from pydantic import Field + +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer + +if TYPE_CHECKING: + from semantic_kernel.processes.process_message import ProcessMessage + + +class EventBufferActor(Actor, MessageBuffer, KernelBaseModel): + """Represents a message buffer actor that follows the MessageBuffer abstract class.""" + + queue: Queue = Field(default_factory=Queue) + + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): + """Initializes a new instance of StepActor.""" + super().__init__(ctx, actor_id) + + async def enqueue(self, message: "ProcessMessage") -> None: + """Enqueues a message event into the buffer. + + Args: + message: The message event to enqueue. + """ + self.queue.put(message) + + await self._state_manager.add_or_update_state(ActorStateKeys.EventQueueState.value, self.queue) + await self._state_manager.save_state() + + async def dequeue_all(self) -> "list[ProcessMessage]": + """Dequeues all process events from the buffer. + + Returns: + The dequeued message event. + """ + items = [] + while not self.queue.empty(): + items.append(self.queue.get()) + + await self._state_manager.add_or_update_state(ActorStateKeys.EventQueueState.value, self.queue) + await self._state_manager.save_state() + + return items + + async def on_activate(self) -> None: + """Called when the actor is activated.""" + state_exists, event_queue_state = await self._state_manager.try_get_state( + ActorStateKeys.EventQueueState.value, self.queue + ) + if state_exists: + self.queue = event_queue_state + else: + self.queue: Queue[ProcessMessage] = Queue() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py new file mode 100644 index 000000000000..a0e5439093ef --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py @@ -0,0 +1,62 @@ +# Copyright (c) Microsoft. All rights reserved. + +from queue import Queue +from typing import TYPE_CHECKING + +from dapr.actor import Actor, ActorId +from dapr.actor.runtime.context import ActorRuntimeContext +from pydantic import Field + +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.external_event_buffer import ExternalEventBuffer +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent + +if TYPE_CHECKING: + from semantic_kernel.processes.process_message import ProcessMessage + + +class ExternalEventBufferActor(Actor, ExternalEventBuffer, KernelBaseModel): + """Represents a message buffer actor that follows the MessageBuffer abstract class.""" + + queue: Queue[KernelProcessEvent] = Field(default_factory=Queue) + + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): + """Initializes a new instance of StepActor.""" + super().__init__(ctx, actor_id) + + async def enqueue(self, message: "ProcessMessage") -> None: + """Enqueues a message event into the buffer. + + Args: + message: The message event to enqueue. + """ + self.queue.put(message) + + await self._state_manager.add_or_update_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) + await self._state_manager.save_state() + + async def dequeue_all(self) -> "list[KernelProcessEvent]": + """Dequeues all process events from the buffer. + + Returns: + The dequeued message event. + """ + items = [] + while not self.queue.empty(): + items.append(self.queue.get()) + + await self._state_manager.add_or_update_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) + await self._state_manager.save_state() + + return items + + async def on_activate(self) -> None: + """Called when the actor is activated.""" + state_exists, event_queue_state = await self._state_manager.try_get_state( + ActorStateKeys.ExternalEventQueueState.value, self.queue + ) + if state_exists: + self.queue = event_queue_state + else: + self.queue: Queue[KernelProcessEvent] = Queue() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py new file mode 100644 index 000000000000..41196cfded34 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py @@ -0,0 +1,59 @@ +# Copyright (c) Microsoft. All rights reserved. + +from queue import Queue +from typing import TYPE_CHECKING + +from dapr.actor import Actor, ActorId +from dapr.actor.runtime.context import ActorRuntimeContext +from pydantic import Field + +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer + +if TYPE_CHECKING: + from semantic_kernel.processes.process_message import ProcessMessage + + +class MessageBufferActor(Actor, MessageBuffer, KernelBaseModel): + """Represents a message buffer actor that follows the MessageBuffer abstract class.""" + + queue: Queue = Field(default_factory=Queue) + + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): + """Initializes a new instance of StepActor.""" + super().__init__(ctx, actor_id) + + async def enqueue(self, message: "ProcessMessage") -> None: + """Enqueues a message event into the buffer. + + Args: + message: The message event to enqueue. + """ + self.queue.put(message) + + await self._state_manager.add_or_update_state(ActorStateKeys.MessageQueueState.value, self.queue) + await self._state_manager.save_state() + + async def dequeue_all(self) -> "list[ProcessMessage]": + """Dequeues all process events from the buffer. + + Returns: + The dequeued message event. + """ + items = [] + while not self.queue.empty(): + items.append(self.queue.get()) + + await self._state_manager.add_or_update_state(ActorStateKeys.MessageQueueState.value, self.queue) + await self._state_manager.save_state() + + return items + + async def on_activate(self) -> None: + """Called when the actor is activated.""" + event_queue_state = await self._state_manager.get_state(ActorStateKeys.MessageQueueState.value, self.queue) + if event_queue_state is not None: + self.queue = event_queue_state + else: + self.queue: Queue[ProcessMessage] = Queue() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py new file mode 100644 index 000000000000..d782c07c1758 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py @@ -0,0 +1,228 @@ +# Copyright (c) Microsoft. All rights reserved. + + +import asyncio +import contextlib +import uuid +from queue import Queue +from typing import Any + +from dapr.actor import ActorId, ActorProxy +from dapr.actor.runtime.context import ActorRuntimeContext +from pydantic import Field + +from semantic_kernel.exceptions.kernel_exceptions import KernelException +from semantic_kernel.exceptions.process_exceptions import ProcessEventUndefinedException +from semantic_kernel.kernel import Kernel +from semantic_kernel.processes.const import END_PROCESS_ID +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor +from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo +from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.processes.dapr_runtime.process import Process +from semantic_kernel.processes.dapr_runtime.step import Step +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.processes.process_message import ProcessMessage + + +class ProcessActor(StepActor): + """A local process that contains a collection of steps.""" + + kernel: Kernel + steps: list[Step] = Field(default_factory=list) + step_infos: list[DaprStepInfo] = Field(default_factory=list) + initialize_task: bool | None = False + external_event_queue: Queue = Field(default_factory=Queue) + process_task: asyncio.Task | None = None + process: DaprProcessInfo | None = None + + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel) -> None: + """Initializes the local process.""" + args: dict[str, Any] = { + "ctx": ctx, + "actor_id": actor_id, + "kernel": kernel, + "initialize_task": False, + } + + super().__init__(**args) + + @property + def name(self) -> str: + """Gets the name of the step.""" + if self.process.state.name is None: + raise KernelException("The process must be initialized before accessing the name property.") + return self.step_info.state.name + + async def initialize_process(self, process_info: DaprProcessInfo, parent_process_id: str | None = None) -> None: + """Initializes the process.""" + if process_info is None: + raise ValueError("The process info is not defined.") + + if process_info.steps is None: + raise ValueError("The process info does not contain any steps.") + + if self.initialize_task: + return + + await self.initialize_process_actor(process_info, parent_process_id) + + await self._state_manager.add_or_update_state(ActorStateKeys.ProcessInfoState.value, process_info) + await self._state_manager.add_or_update_state(ActorStateKeys.StepParentProcessId.value, parent_process_id) + await self._state_manager.add_or_update_state(ActorStateKeys.StepActivatedState.value, True) + await self._state_manager.save_state() + + async def start(self, keep_alive: bool = True) -> None: + """Starts the process.""" + if not self.initialize_task: + raise ValueError("The process has not been initialized.") + + self.process_task = asyncio.create_task(self.internal_execute(keep_alive)) + + async def run_once(self, process_event: KernelProcessEvent): + """Starts the process with an initial event and waits for it to finish.""" + if process_event is None: + raise ProcessEventUndefinedException("The process event must be specified.") + external_event_queue: ExternalEventBufferActor = ActorProxy.create( + actor_type=f"{ExternalEventBufferActor.__name__}", + actor_id=self.parent_process_id, + actor_interface=ExternalEventBufferActor, + ) + external_event_queue.put(process_event) + await self.start(keep_alive=False) + if self.process_task: + await self.process_task + + async def stop(self): + """Stops a running process.""" + if not self.process_task or self.process_task.done(): + return # Task is already finished or hasn't started + + self.process_task.cancel() + + with contextlib.suppress(asyncio.CancelledError): + await self.process_task + + async def initialize_step(self): + """Initializes the step.""" + # The process does not need any further initialization + pass + + async def send_message(self, process_event: KernelProcessEvent): + """Sends a message to the process.""" + if process_event is None: + raise ProcessEventUndefinedException("The process event must be specified.") + self.external_event_queue.put(process_event) + + async def get_process_info(self): + """Gets the process information.""" + return await self.to_dapr_process_info() + + # private async Task ToDaprProcessInfoAsync() + # { + # var processState = new KernelProcessState(this.Name, this.Id.GetId()); + # var stepTasks = this._steps.Select(step => step.ToDaprStepInfoAsync()).ToList(); + # var steps = await Task.WhenAll(stepTasks).ConfigureAwait(false); + # return new DaprProcessInfo { InnerStepDotnetType = this._process!.InnerStepDotnetType, Edges = this._process!.Edges, State = processState, Steps = steps.ToList() }; + # } + + async def to_dapr_process_info(self) -> DaprProcessInfo: + """Converts the process to a Dapr process info.""" + process_state = DaprProcessInfo(self.name, self.id.id) + step_tasks = [step.to_dapr_step_info() for step in self.steps] + steps = await asyncio.gather(*step_tasks) + return DaprProcessInfo( + inner_step_dotnet_type=self.inner_step_type, edges=self.process.edges, state=process_state, steps=steps + ) + + async def _initialize_process_actor( + self, process_info: DaprProcessInfo, parent_process_id: str | None = None + ) -> None: + """Initializes the process actor.""" + if process_info is None: + raise ValueError("The process info is not defined.") + + if process_info.steps is None: + raise ValueError("The process info does not contain any steps.") + + self.parent_process_id = parent_process_id + self.process = process_info + self.step_infos = list(self.process.steps) + self.output_edges = {kvp[0]: list(kvp[1]) for kvp in self.process.edges.items()} + + for step in self.step_infos: + step_actor: Step = None + + # The current step should already have a name. + assert step.state and step.state.name is not None # nosec + + if isinstance(step, DaprProcessInfo): + # The process will only have an Id if it's already been executed. + if not step.state.id: + step.state.id = str(uuid.uuid4().hex) + + # Initialize the step as a process + scoped_process_id = self._scoped_actor_id(ActorId(step.state.id)) + process_actor: Process = ActorProxy.create( + actor_id=scoped_process_id, + actor_type=f"{ProcessActor.__name__}", + actor_interface=Process, + ) + await process_actor.initialize_process(step, self.id.id) + step_actor = ActorProxy.create( + actor_id=scoped_process_id, + actor_type=f"{ProcessActor.__name__}", + actor_interface=Step, + ) + else: + # The current step should already have an Id. + assert step.state and step.state.id is not None # nosec + + scoped_step_id = self._scoped_actor_id(ActorId(step.state.id)) + step_actor = ActorProxy.create( + actor_id=scoped_step_id, + actor_type=f"{ProcessActor.__name__}", + actor_interface=Step, + ) + await step_actor.initialize_step(step, self.id.id) + + # Add the local step to the list of steps + self.steps.append(step_actor) + + self.initialize_task = True + + def _scoped_actor_id(self, actor_id: ActorId) -> ActorId: + """Creates a scoped actor ID.""" + return ActorId(f"{self.id}.{actor_id.id}") + + async def internal_execute(self, max_supersteps: int = 100, keep_alive: bool = True): + """Internal execution logic for the process.""" + message_channel: Queue[ProcessMessage] = Queue() + + try: + for _ in range(max_supersteps): + self.enqueue_external_messages(message_channel) + for step in self.steps: + await self.enqueue_step_messages(step, message_channel) + + messages_to_process: list = [] + while not message_channel.empty(): + messages_to_process.append(message_channel.get()) + + if not messages_to_process and (not keep_alive or self.external_event_queue.empty()): + break + + message_tasks = [] + for message in messages_to_process: + if message.destination_id == END_PROCESS_ID: + break + + destination_step = next(step for step in self.steps if step.id == message.destination_id) + message_tasks.append(destination_step.handle_message(message)) + + await asyncio.gather(*message_tasks) + + except Exception as ex: + print("An error occurred while running the process: %s.", ex) + raise diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py new file mode 100644 index 000000000000..34084ed11a51 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -0,0 +1,370 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import logging +from queue import Queue +from typing import Any, Type + +from dapr.actor import Actor, ActorId, ActorProxy +from dapr.actor.runtime.context import ActorRuntimeContext +from pydantic import Field + +from semantic_kernel.exceptions.kernel_exceptions import KernelException +from semantic_kernel.exceptions.process_exceptions import ( + ProcessFunctionNotFoundException, + ProcessTargetFunctionNameMismatchException, +) +from semantic_kernel.functions.kernel_function import KernelFunction +from semantic_kernel.kernel import Kernel +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor +from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer +from semantic_kernel.processes.dapr_runtime.step import Step +from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge +from semantic_kernel.processes.kernel_process.kernel_process_event import ( + KernelProcessEvent, + KernelProcessEventVisibility, +) +from semantic_kernel.processes.kernel_process.kernel_process_message_channel import KernelProcessMessageChannel +from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState +from semantic_kernel.processes.process_event import ProcessEvent +from semantic_kernel.processes.process_message import ProcessMessage +from semantic_kernel.processes.process_message_factory import ProcessMessageFactory +from semantic_kernel.processes.process_types import get_generic_state_type +from semantic_kernel.processes.step_utils import find_input_channels +from semantic_kernel.utils.experimental_decorator import experimental_class + +logger: logging.Logger = logging.getLogger(__name__) + + +@experimental_class +class StepActor(Actor, Step, KernelProcessMessageChannel, KernelBaseModel): + """Represents a step actor that follows the Step abstract class.""" + + kernel: Kernel + parent_process_id: str | None = None + step_info: DaprStepInfo | None = None + initialize_task: bool | None = False + event_namespace: str | None = None + inner_step_type: Type | None = None + incoming_messages: Queue = Field(default_factory=Queue) + step_state: KernelProcessStepState | None = None + step_state_type: Type | None = None + output_edges: dict[str, list[KernelProcessEdge]] = Field(default_factory=dict) + functions: dict[str, KernelFunction] = Field(default_factory=dict) + inputs: dict[str, dict[str, Any | None]] = Field(default_factory=dict) + initial_inputs: dict[str, dict[str, Any | None]] = Field(default_factory=dict) + init_lock: asyncio.Lock = Field(default_factory=asyncio.Lock, exclude=True) + + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): + """Initializes a new instance of StepActor.""" + super().__init__(ctx, actor_id) + self.kernel = kernel + self.activate_task = self.activate_step() + + @property + def name(self) -> str: + """Gets the name of the step.""" + return self.step_info.state.name + + async def initialize_step(self, step_info: DaprStepInfo, parent_process_id: str | None = None) -> None: + """Initializes the step with the provided step information.""" + if step_info is None: + raise ValueError("step_info must not be None") + + if self.initialize_task: + return + + await self._int_initialize_step(step_info, parent_process_id) + + await self._state_manager.add_or_update_state(ActorStateKeys.StepInfoState.value, step_info) + await self._state_manager.add_or_update_state(ActorStateKeys.StepParentProcessId.value, parent_process_id) + + async def _int_initialize_step(self, step_info: DaprStepInfo, parent_process_id: str | None = None) -> None: + """Internal method to initialize the step with the provided step information. + + Args: + step_info: The DaprStepInfo object to initialize the step with. + parent_process_id: Optional parent process ID if one exists. + """ + # TODO(evmattso): investigate this + self.inner_step_type = step_info.inner_step_python_type + + self.parent_process_id = parent_process_id + self.step_info = step_info + self.step_state = self.step_info.state + self.output_edges = {k: v for k, v in step_info.edges.items()} + self.event_namespace = f"{self.step_info.state.name}_{self.step_info.state.id}" + + self.initialize_task = True + + async def prepare_incoming_messages(self) -> int: + """Triggers the step to dequeue all pending messages and prepare for processing. + + Returns: + An integer indicating the number of messages prepared for processing. + """ + message_queue: MessageBuffer = ActorProxy.create( + actor_type=f"{MessageBufferActor.__name__}", actor_id=self.id.id, actor_interface=MessageBufferActor + ) + incoming = await message_queue.dequeue_all() + for message in incoming: + self.incoming_messages.put(message) + + await self._state_manager.set_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) + await self._state_manager.save_state() + + return len(self.incoming_messages) + + async def process_incoming_messages(self) -> None: + """Triggers the step to process all prepared messages.""" + while not self.incoming_messages.empty(): + message = self.incoming_messages.get() + await self.handle_message(message) + + await self._state_manager.set_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) + await self._state_manager.save_state() + + async def activate_step(self): + """Initializes the step.""" + # Instantiate an instance of the inner step object + step_cls = self.inner_step_type + + step_instance: KernelProcessStep = step_cls() # type: ignore + + kernel_plugin = self.kernel.add_plugin( + step_instance, self.step_info.state.name if self.step_info.state else "default_name" + ) + + # Load the kernel functions + for name, f in kernel_plugin.functions.items(): + self.functions[name] = f + + # Initialize the input channels + self.initial_inputs = find_input_channels(channel=self, functions=self.functions) + self.inputs = {k: {kk: vv for kk, vv in v.items()} if v else {} for k, v in self.initial_inputs.items()} + + # Use the existing state or create a new one if not provided + state_object = self.step_info.state + + # Extract TState from inner_step_type + t_state = get_generic_state_type(step_cls) + + if t_state is not None: + # Create state_type as KernelProcessStepState[TState] + state_type = KernelProcessStepState[t_state] + + if state_object is None: + state_object = state_type( + name=step_cls.__name__, + id=step_cls.__name__, + state=None, + ) + else: + # Make sure state_object is an instance of state_type + if not isinstance(state_object, KernelProcessStepState): + error_message = "State object is not of the expected type." + raise KernelException(error_message) + + # Make sure that state_object.state is not None + if state_object.state is None: + try: + state_object.state = t_state() + except Exception as e: + error_message = f"Cannot instantiate state of type {t_state}: {e}" + raise KernelException(error_message) + else: + # The step has no user-defined state; use the base KernelProcessStepState + state_type = KernelProcessStepState + + if state_object is None: + state_object = state_type( + name=step_cls.__name__, + id=step_cls.__name__, + state=None, + ) + + if state_object is None: + error_message = "The state object for the KernelProcessStep could not be created." + raise KernelException(error_message) + + # Set the step state and activate the step with the state object + self.step_state = state_object + await step_instance.activate(state_object) + + async def handle_message(self, message: ProcessMessage): + """Handles a LocalMessage that has been sent to the step.""" + if message is None: + raise ValueError("The message is None.") + + if not self.initialize_task: + async with self.init_lock: + # Second check to ensure that initialization happens only once + # This avoids a race condition where multiple coroutines might + # reach the first check at the same time before any of them acquire the lock. + if not self.initialize_task: + await self.activate_step() + self.initialize_task = True + + if self.functions is None or self.inputs is None or self.initial_inputs is None: + raise ValueError("The step has not been initialized.") + + message_log_parameters = ", ".join(f"{k}: {v}" for k, v in message.values.items()) + logger.info( + f"Received message from `{message.source_id}` targeting function " + f"`{message.function_name}` and parameters `{message_log_parameters}`." + ) + + # Add the message values to the inputs for the function + for k, v in message.values.items(): + if self.inputs.get(message.function_name) and self.inputs[message.function_name].get(k): + logger.info( + f"Step {self.name} already has input for `{message.function_name}.{k}`, " + f"it is being overwritten with a message from Step named `{message.source_id}`." + ) + + if message.function_name not in self.inputs: + self.inputs[message.function_name] = {} + + self.inputs[message.function_name][k] = v + + invocable_functions = [ + k + for k, v in self.inputs.items() + if v is not None and (v == {} or all(val is not None for val in v.values())) + ] + missing_keys = [ + f"{outer_key}.{inner_key}" + for outer_key, outer_value in self.inputs.items() + for inner_key, inner_value in outer_value.items() + if inner_value is None + ] + + if not invocable_functions: + logger.info(f"No invocable functions, missing keys: {', '.join(missing_keys)}") + return + + target_function = next((name for name in invocable_functions if name == message.function_name), None) + + if not target_function: + raise ProcessTargetFunctionNameMismatchException( + f"A message targeting function `{message.function_name}` has resulted in a different function " + f"`{invocable_functions[0]}` becoming invocable. Check the function names." + ) + + logger.info( + f"Step with Id '{self.id}' received all required input for function [{target_function}] and is executing." + ) + + # Concatenate all inputs and run the function + arguments = self.inputs[target_function] + function = self.functions.get(target_function) + + if function is None: + raise ProcessFunctionNotFoundException(f"Function {target_function} not found in plugin {self.name}") + + invoke_result = None + event_name = None + event_value = None + + try: + logger.info( + f"Invoking plugin `{function.plugin_name}` and function `{function.name}` with arguments: {arguments}" + ) + invoke_result = await self.invoke_function(function, self.kernel, arguments) + event_name = f"{target_function}.OnResult" + event_value = invoke_result.value + + state_dict = self.step_state.model_dump() + await self._state_manager.set_state(ActorStateKeys.StepStateJson.value, state_dict) + await self._state_manager.save_state() + except Exception as ex: + logger.error(f"Error in Step {self.name}: {ex!s}") + event_name = f"{target_function}.OnError" + event_value = str(ex) + finally: + await self.emit_event(KernelProcessEvent(id=event_name, data=event_value)) + + # Reset the inputs for the function that was just executed + self.inputs[target_function] = self.initial_inputs.get(target_function, {}).copy() + + async def invoke_function(self, function: "KernelFunction", kernel: "Kernel", arguments: dict[str, Any]): + """Invokes the function.""" + return await kernel.invoke(function, **arguments) + + async def emit_event(self, process_event: KernelProcessEvent): + """Emits an event from the step.""" + await self.emit_local_event(ProcessEvent.from_kernel_process_event(process_event, self.event_namespace)) + + async def emit_process_event(self, dapr_event: ProcessEvent): + """Emits an event from the step.""" + scoped_event = self.scoped_event(dapr_event) + + if dapr_event.visibility == KernelProcessEventVisibility.Public and self.parent_process_id is not None: + parent_process: EventBufferActor = ActorProxy.create( + actor_type=f"{EventBufferActor.__name__}", + actor_id=self.parent_process_id, + actor_interface=EventBufferActor, + ) + await parent_process.enqueue(scoped_event) + + for edge in self.get_edge_for_event(dapr_event.id): + message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, dapr_event.data) + scoped_step_id = self._scoped_actor_id(ActorId(edge.output_target.step_id)) + target_step: MessageBuffer = ActorProxy.create( + actor_id=scoped_step_id, + actor_interface=MessageBuffer, + actor_type=f"{MessageBuffer.__name__}", + ) + await target_step.enqueue(message) + + async def to_dapr_step_info(self) -> DaprStepInfo: + """Converts the step to a DaprStepInfo object.""" + if not self.initialize_task: + async with self.init_lock: + # Second check to ensure that initialization happens only once + # This avoids a race condition where multiple coroutines might + # reach the first check at the same time before any of them acquire the lock. + if not self.initialize_task: + await self.activate_step() + self.initialize_task = True + + return DaprStepInfo( + inner_step_python_type=self.inner_step_type, state=self.step_info.state, edges=self.step_info.edges + ) + + async def _on_activate(self) -> None: + """Override the Actor's on_activate method.""" + has_value, existing_step_info = await self._state_manager.try_get_state(ActorStateKeys.StepInfoState.value) + if has_value: + parent_process_id = await self._state_manager.get_state(ActorStateKeys.StepParentProcessId.value) + await self._int_initialize_step(existing_step_info, parent_process_id=parent_process_id) + + # Load persisted incoming messages + exists, incoming_messages = await self._state_manager.try_get_state( + ActorStateKeys.StepIncomingMessagesState.value + ) + if exists: + self.incoming_messages = incoming_messages + + def scoped_event(self, dapr_event: "ProcessEvent") -> "ProcessEvent": + """Generates a scoped event for the step.""" + if dapr_event is None: + raise ValueError("The Dapr event must be specified.") + dapr_event.namespace = f"{self.name}_{self.id.id}" + return dapr_event + + def _scoped_actor_id(self, actor_id: ActorId) -> ActorId: + """Generates a scoped actor ID for the step.""" + return ActorId(f"{self.parent_process_id}.{actor_id.id}") + + def get_edge_for_event(self, event_id: str) -> list["KernelProcessEdge"]: + """Retrieves all edges that are associated with the provided event Id.""" + if not self.output_edges: + return [] + + return self.output_edges.get(event_id, []) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py new file mode 100644 index 000000000000..fd66a69d1179 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py @@ -0,0 +1,40 @@ +# Copyright (c) Microsoft. All rights reserved. +from typing import TYPE_CHECKING + +from semantic_kernel.exceptions.process_exceptions import ProcessInvalidConfigurationException +from semantic_kernel.processes.dapr_runtime.dapr_kernel_process_context import DaprKernelProcessContext +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.utils.experimental_decorator import experimental_function + +if TYPE_CHECKING: + from semantic_kernel.kernel import Kernel + from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess + + +@experimental_function +async def start( + process: "KernelProcess", + kernel: "Kernel", + initial_event: KernelProcessEvent | str, + process_id: str | None = None, + **kwargs, +) -> DaprKernelProcessContext: + """Start the kernel process.""" + if process is None: + raise ProcessInvalidConfigurationException("process cannot be None") + if process.state is None or not process.state.name: + raise ProcessInvalidConfigurationException("process state name cannot be empty") + if kernel is None: + raise ProcessInvalidConfigurationException("kernel cannot be None") + if initial_event is None: + raise ProcessInvalidConfigurationException("initial_event cannot be None") + + if isinstance(initial_event, str): + initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data", None)) + + if process_id is not None: + process.state.id = process_id + + process_context = DaprKernelProcessContext(process, kernel) + await process_context.start_with_event(initial_event) + return process_context diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py new file mode 100644 index 000000000000..d5812bec497d --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -0,0 +1,47 @@ +# Copyright (c) Microsoft. All rights reserved. + +import uuid + +from dapr.actor import ActorId, ActorProxy + +from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo +from semantic_kernel.processes.dapr_runtime.process import Process +from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent + + +class DaprKernelProcessContext: + """A Dapr kernel process context.""" + + dapr_process: Process + process: KernelProcess + + def __init__(self, process: KernelProcess): + """Initialize a new instance of DaprKernelProcessContext.""" + if process.state.name is None: + raise ValueError("Process state name must not be None") + if process.state.id is None or process.state.id == "": + process.state.id = str(uuid.uuid4().hex) + + self.process = process + process_id = ActorId(process.state.id) + self.dapr_process = ActorProxy.create(actor_interface=Process, actor_id=process_id, actor_type="ProcessActor") + + async def start_with_event(self, initial_event: KernelProcessEvent) -> None: + """Starts the process with the provided initial event.""" + dapr_process = DaprProcessInfo.from_kernel_process(self.process) + await self.dapr_process.initialize_process(dapr_process, None) + await self.dapr_process.run_once(initial_event) + + async def send_event(self, event: KernelProcessEvent) -> None: + """Sends an event to the process.""" + await self.dapr_process.send_message(event) + + async def stop(self) -> None: + """Stops the process.""" + await self.dapr_process.stop() + + async def get_state(self) -> KernelProcess: + """Retrieves the current state of the process.""" + dapr_process = await self.dapr_process.get_process_info() + return dapr_process.to_kernel_process() diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py new file mode 100644 index 000000000000..63beb8ea827f --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py @@ -0,0 +1,57 @@ +# Copyright (c) Microsoft. All rights reserved. + + +from pydantic import Field + +from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess +from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge +from semantic_kernel.processes.kernel_process.kernel_process_state import KernelProcessState +from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState +from semantic_kernel.processes.process_types import TState + + +class DaprProcessInfo(DaprStepInfo): + """A Dapr process info.""" + + info: KernelProcessEdge | KernelProcessState | KernelProcessStepState | KernelProcessStepState[TState] = Field( + discriminator="type" + ) + steps: list[DaprStepInfo] = Field(default_factory=list) + + def to_kernel_process(self) -> KernelProcess: + """Converts the Dapr process info to a kernel process.""" + if not isinstance(self.state, KernelProcessState): + raise ValueError("State must be a kernel process state") + + steps: list[KernelProcessStepInfo] = [] + for step in self.steps: + if isinstance(step, DaprProcessInfo): + steps.append(step.to_kernel_process()) + else: + steps.append(step.to_kernel_process_step_info()) + + return KernelProcess(state=self.state, steps=steps, edges=self.edges) + + @classmethod + def from_kernel_process(cls, kernel_process: KernelProcess) -> "DaprProcessInfo": + """Creates a Dapr process info from a kernel process.""" + if kernel_process is None: + raise ValueError("Kernel process must be provided") + + dapr_step_info = DaprStepInfo.from_kernel_step_info(kernel_process) + dapr_steps = [] + + for step in kernel_process.steps: + if isinstance(step, KernelProcess): + dapr_steps.append(DaprProcessInfo.from_kernel_process(step)) + else: + dapr_steps.append(DaprStepInfo.from_kernel_step_info(step)) + + return DaprProcessInfo( + inner_step_python_type=dapr_step_info.inner_step_python_type, + state=dapr_step_info.state, + edges={key: list(value) for key, value in dapr_step_info.edges.items()}, + steps=dapr_steps, + ) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py new file mode 100644 index 000000000000..6b77a04672e1 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py @@ -0,0 +1,50 @@ +# Copyright (c) Microsoft. All rights reserved. + +import importlib + +from pydantic import Field + +from semantic_kernel.exceptions.kernel_exceptions import KernelException +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge +from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState + + +class DaprStepInfo(KernelBaseModel): + """A Dapr step info.""" + + info: KernelProcessEdge | KernelProcessStepState = Field(discriminator="type") + inner_step_python_type: str + state: KernelProcessStepState + edges: dict[str, list[KernelProcessEdge]] = Field(default_factory=dict) + + def to_kernel_process_step_info(self) -> KernelProcessStepInfo: + """Converts the Dapr step info to a kernel process step info.""" + inner_step_type = self._get_class_from_string(self.inner_step_python_type) + if inner_step_type is None: + raise KernelException( + f"Unable to create inner step type from assembly qualified name `{self.inner_step_python_type}`" + ) + return KernelProcessStepInfo(inner_step_type=inner_step_type, state=self.state, edges=self.edges) + + @classmethod + def from_kernel_step_info(cls, kernel_step_info: KernelProcessStepInfo) -> "DaprStepInfo": + """Creates a Dapr step info from a kernel step info.""" + if kernel_step_info is None: + raise KernelException("Kernel step info must be provided") + inner_step_type = DaprStepInfo._get_fully_qualified_name(kernel_step_info.__class__) + return DaprStepInfo( + inner_step_type=inner_step_type, + state=kernel_step_info.state, + edges={key: list(value) for key, value in kernel_step_info.edges.items()}, + ) + + def _get_class_from_string(self, full_class_name: str): + """Gets a class from a string.""" + module_name, class_name = full_class_name.rsplit(".", 1) + module = importlib.import_module(module_name) + return getattr(module, class_name) + + def _get_fully_qualified_name(cls): + return f"{cls.__module__}.{cls.__name__}" diff --git a/python/semantic_kernel/processes/dapr_runtime/event_buffer.py b/python/semantic_kernel/processes/dapr_runtime/event_buffer.py new file mode 100644 index 000000000000..f092cdfe7532 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/event_buffer.py @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft. All rights reserved. + +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING + +from dapr.actor import ActorInterface + +if TYPE_CHECKING: + from semantic_kernel.processes.process_event import ProcessEvent + + +class EventBuffer(ActorInterface, ABC): + """Abstract base class for an event buffer that follows the ActorInterface.""" + + @abstractmethod + async def enqueue(self, step_event: "ProcessEvent") -> None: + """Enqueues a step event into the buffer. + + Args: + step_event: The step event to enqueue. + """ + pass + + @abstractmethod + async def dequeue_all(self) -> "list[ProcessEvent]": + """Dequeues a step event from the buffer. + + Returns: + The dequeued step event. + """ + pass diff --git a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py new file mode 100644 index 000000000000..5b8f0f62d02d --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py @@ -0,0 +1,31 @@ +# Copyright (c) Microsoft. All rights reserved. + +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING + +from dapr.actor import ActorInterface + +if TYPE_CHECKING: + from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent + + +class ExternalEventBuffer(ActorInterface, ABC): + """Abstract base class for an external event buffer that follows the ActorInterface.""" + + @abstractmethod + async def enqueue(self, external_event: "KernelProcessEvent") -> None: + """Enqueues an external event into the buffer. + + Args: + external_event: The external event to enqueue. + """ + pass + + @abstractmethod + async def dequeue_all(self) -> "list[KernelProcessEvent]": + """Dequeues all external events from the buffer. + + Returns: + The dequeued external event. + """ + pass diff --git a/python/semantic_kernel/processes/dapr_runtime/message_buffer.py b/python/semantic_kernel/processes/dapr_runtime/message_buffer.py new file mode 100644 index 000000000000..66abb16bfeb6 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/message_buffer.py @@ -0,0 +1,30 @@ +# Copyright (c) Microsoft. All rights reserved. + +from typing import TYPE_CHECKING + +from dapr.actor import ActorInterface, actormethod + +if TYPE_CHECKING: + from semantic_kernel.processes.process_event import ProcessEvent + + +class MessageBuffer(ActorInterface): + """Abstract base class for a message event buffer that follows the ActorInterface.""" + + @actormethod + async def enqueue(self, message: "ProcessEvent") -> None: + """Enqueues a message event into the buffer. + + Args: + message: The message event to enqueue. + """ + pass + + @actormethod + async def dequeue_all(self) -> "list[ProcessEvent]": + """Dequeues all process events from the buffer. + + Returns: + The dequeued message event. + """ + pass diff --git a/python/semantic_kernel/processes/dapr_runtime/process.py b/python/semantic_kernel/processes/dapr_runtime/process.py new file mode 100644 index 000000000000..ca6d9e4f6b8e --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/process.py @@ -0,0 +1,57 @@ +# Copyright (c) Microsoft. All rights reserved. + + +from dapr.actor import ActorInterface, actormethod + +from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent + + +class Process(ActorInterface): + """Abstract base class for a process that follows the ActorInterface.""" + + @actormethod + async def initialize_process(self, process_info: "DaprProcessInfo", parent_process_id: str | None = None) -> None: + """Initializes the process with the specified instance of DaprProcessInfo. + + :param process_info: Used to initialize the process. + :param parent_process_id: The parent ID of the process if one exists. + """ + pass + + @actormethod + async def start(self, keep_alive: bool) -> None: + """Starts an initialized process. + + :param keep_alive: Indicates if the process should wait for external events after it's finished processing. + """ + pass + + @actormethod + async def run_once(self, process_event: "KernelProcessEvent") -> None: + """Starts the process with an initial event and then waits for the process to finish. + + :param process_event: Required. The KernelProcessEvent to start the process with. + """ + pass + + @actormethod + async def stop(self) -> None: + """Stops a running process, canceling and waiting for it to complete before returning.""" + pass + + @actormethod + async def send_message(self, process_event: "KernelProcessEvent") -> None: + """Sends a message to the process without starting it if it is not already running. + + :param process_event: Required. The KernelProcessEvent to queue for the process. + """ + pass + + @actormethod + async def get_process_info(self) -> "DaprProcessInfo": + """Retrieves the process information. + + :return: An instance of DaprProcessInfo. + """ + pass diff --git a/python/semantic_kernel/processes/dapr_runtime/step.py b/python/semantic_kernel/processes/dapr_runtime/step.py new file mode 100644 index 000000000000..dfc35767c6df --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/step.py @@ -0,0 +1,41 @@ +# Copyright (c) Microsoft. All rights reserved. + + +from dapr.actor import ActorInterface, actormethod + +from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo + + +class Step(ActorInterface): + """Abstract base class for a step in the process workflow.""" + + @actormethod + async def initialize_step(self, step_info: "DaprStepInfo", parent_process_id: str | None = None) -> None: + """Initializes the step with the provided step information. + + :param step_info: The DaprStepInfo object to initialize the step with. + :param parent_process_id: Optional parent process ID if one exists. + :raises KernelException: If an error occurs during initialization. + """ + pass + + @actormethod + async def prepare_incoming_messages(self) -> int: + """Triggers the step to dequeue all pending messages and prepare for processing. + + :return: An integer indicating the number of messages prepared for processing. + """ + pass + + @actormethod + async def process_incoming_messages(self) -> None: + """Triggers the step to process all prepared messages.""" + pass + + @actormethod + async def to_dapr_step_info(self) -> "DaprStepInfo": + """Builds the current state of the step into a DaprStepInfo. + + :return: An instance of DaprStepInfo representing the step's current state. + """ + pass diff --git a/python/semantic_kernel/processes/local_runtime/local_step.py b/python/semantic_kernel/processes/local_runtime/local_step.py index c5af81f324e0..8df5c3ce0740 100644 --- a/python/semantic_kernel/processes/local_runtime/local_step.py +++ b/python/semantic_kernel/processes/local_runtime/local_step.py @@ -20,12 +20,12 @@ from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent from semantic_kernel.processes.kernel_process.kernel_process_message_channel import KernelProcessMessageChannel from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep -from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState from semantic_kernel.processes.local_runtime.local_event import LocalEvent from semantic_kernel.processes.local_runtime.local_message import LocalMessage from semantic_kernel.processes.process_types import get_generic_state_type +from semantic_kernel.processes.step_utils import find_input_channels from semantic_kernel.utils.experimental_decorator import experimental_class logger: logging.Logger = logging.getLogger(__name__) @@ -197,7 +197,7 @@ async def initialize_step(self): self.functions[name] = f # Initialize the input channels - self.initial_inputs = self.find_input_channels() + self.initial_inputs = find_input_channels(channel=self, functions=self.functions) self.inputs = {k: {kk: vv for kk, vv in v.items()} if v else {} for k, v in self.initial_inputs.items()} # Use the existing state or create a new one if not provided @@ -248,27 +248,6 @@ async def initialize_step(self): self.step_state = state_object await step_instance.activate(state_object) - def find_input_channels(self) -> dict[str, dict[str, Any | None]]: - """Finds and creates input channels.""" - if not self.functions: - raise ValueError("The step has not been initialized.") - - inputs: dict[str, Any] = {} - for name, function in self.functions.items(): - inputs[name] = {} - for param in function.metadata.parameters: - # Check for Kernel, and skip if necessary, since it is populated later on - if param.type_ == "Kernel": - continue - if not param.is_required: - continue - if param.type_ == "KernelProcessStepContext": - inputs[name][param.name] = KernelProcessStepContext(self) - else: - inputs[name][param.name] = None - - return inputs - def get_all_events(self) -> list["LocalEvent"]: """Retrieves all events that have been emitted by this step in the previous superstep.""" all_events = [] diff --git a/python/semantic_kernel/processes/process_event.py b/python/semantic_kernel/processes/process_event.py new file mode 100644 index 000000000000..583fd1364ea8 --- /dev/null +++ b/python/semantic_kernel/processes/process_event.py @@ -0,0 +1,36 @@ +# Copyright (c) Microsoft. All rights reserved. + +from typing import Optional + +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.kernel_process.kernel_process_event import ( + KernelProcessEvent, + KernelProcessEventVisibility, +) + + +class ProcessEvent(KernelBaseModel): + """A wrapper around KernelProcessEvent that helps to manage the namespace of the event.""" + + namespace: str | None = None + inner_event: KernelProcessEvent + + @property + def id(self) -> str: + """The Id of the event.""" + return f"{self.namespace}.{self.inner_event.id}" + + @property + def data(self) -> Optional[object]: + """The data of the event.""" + return self.inner_event.data + + @property + def visibility(self) -> "KernelProcessEventVisibility": + """The visibility of the event.""" + return self.inner_event.visibility + + @classmethod + def from_kernel_process_event(cls, kernel_process_event: KernelProcessEvent, namespace: str) -> "ProcessEvent": + """Creates a new ProcessEvent from a KernelProcessEvent.""" + return cls(namespace=namespace, inner_event=kernel_process_event) diff --git a/python/semantic_kernel/processes/process_message.py b/python/semantic_kernel/processes/process_message.py new file mode 100644 index 000000000000..baba04332c96 --- /dev/null +++ b/python/semantic_kernel/processes/process_message.py @@ -0,0 +1,17 @@ +# Copyright (c) Microsoft. All rights reserved. + +from typing import Any + +from semantic_kernel.kernel_pydantic import KernelBaseModel + + +class ProcessMessage(KernelBaseModel): + """Represents a message used in a process runtime.""" + + source_id: str + destination_id: str + function_name: str + values: dict[str, Any] + + target_event_id: str | None = None + target_event_data: Any | None = None diff --git a/python/semantic_kernel/processes/process_message_factory.py b/python/semantic_kernel/processes/process_message_factory.py new file mode 100644 index 000000000000..4956bf713952 --- /dev/null +++ b/python/semantic_kernel/processes/process_message_factory.py @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft. All rights reserved. + +from typing import Any + +from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge +from semantic_kernel.processes.process_message import ProcessMessage + + +class ProcessMessageFactory: + """Factory class for creating ProcessMessage instances.""" + + @staticmethod + def create_from_edge(edge: KernelProcessEdge, data: Any) -> ProcessMessage: + """Creates a new ProcessMessage from a KernelProcessEdge.""" + target = edge.output_target + parameter_value: dict[str, Any] = {} + if target.parameter_name is not None: + parameter_value[target.parameter_name] = data + + return ProcessMessage( + source_id=edge.source_step_id, + destination_id=target.step_id, + function_name=target.function_name, + values=parameter_value, + target_event_id=target.target_event_id, + target_event_data=data, + ) diff --git a/python/semantic_kernel/processes/step_utils.py b/python/semantic_kernel/processes/step_utils.py new file mode 100644 index 000000000000..cd95fde26ed9 --- /dev/null +++ b/python/semantic_kernel/processes/step_utils.py @@ -0,0 +1,29 @@ +from typing import Any + +from semantic_kernel.functions.kernel_function import KernelFunction +from semantic_kernel.processes.kernel_process.kernel_process_message_channel import KernelProcessMessageChannel +from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext + + +def find_input_channels( + channel: KernelProcessMessageChannel, function: dict[str, KernelFunction] +) -> dict[str, dict[str, Any | None]]: + """Finds and creates input channels.""" + if not self.functions: + raise ValueError("The step has not been initialized.") + + inputs: dict[str, Any] = {} + for name, function in self.functions.items(): + inputs[name] = {} + for param in function.metadata.parameters: + # Check for Kernel, and skip if necessary, since it is populated later on + if param.type_ == "Kernel": + continue + if not param.is_required: + continue + if param.type_ == "KernelProcessStepContext": + inputs[name][param.name] = KernelProcessStepContext(self) + else: + inputs[name][param.name] = None + + return inputs diff --git a/python/uv.lock b/python/uv.lock index 5112d93bc199..331042a711f6 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -170,21 +170,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/c2/f7eed4d602f3f224600d03ab2e1a7734999b0901b1c49b94dc5891340433/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6", size = 1329459 }, { url = "https://files.pythonhosted.org/packages/ce/8f/27f205b76531fc592abe29e1ad265a16bf934a9f609509c02d765e6a8055/aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12", size = 356968 }, { url = "https://files.pythonhosted.org/packages/39/8c/4f6c0b2b3629f6be6c81ab84d9d577590f74f01d4412bfc4067958eaa1e1/aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc", size = 377650 }, - { url = "https://files.pythonhosted.org/packages/7b/b9/03b4327897a5b5d29338fa9b514f1c2f66a3e4fc88a4e40fad478739314d/aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092", size = 576994 }, - { url = "https://files.pythonhosted.org/packages/67/1b/20c2e159cd07b8ed6dde71c2258233902fdf415b2fe6174bd2364ba63107/aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77", size = 390684 }, - { url = "https://files.pythonhosted.org/packages/4d/6b/ff83b34f157e370431d8081c5d1741963f4fb12f9aaddb2cacbf50305225/aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385", size = 386176 }, - { url = "https://files.pythonhosted.org/packages/4d/a1/6e92817eb657de287560962df4959b7ddd22859c4b23a0309e2d3de12538/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972", size = 1303310 }, - { url = "https://files.pythonhosted.org/packages/04/29/200518dc7a39c30ae6d5bc232d7207446536e93d3d9299b8e95db6e79c54/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16", size = 1340445 }, - { url = "https://files.pythonhosted.org/packages/8e/20/53f7bba841ba7b5bb5dea580fea01c65524879ba39cb917d08c845524717/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6", size = 1385121 }, - { url = "https://files.pythonhosted.org/packages/f1/b4/d99354ad614c48dd38fb1ee880a1a54bd9ab2c3bcad3013048d4a1797d3a/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa", size = 1299669 }, - { url = "https://files.pythonhosted.org/packages/51/39/ca1de675f2a5729c71c327e52ac6344e63f036bd37281686ae5c3fb13bfb/aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689", size = 1252638 }, - { url = "https://files.pythonhosted.org/packages/54/cf/a3ae7ff43138422d477348e309ef8275779701bf305ff6054831ef98b782/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57", size = 1266889 }, - { url = "https://files.pythonhosted.org/packages/6e/7a/c6027ad70d9fb23cf254a26144de2723821dade1a624446aa22cd0b6d012/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f", size = 1266249 }, - { url = "https://files.pythonhosted.org/packages/64/fd/ed136d46bc2c7e3342fed24662b4827771d55ceb5a7687847aae977bfc17/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599", size = 1311036 }, - { url = "https://files.pythonhosted.org/packages/76/9a/43eeb0166f1119256d6f43468f900db1aed7fbe32069d2a71c82f987db4d/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5", size = 1338756 }, - { url = "https://files.pythonhosted.org/packages/d5/bc/d01ff0810b3f5e26896f76d44225ed78b088ddd33079b85cd1a23514318b/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987", size = 1299976 }, - { url = "https://files.pythonhosted.org/packages/3e/c9/50a297c4f7ab57a949f4add2d3eafe5f3e68bb42f739e933f8b32a092bda/aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04", size = 355609 }, - { url = "https://files.pythonhosted.org/packages/65/28/aee9d04fb0b3b1f90622c338a08e54af5198e704a910e20947c473298fd0/aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022", size = 375697 }, ] [[package]] @@ -606,17 +591,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, ] [[package]] @@ -857,26 +831,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 }, { url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 }, { url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 }, - { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, - { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, - { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, - { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, - { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, - { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, - { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, - { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, - { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, - { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, - { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, - { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, - { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, - { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, - { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, - { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, - { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, - { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, - { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, - { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, { url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 }, ] @@ -918,6 +872,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/80/fb7d668f1be5e4443b7ac191f68390be24f7c2ebd36011741f62c7645eb2/cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", size = 2989208 }, ] +[[package]] +name = "dapr" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "grpcio", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "grpcio-status", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "protobuf", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "python-dateutil", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/b9/a170cba83c3038b84cacea27556ac1cbfe6e8e9b0160671196ea942fc0d6/dapr-1.14.0.tar.gz", hash = "sha256:d901b787a5154f4b4e448e439825693f3352dda374889ef541281dd2727b8d61", size = 92544 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/44/7f728f4985a173edd70436f07a1a8a4a3d2d71ff4664d1d5cfe93bcafb9e/dapr-1.14.0-py3-none-any.whl", hash = "sha256:31bfa9587b58d410a575dd46e568cd731e790e235d7b61b18cb17420977e9c84", size = 131503 }, +] + [[package]] name = "debugpy" version = "1.8.5" @@ -2237,22 +2208,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/0c/f30776ad91410d35148fcd7595ca2489e6f9c8cead8350ac976fc2ccf162/mmh3-5.0.0-cp312-cp312-win32.whl", hash = "sha256:cb1a96488dc8fccf843ccdbdd10faf1939e6e18cd928c2beff17e70c2ab09ec1", size = 34857 }, { url = "https://files.pythonhosted.org/packages/86/6b/24c9c618993a5d5612a12c156aa30b6a58e9123d9798642ed8d9608ef6f2/mmh3-5.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:897ebafa83bbbbb1958ee30cda78c7ad4b12f2b9360f96b22e488eb127b2cb4f", size = 35456 }, { url = "https://files.pythonhosted.org/packages/88/a1/e8f896aa6a61c8655e5ba708004700c142f2c34d02222d3e1afdcf2aaead/mmh3-5.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:e6e3334985865ec3bdfcc4ae8df4a1939be048c5ae3ce1c8c309744400f8e4de", size = 32189 }, - { url = "https://files.pythonhosted.org/packages/1f/1d/621df14c109a53148717a6e9aceef93b1a65bb46938cfc176eb5fb8664b4/mmh3-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:05b09d98cbdb6ad03eb9c701e87cea005ececd4fd7d2968ff0f5a86af1ef340d", size = 48594 }, - { url = "https://files.pythonhosted.org/packages/1a/90/f3f4fe3fea68d949fbe554841e036c33d571756ae4a9921d27e8fdb5e3e8/mmh3-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d4ac0b8d48ce1e7561cf330ec73b9582f6773e40aaf8a771dd51a0bb483ec94f", size = 34084 }, - { url = "https://files.pythonhosted.org/packages/77/eb/f6f734766113017a9d76bf25f83a8bc7b09a3798b92d357ad0418ed18bbc/mmh3-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5a1c056b65be3077496ed655731eff1f65ee67f2b31f40a027f3171ba0ac20d1", size = 33893 }, - { url = "https://files.pythonhosted.org/packages/65/24/e52443fb243a479513b7c1811798dd29d285b4d5edd2ef412aa77d0637bb/mmh3-5.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a572adb41cf831d79b3b38c7994e5a5bc1a8ea8d7b574ce0c24272fc5abb52df", size = 90675 }, - { url = "https://files.pythonhosted.org/packages/99/ad/9f1e0d11d4ed095b0c02a424b414b51596a18dacfb8f06912d042d597bb6/mmh3-5.0.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0be4d14ab3a690bac6c127733490493b8698f84eadb9d667be7eb952281c51e4", size = 95656 }, - { url = "https://files.pythonhosted.org/packages/f2/12/a7a3b84645106ad5c64e16557a97ab305673bbb6fe14ab55c1fc23083939/mmh3-5.0.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b65b6eabd9e78e2b8eee2b8d4db34d4d2f5b540f2ac06ec0a76a1f1566f0ff7", size = 95353 }, - { url = "https://files.pythonhosted.org/packages/68/66/6ccf44dc2adcde5bfd30a642880a51cf78712fd74195d88e103b8d10d084/mmh3-5.0.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b433656f371af5edf44cf00862e288e08327bb9e90c8aaa5e4e60dfebc62039", size = 83291 }, - { url = "https://files.pythonhosted.org/packages/43/55/a924e81867406bb0d1bf59039732e927a05a5c56b08e7b894687fda71881/mmh3-5.0.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1b12073a58be5e6408c6bd8366bbf6253defe042cdec25ee51f123c944e5a8f", size = 90524 }, - { url = "https://files.pythonhosted.org/packages/a0/c4/aa8f8527dfeff955e7be85901fde840df407a26b7f52e2a114e094c08422/mmh3-5.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:29b2c8eb7a473f6f235c2d9905912a76350dd11b42058364de984264fa4f74ca", size = 86180 }, - { url = "https://files.pythonhosted.org/packages/96/84/16a2a0a196c151d5d3d5513c5a5042b9c1cef428f68f2668337924b04fad/mmh3-5.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b178b744685de956ff84b3b2531271824a2e4372aff199ab805e1fdd7f996f5c", size = 85283 }, - { url = "https://files.pythonhosted.org/packages/e4/84/07584c6fbf82981359e3f702ed56a1e42657f4d670ae8e505c62df55a0cf/mmh3-5.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fcac7a75846aec7bd168c05576dc8c9448a9705165dfa0986d0f48952eca62a4", size = 90621 }, - { url = "https://files.pythonhosted.org/packages/c9/1b/cefb28385f8bfa24c058caf106a5cf7a28a238d06a7ce27a41b50a7b06bf/mmh3-5.0.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cc0caa0d2800d54384cc048e49e6c2b4a90cba1afff0597d7c2a5006c42b5536", size = 87006 }, - { url = "https://files.pythonhosted.org/packages/7b/cb/9da22a15b73ae5346fb51c7fab665adb9b4cf79038299c6eaea9b68b4f55/mmh3-5.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:05b10476fd5cfb0fd63ceebf7430612423e7f79e9732e0b344225aa642e12be4", size = 85546 }, - { url = "https://files.pythonhosted.org/packages/e4/03/249dc33217095088c9519ddda809e728d18a8cf1eefa2619c2586224eb2c/mmh3-5.0.0-cp313-cp313-win32.whl", hash = "sha256:7101a12a2a4b39d7748d2d83310d5e0415950ccf6b9ec8da1d35af3f50b3ef0e", size = 34852 }, - { url = "https://files.pythonhosted.org/packages/a2/b5/cb5b2fa2ceb34a65367afef283126c79f15e8f864bea50742f7184f6acf2/mmh3-5.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:47d9a9c1c48accaf78ddb77669c40c837e90be2ecddd39bf7ef2f8dacff85ca6", size = 35462 }, - { url = "https://files.pythonhosted.org/packages/8c/df/c070cf4dd4425f1c2abbff9b922ffb7a5161667a39cf32c618422406d78b/mmh3-5.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9126155ad1a9418920360497a0b44906dce32f0732cb44378ace08c62751dd1e", size = 32193 }, ] [[package]] @@ -2375,21 +2330,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, - { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, - { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, - { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, - { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, - { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, - { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, - { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, - { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, - { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, - { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, - { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, - { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, - { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, - { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, - { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, ] @@ -2550,24 +2490,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bf/f8/5edf1105b0dc24fd66fc3e9e7f3bca3d920cde571caaa4375ec1566073c3/numpy-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8661c94e3aad18e1ea17a11f60f843a4933ccaf1a25a7c6a9182af70610b2313", size = 14172488 }, { url = "https://files.pythonhosted.org/packages/f4/c2/dddca3e69a024d2f249a5b68698328163cbdafb7e65fbf6d36373bbabf12/numpy-2.1.1-cp312-cp312-win32.whl", hash = "sha256:950802d17a33c07cba7fd7c3dcfa7d64705509206be1606f196d179e539111ed", size = 6237195 }, { url = "https://files.pythonhosted.org/packages/b7/98/5640a09daa3abf0caeaefa6e7bf0d10c0aa28a77c84e507d6a716e0e23df/numpy-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fc5eabfc720db95d68e6646e88f8b399bfedd235994016351b1d9e062c4b270", size = 12568082 }, - { url = "https://files.pythonhosted.org/packages/6b/9e/8bc6f133bc6d359ccc9ec051853aded45504d217685191f31f46d36b7065/numpy-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:046356b19d7ad1890c751b99acad5e82dc4a02232013bd9a9a712fddf8eb60f5", size = 20834810 }, - { url = "https://files.pythonhosted.org/packages/32/1b/429519a2fa28681814c511574017d35f3aab7136d554cc65f4c1526dfbf5/numpy-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5a9cb2be39350ae6c8f79410744e80154df658d5bea06e06e0ac5bb75480d5", size = 13507739 }, - { url = "https://files.pythonhosted.org/packages/25/18/c732d7dd9896d11e4afcd487ac65e62f9fa0495563b7614eb850765361fa/numpy-2.1.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:d4c57b68c8ef5e1ebf47238e99bf27657511ec3f071c465f6b1bccbef12d4136", size = 5074465 }, - { url = "https://files.pythonhosted.org/packages/3e/37/838b7ae9262c370ab25312bab365492016f11810ffc03ebebbd54670b669/numpy-2.1.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8ae0fd135e0b157365ac7cc31fff27f07a5572bdfc38f9c2d43b2aff416cc8b0", size = 6606418 }, - { url = "https://files.pythonhosted.org/packages/8b/b9/7ff3bfb71e316a5b43a124c4b7a5881ab12f3c32636014bef1f757f19dbd/numpy-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981707f6b31b59c0c24bcda52e5605f9701cb46da4b86c2e8023656ad3e833cb", size = 13692464 }, - { url = "https://files.pythonhosted.org/packages/42/78/75bcf16e6737cd196ff7ecf0e1fd3f953293a34dff4fd93fb488e8308536/numpy-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca4b53e1e0b279142113b8c5eb7d7a877e967c306edc34f3b58e9be12fda8df", size = 16037763 }, - { url = "https://files.pythonhosted.org/packages/23/99/36bf5ffe034d06df307bc783e25cf164775863166dcd878879559fe0379f/numpy-2.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e097507396c0be4e547ff15b13dc3866f45f3680f789c1a1301b07dadd3fbc78", size = 16410374 }, - { url = "https://files.pythonhosted.org/packages/7f/16/04c5dab564887d4cd31a9ed30e51467fa70d52a4425f5a9bd1eed5b3d34c/numpy-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7506387e191fe8cdb267f912469a3cccc538ab108471291636a96a54e599556", size = 14169873 }, - { url = "https://files.pythonhosted.org/packages/09/e0/d1b5adbf1731886c4186c59a9fa208585df9452a43a2b60e79af7c649717/numpy-2.1.1-cp313-cp313-win32.whl", hash = "sha256:251105b7c42abe40e3a689881e1793370cc9724ad50d64b30b358bbb3a97553b", size = 6234118 }, - { url = "https://files.pythonhosted.org/packages/d0/9c/2391ee6e9ebe77232ddcab29d92662b545e99d78c3eb3b4e26d59b9ca1ca/numpy-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:f212d4f46b67ff604d11fff7cc62d36b3e8714edf68e44e9760e19be38c03eb0", size = 12561742 }, - { url = "https://files.pythonhosted.org/packages/38/0e/c4f754f9e73f9bb520e8bf418c646f2c4f70c5d5f2bc561e90f884593193/numpy-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:920b0911bb2e4414c50e55bd658baeb78281a47feeb064ab40c2b66ecba85553", size = 20858403 }, - { url = "https://files.pythonhosted.org/packages/32/fc/d69092b9171efa0cb8079577e71ce0cac0e08f917d33f6e99c916ed51d44/numpy-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bab7c09454460a487e631ffc0c42057e3d8f2a9ddccd1e60c7bb8ed774992480", size = 13519851 }, - { url = "https://files.pythonhosted.org/packages/14/2a/d7cf2cd9f15b23f623075546ea64a2c367cab703338ca22aaaecf7e704df/numpy-2.1.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:cea427d1350f3fd0d2818ce7350095c1a2ee33e30961d2f0fef48576ddbbe90f", size = 5115444 }, - { url = "https://files.pythonhosted.org/packages/8e/00/e87b2cb4afcecca3b678deefb8fa53005d7054f3b5c39596e5554e5d98f8/numpy-2.1.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:e30356d530528a42eeba51420ae8bf6c6c09559051887196599d96ee5f536468", size = 6628903 }, - { url = "https://files.pythonhosted.org/packages/ab/9d/337ae8721b3beec48c3413d71f2d44b2defbf3c6f7a85184fc18b7b61f4a/numpy-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8dfa9e94fc127c40979c3eacbae1e61fda4fe71d84869cc129e2721973231ef", size = 13665945 }, - { url = "https://files.pythonhosted.org/packages/c0/90/ee8668e84c5d5cc080ef3beb622c016adf19ca3aa51afe9dbdcc6a9baf59/numpy-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910b47a6d0635ec1bd53b88f86120a52bf56dcc27b51f18c7b4a2e2224c29f0f", size = 16023473 }, - { url = "https://files.pythonhosted.org/packages/38/a0/57c24b2131879183051dc698fbb53fd43b77c3fa85b6e6311014f2bc2973/numpy-2.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:13cc11c00000848702322af4de0147ced365c81d66053a67c2e962a485b3717c", size = 16400624 }, - { url = "https://files.pythonhosted.org/packages/bb/4c/14a41eb5c9548c6cee6af0936eabfd985c69230ffa2f2598321431a9aa0a/numpy-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53e27293b3a2b661c03f79aa51c3987492bd4641ef933e366e0f9f6c9bf257ec", size = 14155072 }, { url = "https://files.pythonhosted.org/packages/94/9a/d6a5d138b53ccdc002fdf07f0d1a960326c510e66cbfff7180c88d37c482/numpy-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7be6a07520b88214ea85d8ac8b7d6d8a1839b0b5cb87412ac9f49fa934eb15d5", size = 20982055 }, { url = "https://files.pythonhosted.org/packages/40/b5/78d8b5481aeef6d2aad3724c6aa5398045d2657038dfe54c055cae1fcf75/numpy-2.1.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:52ac2e48f5ad847cd43c4755520a2317f3380213493b9d8a4c5e37f3b87df504", size = 6750222 }, { url = "https://files.pythonhosted.org/packages/eb/9a/59a548ad57df8c432bfac4556504a9fae5c082ffea53d108fcf7ce2956e4/numpy-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a95ca3560a6058d6ea91d4629a83a897ee27c00630aed9d933dff191f170cd", size = 16141236 }, @@ -2993,12 +2915,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/1a/d11805670c29d3a1b29fc4bd048dc90b094784779690592efe8c9f71249a/orjson-3.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2d9f990623f15c0ae7ac608103c33dfe1486d2ed974ac3f40b693bad1a22a7b", size = 167994 }, { url = "https://files.pythonhosted.org/packages/20/5f/03d89b007f9d6733dc11bc35d64812101c85d6c4e9c53af9fa7e7689cb11/orjson-3.10.7-cp312-none-win32.whl", hash = "sha256:7c4c17f8157bd520cdb7195f75ddbd31671997cbe10aee559c2d613592e7d7eb", size = 143130 }, { url = "https://files.pythonhosted.org/packages/c6/9d/9b9fb6c60b8a0e04031ba85414915e19ecea484ebb625402d968ea45b8d5/orjson-3.10.7-cp312-none-win_amd64.whl", hash = "sha256:1d9c0e733e02ada3ed6098a10a8ee0052dd55774de3d9110d29868d24b17faa1", size = 137326 }, - { url = "https://files.pythonhosted.org/packages/15/05/121af8a87513c56745d01ad7cf215c30d08356da9ad882ebe2ba890824cd/orjson-3.10.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:77d325ed866876c0fa6492598ec01fe30e803272a6e8b10e992288b009cbe149", size = 251331 }, - { url = "https://files.pythonhosted.org/packages/73/7f/8d6ccd64a6f8bdbfe6c9be7c58aeb8094aa52a01fbbb2cda42ff7e312bd7/orjson-3.10.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea2c232deedcb605e853ae1db2cc94f7390ac776743b699b50b071b02bea6fe", size = 142012 }, - { url = "https://files.pythonhosted.org/packages/04/65/f2a03fd1d4f0308f01d372e004c049f7eb9bc5676763a15f20f383fa9c01/orjson-3.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3dcfbede6737fdbef3ce9c37af3fb6142e8e1ebc10336daa05872bfb1d87839c", size = 169920 }, - { url = "https://files.pythonhosted.org/packages/e2/1c/3ef8d83d7c6a619ad3d69a4d5318591b4ce5862e6eda7c26bbe8208652ca/orjson-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11748c135f281203f4ee695b7f80bb1358a82a63905f9f0b794769483ea854ad", size = 167916 }, - { url = "https://files.pythonhosted.org/packages/f2/0d/820a640e5a7dfbe525e789c70871ebb82aff73b0c7bf80082653f86b9431/orjson-3.10.7-cp313-none-win32.whl", hash = "sha256:a7e19150d215c7a13f39eb787d84db274298d3f83d85463e61d277bbd7f401d2", size = 143089 }, - { url = "https://files.pythonhosted.org/packages/1a/72/a424db9116c7cad2950a8f9e4aeb655a7b57de988eb015acd0fcd1b4609b/orjson-3.10.7-cp313-none-win_amd64.whl", hash = "sha256:eef44224729e9525d5261cc8d28d6b11cafc90e6bd0be2157bde69a52ec83024", size = 137081 }, ] [[package]] @@ -3052,19 +2968,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 }, { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 }, { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 }, - { url = "https://files.pythonhosted.org/packages/64/22/3b8f4e0ed70644e85cfdcd57454686b9057c6c38d2f74fe4b8bc2527214a/pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", size = 12477643 }, - { url = "https://files.pythonhosted.org/packages/e4/93/b3f5d1838500e22c8d793625da672f3eec046b1a99257666c94446969282/pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", size = 11281573 }, - { url = "https://files.pythonhosted.org/packages/f5/94/6c79b07f0e5aab1dcfa35a75f4817f5c4f677931d4234afcd75f0e6a66ca/pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", size = 15196085 }, - { url = "https://files.pythonhosted.org/packages/e8/31/aa8da88ca0eadbabd0a639788a6da13bb2ff6edbbb9f29aa786450a30a91/pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", size = 12711809 }, - { url = "https://files.pythonhosted.org/packages/ee/7c/c6dbdb0cb2a4344cacfb8de1c5808ca885b2e4dcfde8008266608f9372af/pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", size = 16356316 }, - { url = "https://files.pythonhosted.org/packages/57/b7/8b757e7d92023b832869fa8881a992696a0bfe2e26f72c9ae9f255988d42/pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", size = 14022055 }, - { url = "https://files.pythonhosted.org/packages/3b/bc/4b18e2b8c002572c5a441a64826252ce5da2aa738855747247a971988043/pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", size = 11481175 }, - { url = "https://files.pythonhosted.org/packages/76/a3/a5d88146815e972d40d19247b2c162e88213ef51c7c25993942c39dbf41d/pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", size = 12615650 }, - { url = "https://files.pythonhosted.org/packages/9c/8c/f0fd18f6140ddafc0c24122c8a964e48294acc579d47def376fef12bcb4a/pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", size = 11290177 }, - { url = "https://files.pythonhosted.org/packages/ed/f9/e995754eab9c0f14c6777401f7eece0943840b7a9fc932221c19d1abee9f/pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", size = 14651526 }, - { url = "https://files.pythonhosted.org/packages/25/b0/98d6ae2e1abac4f35230aa756005e8654649d305df9a28b16b9ae4353bff/pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", size = 11871013 }, - { url = "https://files.pythonhosted.org/packages/cc/57/0f72a10f9db6a4628744c8e8f0df4e6e21de01212c7c981d31e50ffc8328/pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", size = 15711620 }, - { url = "https://files.pythonhosted.org/packages/ab/5f/b38085618b950b79d2d9164a711c52b10aefc0ae6833b96f626b7021b2ed/pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", size = 13098436 }, ] [[package]] @@ -3154,17 +3057,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/04/5e6de6e6120451ec0c24516c41dbaf80cce1b6451f96561235ef2429da2e/pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", size = 2235690 }, { url = "https://files.pythonhosted.org/packages/74/0a/d4ce3c44bca8635bd29a2eab5aa181b654a734a29b263ca8efe013beea98/pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", size = 2554951 }, { url = "https://files.pythonhosted.org/packages/b5/ca/184349ee40f2e92439be9b3502ae6cfc43ac4b50bc4fc6b3de7957563894/pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", size = 2243427 }, - { url = "https://files.pythonhosted.org/packages/c3/00/706cebe7c2c12a6318aabe5d354836f54adff7156fd9e1bd6c89f4ba0e98/pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", size = 3525685 }, - { url = "https://files.pythonhosted.org/packages/cf/76/f658cbfa49405e5ecbfb9ba42d07074ad9792031267e782d409fd8fe7c69/pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", size = 3374883 }, - { url = "https://files.pythonhosted.org/packages/46/2b/99c28c4379a85e65378211971c0b430d9c7234b1ec4d59b2668f6299e011/pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", size = 4339837 }, - { url = "https://files.pythonhosted.org/packages/f1/74/b1ec314f624c0c43711fdf0d8076f82d9d802afd58f1d62c2a86878e8615/pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", size = 4455562 }, - { url = "https://files.pythonhosted.org/packages/4a/2a/4b04157cb7b9c74372fa867096a1607e6fedad93a44deeff553ccd307868/pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", size = 4366761 }, - { url = "https://files.pythonhosted.org/packages/ac/7b/8f1d815c1a6a268fe90481232c98dd0e5fa8c75e341a75f060037bd5ceae/pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", size = 4536767 }, - { url = "https://files.pythonhosted.org/packages/e5/77/05fa64d1f45d12c22c314e7b97398ffb28ef2813a485465017b7978b3ce7/pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", size = 4477989 }, - { url = "https://files.pythonhosted.org/packages/12/63/b0397cfc2caae05c3fb2f4ed1b4fc4fc878f0243510a7a6034ca59726494/pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", size = 4610255 }, - { url = "https://files.pythonhosted.org/packages/7b/f9/cfaa5082ca9bc4a6de66ffe1c12c2d90bf09c309a5f52b27759a596900e7/pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", size = 2235603 }, - { url = "https://files.pythonhosted.org/packages/01/6a/30ff0eef6e0c0e71e55ded56a38d4859bf9d3634a94a88743897b5f96936/pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", size = 2554972 }, - { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, @@ -3334,8 +3226,6 @@ version = "6.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/c7/8c6872f7372eb6a6b2e4708b88419fb46b857f7a2e1892966b851cc79fc9/psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2", size = 508067 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/66/78c9c3020f573c58101dc43a44f6855d01bbbd747e24da2f0c4491200ea3/psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", size = 249766 }, - { url = "https://files.pythonhosted.org/packages/e1/3f/2403aa9558bea4d3854b0e5e567bc3dd8e9fbc1fc4453c0aa9aafeb75467/psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", size = 253024 }, { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 }, { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 }, { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 }, @@ -3404,17 +3294,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/94/3126db7a06fa9fe2ab3b1d6dd7a4add6bc1596b6864e01a77239702827b4/psycopg_binary-3.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66de2dd7d37bf66eb234ca9d907f5cd8caca43ff8d8a50dd5c15844d1cf0390c", size = 3184181 }, { url = "https://files.pythonhosted.org/packages/6c/0e/6cce5ffaa25a25ede5ff08e757232bb425cacafe622627f29d286774073b/psycopg_binary-3.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2eb6f8f410dbbb71b8c633f283b8588b63bee0a7321f00ab76e9c800c593f732", size = 3229942 }, { url = "https://files.pythonhosted.org/packages/10/31/951247b07205711115307f36ec3dbf6726101e086562febf6f989cbd6b95/psycopg_binary-3.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:b45553c6b614d02e1486585980afdfd18f0000aac668e2e87c6e32da1adb051a", size = 2912528 }, - { url = "https://files.pythonhosted.org/packages/87/e5/245f749abdfc33b42ec2bc4d89fe2cdb29cd40dca7156d0e09308c33f933/psycopg_binary-3.2.2-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:1ee891287c2da57e7fee31fbe2fbcdf57125768133d811b02e9523d5a052eb28", size = 3358682 }, - { url = "https://files.pythonhosted.org/packages/93/dc/047a90e2bfd80a8414f5a203c7ff1747e3b3f43231c3c8059e8be91849cc/psycopg_binary-3.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5e95e4a8076ac7611e571623e1113fa84fd48c0459601969ffbf534d7aa236e7", size = 3500354 }, - { url = "https://files.pythonhosted.org/packages/df/72/b905dec41c30a8aad21f7767b21d3e5d3b9a7e92c1844678e4083d79257b/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6269d79a3d7d76b6fcf0fafae8444da00e83777a6c68c43851351a571ad37155", size = 4445322 }, - { url = "https://files.pythonhosted.org/packages/aa/41/aef11d4cda1af4a8181fbd578af39d6920232624fc6222f6b2f9758cc0e0/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6dd5d21a298c3c53af20ced8da4ae4cd038c6fe88c80842a8888fa3660b2094", size = 4248626 }, - { url = "https://files.pythonhosted.org/packages/6c/75/39ed8598f44188e4985f31f2639aa9894851fdfbf061bf926744b08b5790/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cf64e41e238620f05aad862f06bc8424f8f320d8075f1499bd85a225d18bd57", size = 4485767 }, - { url = "https://files.pythonhosted.org/packages/00/5a/ecdc4cf957d0658f77cc6fa61f6ee2e5118c914e5f93497375023389a1e5/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c482c3236ded54add31136a91d5223b233ec301f297fa2db79747404222dca6", size = 4188840 }, - { url = "https://files.pythonhosted.org/packages/2d/71/af4c47a665d13d2477085f77fb64195da5d6463dd54fc3a8bdfd5c082d24/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0718be095cefdad712542169d16fa58b3bd9200a3de1b0217ae761cdec1cf569", size = 3114998 }, - { url = "https://files.pythonhosted.org/packages/38/8f/6d56168d2ce7e7d802e09a4288faceb52f28bd4023cde72ede9e848c9f9b/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fb303b03c243a9041e1873b596e246f7caaf01710b312fafa65b1db5cd77dd6f", size = 3095882 }, - { url = "https://files.pythonhosted.org/packages/8b/76/c77643d97292673d8a5e3eea643812d585993155658f840c86bfa855e077/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:705da5bc4364bd7529473225fca02b795653bc5bd824dbe43e1df0b1a40fe691", size = 3189435 }, - { url = "https://files.pythonhosted.org/packages/30/31/b4ea793bdf44acca51e3fa6f68cc80d03725e8ef87fc2ee2b332c49fa521/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:05406b96139912574571b1c56bb023839a9146cf4b57c4548f36251dd5909fa1", size = 3233951 }, - { url = "https://files.pythonhosted.org/packages/49/e3/633d6d05e40651acb30458e296c90e878fa4caf3b3c21bb9e6adc912b811/psycopg_binary-3.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:7c357cf87e8d7612cfe781225be7669f35038a765d1b53ec9605f6c5aef9ee85", size = 2913412 }, ] [[package]] @@ -3601,18 +3480,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, - { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, - { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, - { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, - { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, - { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, - { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, - { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, - { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, - { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, - { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, - { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, - { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, { url = "https://files.pythonhosted.org/packages/13/a9/5d582eb3204464284611f636b55c0a7410d748ff338756323cb1ce721b96/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", size = 1857135 }, { url = "https://files.pythonhosted.org/packages/2c/57/faf36290933fe16717f97829eabfb1868182ac495f99cf0eda9f59687c9d/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", size = 1740583 }, { url = "https://files.pythonhosted.org/packages/91/7c/d99e3513dc191c4fec363aef1bf4c8af9125d8fa53af7cb97e8babef4e40/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", size = 1793637 }, @@ -3895,15 +3762,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, ] [[package]] @@ -3951,27 +3809,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 }, { url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 }, { url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 }, - { url = "https://files.pythonhosted.org/packages/04/a7/0f7e2f6c126fe6e62dbae0bc93b1bd3f1099cf7fea47a5468defebe3f39d/pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", size = 1006564 }, - { url = "https://files.pythonhosted.org/packages/31/b6/a187165c852c5d49f826a690857684333a6a4a065af0a6015572d2284f6a/pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", size = 1340447 }, - { url = "https://files.pythonhosted.org/packages/68/ba/f4280c58ff71f321602a6e24fd19879b7e79793fb8ab14027027c0fb58ef/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", size = 665485 }, - { url = "https://files.pythonhosted.org/packages/77/b5/c987a5c53c7d8704216f29fc3d810b32f156bcea488a940e330e1bcbb88d/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", size = 903484 }, - { url = "https://files.pythonhosted.org/packages/29/c9/07da157d2db18c72a7eccef8e684cefc155b712a88e3d479d930aa9eceba/pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", size = 859981 }, - { url = "https://files.pythonhosted.org/packages/43/09/e12501bd0b8394b7d02c41efd35c537a1988da67fc9c745cae9c6c776d31/pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", size = 860334 }, - { url = "https://files.pythonhosted.org/packages/eb/ff/f5ec1d455f8f7385cc0a8b2acd8c807d7fade875c14c44b85c1bddabae21/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", size = 1196179 }, - { url = "https://files.pythonhosted.org/packages/ec/8a/bb2ac43295b1950fe436a81fc5b298be0b96ac76fb029b514d3ed58f7b27/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", size = 1507668 }, - { url = "https://files.pythonhosted.org/packages/a9/49/dbc284ebcfd2dca23f6349227ff1616a7ee2c4a35fe0a5d6c3deff2b4fed/pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", size = 1406539 }, - { url = "https://files.pythonhosted.org/packages/00/68/093cdce3fe31e30a341d8e52a1ad86392e13c57970d722c1f62a1d1a54b6/pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", size = 575567 }, - { url = "https://files.pythonhosted.org/packages/92/ae/6cc4657148143412b5819b05e362ae7dd09fb9fe76e2a539dcff3d0386bc/pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", size = 637551 }, - { url = "https://files.pythonhosted.org/packages/6c/67/fbff102e201688f97c8092e4c3445d1c1068c2f27bbd45a578df97ed5f94/pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", size = 540378 }, - { url = "https://files.pythonhosted.org/packages/3f/fe/2d998380b6e0122c6c4bdf9b6caf490831e5f5e2d08a203b5adff060c226/pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", size = 1007378 }, - { url = "https://files.pythonhosted.org/packages/4a/f4/30d6e7157f12b3a0390bde94d6a8567cdb88846ed068a6e17238a4ccf600/pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", size = 1329532 }, - { url = "https://files.pythonhosted.org/packages/82/86/3fe917870e15ee1c3ad48229a2a64458e36036e64b4afa9659045d82bfa8/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", size = 653242 }, - { url = "https://files.pythonhosted.org/packages/50/2d/242e7e6ef6c8c19e6cb52d095834508cd581ffb925699fd3c640cdc758f1/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", size = 888404 }, - { url = "https://files.pythonhosted.org/packages/ac/11/7270566e1f31e4ea73c81ec821a4b1688fd551009a3d2bab11ec66cb1e8f/pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", size = 845858 }, - { url = "https://files.pythonhosted.org/packages/91/d5/72b38fbc69867795c8711bdd735312f9fef1e3d9204e2f63ab57085434b9/pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", size = 847375 }, - { url = "https://files.pythonhosted.org/packages/dd/9a/10ed3c7f72b4c24e719c59359fbadd1a27556a28b36cdf1cd9e4fb7845d5/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", size = 1183489 }, - { url = "https://files.pythonhosted.org/packages/72/2d/8660892543fabf1fe41861efa222455811adac9f3c0818d6c3170a1153e3/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", size = 1492932 }, - { url = "https://files.pythonhosted.org/packages/7b/d6/32fd69744afb53995619bc5effa2a405ae0d343cd3e747d0fbc43fe894ee/pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", size = 1392485 }, { url = "https://files.pythonhosted.org/packages/53/fb/36b2b2548286e9444e52fcd198760af99fd89102b5be50f0660fcfe902df/pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", size = 906955 }, { url = "https://files.pythonhosted.org/packages/77/8f/6ce54f8979a01656e894946db6299e2273fcee21c8e5fa57c6295ef11f57/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", size = 565701 }, { url = "https://files.pythonhosted.org/packages/ee/1c/bf8cd66730a866b16db8483286078892b7f6536f8c389fb46e4beba0a970/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", size = 794312 }, @@ -4079,21 +3916,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 }, { url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 }, { url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 }, - { url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 }, - { url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 }, - { url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 }, - { url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 }, - { url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 }, - { url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 }, - { url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 }, - { url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 }, - { url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 }, - { url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 }, - { url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 }, - { url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 }, - { url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 }, - { url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 }, - { url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 }, ] [[package]] @@ -4194,19 +4016,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/2d/5536d28c507a4679179ab15aa0049440e4d3dd6752050fa0843ed11e9354/rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", size = 528807 }, { url = "https://files.pythonhosted.org/packages/e3/62/7ebe6ec0d3dd6130921f8cffb7e34afb7f71b3819aa0446a24c5e81245ec/rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", size = 200993 }, { url = "https://files.pythonhosted.org/packages/ec/2f/b938864d66b86a6e4acadefdc56de75ef56f7cafdfd568a6464605457bd5/rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", size = 214458 }, - { url = "https://files.pythonhosted.org/packages/99/32/43b919a0a423c270a838ac2726b1c7168b946f2563fd99a51aaa9692d00f/rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", size = 321465 }, - { url = "https://files.pythonhosted.org/packages/58/a9/c4d899cb28e9e47b0ff12462e8f827381f243176036f17bef9c1604667f2/rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", size = 312900 }, - { url = "https://files.pythonhosted.org/packages/8f/90/9e51670575b5dfaa8c823369ef7d943087bfb73d4f124a99ad6ef19a2b26/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", size = 370973 }, - { url = "https://files.pythonhosted.org/packages/fc/c1/523f2a03f853fc0d4c1acbef161747e9ab7df0a8abf6236106e333540921/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", size = 370890 }, - { url = "https://files.pythonhosted.org/packages/51/ca/2458a771f16b0931de4d384decbe43016710bc948036c8f4562d6e063437/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", size = 397174 }, - { url = "https://files.pythonhosted.org/packages/00/7d/6e06807f6305ea2408b364efb0eef83a6e21b5e7b5267ad6b473b9a7e416/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", size = 426449 }, - { url = "https://files.pythonhosted.org/packages/8c/d1/6c9e65260a819a1714510a7d69ac1d68aa23ee9ce8a2d9da12187263c8fc/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", size = 357698 }, - { url = "https://files.pythonhosted.org/packages/5d/fb/ecea8b5286d2f03eec922be7173a03ed17278944f7c124348f535116db15/rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", size = 378530 }, - { url = "https://files.pythonhosted.org/packages/e3/e3/ac72f858957f52a109c588589b73bd2fad4a0fc82387fb55fb34aeb0f9cd/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", size = 545753 }, - { url = "https://files.pythonhosted.org/packages/b2/a4/a27683b519d5fc98e4390a3b130117d80fd475c67aeda8aac83c0e8e326a/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", size = 552443 }, - { url = "https://files.pythonhosted.org/packages/a1/ed/c074d248409b4432b1ccb2056974175fa0af2d1bc1f9c21121f80a358fa3/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", size = 528380 }, - { url = "https://files.pythonhosted.org/packages/d5/bd/04caf938895d2d78201e89c0c8a94dfd9990c34a19ff52fb01d0912343e3/rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", size = 200540 }, - { url = "https://files.pythonhosted.org/packages/95/cc/109eb8b9863680411ae703664abacaa035820c7755acc9686d5dd02cdd2e/rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", size = 214111 }, { url = "https://files.pythonhosted.org/packages/06/39/bf1f664c347c946ef56cecaa896e3693d91acc741afa78ebb3fdb7aba08b/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", size = 319444 }, { url = "https://files.pythonhosted.org/packages/c1/71/876135d3cb90d62468540b84e8e83ff4dc92052ab309bfdea7ea0b9221ad/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", size = 311699 }, { url = "https://files.pythonhosted.org/packages/f7/da/8ccaeba6a3dda7467aebaf893de9eafd56275e2c90773c83bf15fb0b8374/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", size = 367825 }, @@ -4356,16 +4165,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/4d/b6208d918e83daa84b424c0ac3191ae61b44b3191613a3a5a7b38f94b8ad/safetensors-0.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a6ba28118636a130ccbb968bc33d4684c48678695dba2590169d5ab03a45646", size = 605390 }, { url = "https://files.pythonhosted.org/packages/e8/20/bf0e01825dc01ed75538021a98b9a046e60ead63c6c6700764c821a8c873/safetensors-0.4.5-cp312-none-win32.whl", hash = "sha256:c859c7ed90b0047f58ee27751c8e56951452ed36a67afee1b0a87847d065eec6", size = 273250 }, { url = "https://files.pythonhosted.org/packages/f1/5f/ab6b6cec85b40789801f35b7d2fb579ae242d8193929974a106d5ff5c835/safetensors-0.4.5-cp312-none-win_amd64.whl", hash = "sha256:b5a8810ad6a6f933fff6c276eae92c1da217b39b4d8b1bc1c0b8af2d270dc532", size = 286307 }, - { url = "https://files.pythonhosted.org/packages/90/61/0e27b1403e311cba0be20026bee4ee822d90eda7dad372179e7f18bb99f3/safetensors-0.4.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:25e5f8e2e92a74f05b4ca55686234c32aac19927903792b30ee6d7bd5653d54e", size = 392062 }, - { url = "https://files.pythonhosted.org/packages/b1/9f/cc31fafc9f5d79da10a83a820ca37f069bab0717895ad8cbcacf629dd1c5/safetensors-0.4.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:81efb124b58af39fcd684254c645e35692fea81c51627259cdf6d67ff4458916", size = 382517 }, - { url = "https://files.pythonhosted.org/packages/a4/c7/4fda8a0ebb96662550433378f4a74c677fa5fc4d0a43a7ec287d1df254a9/safetensors-0.4.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:585f1703a518b437f5103aa9cf70e9bd437cb78eea9c51024329e4fb8a3e3679", size = 441378 }, - { url = "https://files.pythonhosted.org/packages/14/31/9abb431f6209de9c80dab83e1112ebd769f1e32e7ab7ab228a02424a4693/safetensors-0.4.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4b99fbf72e3faf0b2f5f16e5e3458b93b7d0a83984fe8d5364c60aa169f2da89", size = 438831 }, - { url = "https://files.pythonhosted.org/packages/37/37/99bfb195578a808b8d045159ee9264f8da58d017ac0701853dcacda14d4e/safetensors-0.4.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b17b299ca9966ca983ecda1c0791a3f07f9ca6ab5ded8ef3d283fff45f6bcd5f", size = 477112 }, - { url = "https://files.pythonhosted.org/packages/7d/05/fac3ef107e60d2a78532bed171a91669d4bb259e1236f5ea8c67a6976c75/safetensors-0.4.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76ded72f69209c9780fdb23ea89e56d35c54ae6abcdec67ccb22af8e696e449a", size = 493373 }, - { url = "https://files.pythonhosted.org/packages/cf/7a/825800ee8c68214b4fd3506d5e19209338c69b41e01c6e14dd13969cc8b9/safetensors-0.4.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2783956926303dcfeb1de91a4d1204cd4089ab441e622e7caee0642281109db3", size = 435422 }, - { url = "https://files.pythonhosted.org/packages/5e/6c/7a3233c08bde558d6c33a41219119866cb596139a4673cc6c24024710ffd/safetensors-0.4.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d94581aab8c6b204def4d7320f07534d6ee34cd4855688004a4354e63b639a35", size = 457382 }, - { url = "https://files.pythonhosted.org/packages/a0/58/0b7bcba3788ff503990cf9278d611b56c029400612ba93e772c987b5aa03/safetensors-0.4.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:67e1e7cb8678bb1b37ac48ec0df04faf689e2f4e9e81e566b5c63d9f23748523", size = 619301 }, - { url = "https://files.pythonhosted.org/packages/82/cc/9c2cf58611daf1c83ce5d37f9de66353e23fcda36008b13fd3409a760aa3/safetensors-0.4.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:dbd280b07e6054ea68b0cb4b16ad9703e7d63cd6890f577cb98acc5354780142", size = 605580 }, { url = "https://files.pythonhosted.org/packages/cf/ff/037ae4c0ee32db496669365e66079b6329906c6814722b159aa700e67208/safetensors-0.4.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdadf66b5a22ceb645d5435a0be7a0292ce59648ca1d46b352f13cff3ea80410", size = 392951 }, { url = "https://files.pythonhosted.org/packages/f1/d6/6621e16b35bf83ae099eaab07338f04991a26c9aa43879d05f19f35e149c/safetensors-0.4.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d42ffd4c2259f31832cb17ff866c111684c87bd930892a1ba53fed28370c918c", size = 383417 }, { url = "https://files.pythonhosted.org/packages/ae/88/3068e1bb16f5e9f9068901de3cf7b3db270b9bfe6e7d51d4b55c1da0425d/safetensors-0.4.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd8a1f6d2063a92cd04145c7fd9e31a1c7d85fbec20113a14b487563fdbc0597", size = 442311 }, @@ -4402,11 +4201,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a1/32/4a7a205b14c11225609b75b28402c196e4396ac754dab6a81971b811781c/scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f60021ec1574e56632be2a36b946f8143bf4e5e6af4a06d85281adc22938e0dd", size = 12085794 }, { url = "https://files.pythonhosted.org/packages/c6/29/044048c5e911373827c0e1d3051321b9183b2a4f8d4e2f11c08fcff83f13/scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:394397841449853c2290a32050382edaec3da89e35b3e03d6cc966aebc6a8ae6", size = 12945797 }, { url = "https://files.pythonhosted.org/packages/aa/ce/c0b912f2f31aeb1b756a6ba56bcd84dd1f8a148470526a48515a3f4d48cd/scikit_learn-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:57cc1786cfd6bd118220a92ede80270132aa353647684efa385a74244a41e3b1", size = 10985467 }, - { url = "https://files.pythonhosted.org/packages/a4/50/8891028437858cc510e13578fe7046574a60c2aaaa92b02d64aac5b1b412/scikit_learn-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9a702e2de732bbb20d3bad29ebd77fc05a6b427dc49964300340e4c9328b3f5", size = 12025584 }, - { url = "https://files.pythonhosted.org/packages/d2/79/17feef8a1c14149436083bec0e61d7befb4812e272d5b20f9d79ea3e9ab1/scikit_learn-1.5.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:b0768ad641981f5d3a198430a1d31c3e044ed2e8a6f22166b4d546a5116d7908", size = 10959795 }, - { url = "https://files.pythonhosted.org/packages/b1/c8/f08313f9e2e656bd0905930ae8bf99a573ea21c34666a813b749c338202f/scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:178ddd0a5cb0044464fc1bfc4cca5b1833bfc7bb022d70b05db8530da4bb3dd3", size = 12077302 }, - { url = "https://files.pythonhosted.org/packages/a7/48/fbfb4dc72bed0fe31fe045fb30e924909ad03f717c36694351612973b1a9/scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7284ade780084d94505632241bf78c44ab3b6f1e8ccab3d2af58e0e950f9c12", size = 13002811 }, - { url = "https://files.pythonhosted.org/packages/a5/e7/0c869f9e60d225a77af90d2aefa7a4a4c0e745b149325d1450f0f0ce5399/scikit_learn-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:b7b0f9a0b1040830d38c39b91b3a44e1b643f4b36e36567b80b7c6bd2202a27f", size = 10951354 }, ] [[package]] @@ -4442,19 +4236,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8e/ee/8a26858ca517e9c64f84b4c7734b89bda8e63bec85c3d2f432d225bb1886/scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066", size = 40849331 }, { url = "https://files.pythonhosted.org/packages/a5/cd/06f72bc9187840f1c99e1a8750aad4216fc7dfdd7df46e6280add14b4822/scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1", size = 42544049 }, { url = "https://files.pythonhosted.org/packages/aa/7d/43ab67228ef98c6b5dd42ab386eae2d7877036970a0d7e3dd3eb47a0d530/scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f", size = 44521212 }, - { url = "https://files.pythonhosted.org/packages/50/ef/ac98346db016ff18a6ad7626a35808f37074d25796fd0234c2bb0ed1e054/scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79", size = 39091068 }, - { url = "https://files.pythonhosted.org/packages/b9/cc/70948fe9f393b911b4251e96b55bbdeaa8cca41f37c26fd1df0232933b9e/scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e", size = 29875417 }, - { url = "https://files.pythonhosted.org/packages/3b/2e/35f549b7d231c1c9f9639f9ef49b815d816bf54dd050da5da1c11517a218/scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73", size = 23084508 }, - { url = "https://files.pythonhosted.org/packages/3f/d6/b028e3f3e59fae61fb8c0f450db732c43dd1d836223a589a8be9f6377203/scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e", size = 25503364 }, - { url = "https://files.pythonhosted.org/packages/a7/2f/6c142b352ac15967744d62b165537a965e95d557085db4beab2a11f7943b/scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d", size = 35292639 }, - { url = "https://files.pythonhosted.org/packages/56/46/2449e6e51e0d7c3575f289f6acb7f828938eaab8874dbccfeb0cd2b71a27/scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e", size = 40798288 }, - { url = "https://files.pythonhosted.org/packages/32/cd/9d86f7ed7f4497c9fd3e39f8918dd93d9f647ba80d7e34e4946c0c2d1a7c/scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06", size = 42524647 }, - { url = "https://files.pythonhosted.org/packages/f5/1b/6ee032251bf4cdb0cc50059374e86a9f076308c1512b61c4e003e241efb7/scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84", size = 44469524 }, ] [[package]] name = "semantic-kernel" -version = "1.11.0" +version = "1.12.1" source = { editable = "." } dependencies = [ { name = "aiohttp", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -4490,6 +4276,9 @@ azure = [ chroma = [ { name = "chromadb", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] +dapr = [ + { name = "dapr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +] google = [ { name = "google-cloud-aiplatform", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "google-generativeai", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -4570,6 +4359,7 @@ requires-dist = [ { name = "boto3", marker = "extra == 'aws'", specifier = ">=1.28.57" }, { name = "chromadb", marker = "extra == 'chroma'", specifier = ">=0.4,<0.6" }, { name = "cloudevents", specifier = "~=1.0" }, + { name = "dapr", marker = "extra == 'dapr'", specifier = ">=1.14.0" }, { name = "defusedxml", specifier = "~=0.7" }, { name = "google-cloud-aiplatform", marker = "extra == 'google'", specifier = "~=1.60" }, { name = "google-generativeai", marker = "extra == 'google'", specifier = "~=0.7" }, @@ -4677,12 +4467,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/7d/9a57e187cbf2fbbbdfd4044a4f9ce141c8d221f9963750d3b001f0ec080d/shapely-2.0.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fea108334be345c283ce74bf064fa00cfdd718048a8af7343c59eb40f59726", size = 2524835 }, { url = "https://files.pythonhosted.org/packages/6d/0a/f407509ab56825f39bf8cfce1fb410238da96cf096809c3e404e5bc71ea1/shapely-2.0.6-cp312-cp312-win32.whl", hash = "sha256:42fd4cd4834747e4990227e4cbafb02242c0cffe9ce7ef9971f53ac52d80d55f", size = 1295613 }, { url = "https://files.pythonhosted.org/packages/7b/b3/857afd9dfbfc554f10d683ac412eac6fa260d1f4cd2967ecb655c57e831a/shapely-2.0.6-cp312-cp312-win_amd64.whl", hash = "sha256:665990c84aece05efb68a21b3523a6b2057e84a1afbef426ad287f0796ef8a48", size = 1442539 }, - { url = "https://files.pythonhosted.org/packages/34/e8/d164ef5b0eab86088cde06dee8415519ffd5bb0dd1bd9d021e640e64237c/shapely-2.0.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:42805ef90783ce689a4dde2b6b2f261e2c52609226a0438d882e3ced40bb3013", size = 1445344 }, - { url = "https://files.pythonhosted.org/packages/ce/e2/9fba7ac142f7831757a10852bfa465683724eadbc93d2d46f74a16f9af04/shapely-2.0.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6d2cb146191a47bd0cee8ff5f90b47547b82b6345c0d02dd8b25b88b68af62d7", size = 1296182 }, - { url = "https://files.pythonhosted.org/packages/cf/dc/790d4bda27d196cd56ec66975eaae3351c65614cafd0e16ddde39ec9fb92/shapely-2.0.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3fdef0a1794a8fe70dc1f514440aa34426cc0ae98d9a1027fb299d45741c381", size = 2423426 }, - { url = "https://files.pythonhosted.org/packages/af/b0/f8169f77eac7392d41e231911e0095eb1148b4d40c50ea9e34d999c89a7e/shapely-2.0.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c665a0301c645615a107ff7f52adafa2153beab51daf34587170d85e8ba6805", size = 2513249 }, - { url = "https://files.pythonhosted.org/packages/f6/1d/a8c0e9ab49ff2f8e4dedd71b0122eafb22a18ad7e9d256025e1f10c84704/shapely-2.0.6-cp313-cp313-win32.whl", hash = "sha256:0334bd51828f68cd54b87d80b3e7cee93f249d82ae55a0faf3ea21c9be7b323a", size = 1294848 }, - { url = "https://files.pythonhosted.org/packages/23/38/2bc32dd1e7e67a471d4c60971e66df0bdace88656c47a9a728ace0091075/shapely-2.0.6-cp313-cp313-win_amd64.whl", hash = "sha256:d37d070da9e0e0f0a530a621e17c0b8c3c9d04105655132a87cfff8bd77cc4c2", size = 1441371 }, ] [[package]] @@ -5111,16 +4895,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f2/2c/6990f4ccb41ed93744aaaa3786394bca0875503f97690622f3cafc0adfde/ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e", size = 1043576 }, { url = "https://files.pythonhosted.org/packages/14/f5/a2368463dbb09fbdbf6a696062d0c0f62e4ae6fa65f38f829611da2e8fdd/ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e", size = 38764 }, { url = "https://files.pythonhosted.org/packages/59/2d/691f741ffd72b6c84438a93749ac57bf1a3f217ac4b0ea4fd0e96119e118/ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc", size = 42211 }, - { url = "https://files.pythonhosted.org/packages/0d/69/b3e3f924bb0e8820bb46671979770c5be6a7d51c77a66324cdb09f1acddb/ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287", size = 55646 }, - { url = "https://files.pythonhosted.org/packages/32/8a/9b748eb543c6cabc54ebeaa1f28035b1bd09c0800235b08e85990734c41e/ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e", size = 51806 }, - { url = "https://files.pythonhosted.org/packages/39/50/4b53ea234413b710a18b305f465b328e306ba9592e13a791a6a6b378869b/ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557", size = 51975 }, - { url = "https://files.pythonhosted.org/packages/b4/9d/8061934f960cdb6dd55f0b3ceeff207fcc48c64f58b43403777ad5623d9e/ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988", size = 53693 }, - { url = "https://files.pythonhosted.org/packages/f5/be/7bfa84b28519ddbb67efc8410765ca7da55e6b93aba84d97764cd5794dbc/ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816", size = 58594 }, - { url = "https://files.pythonhosted.org/packages/48/eb/85d465abafb2c69d9699cfa5520e6e96561db787d36c677370e066c7e2e7/ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20", size = 997853 }, - { url = "https://files.pythonhosted.org/packages/9f/76/2a63409fc05d34dd7d929357b7a45e3a2c96f22b4225cd74becd2ba6c4cb/ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0", size = 1140694 }, - { url = "https://files.pythonhosted.org/packages/45/ed/582c4daba0f3e1688d923b5cb914ada1f9defa702df38a1916c899f7c4d1/ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f", size = 1043580 }, - { url = "https://files.pythonhosted.org/packages/d7/0c/9837fece153051e19c7bade9f88f9b409e026b9525927824cdf16293b43b/ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165", size = 38766 }, - { url = "https://files.pythonhosted.org/packages/d7/72/6cb6728e2738c05bbe9bd522d6fc79f86b9a28402f38663e85a28fddd4a0/ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539", size = 42212 }, { url = "https://files.pythonhosted.org/packages/95/53/e5f5e733fc3525e65f36f533b0dbece5e5e2730b760e9beacf7e3d9d8b26/ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64", size = 51846 }, { url = "https://files.pythonhosted.org/packages/59/1f/f7bc02a54ea7b47f3dc2d125a106408f18b0f47b14fc737f0913483ae82b/ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3", size = 48103 }, { url = "https://files.pythonhosted.org/packages/1a/3a/d3921b6f29bc744d8d6c56db5f8bbcbe55115fd0f2b79c3c43ff292cc7c9/ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a", size = 47257 }, @@ -5306,18 +5080,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 }, { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 }, { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 }, - { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 }, - { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 }, - { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 }, - { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 }, - { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 }, - { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 }, - { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 }, - { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 }, - { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 }, - { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 }, - { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 }, - { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, { url = "https://files.pythonhosted.org/packages/df/94/1ad200e937ec91b2a9d6b39ae1cf9c2b1a9cc88d5ceb43aa5c6962eb3c11/watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f", size = 376986 }, { url = "https://files.pythonhosted.org/packages/ee/fd/d9e020d687ccf90fe95efc513fbb39a8049cf5a3ff51f53c59fcf4c47a5d/watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b", size = 369445 }, { url = "https://files.pythonhosted.org/packages/43/cb/c0279b35053555d10ef03559c5aebfcb0c703d9c70a7b4e532df74b9b0e8/watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4", size = 439383 }, @@ -5409,17 +5171,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/47/20af68a313b6453d2d094ccc497b7232e8475175d234e3e5bef5088521e5/websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237", size = 157818 }, { url = "https://files.pythonhosted.org/packages/f8/bb/60aaedc80e388e978617dda1ff38788780c6b0f6e462b85368cb934131a5/websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185", size = 151785 }, { url = "https://files.pythonhosted.org/packages/16/2e/e47692f569e1be2e66c1dbc5e85ea4d2cc93b80027fbafa28ae8b0dee52c/websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99", size = 152214 }, - { url = "https://files.pythonhosted.org/packages/46/37/d8ef4b68684d1fa368a5c64be466db07fc58b68163bc2496db2d4cc208ff/websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa", size = 150962 }, - { url = "https://files.pythonhosted.org/packages/95/49/78aeb3af08ec9887a9065e85cef9d7e199d6c6261fcd39eec087f3a62328/websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231", size = 148621 }, - { url = "https://files.pythonhosted.org/packages/31/0d/dc9b7cec8deaee452092a631ccda894bd7098859f71dd7639b4b5b9c615c/websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9", size = 148853 }, - { url = "https://files.pythonhosted.org/packages/16/bf/734cbd815d7bc94cffe35c934f4e08b619bf3b47df1c6c7af21c1d35bcfe/websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75", size = 158741 }, - { url = "https://files.pythonhosted.org/packages/af/9b/756f89b12fee8931785531a314e6f087b21774a7f8c60878e597c684f91b/websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553", size = 157690 }, - { url = "https://files.pythonhosted.org/packages/d3/37/31f97132d2262e666b797e250879ca833eab55115f88043b3952a2840eb8/websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920", size = 158132 }, - { url = "https://files.pythonhosted.org/packages/41/ce/59c8d44e148c002fec506a9527504fb4281676e2e75c2ee5a58180f1b99a/websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329", size = 158490 }, - { url = "https://files.pythonhosted.org/packages/1a/74/5b31ce0f318b902c0d70c031f8e1228ba1a4d95a46b2a24a2a5ac17f9cf0/websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7", size = 157879 }, - { url = "https://files.pythonhosted.org/packages/0d/a7/6eac4f04177644bbc98deb98d11770cc7fbc216f6f67ab187c150540fd52/websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2", size = 157873 }, - { url = "https://files.pythonhosted.org/packages/72/f6/b8b30a3b134dfdb4ccd1694befa48fddd43783957c988a1dab175732af33/websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb", size = 151782 }, - { url = "https://files.pythonhosted.org/packages/3e/88/d94ccc006c69583168aa9dd73b3f1885c8931f2c676f4bdd8cbfae91c7b6/websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b", size = 152212 }, { url = "https://files.pythonhosted.org/packages/ae/d8/9d0e5c836f89147aa769b72e2d82217ae1c17ffd5f375de8d785e1e16870/websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89", size = 148629 }, { url = "https://files.pythonhosted.org/packages/9c/ff/005a440db101d298b42cc7565579ed55a7e12ccc0c6ea0491e53bb073930/websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad", size = 148863 }, { url = "https://files.pythonhosted.org/packages/9f/06/44d7c7d48e0beaecbacaf0020eafccd490741e496622da6b2a5626fe6689/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e", size = 150226 }, @@ -5535,21 +5286,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/79/e0479e9a3bbb7bdcb82779d89711b97cea30902a4bfe28d681463b7071ce/yarl-1.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45", size = 501273 }, { url = "https://files.pythonhosted.org/packages/8e/85/eab962453e81073276b22f3d1503dffe6bfc3eb9cd0f31899970de05d490/yarl-1.11.1-cp312-cp312-win32.whl", hash = "sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447", size = 101139 }, { url = "https://files.pythonhosted.org/packages/5d/de/618b3e5cab10af8a2ed3eb625dac61c1d16eb155d1f56f9fdb3500786c12/yarl-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639", size = 110504 }, - { url = "https://files.pythonhosted.org/packages/07/b7/948e4f427817e0178f3737adf6712fea83f76921e11e2092f403a8a9dc4a/yarl-1.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c", size = 185061 }, - { url = "https://files.pythonhosted.org/packages/f3/67/8d91ad79a3b907b4fef27fafa912350554443ba53364fff3c347b41105cb/yarl-1.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e", size = 113056 }, - { url = "https://files.pythonhosted.org/packages/a1/77/6b2348a753702fa87f435cc33dcec21981aaca8ef98a46566a7b29940b4a/yarl-1.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93", size = 110958 }, - { url = "https://files.pythonhosted.org/packages/8e/3e/6eadf32656741549041f549a392f3b15245d3a0a0b12a9bc22bd6b69621f/yarl-1.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d", size = 470326 }, - { url = "https://files.pythonhosted.org/packages/3d/a4/1b641a8c7899eeaceec45ff105a2e7206ec0eb0fb9d86403963cc8521c5e/yarl-1.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7", size = 484778 }, - { url = "https://files.pythonhosted.org/packages/8a/f5/80c142f34779a5c26002b2bf1f73b9a9229aa9e019ee6f9fd9d3e9704e78/yarl-1.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089", size = 485568 }, - { url = "https://files.pythonhosted.org/packages/f8/f2/6b40ffea2d5d3a11f514ab23c30d14f52600c36a3210786f5974b6701bb8/yarl-1.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5", size = 477801 }, - { url = "https://files.pythonhosted.org/packages/4c/1a/e60c116f3241e4842ed43c104eb2751abe02f6bac0301cdae69e4fda9c3a/yarl-1.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5", size = 455361 }, - { url = "https://files.pythonhosted.org/packages/b9/98/fe0aeee425a4bc5cd3ed86e867661d2bfa782544fa07a8e3dcd97d51ae3d/yarl-1.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786", size = 473893 }, - { url = "https://files.pythonhosted.org/packages/6b/9b/677455d146bd3cecd350673f0e4bb28854af66726493ace3b640e9c5552b/yarl-1.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318", size = 476407 }, - { url = "https://files.pythonhosted.org/packages/33/ca/ce85766247a9a9b56654428fb78a3e14ea6947a580a9c4e891b3aa7da322/yarl-1.11.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82", size = 490848 }, - { url = "https://files.pythonhosted.org/packages/6d/d6/717f0f19bcf2c4705ad95550b4b6319a0d8d1d4f137ea5e223207f00df50/yarl-1.11.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a", size = 501084 }, - { url = "https://files.pythonhosted.org/packages/14/b5/b93c70d9a462b802c8df65c64b85f49d86b4ba70c393fbad95cf7ec053cb/yarl-1.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da", size = 491776 }, - { url = "https://files.pythonhosted.org/packages/03/0f/5a52eaa402a6a93265ba82f42c6f6085ccbe483e1b058ad34207e75812b1/yarl-1.11.1-cp313-cp313-win32.whl", hash = "sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979", size = 485250 }, - { url = "https://files.pythonhosted.org/packages/dd/97/946d26a5d82706a6769399cabd472c59f9a3227ce1432afb4739b9c29572/yarl-1.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367", size = 492590 }, { url = "https://files.pythonhosted.org/packages/5b/b3/841f7d706137bdc8b741c6826106b6f703155076d58f1830f244da857451/yarl-1.11.1-py3-none-any.whl", hash = "sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38", size = 38648 }, ] From 67e4dd94920979f00dc6ce30cf9ecc6735a49833 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Wed, 30 Oct 2024 14:56:29 -0400 Subject: [PATCH 02/16] dapr updates --- .../dapr_runtime/actors/event_buffer_actor.py | 4 ++-- .../dapr_runtime/actors/external_event_buffer_actor.py | 4 ++-- python/semantic_kernel/processes/step_utils.py | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py index e816e35f27f8..3ab44a1a4ab6 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py @@ -32,7 +32,7 @@ async def enqueue(self, message: "ProcessMessage") -> None: """ self.queue.put(message) - await self._state_manager.add_or_update_state(ActorStateKeys.EventQueueState.value, self.queue) + await self._state_manager.set_state(ActorStateKeys.EventQueueState.value, self.queue) await self._state_manager.save_state() async def dequeue_all(self) -> "list[ProcessMessage]": @@ -45,7 +45,7 @@ async def dequeue_all(self) -> "list[ProcessMessage]": while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.add_or_update_state(ActorStateKeys.EventQueueState.value, self.queue) + await self._state_manager.set_state(ActorStateKeys.EventQueueState.value, self.queue) await self._state_manager.save_state() return items diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py index a0e5439093ef..63f28a56b204 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py @@ -33,7 +33,7 @@ async def enqueue(self, message: "ProcessMessage") -> None: """ self.queue.put(message) - await self._state_manager.add_or_update_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) + await self._state_manager.set_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) await self._state_manager.save_state() async def dequeue_all(self) -> "list[KernelProcessEvent]": @@ -46,7 +46,7 @@ async def dequeue_all(self) -> "list[KernelProcessEvent]": while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.add_or_update_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) + await self._state_manager.set_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) await self._state_manager.save_state() return items diff --git a/python/semantic_kernel/processes/step_utils.py b/python/semantic_kernel/processes/step_utils.py index cd95fde26ed9..a66fda9c83de 100644 --- a/python/semantic_kernel/processes/step_utils.py +++ b/python/semantic_kernel/processes/step_utils.py @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft. All rights reserved. + from typing import Any from semantic_kernel.functions.kernel_function import KernelFunction @@ -6,14 +8,14 @@ def find_input_channels( - channel: KernelProcessMessageChannel, function: dict[str, KernelFunction] + channel: KernelProcessMessageChannel, functions: dict[str, KernelFunction] ) -> dict[str, dict[str, Any | None]]: """Finds and creates input channels.""" - if not self.functions: + if not functions: raise ValueError("The step has not been initialized.") inputs: dict[str, Any] = {} - for name, function in self.functions.items(): + for name, function in functions.items(): inputs[name] = {} for param in function.metadata.parameters: # Check for Kernel, and skip if necessary, since it is populated later on @@ -22,7 +24,7 @@ def find_input_channels( if not param.is_required: continue if param.type_ == "KernelProcessStepContext": - inputs[name][param.name] = KernelProcessStepContext(self) + inputs[name][param.name] = KernelProcessStepContext(channel) else: inputs[name][param.name] = None From b4bb82e011ab75b2f93786b74b4d775ae8dbf159 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Wed, 6 Nov 2024 12:18:38 -0500 Subject: [PATCH 03/16] work on dapr runtime. --- python/.vscode/launch.json | 12 +- python/.vscode/tasks.json | 14 + .../chat_gpt_api_function_calling.py | 3 +- .../chat_completion/azure_chat_gpt_api.py | 2 +- .../json_structured_output.py | 26 +- python/samples/demos/process_with_dapr/app.py | 163 ++++++++++++ .../dapr_runtime/actors/event_buffer_actor.py | 36 ++- .../actors/external_event_buffer_actor.py | 38 +-- .../actors/message_buffer_actor.py | 25 +- .../dapr_runtime/actors/process_actor.py | 243 +++++++++++++----- .../dapr_runtime/actors/step_actor.py | 90 ++++--- .../dapr_runtime/dapr_kernel_process.py | 2 +- .../dapr_kernel_process_context.py | 16 +- .../dapr_runtime/dapr_process_info.py | 9 +- .../processes/dapr_runtime/dapr_step_info.py | 6 +- .../dapr_runtime/external_event_buffer.py | 10 +- .../processes/dapr_runtime/message_buffer.py | 2 +- .../processes/dapr_runtime/process.py | 15 +- .../processes/dapr_runtime/step.py | 11 +- .../kernel_process/kernel_process_event.py | 4 + .../processes/process_step_builder.py | 7 +- 21 files changed, 538 insertions(+), 196 deletions(-) create mode 100644 python/samples/demos/process_with_dapr/app.py diff --git a/python/.vscode/launch.json b/python/.vscode/launch.json index 306f58eb37e8..88d7679775bd 100644 --- a/python/.vscode/launch.json +++ b/python/.vscode/launch.json @@ -11,6 +11,16 @@ "program": "${file}", "console": "integratedTerminal", "justMyCode": true - } + }, + { + "type": "python", + "request": "launch", + "name": "Pythonapp with Dapr", + "program": "${workspaceFolder}/samples/demos/process_with_dapr/app.py", + "console": "integratedTerminal", + "preLaunchTask": "daprd-debug-python", + "postDebugTask": "daprd-down-python", + "justMyCode": false + } ] } \ No newline at end of file diff --git a/python/.vscode/tasks.json b/python/.vscode/tasks.json index dbd972976939..d70c42c92db4 100644 --- a/python/.vscode/tasks.json +++ b/python/.vscode/tasks.json @@ -163,6 +163,20 @@ "panel": "shared" }, "problemMatcher": [] + }, + { + "label": "daprd-debug-python", + "type": "daprd", + "appId": "dapr-processes", + "httpPort": 3500, + "appPort": 5001, + "grpcPort": 53317, + "metricsPort": 9091 + }, + { + "label": "daprd-down-python", + "type": "daprd-down", + "appId": "dapr-processes" } ], "inputs": [ diff --git a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py index 137f9eec0d85..ab699d5f62e5 100644 --- a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py +++ b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py @@ -69,7 +69,7 @@ def search( # This concept example shows how to handle both streaming and non-streaming responses # To toggle the behavior, set the following flag accordingly: -stream = False +stream = True kernel = Kernel() @@ -184,6 +184,7 @@ async def handle_streaming( print("\n") if result_content: + streaming_chat_message = reduce(lambda first, second: first + second, result_content) return "".join([str(content) for content in result_content]) return None diff --git a/python/samples/concepts/chat_completion/azure_chat_gpt_api.py b/python/samples/concepts/chat_completion/azure_chat_gpt_api.py index d2f372ec762f..065940ea368e 100644 --- a/python/samples/concepts/chat_completion/azure_chat_gpt_api.py +++ b/python/samples/concepts/chat_completion/azure_chat_gpt_api.py @@ -8,7 +8,7 @@ from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion from semantic_kernel.contents import ChatHistory -logging.basicConfig(level=logging.WARNING) +logging.basicConfig(level=logging.DEBUG) system_message = """ You are a chat bot. Your name is Mosscap and diff --git a/python/samples/concepts/structured_output/json_structured_output.py b/python/samples/concepts/structured_output/json_structured_output.py index f6ea600cd56f..a65f11ff6bde 100644 --- a/python/samples/concepts/structured_output/json_structured_output.py +++ b/python/samples/concepts/structured_output/json_structured_output.py @@ -40,17 +40,15 @@ # used to parse the structured output from the OpenAI service, # and ensure that the model correctly outputs the schema based # on the Pydantic model. -from semantic_kernel.kernel_pydantic import KernelBaseModel # noqa: E402 - -class Step(KernelBaseModel): - explanation: str - output: str +# class Step(KernelBaseModel): +# explanation: str +# output: str -class Reasoning(KernelBaseModel): - steps: list[Step] - final_answer: str +# class Reasoning(KernelBaseModel): +# steps: list[Step] +# final_answer: str ################################################################### @@ -61,14 +59,14 @@ class Reasoning(KernelBaseModel): # converted to the proper JSON Schema and sent to the LLM. # Uncomment the follow lines and comment out the Pydantic model # above to use this option. -# class Step: -# explanation: str -# output: str +class Step: + explanation: str + output: str -# class Reasoning: -# steps: list[Step] -# final_answer: str +class Reasoning: + steps: list[Step] + final_answer: str ################################################################### diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py new file mode 100644 index 000000000000..3b6e991de696 --- /dev/null +++ b/python/samples/demos/process_with_dapr/app.py @@ -0,0 +1,163 @@ +import asyncio +from contextlib import asynccontextmanager +from enum import Enum +from typing import TYPE_CHECKING, ClassVar + +import uvicorn +from dapr.ext.fastapi import DaprActor, DaprApp +from fastapi import FastAPI +from fastapi.responses import JSONResponse +from pydantic import Field + +from semantic_kernel import Kernel +from semantic_kernel.functions import kernel_function +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor +from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor +from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor +from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start +from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep +from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState +from semantic_kernel.processes.process_builder import ProcessBuilder + +if TYPE_CHECKING: + from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess + + +@asynccontextmanager +async def lifespan(app: FastAPI): + print("~~ actor startup") + await actor.register_actor(ProcessActor) + await actor.register_actor(StepActor) + await actor.register_actor(EventBufferActor) + await actor.register_actor(MessageBufferActor) + await actor.register_actor(ExternalEventBufferActor) + yield + + +app = FastAPI(title="SKProcess", lifespan=lifespan) +dapr_app = DaprApp(app) +actor = DaprActor(app) + + +@app.get("/healthz") +async def healthcheck(): + return "Healthy!" + + +class CommonEvents(Enum): + """Common events for the sample process.""" + + UserInputReceived = "UserInputReceived" + CompletionResponseGenerated = "CompletionResponseGenerated" + WelcomeDone = "WelcomeDone" + AStepDone = "AStepDone" + BStepDone = "BStepDone" + CStepDone = "CStepDone" + StartARequested = "StartARequested" + StartBRequested = "StartBRequested" + ExitRequested = "ExitRequested" + StartProcess = "StartProcess" + + +# Define a sample step that once the `on_input_event` is received, +# it will emit two events to start the A and B steps. +class KickOffStep(KernelProcessStep): + KICK_OFF_FUNCTION: ClassVar[str] = "kick_off" + + @kernel_function(name=KICK_OFF_FUNCTION) + async def print_welcome_message(self, context: KernelProcessStepContext): + await context.emit_event(process_event=CommonEvents.StartARequested.value, data="Get Going A") + await context.emit_event(process_event=CommonEvents.StartBRequested.value, data="Get Going B") + + +# Define a sample `AStep` step that will emit an event after 1 second. +# The event will be sent to the `CStep` step with the data `I did A`. +class AStep(KernelProcessStep): + @kernel_function() + async def do_it(self, context: KernelProcessStepContext): + await asyncio.sleep(1) + await context.emit_event(process_event=CommonEvents.AStepDone.value, data="I did A") + + +# Define a sample `BStep` step that will emit an event after 2 seconds. +# The event will be sent to the `CStep` step with the data `I did B`. +class BStep(KernelProcessStep): + @kernel_function() + async def do_it(self, context: KernelProcessStepContext): + await asyncio.sleep(2) + await context.emit_event(process_event=CommonEvents.BStepDone.value, data="I did B") + + +# Define a sample `CStepState` that will keep track of the current cycle. +class CStepState(KernelBaseModel): + current_cycle: int = 0 + + +# Define a sample `CStep` step that will emit an `ExitRequested` event after 3 cycles. +class CStep(KernelProcessStep[CStepState]): + state: CStepState = Field(default_factory=CStepState) + + # The activate method overrides the base class method to set the state in the step. + async def activate(self, state: KernelProcessStepState[CStepState]): + """Activates the step and sets the state.""" + self.state = state.state + + @kernel_function() + async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str): + self.state.current_cycle += 1 + print(f"CStep Current Cycle: {self.state.current_cycle}") + if self.state.current_cycle == 3: + print("CStep Exit Requested") + await context.emit_event(process_event=CommonEvents.ExitRequested.value) + return + await context.emit_event(process_event=CommonEvents.CStepDone.value) + + +kernel = Kernel() + + +def get_process() -> "KernelProcess": + # Define the process builder + process = ProcessBuilder(name="ProcessWithDapr") + + # Add the step types to the builder + kickoff_step = process.add_step(step_type=KickOffStep) + myAStep = process.add_step(step_type=AStep) + myBStep = process.add_step(step_type=BStep) + myCStep = process.add_step(step_type=CStep) + + # Define the input event and where to send it to + process.on_input_event(event_id=CommonEvents.StartProcess.value).send_event_to(target=kickoff_step) + + # Define the process flow + kickoff_step.on_event(event_id=CommonEvents.StartARequested.value).send_event_to(target=myAStep) + kickoff_step.on_event(event_id=CommonEvents.StartBRequested.value).send_event_to(target=myBStep) + myAStep.on_event(event_id=CommonEvents.AStepDone.value).send_event_to(target=myCStep, parameter_name="astepdata") + + # Define the fan in behavior once both AStep and BStep are done + myBStep.on_event(event_id=CommonEvents.BStepDone.value).send_event_to(target=myCStep, parameter_name="bstepdata") + myCStep.on_event(event_id=CommonEvents.CStepDone.value).send_event_to(target=kickoff_step) + myCStep.on_event(event_id=CommonEvents.ExitRequested.value).stop_process() + + # Build the process + return process.build() + + +@app.get("/processes/{process_id}") +async def start_process(process_id: str): + try: + process = get_process() + _ = await start( + process=process, kernel=kernel, initial_event=CommonEvents.StartProcess.value, process_id=process_id + ) + return JSONResponse(content={"processId": process_id}, status_code=200) + except Exception as e: + return JSONResponse(content={"error": str(e)}, status_code=500) + + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=5001) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py index 3ab44a1a4ab6..b33c40ebbd59 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py @@ -1,41 +1,39 @@ # Copyright (c) Microsoft. All rights reserved. +import json from queue import Queue from typing import TYPE_CHECKING -from dapr.actor import Actor, ActorId -from dapr.actor.runtime.context import ActorRuntimeContext -from pydantic import Field +from dapr.actor import Actor -from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer if TYPE_CHECKING: - from semantic_kernel.processes.process_message import ProcessMessage + from semantic_kernel.processes.process_event import ProcessEvent -class EventBufferActor(Actor, MessageBuffer, KernelBaseModel): +class EventBufferActor(Actor, MessageBuffer): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" - queue: Queue = Field(default_factory=Queue) + queue: Queue = Queue() - def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): - """Initializes a new instance of StepActor.""" - super().__init__(ctx, actor_id) - - async def enqueue(self, message: "ProcessMessage") -> None: + async def enqueue(self, message: "ProcessEvent") -> None: """Enqueues a message event into the buffer. Args: message: The message event to enqueue. """ + from semantic_kernel.processes.process_event import ProcessEvent + + message = ProcessEvent.model_validate(json.loads(message)) + self.queue.put(message) - await self._state_manager.set_state(ActorStateKeys.EventQueueState.value, self.queue) + await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) await self._state_manager.save_state() - async def dequeue_all(self) -> "list[ProcessMessage]": + async def dequeue_all(self) -> "list[ProcessEvent]": """Dequeues all process events from the buffer. Returns: @@ -45,17 +43,15 @@ async def dequeue_all(self) -> "list[ProcessMessage]": while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.set_state(ActorStateKeys.EventQueueState.value, self.queue) + await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) await self._state_manager.save_state() return items async def on_activate(self) -> None: """Called when the actor is activated.""" - state_exists, event_queue_state = await self._state_manager.try_get_state( - ActorStateKeys.EventQueueState.value, self.queue - ) - if state_exists: + has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.EventQueueState.value) + if has_value: self.queue = event_queue_state else: - self.queue: Queue[ProcessMessage] = Queue() + self.queue: Queue["ProcessEvent"] = Queue() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py index 63f28a56b204..9a9bce54e705 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py @@ -1,40 +1,44 @@ # Copyright (c) Microsoft. All rights reserved. +import json from queue import Queue from typing import TYPE_CHECKING -from dapr.actor import Actor, ActorId -from dapr.actor.runtime.context import ActorRuntimeContext -from pydantic import Field +from dapr.actor import Actor -from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.external_event_buffer import ExternalEventBuffer from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent if TYPE_CHECKING: - from semantic_kernel.processes.process_message import ProcessMessage + pass -class ExternalEventBufferActor(Actor, ExternalEventBuffer, KernelBaseModel): +class ExternalEventBufferActor(Actor, ExternalEventBuffer): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" - queue: Queue[KernelProcessEvent] = Field(default_factory=Queue) + queue: Queue = Queue() - def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): - """Initializes a new instance of StepActor.""" - super().__init__(ctx, actor_id) - - async def enqueue(self, message: "ProcessMessage") -> None: + async def enqueue(self, message: str) -> None: """Enqueues a message event into the buffer. Args: message: The message event to enqueue. """ + # Perform validation that we have the correct incoming message + message = KernelProcessEvent.model_validate(json.loads(message)) self.queue.put(message) - await self._state_manager.set_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) - await self._state_manager.save_state() + try: + # Convert each item in the queue to a dictionary for serialization + queue_list = [item.model_dump() for item in self.queue.queue] + queue_dict = json.dumps(queue_list) + + await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_dict) + await self._state_manager.save_state() + except Exception as e: + print(e) + raise e async def dequeue_all(self) -> "list[KernelProcessEvent]": """Dequeues all process events from the buffer. @@ -46,15 +50,15 @@ async def dequeue_all(self) -> "list[KernelProcessEvent]": while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.set_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) + await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) await self._state_manager.save_state() return items - async def on_activate(self) -> None: + async def _on_activate(self) -> None: """Called when the actor is activated.""" state_exists, event_queue_state = await self._state_manager.try_get_state( - ActorStateKeys.ExternalEventQueueState.value, self.queue + ActorStateKeys.ExternalEventQueueState.value ) if state_exists: self.queue = event_queue_state diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py index 41196cfded34..9013cd1826f1 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py @@ -1,13 +1,11 @@ # Copyright (c) Microsoft. All rights reserved. +import json from queue import Queue from typing import TYPE_CHECKING -from dapr.actor import Actor, ActorId -from dapr.actor.runtime.context import ActorRuntimeContext -from pydantic import Field +from dapr.actor import Actor -from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer @@ -15,14 +13,10 @@ from semantic_kernel.processes.process_message import ProcessMessage -class MessageBufferActor(Actor, MessageBuffer, KernelBaseModel): +class MessageBufferActor(Actor, MessageBuffer): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" - queue: Queue = Field(default_factory=Queue) - - def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): - """Initializes a new instance of StepActor.""" - super().__init__(ctx, actor_id) + queue: Queue = Queue() async def enqueue(self, message: "ProcessMessage") -> None: """Enqueues a message event into the buffer. @@ -30,9 +24,12 @@ async def enqueue(self, message: "ProcessMessage") -> None: Args: message: The message event to enqueue. """ + from semantic_kernel.processes.process_message import ProcessMessage + + message = ProcessMessage.model_validate(json.loads(message)) self.queue.put(message) - await self._state_manager.add_or_update_state(ActorStateKeys.MessageQueueState.value, self.queue) + await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, self.queue) await self._state_manager.save_state() async def dequeue_all(self) -> "list[ProcessMessage]": @@ -45,15 +42,15 @@ async def dequeue_all(self) -> "list[ProcessMessage]": while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.add_or_update_state(ActorStateKeys.MessageQueueState.value, self.queue) + await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, self.queue) await self._state_manager.save_state() return items async def on_activate(self) -> None: """Called when the actor is activated.""" - event_queue_state = await self._state_manager.get_state(ActorStateKeys.MessageQueueState.value, self.queue) - if event_queue_state is not None: + has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.MessageQueueState.value) + if has_value: self.queue = event_queue_state else: self.queue: Queue[ProcessMessage] = Queue() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py index d782c07c1758..4561d4fe1438 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py @@ -3,12 +3,11 @@ import asyncio import contextlib +import json import uuid from queue import Queue -from typing import Any from dapr.actor import ActorId, ActorProxy -from dapr.actor.runtime.context import ActorRuntimeContext from pydantic import Field from semantic_kernel.exceptions.kernel_exceptions import KernelException @@ -16,37 +15,50 @@ from semantic_kernel.kernel import Kernel from semantic_kernel.processes.const import END_PROCESS_ID from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.processes.dapr_runtime.external_event_buffer import ExternalEventBuffer from semantic_kernel.processes.dapr_runtime.process import Process from semantic_kernel.processes.dapr_runtime.step import Step -from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.processes.kernel_process.kernel_process_event import ( + KernelProcessEvent, + KernelProcessEventVisibility, +) +from semantic_kernel.processes.process_event import ProcessEvent from semantic_kernel.processes.process_message import ProcessMessage +from semantic_kernel.processes.process_message_factory import ProcessMessageFactory -class ProcessActor(StepActor): +class ProcessActor(StepActor, Process): """A local process that contains a collection of steps.""" - kernel: Kernel - steps: list[Step] = Field(default_factory=list) + kernel: Kernel | None = None + _steps: list[StepActor] = [] step_infos: list[DaprStepInfo] = Field(default_factory=list) initialize_task: bool | None = False external_event_queue: Queue = Field(default_factory=Queue) process_task: asyncio.Task | None = None process: DaprProcessInfo | None = None - def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel) -> None: - """Initializes the local process.""" - args: dict[str, Any] = { - "ctx": ctx, - "actor_id": actor_id, - "kernel": kernel, - "initialize_task": False, - } + # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId) -> None: + # """Initializes the local process.""" + # args: dict[str, Any] = { + # "ctx": ctx, + # "actor_id": actor_id, + # # "kernel": kernel, + # "initialize_task": False, + # } - super().__init__(**args) + # super().__init__(**args) + + # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, **kwargs) -> None: + # """Initializes the local process.""" + # # Initialize the Actor base class explicitly + # super(ProcessActor, self).__init__(ctx, actor_id) @property def name(self) -> str: @@ -55,44 +67,58 @@ def name(self) -> str: raise KernelException("The process must be initialized before accessing the name property.") return self.step_info.state.name - async def initialize_process(self, process_info: DaprProcessInfo, parent_process_id: str | None = None) -> None: + # async def initialize_process(self, process_info: dict[str, Any], parent_process_id: str | None = None) -> None: + async def initialize_process(self, input: dict) -> None: """Initializes the process.""" - if process_info is None: + if input is None: raise ValueError("The process info is not defined.") + process_info = DaprProcessInfo.model_validate(input.get("process_info")) + if process_info.steps is None: raise ValueError("The process info does not contain any steps.") if self.initialize_task: return - await self.initialize_process_actor(process_info, parent_process_id) + await self._initialize_process_actor(process_info, input.get("parent_process_id")) - await self._state_manager.add_or_update_state(ActorStateKeys.ProcessInfoState.value, process_info) - await self._state_manager.add_or_update_state(ActorStateKeys.StepParentProcessId.value, parent_process_id) - await self._state_manager.add_or_update_state(ActorStateKeys.StepActivatedState.value, True) - await self._state_manager.save_state() + try: + await self._state_manager.try_add_state(ActorStateKeys.ProcessInfoState.value, process_info) + await self._state_manager.try_add_state( + ActorStateKeys.StepParentProcessId.value, input.get("parent_process_id") + ) + await self._state_manager.try_add_state(ActorStateKeys.StepActivatedState.value, True) + await self._state_manager.save_state() + except Exception as ex: + print(ex) + raise ex async def start(self, keep_alive: bool = True) -> None: """Starts the process.""" if not self.initialize_task: raise ValueError("The process has not been initialized.") - self.process_task = asyncio.create_task(self.internal_execute(keep_alive)) + self.process_task = asyncio.create_task(self.internal_execute(keep_alive=keep_alive)) - async def run_once(self, process_event: KernelProcessEvent): + async def run_once(self, process_event_payload: str): """Starts the process with an initial event and waits for it to finish.""" - if process_event is None: + if process_event_payload is None: raise ProcessEventUndefinedException("The process event must be specified.") + external_event_queue: ExternalEventBufferActor = ActorProxy.create( actor_type=f"{ExternalEventBufferActor.__name__}", - actor_id=self.parent_process_id, - actor_interface=ExternalEventBufferActor, + actor_id=ActorId(self.id.id), + actor_interface=ExternalEventBuffer, ) - external_event_queue.put(process_event) - await self.start(keep_alive=False) - if self.process_task: - await self.process_task + try: + await external_event_queue.enqueue(process_event_payload) + await self.start(keep_alive=False) + if self.process_task: + await self.process_task + except Exception as ex: + print(ex) + raise ex async def stop(self): """Stops a running process.""" @@ -109,6 +135,15 @@ async def initialize_step(self): # The process does not need any further initialization pass + async def _on_activate(self) -> None: + """Activates the process.""" + has_value, existing_process_info = await self._state_manager.try_get_state( + ActorStateKeys.ProcessInfoState.value + ) + if has_value: + self.parent_process_id = await self._state_manager.get_state(ActorStateKeys.StepParentProcessId.value) + await self._initialize_process_actor(existing_process_info, self.parent_process_id) + async def send_message(self, process_event: KernelProcessEvent): """Sends a message to the process.""" if process_event is None: @@ -119,14 +154,6 @@ async def get_process_info(self): """Gets the process information.""" return await self.to_dapr_process_info() - # private async Task ToDaprProcessInfoAsync() - # { - # var processState = new KernelProcessState(this.Name, this.Id.GetId()); - # var stepTasks = this._steps.Select(step => step.ToDaprStepInfoAsync()).ToList(); - # var steps = await Task.WhenAll(stepTasks).ConfigureAwait(false); - # return new DaprProcessInfo { InnerStepDotnetType = this._process!.InnerStepDotnetType, Edges = this._process!.Edges, State = processState, Steps = steps.ToList() }; - # } - async def to_dapr_process_info(self) -> DaprProcessInfo: """Converts the process to a Dapr process info.""" process_state = DaprProcessInfo(self.name, self.id.id) @@ -136,6 +163,21 @@ async def to_dapr_process_info(self) -> DaprProcessInfo: inner_step_dotnet_type=self.inner_step_type, edges=self.process.edges, state=process_state, steps=steps ) + async def handle_message(self, message: ProcessMessage) -> None: + """Handles a message.""" + if message.target_event_id is None: + raise KernelException( + "Internal Process Error: The target event id must be specified when sending a message to a step." + ) + + event_id = message.target_event_id + if event_id in self.output_edges and self.output_edges[event_id] is not None: + for _ in self.output_edges[event_id]: + nested_event = KernelProcessEvent( + id=event_id, data=message.target_event_data, visibility=KernelProcessEventVisibility.Internal + ) + await self.run_once(nested_event) + async def _initialize_process_actor( self, process_info: DaprProcessInfo, parent_process_id: str | None = None ) -> None: @@ -169,7 +211,8 @@ async def _initialize_process_actor( actor_type=f"{ProcessActor.__name__}", actor_interface=Process, ) - await process_actor.initialize_process(step, self.id.id) + payload = {"process_info": step.model_dump(), "parent_process_id": self.id.id} + await process_actor.initialize_process(payload) step_actor = ActorProxy.create( actor_id=scoped_process_id, actor_type=f"{ProcessActor.__name__}", @@ -182,47 +225,123 @@ async def _initialize_process_actor( scoped_step_id = self._scoped_actor_id(ActorId(step.state.id)) step_actor = ActorProxy.create( actor_id=scoped_step_id, - actor_type=f"{ProcessActor.__name__}", + actor_type=f"{StepActor.__name__}", actor_interface=Step, ) - await step_actor.initialize_step(step, self.id.id) + step_dict = step.model_dump() + payload = {"step_info": step_dict, "parent_process_id": self.id.id} + try: + await step_actor.initialize_step(json.dumps(payload)) + except Exception as ex: + print(ex) + raise ex # Add the local step to the list of steps - self.steps.append(step_actor) + self._steps.append(step_actor) self.initialize_task = True - def _scoped_actor_id(self, actor_id: ActorId) -> ActorId: + def _scoped_actor_id(self, actor_id: ActorId, scope_to_parent: bool = False) -> ActorId: """Creates a scoped actor ID.""" - return ActorId(f"{self.id}.{actor_id.id}") + if scope_to_parent and self.parent_process_id is None: + raise ValueError("The parent process Id must be set before scoping to the parent process.") + + id = self.parent_process_id if scope_to_parent else self.id.id + return ActorId(f"{id}.{actor_id.id}") async def internal_execute(self, max_supersteps: int = 100, keep_alive: bool = True): """Internal execution logic for the process.""" - message_channel: Queue[ProcessMessage] = Queue() - try: for _ in range(max_supersteps): - self.enqueue_external_messages(message_channel) - for step in self.steps: - await self.enqueue_step_messages(step, message_channel) + if await self._is_end_message_sent(): + self.process_task.cancel() + break - messages_to_process: list = [] - while not message_channel.empty(): - messages_to_process.append(message_channel.get()) + # Check for external events + await self._enqueue_external_messages() - if not messages_to_process and (not keep_alive or self.external_event_queue.empty()): - break + # Reach out to all of the steps in the process and instrcut them to retrieve their pending + # messages from their associated queues + step_preparation_tasks = [step.prepare_incoming_messages() for step in self.steps] + message_counts = await asyncio.gather(*step_preparation_tasks) - message_tasks = [] - for message in messages_to_process: - if message.destination_id == END_PROCESS_ID: - break + if sum(message_counts) == 0 and (not keep_alive or self.external_event_queue.empty()): + self.process_task.cancel() + break - destination_step = next(step for step in self.steps if step.id == message.destination_id) - message_tasks.append(destination_step.handle_message(message)) + # Process the incoming messages for each step + step_processing_tasks = [step.process_incoming_messages() for step in self.steps] + await asyncio.gather(*step_processing_tasks) - await asyncio.gather(*message_tasks) + # Handle public events that need to be bubbled out of the process + await self.send_outgoing_public_events() except Exception as ex: print("An error occurred while running the process: %s.", ex) + self.process_task.cancel() raise + + def _scoped_event(self, dapr_event: ProcessEvent): + if dapr_event is None: + raise ValueError("The Dapr event must be specified.") + + dapr_event.namespace = f"{self.name}_{self.process.state.id}" + return dapr_event + + async def send_outgoing_public_events(self) -> None: + """Sends outgoing public events.""" + if self.parent_process_id is not None: + event_queue: EventBufferActor = ActorProxy.create( + actor_id=ActorId(self.id.id), + actor_type=f"{EventBufferActor.__name__}", + actor_interface=EventBufferActor, + ) + all_events: list[ProcessEvent] = await event_queue.dequeue_all() + + for e in all_events: + scoped_event = self._scoped_event(e) + if scoped_event.id in self.output_edges and self.output_edges[scoped_event.id] is not None: + for edge in self.output_edges[scoped_event.id]: + message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, e.data) + scoped_message_buffer_id = self._scoped_actor_id( + ActorId(edge.output_target.step_id), scope_to_parent=True + ) + message_queue: MessageBufferActor = ActorProxy.create( + actor_id=scoped_message_buffer_id, + actor_type=f"{MessageBufferActor.__name__}", + actor_interface=MessageBufferActor, + ) + await message_queue.enqueue(message) + + async def _is_end_message_sent(self) -> bool: + """Checks if the end message has been sent.""" + scoped_message_buffer_id = self._scoped_actor_id(ActorId(END_PROCESS_ID)) + end_message_queue: MessageBufferActor = ActorProxy.create( + actor_id=scoped_message_buffer_id, + actor_type=f"{MessageBufferActor.__name__}", + actor_interface=MessageBufferActor, + ) + messages: list[ProcessMessage] = await end_message_queue.dequeue_all() + return len(messages) > 0 + + async def _enqueue_external_messages(self) -> None: + """Enqueues external messages into the process.""" + external_event_queue: ExternalEventBufferActor = ActorProxy.create( + actor_id=ActorId(self.id.id), + actor_type=f"{ExternalEventBufferActor.__name__}", + actor_interface=ExternalEventBufferActor, + ) + + external_events = await external_event_queue.dequeue_all() + + for external_event in external_events: + if external_event.id in self.output_edges and self.output_edges[external_event.id] is not None: + for edge in self.output_edges[external_event.id]: + message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, external_event.data) + scoped_message_buffer_id = self._scoped_actor_id(ActorId(edge.output_target.step_id)) + message_queue: MessageBufferActor = ActorProxy.create( + actor_id=scoped_message_buffer_id, + actor_type=f"{MessageBufferActor.__name__}", + actor_interface=MessageBufferActor, + ) + await message_queue.enqueue(message) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py index 34084ed11a51..6bc428c92c89 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -1,13 +1,12 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import json import logging from queue import Queue from typing import Any, Type from dapr.actor import Actor, ActorId, ActorProxy -from dapr.actor.runtime.context import ActorRuntimeContext -from pydantic import Field from semantic_kernel.exceptions.kernel_exceptions import KernelException from semantic_kernel.exceptions.process_exceptions import ( @@ -16,7 +15,6 @@ ) from semantic_kernel.functions.kernel_function import KernelFunction from semantic_kernel.kernel import Kernel -from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor @@ -42,47 +40,67 @@ @experimental_class -class StepActor(Actor, Step, KernelProcessMessageChannel, KernelBaseModel): +class StepActor(Actor, Step, KernelProcessMessageChannel): """Represents a step actor that follows the Step abstract class.""" - kernel: Kernel + kernel: Kernel | None = None parent_process_id: str | None = None step_info: DaprStepInfo | None = None initialize_task: bool | None = False event_namespace: str | None = None inner_step_type: Type | None = None - incoming_messages: Queue = Field(default_factory=Queue) + incoming_messages: Queue = Queue() step_state: KernelProcessStepState | None = None step_state_type: Type | None = None - output_edges: dict[str, list[KernelProcessEdge]] = Field(default_factory=dict) - functions: dict[str, KernelFunction] = Field(default_factory=dict) - inputs: dict[str, dict[str, Any | None]] = Field(default_factory=dict) - initial_inputs: dict[str, dict[str, Any | None]] = Field(default_factory=dict) - init_lock: asyncio.Lock = Field(default_factory=asyncio.Lock, exclude=True) - - def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): - """Initializes a new instance of StepActor.""" - super().__init__(ctx, actor_id) - self.kernel = kernel - self.activate_task = self.activate_step() + output_edges: dict[str, list[KernelProcessEdge]] = {} + functions: dict[str, KernelFunction] = {} + inputs: dict[str, dict[str, Any | None]] = {} + initial_inputs: dict[str, dict[str, Any | None]] = {} + init_lock: asyncio.Lock = asyncio.Lock() + + # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): # kernel: Kernel): + # """Initializes a new instance of StepActor.""" + # super(StepActor, self).__init__(ctx, actor_id) + # # self.kernel = kernel + # self.activate_task = self.activate_step() @property def name(self) -> str: """Gets the name of the step.""" return self.step_info.state.name - async def initialize_step(self, step_info: DaprStepInfo, parent_process_id: str | None = None) -> None: + # async def initialize_step(self, step_info: dict[str, Any], parent_process_id: str | None = None) -> None: + async def initialize_step(self, input: dict) -> None: """Initializes the step with the provided step information.""" - if step_info is None: + if input is None: raise ValueError("step_info must not be None") + try: + input = json.loads(input) + except (json.JSONDecodeError, TypeError): + raise ValueError("Input must be a valid JSON string representing a dictionary") + + step_info = DaprStepInfo.model_validate(input.get("step_info")) + if self.initialize_task: return - await self._int_initialize_step(step_info, parent_process_id) + await self._int_initialize_step(step_info, input.get("parent_process_id")) - await self._state_manager.add_or_update_state(ActorStateKeys.StepInfoState.value, step_info) - await self._state_manager.add_or_update_state(ActorStateKeys.StepParentProcessId.value, parent_process_id) + try: + await self._state_manager.try_add_state(ActorStateKeys.StepInfoState.value, step_info) + await self._state_manager.try_add_state( + ActorStateKeys.StepParentProcessId.value, input.get("parent_process_id") + ) + await self._state_manager.save_state() + except Exception as ex: + try: + current_state = await self._state_manager.get_state(ActorStateKeys.StepInfoState.value) + except Exception as ex: + print(ex) + print(current_state) + print(f"Error in Step {self.name}: {ex!s}") + raise ex async def _int_initialize_step(self, step_info: DaprStepInfo, parent_process_id: str | None = None) -> None: """Internal method to initialize the step with the provided step information. @@ -109,7 +127,9 @@ async def prepare_incoming_messages(self) -> int: An integer indicating the number of messages prepared for processing. """ message_queue: MessageBuffer = ActorProxy.create( - actor_type=f"{MessageBufferActor.__name__}", actor_id=self.id.id, actor_interface=MessageBufferActor + actor_type=f"{MessageBufferActor.__name__}", + actor_id=ActorId(self.id.id), + actor_interface=MessageBufferActor, ) incoming = await message_queue.dequeue_all() for message in incoming: @@ -170,6 +190,12 @@ async def activate_step(self): error_message = "State object is not of the expected type." raise KernelException(error_message) + # handle the following: + # // Persist the state type and type object. + # await this.StateManager.AddStateAsync(ActorStateKeys.StepStateType, stateType.AssemblyQualifiedName).ConfigureAwait(false); + # await this.StateManager.AddStateAsync(ActorStateKeys.StepStateJson, JsonSerializer.Serialize(stateObject)).ConfigureAwait(false); + # await this.StateManager.SaveStateAsync().ConfigureAwait(false); + # Make sure that state_object.state is not None if state_object.state is None: try: @@ -298,19 +324,17 @@ async def invoke_function(self, function: "KernelFunction", kernel: "Kernel", ar async def emit_event(self, process_event: KernelProcessEvent): """Emits an event from the step.""" - await self.emit_local_event(ProcessEvent.from_kernel_process_event(process_event, self.event_namespace)) + await self.emit_process_event(ProcessEvent.from_kernel_process_event(process_event, self.event_namespace)) async def emit_process_event(self, dapr_event: ProcessEvent): """Emits an event from the step.""" - scoped_event = self.scoped_event(dapr_event) - if dapr_event.visibility == KernelProcessEventVisibility.Public and self.parent_process_id is not None: parent_process: EventBufferActor = ActorProxy.create( actor_type=f"{EventBufferActor.__name__}", - actor_id=self.parent_process_id, + actor_id=ActorId(self.parent_process_id), actor_interface=EventBufferActor, ) - await parent_process.enqueue(scoped_event) + await parent_process.enqueue(dapr_event) for edge in self.get_edge_for_event(dapr_event.id): message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, dapr_event.data) @@ -339,16 +363,20 @@ async def to_dapr_step_info(self) -> DaprStepInfo: async def _on_activate(self) -> None: """Override the Actor's on_activate method.""" - has_value, existing_step_info = await self._state_manager.try_get_state(ActorStateKeys.StepInfoState.value) + try: + has_value, existing_step_info = await self._state_manager.try_get_state(ActorStateKeys.StepInfoState.value) + except Exception as ex: + print(f"Error in Step {self.name}: {ex!s}") + raise ex if has_value: parent_process_id = await self._state_manager.get_state(ActorStateKeys.StepParentProcessId.value) await self._int_initialize_step(existing_step_info, parent_process_id=parent_process_id) # Load persisted incoming messages - exists, incoming_messages = await self._state_manager.try_get_state( + has_value, incoming_messages = await self._state_manager.try_get_state( ActorStateKeys.StepIncomingMessagesState.value ) - if exists: + if has_value: self.incoming_messages = incoming_messages def scoped_event(self, dapr_event: "ProcessEvent") -> "ProcessEvent": diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py index fd66a69d1179..2390e40c089c 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py @@ -35,6 +35,6 @@ async def start( if process_id is not None: process.state.id = process_id - process_context = DaprKernelProcessContext(process, kernel) + process_context = DaprKernelProcessContext(process=process) await process_context.start_with_event(initial_event) return process_context diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py index d5812bec497d..a3252028e438 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -26,12 +26,24 @@ def __init__(self, process: KernelProcess): self.process = process process_id = ActorId(process.state.id) self.dapr_process = ActorProxy.create(actor_interface=Process, actor_id=process_id, actor_type="ProcessActor") + print(self.dapr_process) async def start_with_event(self, initial_event: KernelProcessEvent) -> None: """Starts the process with the provided initial event.""" dapr_process = DaprProcessInfo.from_kernel_process(self.process) - await self.dapr_process.initialize_process(dapr_process, None) - await self.dapr_process.run_once(initial_event) + dapr_process_dict = dapr_process.model_dump() + + # Prepare the payload with the serialized DaprProcessInfo + payload = { + "process_info": dapr_process_dict, + "parent_process_id": None, # Replace with actual parent process ID if applicable + } + + await self.dapr_process.initialize_process(payload) + + initial_event_json = initial_event.model_dump_json() + + await self.dapr_process.run_once(initial_event_json) async def send_event(self, event: KernelProcessEvent) -> None: """Sends an event to the process.""" diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py index 63beb8ea827f..0d3b5b5fc0eb 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py @@ -5,19 +5,16 @@ from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess -from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge from semantic_kernel.processes.kernel_process.kernel_process_state import KernelProcessState from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo -from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState -from semantic_kernel.processes.process_types import TState class DaprProcessInfo(DaprStepInfo): """A Dapr process info.""" - info: KernelProcessEdge | KernelProcessState | KernelProcessStepState | KernelProcessStepState[TState] = Field( - discriminator="type" - ) + # info: KernelProcessEdge | KernelProcessState | KernelProcessStepState | KernelProcessStepState[TState] = Field( + # discriminator="type" + # ) steps: list[DaprStepInfo] = Field(default_factory=list) def to_kernel_process(self) -> KernelProcess: diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py index 6b77a04672e1..87c07d18434c 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py @@ -14,7 +14,7 @@ class DaprStepInfo(KernelBaseModel): """A Dapr step info.""" - info: KernelProcessEdge | KernelProcessStepState = Field(discriminator="type") + # info: KernelProcessEdge | KernelProcessStepState = Field(discriminator="type") inner_step_python_type: str state: KernelProcessStepState edges: dict[str, list[KernelProcessEdge]] = Field(default_factory=dict) @@ -33,9 +33,9 @@ def from_kernel_step_info(cls, kernel_step_info: KernelProcessStepInfo) -> "Dapr """Creates a Dapr step info from a kernel step info.""" if kernel_step_info is None: raise KernelException("Kernel step info must be provided") - inner_step_type = DaprStepInfo._get_fully_qualified_name(kernel_step_info.__class__) + inner_step_type = kernel_step_info.inner_step_type.__name__ return DaprStepInfo( - inner_step_type=inner_step_type, + inner_step_python_type=inner_step_type, state=kernel_step_info.state, edges={key: list(value) for key, value in kernel_step_info.edges.items()}, ) diff --git a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py index 5b8f0f62d02d..efce11718607 100644 --- a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py +++ b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py @@ -1,9 +1,9 @@ # Copyright (c) Microsoft. All rights reserved. -from abc import ABC, abstractmethod +from abc import ABC from typing import TYPE_CHECKING -from dapr.actor import ActorInterface +from dapr.actor import ActorInterface, actormethod if TYPE_CHECKING: from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent @@ -12,8 +12,8 @@ class ExternalEventBuffer(ActorInterface, ABC): """Abstract base class for an external event buffer that follows the ActorInterface.""" - @abstractmethod - async def enqueue(self, external_event: "KernelProcessEvent") -> None: + @actormethod + async def enqueue(self, external_event: str) -> None: """Enqueues an external event into the buffer. Args: @@ -21,7 +21,7 @@ async def enqueue(self, external_event: "KernelProcessEvent") -> None: """ pass - @abstractmethod + @actormethod async def dequeue_all(self) -> "list[KernelProcessEvent]": """Dequeues all external events from the buffer. diff --git a/python/semantic_kernel/processes/dapr_runtime/message_buffer.py b/python/semantic_kernel/processes/dapr_runtime/message_buffer.py index 66abb16bfeb6..28bb81e3023a 100644 --- a/python/semantic_kernel/processes/dapr_runtime/message_buffer.py +++ b/python/semantic_kernel/processes/dapr_runtime/message_buffer.py @@ -12,7 +12,7 @@ class MessageBuffer(ActorInterface): """Abstract base class for a message event buffer that follows the ActorInterface.""" @actormethod - async def enqueue(self, message: "ProcessEvent") -> None: + async def enqueue(self, message: str) -> None: """Enqueues a message event into the buffer. Args: diff --git a/python/semantic_kernel/processes/dapr_runtime/process.py b/python/semantic_kernel/processes/dapr_runtime/process.py index ca6d9e4f6b8e..5d55a31696bb 100644 --- a/python/semantic_kernel/processes/dapr_runtime/process.py +++ b/python/semantic_kernel/processes/dapr_runtime/process.py @@ -10,8 +10,9 @@ class Process(ActorInterface): """Abstract base class for a process that follows the ActorInterface.""" - @actormethod - async def initialize_process(self, process_info: "DaprProcessInfo", parent_process_id: str | None = None) -> None: + @actormethod(name="initialize_process") + # async def initialize_process(self, process_info: "DaprProcessInfo", parent_process_id: str | None = None) -> None: + async def initialize_process(self, input: dict) -> None: """Initializes the process with the specified instance of DaprProcessInfo. :param process_info: Used to initialize the process. @@ -19,7 +20,7 @@ async def initialize_process(self, process_info: "DaprProcessInfo", parent_proce """ pass - @actormethod + @actormethod(name="start") async def start(self, keep_alive: bool) -> None: """Starts an initialized process. @@ -27,7 +28,7 @@ async def start(self, keep_alive: bool) -> None: """ pass - @actormethod + @actormethod(name="run_once") async def run_once(self, process_event: "KernelProcessEvent") -> None: """Starts the process with an initial event and then waits for the process to finish. @@ -35,12 +36,12 @@ async def run_once(self, process_event: "KernelProcessEvent") -> None: """ pass - @actormethod + @actormethod(name="stop") async def stop(self) -> None: """Stops a running process, canceling and waiting for it to complete before returning.""" pass - @actormethod + @actormethod(name="send_message") async def send_message(self, process_event: "KernelProcessEvent") -> None: """Sends a message to the process without starting it if it is not already running. @@ -48,7 +49,7 @@ async def send_message(self, process_event: "KernelProcessEvent") -> None: """ pass - @actormethod + @actormethod(name="get_process_info") async def get_process_info(self) -> "DaprProcessInfo": """Retrieves the process information. diff --git a/python/semantic_kernel/processes/dapr_runtime/step.py b/python/semantic_kernel/processes/dapr_runtime/step.py index dfc35767c6df..293992b66dd6 100644 --- a/python/semantic_kernel/processes/dapr_runtime/step.py +++ b/python/semantic_kernel/processes/dapr_runtime/step.py @@ -9,8 +9,9 @@ class Step(ActorInterface): """Abstract base class for a step in the process workflow.""" - @actormethod - async def initialize_step(self, step_info: "DaprStepInfo", parent_process_id: str | None = None) -> None: + @actormethod(name="initialize_step") + # async def initialize_step(self, step_info: "DaprStepInfo", parent_process_id: str | None = None) -> None: + async def initialize_step(self, input: dict) -> None: """Initializes the step with the provided step information. :param step_info: The DaprStepInfo object to initialize the step with. @@ -19,7 +20,7 @@ async def initialize_step(self, step_info: "DaprStepInfo", parent_process_id: st """ pass - @actormethod + @actormethod(name="start") async def prepare_incoming_messages(self) -> int: """Triggers the step to dequeue all pending messages and prepare for processing. @@ -27,12 +28,12 @@ async def prepare_incoming_messages(self) -> int: """ pass - @actormethod + @actormethod(name="run_once") async def process_incoming_messages(self) -> None: """Triggers the step to process all prepared messages.""" pass - @actormethod + @actormethod(name="to_dapr_step_info") async def to_dapr_step_info(self) -> "DaprStepInfo": """Builds the current state of the step into a DaprStepInfo. diff --git a/python/semantic_kernel/processes/kernel_process/kernel_process_event.py b/python/semantic_kernel/processes/kernel_process/kernel_process_event.py index 5883e4dcd7ec..b51efb334f64 100644 --- a/python/semantic_kernel/processes/kernel_process/kernel_process_event.py +++ b/python/semantic_kernel/processes/kernel_process/kernel_process_event.py @@ -3,6 +3,8 @@ from enum import Enum from typing import Any +from pydantic import ConfigDict + from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.utils.experimental_decorator import experimental_class @@ -26,3 +28,5 @@ class KernelProcessEvent(KernelBaseModel): id: str data: Any | None = None visibility: KernelProcessEventVisibility = KernelProcessEventVisibility.Internal + + model_config = ConfigDict(use_enum_values=True) diff --git a/python/semantic_kernel/processes/process_step_builder.py b/python/semantic_kernel/processes/process_step_builder.py index 52cc051de98e..41d801313f6a 100644 --- a/python/semantic_kernel/processes/process_step_builder.py +++ b/python/semantic_kernel/processes/process_step_builder.py @@ -166,11 +166,8 @@ def build_step(self) -> "KernelProcessStepInfo": # Create state_object as KernelProcessStepState[TState] state_type = KernelProcessStepState[t_state] # type: ignore - state_object = state_type( - name=self.name, - id=self.id, - state=self.initial_state, # Can be None - ) + initial_state = self.initial_state or t_state() + state_object = state_type(name=self.name, id=self.id, state=initial_state) else: # The step has no user-defined state; use the base KernelProcessStepState if self.initial_state is not None: From f48b1a0fb8af42601ab86d41305a5b9a7a0a42f2 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 7 Nov 2024 09:17:04 -0500 Subject: [PATCH 04/16] Further work on dapr runtime. --- .../chat_gpt_api_function_calling.py | 2 +- .../dapr_runtime/actors/event_buffer_actor.py | 80 ++++++++--- .../actors/external_event_buffer_actor.py | 123 ++++++++++++----- .../actors/message_buffer_actor.py | 95 +++++++------ .../dapr_runtime/actors/process_actor.py | 129 ++++++++++-------- .../dapr_runtime/actors/step_actor.py | 120 ++++++++++------ .../dapr_kernel_process_context.py | 11 +- ...nt_buffer.py => event_buffer_interface.py} | 15 +- ....py => external_event_buffer_interface.py} | 7 +- ..._buffer.py => message_buffer_interface.py} | 6 +- .../{process.py => process_interface.py} | 2 +- .../{step.py => step_interface.py} | 6 +- 12 files changed, 384 insertions(+), 212 deletions(-) rename python/semantic_kernel/processes/dapr_runtime/{event_buffer.py => event_buffer_interface.py} (58%) rename python/semantic_kernel/processes/dapr_runtime/{external_event_buffer.py => external_event_buffer_interface.py} (86%) rename python/semantic_kernel/processes/dapr_runtime/{message_buffer.py => message_buffer_interface.py} (85%) rename python/semantic_kernel/processes/dapr_runtime/{process.py => process_interface.py} (98%) rename python/semantic_kernel/processes/dapr_runtime/{step.py => step_interface.py} (91%) diff --git a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py index ab699d5f62e5..14000da622ec 100644 --- a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py +++ b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py @@ -69,7 +69,7 @@ def search( # This concept example shows how to handle both streaming and non-streaming responses # To toggle the behavior, set the following flag accordingly: -stream = True +stream = False kernel = Kernel() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py index b33c40ebbd59..4c84ece081b2 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py @@ -7,51 +7,89 @@ from dapr.actor import Actor from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys -from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer +from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface if TYPE_CHECKING: from semantic_kernel.processes.process_event import ProcessEvent -class EventBufferActor(Actor, MessageBuffer): +class EventBufferActor(Actor, MessageBufferInterface): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" queue: Queue = Queue() - async def enqueue(self, message: "ProcessEvent") -> None: - """Enqueues a message event into the buffer. + # async def enqueue(self, message: "ProcessEvent") -> None: + # """Enqueues a message event into the buffer. - Args: - message: The message event to enqueue. - """ - from semantic_kernel.processes.process_event import ProcessEvent + # Args: + # message: The message event to enqueue. + # """ + # from semantic_kernel.processes.process_event import ProcessEvent - message = ProcessEvent.model_validate(json.loads(message)) + # message = ProcessEvent.model_validate(json.loads(message)) + + # self.queue.put(message) + + # await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) + # await self._state_manager.save_state() + + # async def dequeue_all(self) -> "list[ProcessEvent]": + # """Dequeues all process events from the buffer. + + # Returns: + # The dequeued message event. + # """ + # items = [] + # while not self.queue.empty(): + # items.append(self.queue.get()) + + # await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) + # await self._state_manager.save_state() + # return items + + # async def on_activate(self) -> None: + # """Called when the actor is activated.""" + # has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.EventQueueState.value) + # if has_value: + # self.queue = event_queue_state + # else: + # self.queue: Queue["ProcessEvent"] = Queue() + + async def enqueue(self, message: "ProcessEvent") -> None: + # Validate and deserialize the message + message = ProcessEvent.model_validate(json.loads(message)) self.queue.put(message) - await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) + # Convert queue to a list of serializable dictionaries + queue_items = list(self.queue.queue) + queue_dicts = [item.model_dump() for item in queue_items] + + # Save the serializable queue to Dapr state + await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, queue_dicts) await self._state_manager.save_state() async def dequeue_all(self) -> "list[ProcessEvent]": - """Dequeues all process events from the buffer. - - Returns: - The dequeued message event. - """ items = [] while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) + # Save the updated queue state + queue_items = list(self.queue.queue) + queue_dicts = [item.model_dump() for item in queue_items] + await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, queue_dicts) await self._state_manager.save_state() - return items + # Return a list of serializable dictionaries + return [item.model_dump() for item in items] - async def on_activate(self) -> None: - """Called when the actor is activated.""" + async def _on_activate(self) -> None: has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.EventQueueState.value) if has_value: - self.queue = event_queue_state + queue_dicts = event_queue_state + self.queue = Queue() + for item_dict in queue_dicts: + message = ProcessEvent(**item_dict) + self.queue.put(message) else: - self.queue: Queue["ProcessEvent"] = Queue() + self.queue = Queue() diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py index 9a9bce54e705..5181fb30fd90 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py @@ -1,66 +1,123 @@ # Copyright (c) Microsoft. All rights reserved. import json +import logging from queue import Queue -from typing import TYPE_CHECKING +from typing import List -from dapr.actor import Actor +from dapr.actor import Actor, ActorId +from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys -from semantic_kernel.processes.dapr_runtime.external_event_buffer import ExternalEventBuffer +from semantic_kernel.processes.dapr_runtime.external_event_buffer_interface import ExternalEventBufferInterface from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent -if TYPE_CHECKING: - pass +# Set up logging +logger = logging.getLogger(__name__) -class ExternalEventBufferActor(Actor, ExternalEventBuffer): +class ExternalEventBufferActor(Actor, ExternalEventBufferInterface): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" - queue: Queue = Queue() + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): + """Initializes a new instance of ExternalEventBufferActor. + + Args: + ctx: The actor runtime context. + actor_id: The unique ID for the actor. + """ + super().__init__(ctx, actor_id) + self.queue: Queue[KernelProcessEvent] = Queue() async def enqueue(self, message: str) -> None: """Enqueues a message event into the buffer. Args: - message: The message event to enqueue. + message: The message event to enqueue as a JSON string. + + Raises: + Exception: If an error occurs during enqueue operation. """ - # Perform validation that we have the correct incoming message - message = KernelProcessEvent.model_validate(json.loads(message)) - self.queue.put(message) + from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent try: - # Convert each item in the queue to a dictionary for serialization - queue_list = [item.model_dump() for item in self.queue.queue] - queue_dict = json.dumps(queue_list) + # Deserialize and validate the incoming message + message_obj = KernelProcessEvent.model_validate(json.loads(message)) + self.queue.put(message_obj) - await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_dict) + # Serialize the queue to a JSON string + queue_list = [item.model_dump() for item in list(self.queue.queue)] + queue_json = json.dumps(queue_list) + + # Save the serialized queue to Dapr state + await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_json) await self._state_manager.save_state() + logger.debug(f"Enqueued message and updated state for actor ID: {self.id.id}") except Exception as e: - print(e) - raise e + error_message = str(e) + logger.error(f"Error in enqueue: {error_message}") + # Raise exception with JSON-serializable message + raise Exception(error_message) - async def dequeue_all(self) -> "list[KernelProcessEvent]": + async def dequeue_all(self) -> List[dict]: """Dequeues all process events from the buffer. Returns: - The dequeued message event. + A list of dictionaries representing the dequeued `KernelProcessEvent` messages. + + Raises: + Exception: If an error occurs during dequeue operation. """ - items = [] - while not self.queue.empty(): - items.append(self.queue.get()) + try: + items = [] + while not self.queue.empty(): + item = self.queue.get() + items.append(item) - await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, self.queue) - await self._state_manager.save_state() + # After dequeuing, update the state to reflect the empty queue + queue_list = [item.model_dump() for item in list(self.queue.queue)] + queue_json = json.dumps(queue_list) - return items + await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_json) + await self._state_manager.save_state() + logger.debug(f"Dequeued all messages and updated state for actor ID: {self.id.id}") + + # Return the dequeued items as a list of dictionaries + return [item.model_dump() for item in items] + except Exception as e: + error_message = str(e) + logger.error(f"Error in dequeue_all: {error_message}") + # Raise exception with JSON-serializable message + raise Exception(error_message) async def _on_activate(self) -> None: - """Called when the actor is activated.""" - state_exists, event_queue_state = await self._state_manager.try_get_state( - ActorStateKeys.ExternalEventQueueState.value - ) - if state_exists: - self.queue = event_queue_state - else: - self.queue: Queue[KernelProcessEvent] = Queue() + """Called when the actor is activated to initialize state. + + Raises: + Exception: If an error occurs during actor activation. + """ + from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent + + try: + logger.debug(f"Activating actor with ID: {self.id.id}") + + # Retrieve the stored queue from Dapr state + state_exists, queue_json = await self._state_manager.try_get_state( + ActorStateKeys.ExternalEventQueueState.value + ) + if state_exists and queue_json: + # Deserialize the JSON string back to a list of dictionaries + queue_list = json.loads(queue_json) + self.queue = Queue() + for item_dict in queue_list: + message_obj = KernelProcessEvent(**item_dict) + self.queue.put(message_obj) + logger.debug(f"Reconstructed queue from state for actor ID: {self.id.id}") + else: + self.queue = Queue() + logger.debug(f"No existing state found. Initialized empty queue for actor ID: {self.id.id}") + except Exception as e: + error_message = str(e) + logger.error(f"Error in _on_activate: {error_message}") + # Raise exception with JSON-serializable message + raise Exception(error_message) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py index 9013cd1826f1..45359a09ea33 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py @@ -1,56 +1,75 @@ # Copyright (c) Microsoft. All rights reserved. import json +import logging from queue import Queue -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any -from dapr.actor import Actor +from dapr.actor import Actor, ActorId +from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys -from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer +from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface if TYPE_CHECKING: from semantic_kernel.processes.process_message import ProcessMessage +logger: logging.Logger = logging.getLogger(__name__) -class MessageBufferActor(Actor, MessageBuffer): - """Represents a message buffer actor that follows the MessageBuffer abstract class.""" - queue: Queue = Queue() +class MessageBufferActor(Actor, MessageBufferInterface): + """Represents a message buffer actor that follows the MessageBuffer abstract class.""" - async def enqueue(self, message: "ProcessMessage") -> None: - """Enqueues a message event into the buffer. + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): + super().__init__(ctx, actor_id) + self.queue: Queue[ProcessMessage] = Queue() - Args: - message: The message event to enqueue. - """ + async def enqueue(self, message: str) -> None: from semantic_kernel.processes.process_message import ProcessMessage - message = ProcessMessage.model_validate(json.loads(message)) - self.queue.put(message) - - await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, self.queue) - await self._state_manager.save_state() - - async def dequeue_all(self) -> "list[ProcessMessage]": - """Dequeues all process events from the buffer. - - Returns: - The dequeued message event. - """ - items = [] - while not self.queue.empty(): - items.append(self.queue.get()) - - await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, self.queue) - await self._state_manager.save_state() - - return items + try: + message_obj = ProcessMessage.model_validate(json.loads(message)) + self.queue.put(message_obj) + + queue_list = [item.model_dump() for item in list(self.queue.queue)] + await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, queue_list) + await self._state_manager.save_state() + except Exception as e: + error_message = str(e) + logger.error(f"Error in enqueue: {error_message}") + raise Exception(error_message) + + async def dequeue_all(self) -> list[dict[str, Any]]: + try: + items = [] + while not self.queue.empty(): + items.append(self.queue.get()) + + queue_list = [item.model_dump() for item in list(self.queue.queue)] + await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, queue_list) + await self._state_manager.save_state() + + return [item.model_dump() for item in items] + except Exception as e: + error_message = str(e) + logger.error(f"Error in dequeue_all: {error_message}") + raise Exception(error_message) + + async def _on_activate(self) -> None: + from semantic_kernel.processes.process_message import ProcessMessage - async def on_activate(self) -> None: - """Called when the actor is activated.""" - has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.MessageQueueState.value) - if has_value: - self.queue = event_queue_state - else: - self.queue: Queue[ProcessMessage] = Queue() + try: + logger.debug(f"Activating actor with ID: {self.id.id}") + + has_value, queue_list = await self._state_manager.try_get_state(ActorStateKeys.MessageQueueState.value) + if has_value and queue_list: + self.queue = Queue() + for item_dict in queue_list: + message_obj = ProcessMessage(**item_dict) + self.queue.put(message_obj) + else: + self.queue = Queue() + except Exception as e: + error_message = str(e) + logger.error(f"Error in _on_activate: {error_message}") + raise Exception(error_message) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py index 4561d4fe1438..5c45ab74606a 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py @@ -8,7 +8,7 @@ from queue import Queue from dapr.actor import ActorId, ActorProxy -from pydantic import Field +from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.exceptions.kernel_exceptions import KernelException from semantic_kernel.exceptions.process_exceptions import ProcessEventUndefinedException @@ -21,9 +21,11 @@ from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo -from semantic_kernel.processes.dapr_runtime.external_event_buffer import ExternalEventBuffer -from semantic_kernel.processes.dapr_runtime.process import Process -from semantic_kernel.processes.dapr_runtime.step import Step +from semantic_kernel.processes.dapr_runtime.event_buffer_interface import EventBufferInterface +from semantic_kernel.processes.dapr_runtime.external_event_buffer_interface import ExternalEventBufferInterface +from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface +from semantic_kernel.processes.dapr_runtime.process_interface import ProcessInterface +from semantic_kernel.processes.dapr_runtime.step_interface import StepInterface from semantic_kernel.processes.kernel_process.kernel_process_event import ( KernelProcessEvent, KernelProcessEventVisibility, @@ -32,33 +34,36 @@ from semantic_kernel.processes.process_message import ProcessMessage from semantic_kernel.processes.process_message_factory import ProcessMessageFactory +# class ProcessActor(StepActor, ProcessInterface): +# """A local process that contains a collection of steps.""" -class ProcessActor(StepActor, Process): +# kernel: Kernel | None = None +# steps: list[StepActor] = [] +# step_infos: list[DaprStepInfo] = [] +# initialize_task: bool | None = False +# external_event_queue: Queue = Queue() +# process_task: asyncio.Task | None = None +# process: DaprProcessInfo | None = None + + +class ProcessActor(StepActor, ProcessInterface): """A local process that contains a collection of steps.""" - kernel: Kernel | None = None - _steps: list[StepActor] = [] - step_infos: list[DaprStepInfo] = Field(default_factory=list) - initialize_task: bool | None = False - external_event_queue: Queue = Field(default_factory=Queue) - process_task: asyncio.Task | None = None - process: DaprProcessInfo | None = None - - # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId) -> None: - # """Initializes the local process.""" - # args: dict[str, Any] = { - # "ctx": ctx, - # "actor_id": actor_id, - # # "kernel": kernel, - # "initialize_task": False, - # } - - # super().__init__(**args) - - # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, **kwargs) -> None: - # """Initializes the local process.""" - # # Initialize the Actor base class explicitly - # super(ProcessActor, self).__init__(ctx, actor_id) + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): + """Initializes a new instance of ProcessActor. + + Args: + ctx: The actor runtime context. + actor_id: The unique ID for the actor. + kernel: The Kernel dependency to be injected. + """ + super().__init__(ctx, actor_id, kernel) + self.steps: list[StepActor] = [] + self.step_infos: list[DaprStepInfo] = [] + self.initialize_task: bool | None = False + self.external_event_queue: Queue = Queue() + self.process_task: asyncio.Task | None = None + self.process: DaprProcessInfo | None = None @property def name(self) -> str: @@ -99,7 +104,9 @@ async def start(self, keep_alive: bool = True) -> None: if not self.initialize_task: raise ValueError("The process has not been initialized.") - self.process_task = asyncio.create_task(self.internal_execute(keep_alive=keep_alive)) + # Only create the task if it doesn't already exist or is not running + if not self.process_task or self.process_task.done(): + self.process_task = asyncio.create_task(self.internal_execute(keep_alive=keep_alive)) async def run_once(self, process_event_payload: str): """Starts the process with an initial event and waits for it to finish.""" @@ -109,13 +116,17 @@ async def run_once(self, process_event_payload: str): external_event_queue: ExternalEventBufferActor = ActorProxy.create( actor_type=f"{ExternalEventBufferActor.__name__}", actor_id=ActorId(self.id.id), - actor_interface=ExternalEventBuffer, + actor_interface=ExternalEventBufferInterface, ) try: await external_event_queue.enqueue(process_event_payload) await self.start(keep_alive=False) if self.process_task: - await self.process_task + try: + await self.process_task + except asyncio.CancelledError: + print("Process task was cancelled") + # Optionally handle the cancellation except Exception as ex: print(ex) raise ex @@ -194,7 +205,7 @@ async def _initialize_process_actor( self.output_edges = {kvp[0]: list(kvp[1]) for kvp in self.process.edges.items()} for step in self.step_infos: - step_actor: Step = None + step_actor: StepInterface = None # The current step should already have a name. assert step.state and step.state.name is not None # nosec @@ -206,17 +217,17 @@ async def _initialize_process_actor( # Initialize the step as a process scoped_process_id = self._scoped_actor_id(ActorId(step.state.id)) - process_actor: Process = ActorProxy.create( - actor_id=scoped_process_id, + process_actor: ProcessInterface = ActorProxy.create( actor_type=f"{ProcessActor.__name__}", - actor_interface=Process, + actor_id=scoped_process_id, + actor_interface=ProcessInterface, ) payload = {"process_info": step.model_dump(), "parent_process_id": self.id.id} await process_actor.initialize_process(payload) step_actor = ActorProxy.create( - actor_id=scoped_process_id, actor_type=f"{ProcessActor.__name__}", - actor_interface=Step, + actor_id=scoped_process_id, + actor_interface=StepInterface, ) else: # The current step should already have an Id. @@ -224,9 +235,9 @@ async def _initialize_process_actor( scoped_step_id = self._scoped_actor_id(ActorId(step.state.id)) step_actor = ActorProxy.create( - actor_id=scoped_step_id, actor_type=f"{StepActor.__name__}", - actor_interface=Step, + actor_id=scoped_step_id, + actor_interface=StepInterface, ) step_dict = step.model_dump() payload = {"step_info": step_dict, "parent_process_id": self.id.id} @@ -237,7 +248,7 @@ async def _initialize_process_actor( raise ex # Add the local step to the list of steps - self._steps.append(step_actor) + self.steps.append(step_actor) self.initialize_task = True @@ -254,31 +265,30 @@ async def internal_execute(self, max_supersteps: int = 100, keep_alive: bool = T try: for _ in range(max_supersteps): if await self._is_end_message_sent(): - self.process_task.cancel() + # Exit the loop without cancelling the task break # Check for external events await self._enqueue_external_messages() - # Reach out to all of the steps in the process and instrcut them to retrieve their pending - # messages from their associated queues + # Prepare incoming messages for each step step_preparation_tasks = [step.prepare_incoming_messages() for step in self.steps] message_counts = await asyncio.gather(*step_preparation_tasks) if sum(message_counts) == 0 and (not keep_alive or self.external_event_queue.empty()): - self.process_task.cancel() + # Exit the loop without cancelling the task break # Process the incoming messages for each step step_processing_tasks = [step.process_incoming_messages() for step in self.steps] await asyncio.gather(*step_processing_tasks) - # Handle public events that need to be bubbled out of the process + # Handle public events await self.send_outgoing_public_events() except Exception as ex: - print("An error occurred while running the process: %s.", ex) - self.process_task.cancel() + print(f"An error occurred while running the process: {ex}") + # Optionally handle the exception raise def _scoped_event(self, dapr_event: ProcessEvent): @@ -292,9 +302,9 @@ async def send_outgoing_public_events(self) -> None: """Sends outgoing public events.""" if self.parent_process_id is not None: event_queue: EventBufferActor = ActorProxy.create( - actor_id=ActorId(self.id.id), actor_type=f"{EventBufferActor.__name__}", - actor_interface=EventBufferActor, + actor_id=ActorId(self.id.id), + actor_interface=EventBufferInterface, ) all_events: list[ProcessEvent] = await event_queue.dequeue_all() @@ -309,7 +319,7 @@ async def send_outgoing_public_events(self) -> None: message_queue: MessageBufferActor = ActorProxy.create( actor_id=scoped_message_buffer_id, actor_type=f"{MessageBufferActor.__name__}", - actor_interface=MessageBufferActor, + actor_interface=MessageBufferInterface, ) await message_queue.enqueue(message) @@ -317,9 +327,9 @@ async def _is_end_message_sent(self) -> bool: """Checks if the end message has been sent.""" scoped_message_buffer_id = self._scoped_actor_id(ActorId(END_PROCESS_ID)) end_message_queue: MessageBufferActor = ActorProxy.create( - actor_id=scoped_message_buffer_id, actor_type=f"{MessageBufferActor.__name__}", - actor_interface=MessageBufferActor, + actor_id=scoped_message_buffer_id, + actor_interface=MessageBufferInterface, ) messages: list[ProcessMessage] = await end_message_queue.dequeue_all() return len(messages) > 0 @@ -327,12 +337,14 @@ async def _is_end_message_sent(self) -> bool: async def _enqueue_external_messages(self) -> None: """Enqueues external messages into the process.""" external_event_queue: ExternalEventBufferActor = ActorProxy.create( - actor_id=ActorId(self.id.id), actor_type=f"{ExternalEventBufferActor.__name__}", - actor_interface=ExternalEventBufferActor, + actor_id=ActorId(self.id.id), + actor_interface=ExternalEventBufferInterface, ) - external_events = await external_event_queue.dequeue_all() + external_events_json = await external_event_queue.dequeue_all() + + external_events = [KernelProcessEvent.model_validate(e) for e in external_events_json] for external_event in external_events: if external_event.id in self.output_edges and self.output_edges[external_event.id] is not None: @@ -340,8 +352,9 @@ async def _enqueue_external_messages(self) -> None: message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, external_event.data) scoped_message_buffer_id = self._scoped_actor_id(ActorId(edge.output_target.step_id)) message_queue: MessageBufferActor = ActorProxy.create( - actor_id=scoped_message_buffer_id, actor_type=f"{MessageBufferActor.__name__}", - actor_interface=MessageBufferActor, + actor_id=scoped_message_buffer_id, + actor_interface=MessageBufferInterface, ) - await message_queue.enqueue(message) + message_json = json.dumps(message.model_dump()) + await message_queue.enqueue(message_json) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py index 6bc428c92c89..9f81ca427935 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -7,6 +7,7 @@ from typing import Any, Type from dapr.actor import Actor, ActorId, ActorProxy +from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.exceptions.kernel_exceptions import KernelException from semantic_kernel.exceptions.process_exceptions import ( @@ -19,8 +20,9 @@ from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo -from semantic_kernel.processes.dapr_runtime.message_buffer import MessageBuffer -from semantic_kernel.processes.dapr_runtime.step import Step +from semantic_kernel.processes.dapr_runtime.event_buffer_interface import EventBufferInterface +from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface +from semantic_kernel.processes.dapr_runtime.step_interface import StepInterface from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge from semantic_kernel.processes.kernel_process.kernel_process_event import ( KernelProcessEvent, @@ -40,29 +42,54 @@ @experimental_class -class StepActor(Actor, Step, KernelProcessMessageChannel): +# class StepActor(Actor, StepInterface, KernelProcessMessageChannel): +# """Represents a step actor that follows the Step abstract class.""" +# kernel: Kernel | None = None +# parent_process_id: str | None = None +# step_info: DaprStepInfo | None = None +# initialize_task: bool | None = False +# event_namespace: str | None = None +# inner_step_type: Type | None = None +# incoming_messages: Queue = Queue() +# step_state: KernelProcessStepState | None = None +# step_state_type: Type | None = None +# output_edges: dict[str, list[KernelProcessEdge]] = {} +# functions: dict[str, KernelFunction] = {} +# inputs: dict[str, dict[str, Any | None]] = {} +# initial_inputs: dict[str, dict[str, Any | None]] = {} +# init_lock: asyncio.Lock = asyncio.Lock() +# # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): # kernel: Kernel): +# # """Initializes a new instance of StepActor.""" +# # super(StepActor, self).__init__(ctx, actor_id) +# # # self.kernel = kernel +# # self.activate_task = self.activate_step() +class StepActor(Actor, StepInterface, KernelProcessMessageChannel): """Represents a step actor that follows the Step abstract class.""" - kernel: Kernel | None = None - parent_process_id: str | None = None - step_info: DaprStepInfo | None = None - initialize_task: bool | None = False - event_namespace: str | None = None - inner_step_type: Type | None = None - incoming_messages: Queue = Queue() - step_state: KernelProcessStepState | None = None - step_state_type: Type | None = None - output_edges: dict[str, list[KernelProcessEdge]] = {} - functions: dict[str, KernelFunction] = {} - inputs: dict[str, dict[str, Any | None]] = {} - initial_inputs: dict[str, dict[str, Any | None]] = {} - init_lock: asyncio.Lock = asyncio.Lock() - - # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): # kernel: Kernel): - # """Initializes a new instance of StepActor.""" - # super(StepActor, self).__init__(ctx, actor_id) - # # self.kernel = kernel - # self.activate_task = self.activate_step() + def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): + """Initializes a new instance of StepActor. + + Args: + ctx: The actor runtime context. + actor_id: The unique ID for the actor. + kernel: The Kernel dependency to be injected. + """ + super().__init__(ctx, actor_id) + self.kernel = kernel + self.parent_process_id: str | None = None + self.step_info: DaprStepInfo | None = None + self.initialize_task: bool | None = False + self.event_namespace: str | None = None + self.inner_step_type: Type | None = None + self.incoming_messages: Queue = Queue() + self.step_state: KernelProcessStepState | None = None + self.step_state_type: Type | None = None + self.output_edges: dict[str, list[KernelProcessEdge]] = {} + self.functions: dict[str, KernelFunction] = {} + self.inputs: dict[str, dict[str, Any | None]] = {} + self.initial_inputs: dict[str, dict[str, Any | None]] = {} + self.init_lock: asyncio.Lock = asyncio.Lock() + self.activate_task = self.activate_step() @property def name(self) -> str: @@ -126,19 +153,34 @@ async def prepare_incoming_messages(self) -> int: Returns: An integer indicating the number of messages prepared for processing. """ - message_queue: MessageBuffer = ActorProxy.create( - actor_type=f"{MessageBufferActor.__name__}", - actor_id=ActorId(self.id.id), - actor_interface=MessageBufferActor, - ) - incoming = await message_queue.dequeue_all() - for message in incoming: - self.incoming_messages.put(message) + try: + message_queue: MessageBufferInterface = ActorProxy.create( + actor_type=f"{MessageBufferActor.__name__}", + actor_id=ActorId(self.id.id), + actor_interface=MessageBufferInterface, + ) + incoming = await message_queue.dequeue_all() - await self._state_manager.set_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) - await self._state_manager.save_state() + messages = [] + json_msg = [] + for message in incoming: + json_msg.append(message) + process_event = ProcessEvent.model_validate(message) + messages.append(process_event) + + for msg in messages: + self.incoming_messages.put(msg) + + await self._state_manager.try_add_state( + ActorStateKeys.StepIncomingMessagesState.value, json.dumps(json_msg) + ) + await self._state_manager.save_state() - return len(self.incoming_messages) + return self.incoming_messages.qsize() if self.incoming_messages else 0 + except Exception as e: + error_message = str(e) + logger.error(f"Error in prepare_incoming_messages: {error_message}") + raise Exception(error_message) async def process_incoming_messages(self) -> None: """Triggers the step to process all prepared messages.""" @@ -146,7 +188,7 @@ async def process_incoming_messages(self) -> None: message = self.incoming_messages.get() await self.handle_message(message) - await self._state_manager.set_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) + await self._state_manager.try_add_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) await self._state_manager.save_state() async def activate_step(self): @@ -332,17 +374,17 @@ async def emit_process_event(self, dapr_event: ProcessEvent): parent_process: EventBufferActor = ActorProxy.create( actor_type=f"{EventBufferActor.__name__}", actor_id=ActorId(self.parent_process_id), - actor_interface=EventBufferActor, + actor_interface=EventBufferInterface, ) await parent_process.enqueue(dapr_event) for edge in self.get_edge_for_event(dapr_event.id): message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, dapr_event.data) scoped_step_id = self._scoped_actor_id(ActorId(edge.output_target.step_id)) - target_step: MessageBuffer = ActorProxy.create( + target_step: MessageBufferInterface = ActorProxy.create( + actor_type=f"{MessageBufferActor.__name__}", actor_id=scoped_step_id, - actor_interface=MessageBuffer, - actor_type=f"{MessageBuffer.__name__}", + actor_interface=MessageBufferInterface, ) await target_step.enqueue(message) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py index a3252028e438..f299f0d84c88 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -4,8 +4,9 @@ from dapr.actor import ActorId, ActorProxy +from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo -from semantic_kernel.processes.dapr_runtime.process import Process +from semantic_kernel.processes.dapr_runtime.process_interface import ProcessInterface from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent @@ -13,7 +14,7 @@ class DaprKernelProcessContext: """A Dapr kernel process context.""" - dapr_process: Process + dapr_process: ProcessInterface process: KernelProcess def __init__(self, process: KernelProcess): @@ -25,7 +26,11 @@ def __init__(self, process: KernelProcess): self.process = process process_id = ActorId(process.state.id) - self.dapr_process = ActorProxy.create(actor_interface=Process, actor_id=process_id, actor_type="ProcessActor") + self.dapr_process = ActorProxy.create( + actor_type=f"{ProcessActor.__name__}", + actor_id=process_id, + actor_interface=ProcessInterface, + ) print(self.dapr_process) async def start_with_event(self, initial_event: KernelProcessEvent) -> None: diff --git a/python/semantic_kernel/processes/dapr_runtime/event_buffer.py b/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py similarity index 58% rename from python/semantic_kernel/processes/dapr_runtime/event_buffer.py rename to python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py index f092cdfe7532..27d71d16bfc7 100644 --- a/python/semantic_kernel/processes/dapr_runtime/event_buffer.py +++ b/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py @@ -1,31 +1,30 @@ # Copyright (c) Microsoft. All rights reserved. -from abc import ABC, abstractmethod from typing import TYPE_CHECKING -from dapr.actor import ActorInterface +from dapr.actor import ActorInterface, actormethod if TYPE_CHECKING: from semantic_kernel.processes.process_event import ProcessEvent -class EventBuffer(ActorInterface, ABC): +class EventBufferInterface(ActorInterface): """Abstract base class for an event buffer that follows the ActorInterface.""" - @abstractmethod - async def enqueue(self, step_event: "ProcessEvent") -> None: - """Enqueues a step event into the buffer. + @actormethod(name="enqueue") + async def enqueue(self, step_event: str) -> None: + """Enqueues a `ProcessEvent` step event into the buffer. Args: step_event: The step event to enqueue. """ pass - @abstractmethod + @actormethod(name="dequeue_all") async def dequeue_all(self) -> "list[ProcessEvent]": """Dequeues a step event from the buffer. Returns: - The dequeued step event. + The dequeued step event as a list of `ProcessEvent`. """ pass diff --git a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py similarity index 86% rename from python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py rename to python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py index efce11718607..4f3857e2bd61 100644 --- a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer.py +++ b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py @@ -1,6 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. -from abc import ABC from typing import TYPE_CHECKING from dapr.actor import ActorInterface, actormethod @@ -9,10 +8,10 @@ from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent -class ExternalEventBuffer(ActorInterface, ABC): +class ExternalEventBufferInterface(ActorInterface): """Abstract base class for an external event buffer that follows the ActorInterface.""" - @actormethod + @actormethod(name="enqueue") async def enqueue(self, external_event: str) -> None: """Enqueues an external event into the buffer. @@ -21,7 +20,7 @@ async def enqueue(self, external_event: str) -> None: """ pass - @actormethod + @actormethod(name="dequeue_all") async def dequeue_all(self) -> "list[KernelProcessEvent]": """Dequeues all external events from the buffer. diff --git a/python/semantic_kernel/processes/dapr_runtime/message_buffer.py b/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py similarity index 85% rename from python/semantic_kernel/processes/dapr_runtime/message_buffer.py rename to python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py index 28bb81e3023a..f0b58e3816f7 100644 --- a/python/semantic_kernel/processes/dapr_runtime/message_buffer.py +++ b/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py @@ -8,10 +8,10 @@ from semantic_kernel.processes.process_event import ProcessEvent -class MessageBuffer(ActorInterface): +class MessageBufferInterface(ActorInterface): """Abstract base class for a message event buffer that follows the ActorInterface.""" - @actormethod + @actormethod(name="enqueue") async def enqueue(self, message: str) -> None: """Enqueues a message event into the buffer. @@ -20,7 +20,7 @@ async def enqueue(self, message: str) -> None: """ pass - @actormethod + @actormethod(name="dequeue_all") async def dequeue_all(self) -> "list[ProcessEvent]": """Dequeues all process events from the buffer. diff --git a/python/semantic_kernel/processes/dapr_runtime/process.py b/python/semantic_kernel/processes/dapr_runtime/process_interface.py similarity index 98% rename from python/semantic_kernel/processes/dapr_runtime/process.py rename to python/semantic_kernel/processes/dapr_runtime/process_interface.py index 5d55a31696bb..46f19dce72b7 100644 --- a/python/semantic_kernel/processes/dapr_runtime/process.py +++ b/python/semantic_kernel/processes/dapr_runtime/process_interface.py @@ -7,7 +7,7 @@ from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent -class Process(ActorInterface): +class ProcessInterface(ActorInterface): """Abstract base class for a process that follows the ActorInterface.""" @actormethod(name="initialize_process") diff --git a/python/semantic_kernel/processes/dapr_runtime/step.py b/python/semantic_kernel/processes/dapr_runtime/step_interface.py similarity index 91% rename from python/semantic_kernel/processes/dapr_runtime/step.py rename to python/semantic_kernel/processes/dapr_runtime/step_interface.py index 293992b66dd6..97d31467b00f 100644 --- a/python/semantic_kernel/processes/dapr_runtime/step.py +++ b/python/semantic_kernel/processes/dapr_runtime/step_interface.py @@ -6,7 +6,7 @@ from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo -class Step(ActorInterface): +class StepInterface(ActorInterface): """Abstract base class for a step in the process workflow.""" @actormethod(name="initialize_step") @@ -20,7 +20,7 @@ async def initialize_step(self, input: dict) -> None: """ pass - @actormethod(name="start") + @actormethod(name="prepare_incoming_messages") async def prepare_incoming_messages(self) -> int: """Triggers the step to dequeue all pending messages and prepare for processing. @@ -28,7 +28,7 @@ async def prepare_incoming_messages(self) -> int: """ pass - @actormethod(name="run_once") + @actormethod(name="process_incoming_messages") async def process_incoming_messages(self) -> None: """Triggers the step to process all prepared messages.""" pass From 221a429f49545cdd2374b30a0c6ce0c3ea04298e Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Fri, 8 Nov 2024 14:13:45 -0500 Subject: [PATCH 05/16] Working dapr FastAPI sample app. --- python/pyproject.toml | 1 + .../chat_gpt_api_function_calling.py | 19 +- python/samples/demos/process_with_dapr/app.py | 26 +- .../getting_started_with_agents/step3_chat.py | 4 + .../dapr_runtime/actors/event_buffer_actor.py | 129 +- .../actors/external_event_buffer_actor.py | 61 +- .../actors/message_buffer_actor.py | 34 +- .../dapr_runtime/actors/process_actor.py | 81 +- .../dapr_runtime/actors/step_actor.py | 91 +- .../dapr_kernel_process_context.py | 6 +- .../processes/dapr_runtime/dapr_step_info.py | 10 +- .../dapr_runtime/event_buffer_interface.py | 7 +- .../external_event_buffer_interface.py | 10 +- .../dapr_runtime/message_buffer_interface.py | 10 +- .../dapr_runtime/process_interface.py | 2 +- .../semantic_kernel/processes/step_utils.py | 6 + python/uv.lock | 1254 ++++++++++------- 17 files changed, 958 insertions(+), 793 deletions(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index d2decda1d4a1..07345f91300d 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -118,6 +118,7 @@ aws = [ ] dapr = [ "dapr>=1.14.0", + "dapr.ext.fastapi>=1.14.0", ] [tool.uv] diff --git a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py index 14000da622ec..a5f53fe32fbe 100644 --- a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py +++ b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py @@ -13,6 +13,8 @@ from semantic_kernel.contents.chat_message_content import ChatMessageContent from semantic_kernel.contents.function_call_content import FunctionCallContent from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent +from semantic_kernel.core_plugins.math_plugin import MathPlugin +from semantic_kernel.core_plugins.time_plugin import TimePlugin from semantic_kernel.functions import KernelArguments from semantic_kernel.functions.kernel_function_decorator import kernel_function @@ -78,8 +80,8 @@ def search( plugins_directory = os.path.join(__file__, "../../../../../prompt_template_samples/") # adding plugins to the kernel -# kernel.add_plugin(MathPlugin(), plugin_name="math") -# kernel.add_plugin(TimePlugin(), plugin_name="time") +kernel.add_plugin(MathPlugin(), plugin_name="math") +kernel.add_plugin(TimePlugin(), plugin_name="time") kernel.add_plugin(TravelPlugin(), plugin_name="travel") chat_function = kernel.add_function( @@ -118,7 +120,7 @@ def search( max_tokens=2000, temperature=0.7, top_p=0.8, - function_choice_behavior=FunctionChoiceBehavior.Auto(filters={"included_plugins": ["travel"]}), + function_choice_behavior=FunctionChoiceBehavior.Auto(filters={"included_plugins": ["travel", "math", "time"]}), ) history = ChatHistory() @@ -210,6 +212,17 @@ async def chat() -> bool: else: result = await kernel.invoke(chat_function, arguments=arguments) + chat_history: ChatHistory = result.metadata["messages"] + + # for msg in chat_history: + # if hasattr(msg, "inner_content"): + # msg.inner_content = None + # for item in msg.items: + # if isinstance(item, (FunctionCallContent, FunctionResultContent)): + # item.inner_content = None + + print(chat_history.model_dump_json()) + # If tools are used, and auto invoke tool calls is False, the response will be of type # ChatMessageContent with information about the tool calls, which need to be sent # back to the model to get the final response. diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index 3b6e991de696..c837c33ba19c 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -1,9 +1,14 @@ +# Copyright (c) Microsoft. All rights reserved. + import asyncio +import logging from contextlib import asynccontextmanager from enum import Enum from typing import TYPE_CHECKING, ClassVar import uvicorn +from dapr.actor import ActorId +from dapr.actor.runtime.context import ActorRuntimeContext from dapr.ext.fastapi import DaprActor, DaprApp from fastapi import FastAPI from fastapi.responses import JSONResponse @@ -26,12 +31,27 @@ if TYPE_CHECKING: from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess +logging.basicConfig(level=logging.DEBUG) + + +kernel = Kernel() + + +def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: + """Factory function to create ProcessActor instances with dependencies.""" + return ProcessActor(ctx, actor_id, kernel) + + +def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor: + """Factory function to create StepActor instances with dependencies.""" + return StepActor(ctx, actor_id, kernel=kernel) + @asynccontextmanager async def lifespan(app: FastAPI): print("~~ actor startup") - await actor.register_actor(ProcessActor) - await actor.register_actor(StepActor) + await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) + await actor.register_actor(StepActor, actor_factory=step_actor_factory) await actor.register_actor(EventBufferActor) await actor.register_actor(MessageBufferActor) await actor.register_actor(ExternalEventBufferActor) @@ -160,4 +180,4 @@ async def start_process(process_id: str): if __name__ == "__main__": - uvicorn.run(app, host="0.0.0.0", port=5001) + uvicorn.run(app, host="0.0.0.0", port=5001) # nosec diff --git a/python/samples/getting_started_with_agents/step3_chat.py b/python/samples/getting_started_with_agents/step3_chat.py index e81c5d0c516c..a2c536aca22a 100644 --- a/python/samples/getting_started_with_agents/step3_chat.py +++ b/python/samples/getting_started_with_agents/step3_chat.py @@ -75,10 +75,14 @@ async def main(): await chat.add_chat_message(ChatMessageContent(role=AuthorRole.USER, content=input)) print(f"# {AuthorRole.USER}: '{input}'") + chat_history: list[ChatMessageContent] = [] async for content in chat.invoke(): print(f"# {content.role} - {content.name or '*'}: '{content.content}'") + chat_history.append(content) print(f"# IS COMPLETE: {chat.is_complete}") + for msg in chat_history: + print(msg.model_dump_json()) if __name__ == "__main__": diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py index 4c84ece081b2..e166f3beb5c7 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py @@ -1,95 +1,90 @@ # Copyright (c) Microsoft. All rights reserved. import json +import logging from queue import Queue -from typing import TYPE_CHECKING from dapr.actor import Actor from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface -if TYPE_CHECKING: - from semantic_kernel.processes.process_event import ProcessEvent +logger = logging.getLogger(__name__) class EventBufferActor(Actor, MessageBufferInterface): - """Represents a message buffer actor that follows the MessageBuffer abstract class.""" + """Represents a message buffer actor that manages a queue of JSON strings representing events.""" queue: Queue = Queue() - # async def enqueue(self, message: "ProcessEvent") -> None: - # """Enqueues a message event into the buffer. + async def enqueue(self, message: str) -> None: + """Enqueues a JSON string message event into the buffer and updates the state. - # Args: - # message: The message event to enqueue. - # """ - # from semantic_kernel.processes.process_event import ProcessEvent + Args: + message: The message event to enqueue as a JSON string. - # message = ProcessEvent.model_validate(json.loads(message)) + Raises: + Exception: If an error occurs during the enqueue operation. + """ + try: + self.queue.put(message) - # self.queue.put(message) + queue_list = list(self.queue.queue) + queue_json = json.dumps(queue_list) - # await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) - # await self._state_manager.save_state() + await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, queue_json) + await self._state_manager.save_state() + logger.info(f"Enqueued message and updated state for actor ID: {self.id.id}") + except Exception as e: + error_message = str(e) + logger.error(f"Error in enqueue: {error_message}") + raise Exception(error_message) - # async def dequeue_all(self) -> "list[ProcessEvent]": - # """Dequeues all process events from the buffer. + async def dequeue_all(self) -> list[str]: + """Dequeues all process events from the buffer and returns them as JSON strings. - # Returns: - # The dequeued message event. - # """ - # items = [] - # while not self.queue.empty(): - # items.append(self.queue.get()) + Returns: + A list of JSON strings representing the dequeued messages. - # await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, self.queue) - # await self._state_manager.save_state() + Raises: + Exception: If an error occurs during the dequeue operation. + """ + try: + items = [] - # return items + while not self.queue.empty(): + items.append(self.queue.get()) - # async def on_activate(self) -> None: - # """Called when the actor is activated.""" - # has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.EventQueueState.value) - # if has_value: - # self.queue = event_queue_state - # else: - # self.queue: Queue["ProcessEvent"] = Queue() + await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, json.dumps([])) + await self._state_manager.save_state() + logger.info(f"Dequeued all messages and updated state for actor ID: {self.id.id}") - async def enqueue(self, message: "ProcessEvent") -> None: - # Validate and deserialize the message - message = ProcessEvent.model_validate(json.loads(message)) - self.queue.put(message) - - # Convert queue to a list of serializable dictionaries - queue_items = list(self.queue.queue) - queue_dicts = [item.model_dump() for item in queue_items] - - # Save the serializable queue to Dapr state - await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, queue_dicts) - await self._state_manager.save_state() - - async def dequeue_all(self) -> "list[ProcessEvent]": - items = [] - while not self.queue.empty(): - items.append(self.queue.get()) - - # Save the updated queue state - queue_items = list(self.queue.queue) - queue_dicts = [item.model_dump() for item in queue_items] - await self._state_manager.try_add_state(ActorStateKeys.EventQueueState.value, queue_dicts) - await self._state_manager.save_state() - - # Return a list of serializable dictionaries - return [item.model_dump() for item in items] + return items + except Exception as e: + error_message = str(e) + logger.error(f"Error in dequeue_all: {error_message}") + raise Exception(error_message) async def _on_activate(self) -> None: - has_value, event_queue_state = await self._state_manager.try_get_state(ActorStateKeys.EventQueueState.value) - if has_value: - queue_dicts = event_queue_state - self.queue = Queue() - for item_dict in queue_dicts: - message = ProcessEvent(**item_dict) - self.queue.put(message) - else: - self.queue = Queue() + """Activates the actor and initializes the queue state from Dapr storage. + + Raises: + Exception: If an error occurs during actor activation. + """ + try: + logger.info(f"Activating actor with ID: {self.id.id}") + + state_exists, queue_json = await self._state_manager.try_get_state(ActorStateKeys.EventQueueState.value) + if state_exists and queue_json: + queue_list = json.loads(queue_json) + self.queue = Queue() + for item in queue_list: + self.queue.put(item) + logger.info(f"Reconstructed queue from state for actor ID: {self.id.id}") + else: + self.queue = Queue() + logger.info(f"No existing state found. Initialized empty queue for actor ID: {self.id.id}") + except Exception as e: + error_message = str(e) + logger.error(f"Error in _on_activate: {error_message}") + raise Exception(error_message) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py index 5181fb30fd90..c37fb1007137 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py @@ -3,16 +3,13 @@ import json import logging from queue import Queue -from typing import List from dapr.actor import Actor, ActorId from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.external_event_buffer_interface import ExternalEventBufferInterface -from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent -# Set up logging logger = logging.getLogger(__name__) @@ -27,7 +24,7 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): actor_id: The unique ID for the actor. """ super().__init__(ctx, actor_id) - self.queue: Queue[KernelProcessEvent] = Queue() + self.queue: Queue[str] = Queue() async def enqueue(self, message: str) -> None: """Enqueues a message event into the buffer. @@ -38,56 +35,44 @@ async def enqueue(self, message: str) -> None: Raises: Exception: If an error occurs during enqueue operation. """ - from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent - try: - # Deserialize and validate the incoming message - message_obj = KernelProcessEvent.model_validate(json.loads(message)) - self.queue.put(message_obj) + self.queue.put(message) - # Serialize the queue to a JSON string - queue_list = [item.model_dump() for item in list(self.queue.queue)] - queue_json = json.dumps(queue_list) + queue_list = list(self.queue.queue) + queue_state = json.dumps(queue_list) - # Save the serialized queue to Dapr state - await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_json) + await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_state) await self._state_manager.save_state() - logger.debug(f"Enqueued message and updated state for actor ID: {self.id.id}") + + logger.info(f"Enqueued message and updated state for actor ID: {self.id.id}") except Exception as e: error_message = str(e) logger.error(f"Error in enqueue: {error_message}") - # Raise exception with JSON-serializable message raise Exception(error_message) - async def dequeue_all(self) -> List[dict]: - """Dequeues all process events from the buffer. + async def dequeue_all(self) -> list[str]: + """Dequeues all process events from the buffer and returns them as JSON strings. Returns: - A list of dictionaries representing the dequeued `KernelProcessEvent` messages. + A list of JSON strings representing the dequeued messages. Raises: Exception: If an error occurs during dequeue operation. """ try: items = [] - while not self.queue.empty(): - item = self.queue.get() - items.append(item) - # After dequeuing, update the state to reflect the empty queue - queue_list = [item.model_dump() for item in list(self.queue.queue)] - queue_json = json.dumps(queue_list) + while not self.queue.empty(): + items.append(self.queue.get()) - await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, queue_json) + await self._state_manager.try_add_state(ActorStateKeys.ExternalEventQueueState.value, json.dumps([])) await self._state_manager.save_state() - logger.debug(f"Dequeued all messages and updated state for actor ID: {self.id.id}") + logger.info(f"Dequeued all messages and updated state for actor ID: {self.id.id}") - # Return the dequeued items as a list of dictionaries - return [item.model_dump() for item in items] + return items except Exception as e: error_message = str(e) logger.error(f"Error in dequeue_all: {error_message}") - # Raise exception with JSON-serializable message raise Exception(error_message) async def _on_activate(self) -> None: @@ -96,28 +81,22 @@ async def _on_activate(self) -> None: Raises: Exception: If an error occurs during actor activation. """ - from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent - try: - logger.debug(f"Activating actor with ID: {self.id.id}") + logger.info(f"Activating actor with ID: {self.id.id}") - # Retrieve the stored queue from Dapr state state_exists, queue_json = await self._state_manager.try_get_state( ActorStateKeys.ExternalEventQueueState.value ) if state_exists and queue_json: - # Deserialize the JSON string back to a list of dictionaries queue_list = json.loads(queue_json) self.queue = Queue() - for item_dict in queue_list: - message_obj = KernelProcessEvent(**item_dict) - self.queue.put(message_obj) - logger.debug(f"Reconstructed queue from state for actor ID: {self.id.id}") + for item in queue_list: + self.queue.put(item) + logger.info(f"Reconstructed queue from state for actor ID: {self.id.id}") else: self.queue = Queue() - logger.debug(f"No existing state found. Initialized empty queue for actor ID: {self.id.id}") + logger.info(f"No existing state found. Initialized empty queue for actor ID: {self.id.id}") except Exception as e: error_message = str(e) logger.error(f"Error in _on_activate: {error_message}") - # Raise exception with JSON-serializable message raise Exception(error_message) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py index 45359a09ea33..8c2e626b872b 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py @@ -3,7 +3,6 @@ import json import logging from queue import Queue -from typing import TYPE_CHECKING, Any from dapr.actor import Actor, ActorId from dapr.actor.runtime.context import ActorRuntimeContext @@ -11,9 +10,6 @@ from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface -if TYPE_CHECKING: - from semantic_kernel.processes.process_message import ProcessMessage - logger: logging.Logger = logging.getLogger(__name__) @@ -21,45 +17,47 @@ class MessageBufferActor(Actor, MessageBufferInterface): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): + """Initializes a new instance of MessageBufferActor.""" super().__init__(ctx, actor_id) - self.queue: Queue[ProcessMessage] = Queue() + self.queue: Queue[str] = Queue() async def enqueue(self, message: str) -> None: - from semantic_kernel.processes.process_message import ProcessMessage - + """Enqueues a message event into the buffer and updates the state.""" try: - message_obj = ProcessMessage.model_validate(json.loads(message)) - self.queue.put(message_obj) + self.queue.put(message) - queue_list = [item.model_dump() for item in list(self.queue.queue)] + queue_list = list(self.queue.queue) await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, queue_list) await self._state_manager.save_state() + except Exception as e: error_message = str(e) - logger.error(f"Error in enqueue: {error_message}") + logger.error(f"Error in MessageBufferActor enqueue: {error_message}") raise Exception(error_message) - async def dequeue_all(self) -> list[dict[str, Any]]: + async def dequeue_all(self) -> list[str]: + """Dequeues all process events from the buffer and returns them as a list of strings.""" try: items = [] + while not self.queue.empty(): items.append(self.queue.get()) - queue_list = [item.model_dump() for item in list(self.queue.queue)] - await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, queue_list) + await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, json.dumps(items)) await self._state_manager.save_state() - return [item.model_dump() for item in items] + return items + except Exception as e: error_message = str(e) - logger.error(f"Error in dequeue_all: {error_message}") + logger.error(f"Error in MessageBufferActor dequeue_all: {error_message}") raise Exception(error_message) async def _on_activate(self) -> None: from semantic_kernel.processes.process_message import ProcessMessage try: - logger.debug(f"Activating actor with ID: {self.id.id}") + logger.info(f"Activating actor with ID: {self.id.id}") has_value, queue_list = await self._state_manager.try_get_state(ActorStateKeys.MessageQueueState.value) if has_value and queue_list: @@ -71,5 +69,5 @@ async def _on_activate(self) -> None: self.queue = Queue() except Exception as e: error_message = str(e) - logger.error(f"Error in _on_activate: {error_message}") + logger.error(f"Error in MessageBufferActor _on_activate: {error_message}") raise Exception(error_message) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py index 5c45ab74606a..9e0e46123bea 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py @@ -1,9 +1,9 @@ # Copyright (c) Microsoft. All rights reserved. - import asyncio import contextlib import json +import logging import uuid from queue import Queue @@ -34,16 +34,7 @@ from semantic_kernel.processes.process_message import ProcessMessage from semantic_kernel.processes.process_message_factory import ProcessMessageFactory -# class ProcessActor(StepActor, ProcessInterface): -# """A local process that contains a collection of steps.""" - -# kernel: Kernel | None = None -# steps: list[StepActor] = [] -# step_infos: list[DaprStepInfo] = [] -# initialize_task: bool | None = False -# external_event_queue: Queue = Queue() -# process_task: asyncio.Task | None = None -# process: DaprProcessInfo | None = None +logger: logging.Logger = logging.getLogger(__name__) class ProcessActor(StepActor, ProcessInterface): @@ -58,6 +49,7 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): kernel: The Kernel dependency to be injected. """ super().__init__(ctx, actor_id, kernel) + self.kernel = kernel self.steps: list[StepActor] = [] self.step_infos: list[DaprStepInfo] = [] self.initialize_task: bool | None = False @@ -75,29 +67,38 @@ def name(self) -> str: # async def initialize_process(self, process_info: dict[str, Any], parent_process_id: str | None = None) -> None: async def initialize_process(self, input: dict) -> None: """Initializes the process.""" - if input is None: + process_info_dict = input.get("process_info") + + if process_info_dict is None: raise ValueError("The process info is not defined.") - process_info = DaprProcessInfo.model_validate(input.get("process_info")) + parent_process_id = input.get("parent_process_id") - if process_info.steps is None: + # Reconstruct the DaprProcessInfo from the dictionary + dapr_process_info = DaprProcessInfo.model_validate(process_info_dict) + + if dapr_process_info.steps is None: raise ValueError("The process info does not contain any steps.") if self.initialize_task: return - await self._initialize_process_actor(process_info, input.get("parent_process_id")) + await self._initialize_process_actor(dapr_process_info, parent_process_id) try: - await self._state_manager.try_add_state(ActorStateKeys.ProcessInfoState.value, process_info) + # Serialize dapr_process_info before saving + process_info_serialized = dapr_process_info.model_dump() + + await self._state_manager.try_add_state(ActorStateKeys.ProcessInfoState.value, process_info_serialized) await self._state_manager.try_add_state( - ActorStateKeys.StepParentProcessId.value, input.get("parent_process_id") + ActorStateKeys.StepParentProcessId.value, parent_process_id if parent_process_id else "" ) await self._state_manager.try_add_state(ActorStateKeys.StepActivatedState.value, True) await self._state_manager.save_state() except Exception as ex: - print(ex) - raise ex + error_message = str(ex) + logger.error(f"Error in initialize_process: {error_message}") + raise Exception(error_message) async def start(self, keep_alive: bool = True) -> None: """Starts the process.""" @@ -108,9 +109,13 @@ async def start(self, keep_alive: bool = True) -> None: if not self.process_task or self.process_task.done(): self.process_task = asyncio.create_task(self.internal_execute(keep_alive=keep_alive)) - async def run_once(self, process_event_payload: str): - """Starts the process with an initial event and waits for it to finish.""" - if process_event_payload is None: + async def run_once(self, process_event: str) -> None: + """Starts the process with an initial event and waits for it to finish. + + Args: + process_event: The initial event to start the process represented as a string of a KernelProcessEvent + """ + if process_event is None: raise ProcessEventUndefinedException("The process event must be specified.") external_event_queue: ExternalEventBufferActor = ActorProxy.create( @@ -119,16 +124,16 @@ async def run_once(self, process_event_payload: str): actor_interface=ExternalEventBufferInterface, ) try: - await external_event_queue.enqueue(process_event_payload) + await external_event_queue.enqueue(process_event) await self.start(keep_alive=False) if self.process_task: try: await self.process_task except asyncio.CancelledError: print("Process task was cancelled") - # Optionally handle the cancellation except Exception as ex: print(ex) + logger.error(f"Error in run_once: {ex}") raise ex async def stop(self): @@ -147,13 +152,21 @@ async def initialize_step(self): pass async def _on_activate(self) -> None: - """Activates the process.""" - has_value, existing_process_info = await self._state_manager.try_get_state( - ActorStateKeys.ProcessInfoState.value - ) - if has_value: - self.parent_process_id = await self._state_manager.get_state(ActorStateKeys.StepParentProcessId.value) - await self._initialize_process_actor(existing_process_info, self.parent_process_id) + """Called when the actor is activated.""" + try: + has_value, existing_process_info = await self._state_manager.try_get_state( + ActorStateKeys.ProcessInfoState.value + ) + if has_value and existing_process_info: + has_value, parent_process_id = await self._state_manager.try_get_state( + ActorStateKeys.StepParentProcessId.value + ) + combined_input = {**existing_process_info, **parent_process_id} + await self.initialize_process(combined_input) + except Exception as e: + error_message = str(e) + logger.error(f"Error in _on_activate: {error_message}") + raise Exception(error_message) async def send_message(self, process_event: KernelProcessEvent): """Sends a message to the process.""" @@ -321,7 +334,7 @@ async def send_outgoing_public_events(self) -> None: actor_type=f"{MessageBufferActor.__name__}", actor_interface=MessageBufferInterface, ) - await message_queue.enqueue(message) + await message_queue.enqueue(message.model_dump_json()) async def _is_end_message_sent(self) -> bool: """Checks if the end message has been sent.""" @@ -331,7 +344,7 @@ async def _is_end_message_sent(self) -> bool: actor_id=scoped_message_buffer_id, actor_interface=MessageBufferInterface, ) - messages: list[ProcessMessage] = await end_message_queue.dequeue_all() + messages: list[str] = await end_message_queue.dequeue_all() return len(messages) > 0 async def _enqueue_external_messages(self) -> None: @@ -344,7 +357,7 @@ async def _enqueue_external_messages(self) -> None: external_events_json = await external_event_queue.dequeue_all() - external_events = [KernelProcessEvent.model_validate(e) for e in external_events_json] + external_events = [KernelProcessEvent.model_validate(json.loads(e)) for e in external_events_json] for external_event in external_events: if external_event.id in self.output_edges and self.output_edges[external_event.id] is not None: diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py index 9f81ca427935..e4bb14363417 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -1,10 +1,11 @@ # Copyright (c) Microsoft. All rights reserved. import asyncio +import importlib import json import logging from queue import Queue -from typing import Any, Type +from typing import Any from dapr.actor import Actor, ActorId, ActorProxy from dapr.actor.runtime.context import ActorRuntimeContext @@ -35,34 +36,13 @@ from semantic_kernel.processes.process_message import ProcessMessage from semantic_kernel.processes.process_message_factory import ProcessMessageFactory from semantic_kernel.processes.process_types import get_generic_state_type -from semantic_kernel.processes.step_utils import find_input_channels +from semantic_kernel.processes.step_utils import find_input_channels, get_fully_qualified_name from semantic_kernel.utils.experimental_decorator import experimental_class logger: logging.Logger = logging.getLogger(__name__) @experimental_class -# class StepActor(Actor, StepInterface, KernelProcessMessageChannel): -# """Represents a step actor that follows the Step abstract class.""" -# kernel: Kernel | None = None -# parent_process_id: str | None = None -# step_info: DaprStepInfo | None = None -# initialize_task: bool | None = False -# event_namespace: str | None = None -# inner_step_type: Type | None = None -# incoming_messages: Queue = Queue() -# step_state: KernelProcessStepState | None = None -# step_state_type: Type | None = None -# output_edges: dict[str, list[KernelProcessEdge]] = {} -# functions: dict[str, KernelFunction] = {} -# inputs: dict[str, dict[str, Any | None]] = {} -# initial_inputs: dict[str, dict[str, Any | None]] = {} -# init_lock: asyncio.Lock = asyncio.Lock() -# # def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): # kernel: Kernel): -# # """Initializes a new instance of StepActor.""" -# # super(StepActor, self).__init__(ctx, actor_id) -# # # self.kernel = kernel -# # self.activate_task = self.activate_step() class StepActor(Actor, StepInterface, KernelProcessMessageChannel): """Represents a step actor that follows the Step abstract class.""" @@ -80,23 +60,22 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): self.step_info: DaprStepInfo | None = None self.initialize_task: bool | None = False self.event_namespace: str | None = None - self.inner_step_type: Type | None = None + self.inner_step_type: type | None = None self.incoming_messages: Queue = Queue() self.step_state: KernelProcessStepState | None = None - self.step_state_type: Type | None = None + self.step_state_type: type | None = None self.output_edges: dict[str, list[KernelProcessEdge]] = {} self.functions: dict[str, KernelFunction] = {} self.inputs: dict[str, dict[str, Any | None]] = {} self.initial_inputs: dict[str, dict[str, Any | None]] = {} self.init_lock: asyncio.Lock = asyncio.Lock() - self.activate_task = self.activate_step() + self.step_activated: bool = False @property def name(self) -> str: """Gets the name of the step.""" return self.step_info.state.name - # async def initialize_step(self, step_info: dict[str, Any], parent_process_id: str | None = None) -> None: async def initialize_step(self, input: dict) -> None: """Initializes the step with the provided step information.""" if input is None: @@ -136,7 +115,6 @@ async def _int_initialize_step(self, step_info: DaprStepInfo, parent_process_id: step_info: The DaprStepInfo object to initialize the step with. parent_process_id: Optional parent process ID if one exists. """ - # TODO(evmattso): investigate this self.inner_step_type = step_info.inner_step_python_type self.parent_process_id = parent_process_id @@ -148,11 +126,7 @@ async def _int_initialize_step(self, step_info: DaprStepInfo, parent_process_id: self.initialize_task = True async def prepare_incoming_messages(self) -> int: - """Triggers the step to dequeue all pending messages and prepare for processing. - - Returns: - An integer indicating the number of messages prepared for processing. - """ + """Prepares the incoming messages for processing.""" try: message_queue: MessageBufferInterface = ActorProxy.create( actor_type=f"{MessageBufferActor.__name__}", @@ -162,17 +136,16 @@ async def prepare_incoming_messages(self) -> int: incoming = await message_queue.dequeue_all() messages = [] - json_msg = [] for message in incoming: - json_msg.append(message) - process_event = ProcessEvent.model_validate(message) - messages.append(process_event) + process_message = ProcessMessage.model_validate(json.loads(message)) + messages.append(process_message) for msg in messages: self.incoming_messages.put(msg) await self._state_manager.try_add_state( - ActorStateKeys.StepIncomingMessagesState.value, json.dumps(json_msg) + ActorStateKeys.StepIncomingMessagesState.value, + incoming, ) await self._state_manager.save_state() @@ -191,10 +164,16 @@ async def process_incoming_messages(self) -> None: await self._state_manager.try_add_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) await self._state_manager.save_state() + def _get_class_from_string(self, full_class_name: str): + """Gets a class from a string.""" + module_name, class_name = full_class_name.rsplit(".", 1) + module = importlib.import_module(module_name) + return getattr(module, class_name) + async def activate_step(self): """Initializes the step.""" # Instantiate an instance of the inner step object - step_cls = self.inner_step_type + step_cls = self._get_class_from_string(self.inner_step_type) step_instance: KernelProcessStep = step_cls() # type: ignore @@ -232,11 +211,17 @@ async def activate_step(self): error_message = "State object is not of the expected type." raise KernelException(error_message) - # handle the following: - # // Persist the state type and type object. - # await this.StateManager.AddStateAsync(ActorStateKeys.StepStateType, stateType.AssemblyQualifiedName).ConfigureAwait(false); - # await this.StateManager.AddStateAsync(ActorStateKeys.StepStateJson, JsonSerializer.Serialize(stateObject)).ConfigureAwait(false); - # await this.StateManager.SaveStateAsync().ConfigureAwait(false); + await self._state_manager.try_add_state( + ActorStateKeys.StepStateType.value, + get_fully_qualified_name(t_state), + ) + + await self._state_manager.try_add_state( + ActorStateKeys.StepStateJson.value, + json.dumps(state_object.model_dump()), + ) + + await self._state_manager.save_state() # Make sure that state_object.state is not None if state_object.state is None: @@ -269,14 +254,14 @@ async def handle_message(self, message: ProcessMessage): if message is None: raise ValueError("The message is None.") - if not self.initialize_task: + if not self.step_activated: async with self.init_lock: # Second check to ensure that initialization happens only once # This avoids a race condition where multiple coroutines might # reach the first check at the same time before any of them acquire the lock. - if not self.initialize_task: + if not self.step_activated: await self.activate_step() - self.initialize_task = True + self.step_activated = True if self.functions is None or self.inputs is None or self.initial_inputs is None: raise ValueError("The step has not been initialized.") @@ -348,7 +333,7 @@ async def handle_message(self, message: ProcessMessage): event_value = invoke_result.value state_dict = self.step_state.model_dump() - await self._state_manager.set_state(ActorStateKeys.StepStateJson.value, state_dict) + await self._state_manager.set_state(ActorStateKeys.StepStateJson.value, json.dumps(state_dict)) await self._state_manager.save_state() except Exception as ex: logger.error(f"Error in Step {self.name}: {ex!s}") @@ -376,7 +361,7 @@ async def emit_process_event(self, dapr_event: ProcessEvent): actor_id=ActorId(self.parent_process_id), actor_interface=EventBufferInterface, ) - await parent_process.enqueue(dapr_event) + await parent_process.enqueue(dapr_event.model_dump_json()) for edge in self.get_edge_for_event(dapr_event.id): message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, dapr_event.data) @@ -386,18 +371,18 @@ async def emit_process_event(self, dapr_event: ProcessEvent): actor_id=scoped_step_id, actor_interface=MessageBufferInterface, ) - await target_step.enqueue(message) + await target_step.enqueue(message.model_dump_json()) async def to_dapr_step_info(self) -> DaprStepInfo: """Converts the step to a DaprStepInfo object.""" - if not self.initialize_task: + if not self.step_activated: async with self.init_lock: # Second check to ensure that initialization happens only once # This avoids a race condition where multiple coroutines might # reach the first check at the same time before any of them acquire the lock. - if not self.initialize_task: + if not self.step_activated: await self.activate_step() - self.initialize_task = True + self.step_activated = True return DaprStepInfo( inner_step_python_type=self.inner_step_type, state=self.step_info.state, edges=self.step_info.edges diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py index f299f0d84c88..ed6b6ad3bb28 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -31,7 +31,6 @@ def __init__(self, process: KernelProcess): actor_id=process_id, actor_interface=ProcessInterface, ) - print(self.dapr_process) async def start_with_event(self, initial_event: KernelProcessEvent) -> None: """Starts the process with the provided initial event.""" @@ -41,13 +40,16 @@ async def start_with_event(self, initial_event: KernelProcessEvent) -> None: # Prepare the payload with the serialized DaprProcessInfo payload = { "process_info": dapr_process_dict, - "parent_process_id": None, # Replace with actual parent process ID if applicable + "parent_process_id": None, } + # Send the payload to the actor method await self.dapr_process.initialize_process(payload) + # Serialize the initial event initial_event_json = initial_event.model_dump_json() + # Start the process with the initial event await self.dapr_process.run_once(initial_event_json) async def send_event(self, event: KernelProcessEvent) -> None: diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py index 87c07d18434c..74060c6918ce 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py @@ -9,12 +9,12 @@ from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState +from semantic_kernel.processes.step_utils import get_fully_qualified_name class DaprStepInfo(KernelBaseModel): """A Dapr step info.""" - # info: KernelProcessEdge | KernelProcessStepState = Field(discriminator="type") inner_step_python_type: str state: KernelProcessStepState edges: dict[str, list[KernelProcessEdge]] = Field(default_factory=dict) @@ -33,7 +33,10 @@ def from_kernel_step_info(cls, kernel_step_info: KernelProcessStepInfo) -> "Dapr """Creates a Dapr step info from a kernel step info.""" if kernel_step_info is None: raise KernelException("Kernel step info must be provided") - inner_step_type = kernel_step_info.inner_step_type.__name__ + + # Get the fully qualified name of the inner step type + inner_step_type = get_fully_qualified_name(kernel_step_info.inner_step_type) + return DaprStepInfo( inner_step_python_type=inner_step_type, state=kernel_step_info.state, @@ -45,6 +48,3 @@ def _get_class_from_string(self, full_class_name: str): module_name, class_name = full_class_name.rsplit(".", 1) module = importlib.import_module(module_name) return getattr(module, class_name) - - def _get_fully_qualified_name(cls): - return f"{cls.__module__}.{cls.__name__}" diff --git a/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py b/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py index 27d71d16bfc7..2c537aa3654f 100644 --- a/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py @@ -1,12 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. -from typing import TYPE_CHECKING - from dapr.actor import ActorInterface, actormethod -if TYPE_CHECKING: - from semantic_kernel.processes.process_event import ProcessEvent - class EventBufferInterface(ActorInterface): """Abstract base class for an event buffer that follows the ActorInterface.""" @@ -21,7 +16,7 @@ async def enqueue(self, step_event: str) -> None: pass @actormethod(name="dequeue_all") - async def dequeue_all(self) -> "list[ProcessEvent]": + async def dequeue_all(self) -> list[str]: """Dequeues a step event from the buffer. Returns: diff --git a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py index 4f3857e2bd61..8023f94bc6fd 100644 --- a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py @@ -1,12 +1,8 @@ # Copyright (c) Microsoft. All rights reserved. -from typing import TYPE_CHECKING from dapr.actor import ActorInterface, actormethod -if TYPE_CHECKING: - from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent - class ExternalEventBufferInterface(ActorInterface): """Abstract base class for an external event buffer that follows the ActorInterface.""" @@ -21,8 +17,10 @@ async def enqueue(self, external_event: str) -> None: pass @actormethod(name="dequeue_all") - async def dequeue_all(self) -> "list[KernelProcessEvent]": - """Dequeues all external events from the buffer. + async def dequeue_all(self) -> list[str]: + """Dequeues all external events from the buffer as. + + The list is of string representations of KernelProcessEvent. Returns: The dequeued external event. diff --git a/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py b/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py index f0b58e3816f7..a1c3fcb2cadb 100644 --- a/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py @@ -1,12 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. -from typing import TYPE_CHECKING - from dapr.actor import ActorInterface, actormethod -if TYPE_CHECKING: - from semantic_kernel.processes.process_event import ProcessEvent - class MessageBufferInterface(ActorInterface): """Abstract base class for a message event buffer that follows the ActorInterface.""" @@ -21,10 +16,11 @@ async def enqueue(self, message: str) -> None: pass @actormethod(name="dequeue_all") - async def dequeue_all(self) -> "list[ProcessEvent]": + async def dequeue_all(self) -> list[str]: """Dequeues all process events from the buffer. Returns: - The dequeued message event. + The dequeued message event as a list of string + representing a ProcessEvent. """ pass diff --git a/python/semantic_kernel/processes/dapr_runtime/process_interface.py b/python/semantic_kernel/processes/dapr_runtime/process_interface.py index 46f19dce72b7..92add53bb779 100644 --- a/python/semantic_kernel/processes/dapr_runtime/process_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/process_interface.py @@ -29,7 +29,7 @@ async def start(self, keep_alive: bool) -> None: pass @actormethod(name="run_once") - async def run_once(self, process_event: "KernelProcessEvent") -> None: + async def run_once(self, process_event: KernelProcessEvent) -> None: """Starts the process with an initial event and then waits for the process to finish. :param process_event: Required. The KernelProcessEvent to start the process with. diff --git a/python/semantic_kernel/processes/step_utils.py b/python/semantic_kernel/processes/step_utils.py index a66fda9c83de..74d4be1abcd5 100644 --- a/python/semantic_kernel/processes/step_utils.py +++ b/python/semantic_kernel/processes/step_utils.py @@ -29,3 +29,9 @@ def find_input_channels( inputs[name][param.name] = None return inputs + + +@staticmethod +def get_fully_qualified_name(cls): + """Gets the fully qualified name of a class.""" + return f"{cls.__module__}.{cls.__name__}" diff --git a/python/uv.lock b/python/uv.lock index 1fd8cb4dc2c3..f1a1e59c04ad 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -5,17 +5,20 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform == 'darwin'", "python_full_version < '3.11' and sys_platform == 'darwin'", "python_full_version == '3.11.*' and sys_platform == 'darwin'", - "python_full_version >= '3.12' and sys_platform == 'darwin'", + "python_full_version == '3.12.*' and sys_platform == 'darwin'", + "python_full_version >= '3.13' and sys_platform == 'darwin'", "python_full_version < '3.11' and sys_platform == 'linux'", "python_full_version == '3.11.*' and sys_platform == 'linux'", "python_full_version < '3.11' and sys_platform == 'linux'", "python_full_version == '3.11.*' and sys_platform == 'linux'", - "python_full_version >= '3.12' and sys_platform == 'linux'", + "python_full_version == '3.12.*' and sys_platform == 'linux'", + "python_full_version >= '3.13' and sys_platform == 'linux'", "python_full_version < '3.11' and sys_platform == 'win32'", "python_full_version == '3.11.*' and sys_platform == 'win32'", "python_full_version < '3.11' and sys_platform == 'win32'", "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version >= '3.12' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version >= '3.13' and sys_platform == 'win32'", ] supported-markers = [ "sys_platform == 'darwin'", @@ -65,66 +68,66 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/4a/b27dd9b88fe22dde88742b341fd10251746a6ffcfe1c0b8b15b4a8cbd7c1/aiohttp-3.10.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:18a01eba2574fb9edd5f6e5fb25f66e6ce061da5dab5db75e13fe1558142e0a3", size = 587010 }, - { url = "https://files.pythonhosted.org/packages/de/a9/0f7e2b71549c9d641086c423526ae7a10de3b88d03ba104a3df153574d0d/aiohttp-3.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:94fac7c6e77ccb1ca91e9eb4cb0ac0270b9fb9b289738654120ba8cebb1189c6", size = 397698 }, - { url = "https://files.pythonhosted.org/packages/3b/52/26baa486e811c25b0cd16a494038260795459055568713f841e78f016481/aiohttp-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f1f1c75c395991ce9c94d3e4aa96e5c59c8356a15b1c9231e783865e2772699", size = 389052 }, - { url = "https://files.pythonhosted.org/packages/33/df/71ba374a3e925539cb2f6e6d4f5326e7b6b200fabbe1b3cc5e6368f07ce7/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7acae3cf1a2a2361ec4c8e787eaaa86a94171d2417aae53c0cca6ca3118ff6", size = 1248615 }, - { url = "https://files.pythonhosted.org/packages/67/02/bb89c1eba08a27fc844933bee505d63d480caf8e2816c06961d2941cd128/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94c4381ffba9cc508b37d2e536b418d5ea9cfdc2848b9a7fea6aebad4ec6aac1", size = 1282930 }, - { url = "https://files.pythonhosted.org/packages/db/36/07d8cfcc37f39c039f93a4210cc71dadacca003609946c63af23659ba656/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c31ad0c0c507894e3eaa843415841995bf8de4d6b2d24c6e33099f4bc9fc0d4f", size = 1317250 }, - { url = "https://files.pythonhosted.org/packages/9a/44/cabeac994bef8ba521b552ae996928afc6ee1975a411385a07409811b01f/aiohttp-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0912b8a8fadeb32ff67a3ed44249448c20148397c1ed905d5dac185b4ca547bb", size = 1243212 }, - { url = "https://files.pythonhosted.org/packages/5a/11/23f1e31f5885ac72be52fd205981951dd2e4c87c5b1487cf82fde5bbd46c/aiohttp-3.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d93400c18596b7dc4794d48a63fb361b01a0d8eb39f28800dc900c8fbdaca91", size = 1213401 }, - { url = "https://files.pythonhosted.org/packages/3f/e7/6e69a0b0d896fbaf1192d492db4c21688e6c0d327486da610b0e8195bcc9/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3c5e0d764a5c9aa5a62d99728c56d455310bcc288a79cab10157b3af426f", size = 1212450 }, - { url = "https://files.pythonhosted.org/packages/a9/7f/a42f51074c723ea848254946aec118f1e59914a639dc8ba20b0c9247c195/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d742c36ed44f2798c8d3f4bc511f479b9ceef2b93f348671184139e7d708042c", size = 1211324 }, - { url = "https://files.pythonhosted.org/packages/d5/43/c2f9d2f588ccef8f028f0a0c999b5ceafecbda50b943313faee7e91f3e03/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:814375093edae5f1cb31e3407997cf3eacefb9010f96df10d64829362ae2df69", size = 1266838 }, - { url = "https://files.pythonhosted.org/packages/c1/a7/ff9f067ecb06896d859e4f2661667aee4bd9c616689599ff034b63cbd9d7/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8224f98be68a84b19f48e0bdc14224b5a71339aff3a27df69989fa47d01296f3", size = 1285301 }, - { url = "https://files.pythonhosted.org/packages/9a/e3/dd56bb4c67d216046ce61d98dec0f3023043f1de48f561df1bf93dd47aea/aiohttp-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9a487ef090aea982d748b1b0d74fe7c3950b109df967630a20584f9a99c0683", size = 1235806 }, - { url = "https://files.pythonhosted.org/packages/a7/64/90dcd42ac21927a49ba4140b2e4d50e1847379427ef6c43eb338ef9960e3/aiohttp-3.10.5-cp310-cp310-win32.whl", hash = "sha256:d9ef084e3dc690ad50137cc05831c52b6ca428096e6deb3c43e95827f531d5ef", size = 360162 }, - { url = "https://files.pythonhosted.org/packages/f3/45/145d8b4853fc92c0c8509277642767e7726a085e390ce04353dc68b0f5b5/aiohttp-3.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:66bf9234e08fe561dccd62083bf67400bdbf1c67ba9efdc3dac03650e97c6088", size = 379173 }, - { url = "https://files.pythonhosted.org/packages/f1/90/54ccb1e4eadfb6c95deff695582453f6208584431d69bf572782e9ae542b/aiohttp-3.10.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c6a4e5e40156d72a40241a25cc226051c0a8d816610097a8e8f517aeacd59a2", size = 586455 }, - { url = "https://files.pythonhosted.org/packages/c3/7a/95e88c02756e7e718f054e1bb3ec6ad5d0ee4a2ca2bb1768c5844b3de30a/aiohttp-3.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c634a3207a5445be65536d38c13791904fda0748b9eabf908d3fe86a52941cf", size = 397255 }, - { url = "https://files.pythonhosted.org/packages/07/4f/767387b39990e1ee9aba8ce642abcc286d84d06e068dc167dab983898f18/aiohttp-3.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4aff049b5e629ef9b3e9e617fa6e2dfeda1bf87e01bcfecaf3949af9e210105e", size = 388973 }, - { url = "https://files.pythonhosted.org/packages/61/46/0df41170a4d228c07b661b1ba9d87101d99a79339dc93b8b1183d8b20545/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1942244f00baaacaa8155eca94dbd9e8cc7017deb69b75ef67c78e89fdad3c77", size = 1326126 }, - { url = "https://files.pythonhosted.org/packages/af/20/da0d65e07ce49d79173fed41598f487a0a722e87cfbaa8bb7e078a7c1d39/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04a1f2a65ad2f93aa20f9ff9f1b672bf912413e5547f60749fa2ef8a644e061", size = 1364538 }, - { url = "https://files.pythonhosted.org/packages/aa/20/b59728405114e57541ba9d5b96033e69d004e811ded299537f74237629ca/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f2bfc0032a00405d4af2ba27f3c429e851d04fad1e5ceee4080a1c570476697", size = 1399896 }, - { url = "https://files.pythonhosted.org/packages/2a/92/006690c31b830acbae09d2618e41308fe4c81c0679b3b33a3af859e0b7bf/aiohttp-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:424ae21498790e12eb759040bbb504e5e280cab64693d14775c54269fd1d2bb7", size = 1312914 }, - { url = "https://files.pythonhosted.org/packages/d4/71/1a253ca215b6c867adbd503f1e142117527ea8775e65962bc09b2fad1d2c/aiohttp-3.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:975218eee0e6d24eb336d0328c768ebc5d617609affaca5dbbd6dd1984f16ed0", size = 1271301 }, - { url = "https://files.pythonhosted.org/packages/0a/ab/5d1d9ff9ce6cce8fa54774d0364e64a0f3cd50e512ff09082ced8e5217a1/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4120d7fefa1e2d8fb6f650b11489710091788de554e2b6f8347c7a20ceb003f5", size = 1291652 }, - { url = "https://files.pythonhosted.org/packages/75/5f/f90510ea954b9ae6e7a53d2995b97a3e5c181110fdcf469bc9238445871d/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b90078989ef3fc45cf9221d3859acd1108af7560c52397ff4ace8ad7052a132e", size = 1286289 }, - { url = "https://files.pythonhosted.org/packages/be/9e/1f523414237798660921817c82b9225a363af436458caf584d2fa6a2eb4a/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ba5a8b74c2a8af7d862399cdedce1533642fa727def0b8c3e3e02fcb52dca1b1", size = 1341848 }, - { url = "https://files.pythonhosted.org/packages/f6/36/443472ddaa85d7d80321fda541d9535b23ecefe0bf5792cc3955ea635190/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:02594361128f780eecc2a29939d9dfc870e17b45178a867bf61a11b2a4367277", size = 1361619 }, - { url = "https://files.pythonhosted.org/packages/19/f6/3ecbac0bc4359c7d7ba9e85c6b10f57e20edaf1f97751ad2f892db231ad0/aiohttp-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4fc029e135859f533025bc82047334e24b0d489e75513144f25408ecaf058", size = 1320869 }, - { url = "https://files.pythonhosted.org/packages/34/7e/ed74ffb36e3a0cdec1b05d8fbaa29cb532371d5a20058b3a8052fc90fe7c/aiohttp-3.10.5-cp311-cp311-win32.whl", hash = "sha256:e1ca1ef5ba129718a8fc827b0867f6aa4e893c56eb00003b7367f8a733a9b072", size = 359271 }, - { url = "https://files.pythonhosted.org/packages/98/1b/718901f04bc8c886a742be9e83babb7b93facabf7c475cc95e2b3ab80b4d/aiohttp-3.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:349ef8a73a7c5665cca65c88ab24abe75447e28aa3bc4c93ea5093474dfdf0ff", size = 379143 }, - { url = "https://files.pythonhosted.org/packages/d9/1c/74f9dad4a2fc4107e73456896283d915937f48177b99867b63381fadac6e/aiohttp-3.10.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:305be5ff2081fa1d283a76113b8df7a14c10d75602a38d9f012935df20731487", size = 583468 }, - { url = "https://files.pythonhosted.org/packages/12/29/68d090551f2b58ce76c2b436ced8dd2dfd32115d41299bf0b0c308a5483c/aiohttp-3.10.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3a1c32a19ee6bbde02f1cb189e13a71b321256cc1d431196a9f824050b160d5a", size = 394066 }, - { url = "https://files.pythonhosted.org/packages/8f/f7/971f88b4cdcaaa4622925ba7d86de47b48ec02a9040a143514b382f78da4/aiohttp-3.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:61645818edd40cc6f455b851277a21bf420ce347baa0b86eaa41d51ef58ba23d", size = 389098 }, - { url = "https://files.pythonhosted.org/packages/f1/5a/fe3742efdce551667b2ddf1158b27c5b8eb1edc13d5e14e996e52e301025/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c225286f2b13bab5987425558baa5cbdb2bc925b2998038fa028245ef421e75", size = 1332742 }, - { url = "https://files.pythonhosted.org/packages/1a/52/a25c0334a1845eb4967dff279151b67ca32a948145a5812ed660ed900868/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ba01ebc6175e1e6b7275c907a3a36be48a2d487549b656aa90c8a910d9f3178", size = 1372134 }, - { url = "https://files.pythonhosted.org/packages/96/3d/33c1d8efc2d8ec36bff9a8eca2df9fdf8a45269c6e24a88e74f2aa4f16bd/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8eaf44ccbc4e35762683078b72bf293f476561d8b68ec8a64f98cf32811c323e", size = 1414413 }, - { url = "https://files.pythonhosted.org/packages/64/74/0f1ddaa5f0caba1d946f0dd0c31f5744116e4a029beec454ec3726d3311f/aiohttp-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c43eb1ab7cbf411b8e387dc169acb31f0ca0d8c09ba63f9eac67829585b44f", size = 1328107 }, - { url = "https://files.pythonhosted.org/packages/0a/32/c10118f0ad50e4093227234f71fd0abec6982c29367f65f32ee74ed652c4/aiohttp-3.10.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de7a5299827253023c55ea549444e058c0eb496931fa05d693b95140a947cb73", size = 1280126 }, - { url = "https://files.pythonhosted.org/packages/c6/c9/77e3d648d97c03a42acfe843d03e97be3c5ef1b4d9de52e5bd2d28eed8e7/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4790f0e15f00058f7599dab2b206d3049d7ac464dc2e5eae0e93fa18aee9e7bf", size = 1292660 }, - { url = "https://files.pythonhosted.org/packages/7e/5d/99c71f8e5c8b64295be421b4c42d472766b263a1fe32e91b64bf77005bf2/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44b324a6b8376a23e6ba25d368726ee3bc281e6ab306db80b5819999c737d820", size = 1300988 }, - { url = "https://files.pythonhosted.org/packages/8f/2c/76d2377dd947f52fbe8afb19b18a3b816d66c7966755c04030f93b1f7b2d/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0d277cfb304118079e7044aad0b76685d30ecb86f83a0711fc5fb257ffe832ca", size = 1339268 }, - { url = "https://files.pythonhosted.org/packages/fd/e6/3d9d935cc705d57ed524d82ec5d6b678a53ac1552720ae41282caa273584/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:54d9ddea424cd19d3ff6128601a4a4d23d54a421f9b4c0fff740505813739a91", size = 1366993 }, - { url = "https://files.pythonhosted.org/packages/fe/c2/f7eed4d602f3f224600d03ab2e1a7734999b0901b1c49b94dc5891340433/aiohttp-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4f1c9866ccf48a6df2b06823e6ae80573529f2af3a0992ec4fe75b1a510df8a6", size = 1329459 }, - { url = "https://files.pythonhosted.org/packages/ce/8f/27f205b76531fc592abe29e1ad265a16bf934a9f609509c02d765e6a8055/aiohttp-3.10.5-cp312-cp312-win32.whl", hash = "sha256:dc4826823121783dccc0871e3f405417ac116055bf184ac04c36f98b75aacd12", size = 356968 }, - { url = "https://files.pythonhosted.org/packages/39/8c/4f6c0b2b3629f6be6c81ab84d9d577590f74f01d4412bfc4067958eaa1e1/aiohttp-3.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:22c0a23a3b3138a6bf76fc553789cb1a703836da86b0f306b6f0dc1617398abc", size = 377650 }, - { url = "https://files.pythonhosted.org/packages/7b/b9/03b4327897a5b5d29338fa9b514f1c2f66a3e4fc88a4e40fad478739314d/aiohttp-3.10.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7f6b639c36734eaa80a6c152a238242bedcee9b953f23bb887e9102976343092", size = 576994 }, - { url = "https://files.pythonhosted.org/packages/67/1b/20c2e159cd07b8ed6dde71c2258233902fdf415b2fe6174bd2364ba63107/aiohttp-3.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29930bc2921cef955ba39a3ff87d2c4398a0394ae217f41cb02d5c26c8b1b77", size = 390684 }, - { url = "https://files.pythonhosted.org/packages/4d/6b/ff83b34f157e370431d8081c5d1741963f4fb12f9aaddb2cacbf50305225/aiohttp-3.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f489a2c9e6455d87eabf907ac0b7d230a9786be43fbe884ad184ddf9e9c1e385", size = 386176 }, - { url = "https://files.pythonhosted.org/packages/4d/a1/6e92817eb657de287560962df4959b7ddd22859c4b23a0309e2d3de12538/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:123dd5b16b75b2962d0fff566effb7a065e33cd4538c1692fb31c3bda2bfb972", size = 1303310 }, - { url = "https://files.pythonhosted.org/packages/04/29/200518dc7a39c30ae6d5bc232d7207446536e93d3d9299b8e95db6e79c54/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b98e698dc34966e5976e10bbca6d26d6724e6bdea853c7c10162a3235aba6e16", size = 1340445 }, - { url = "https://files.pythonhosted.org/packages/8e/20/53f7bba841ba7b5bb5dea580fea01c65524879ba39cb917d08c845524717/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3b9162bab7e42f21243effc822652dc5bb5e8ff42a4eb62fe7782bcbcdfacf6", size = 1385121 }, - { url = "https://files.pythonhosted.org/packages/f1/b4/d99354ad614c48dd38fb1ee880a1a54bd9ab2c3bcad3013048d4a1797d3a/aiohttp-3.10.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1923a5c44061bffd5eebeef58cecf68096e35003907d8201a4d0d6f6e387ccaa", size = 1299669 }, - { url = "https://files.pythonhosted.org/packages/51/39/ca1de675f2a5729c71c327e52ac6344e63f036bd37281686ae5c3fb13bfb/aiohttp-3.10.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d55f011da0a843c3d3df2c2cf4e537b8070a419f891c930245f05d329c4b0689", size = 1252638 }, - { url = "https://files.pythonhosted.org/packages/54/cf/a3ae7ff43138422d477348e309ef8275779701bf305ff6054831ef98b782/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afe16a84498441d05e9189a15900640a2d2b5e76cf4efe8cbb088ab4f112ee57", size = 1266889 }, - { url = "https://files.pythonhosted.org/packages/6e/7a/c6027ad70d9fb23cf254a26144de2723821dade1a624446aa22cd0b6d012/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8112fb501b1e0567a1251a2fd0747baae60a4ab325a871e975b7bb67e59221f", size = 1266249 }, - { url = "https://files.pythonhosted.org/packages/64/fd/ed136d46bc2c7e3342fed24662b4827771d55ceb5a7687847aae977bfc17/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1e72589da4c90337837fdfe2026ae1952c0f4a6e793adbbfbdd40efed7c63599", size = 1311036 }, - { url = "https://files.pythonhosted.org/packages/76/9a/43eeb0166f1119256d6f43468f900db1aed7fbe32069d2a71c82f987db4d/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4d46c7b4173415d8e583045fbc4daa48b40e31b19ce595b8d92cf639396c15d5", size = 1338756 }, - { url = "https://files.pythonhosted.org/packages/d5/bc/d01ff0810b3f5e26896f76d44225ed78b088ddd33079b85cd1a23514318b/aiohttp-3.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:33e6bc4bab477c772a541f76cd91e11ccb6d2efa2b8d7d7883591dfb523e5987", size = 1299976 }, - { url = "https://files.pythonhosted.org/packages/3e/c9/50a297c4f7ab57a949f4add2d3eafe5f3e68bb42f739e933f8b32a092bda/aiohttp-3.10.5-cp313-cp313-win32.whl", hash = "sha256:c58c6837a2c2a7cf3133983e64173aec11f9c2cd8e87ec2fdc16ce727bcf1a04", size = 355609 }, - { url = "https://files.pythonhosted.org/packages/65/28/aee9d04fb0b3b1f90622c338a08e54af5198e704a910e20947c473298fd0/aiohttp-3.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:38172a70005252b6893088c0f5e8a47d173df7cc2b2bd88650957eb84fcf5022", size = 375697 }, + { url = "https://files.pythonhosted.org/packages/3d/dd/3d40c0e67e79c5c42671e3e268742f1ff96c6573ca43823563d01abd9475/aiohttp-3.10.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be7443669ae9c016b71f402e43208e13ddf00912f47f623ee5994e12fc7d4b3f", size = 586969 }, + { url = "https://files.pythonhosted.org/packages/75/64/8de41b5555e5b43ef6d4ed1261891d33fe45ecc6cb62875bfafb90b9ab93/aiohttp-3.10.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b06b7843929e41a94ea09eb1ce3927865387e3e23ebe108e0d0d09b08d25be9", size = 399367 }, + { url = "https://files.pythonhosted.org/packages/96/36/27bd62ea7ce43906d1443a73691823fc82ffb8fa03276b0e2f7e1037c286/aiohttp-3.10.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:333cf6cf8e65f6a1e06e9eb3e643a0c515bb850d470902274239fea02033e9a8", size = 390720 }, + { url = "https://files.pythonhosted.org/packages/e8/4d/d516b050d811ce0dd26325c383013c104ffa8b58bd361b82e52833f68e78/aiohttp-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:274cfa632350225ce3fdeb318c23b4a10ec25c0e2c880eff951a3842cf358ac1", size = 1228820 }, + { url = "https://files.pythonhosted.org/packages/53/94/964d9327a3e336d89aad52260836e4ec87fdfa1207176550fdf384eaffe7/aiohttp-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9e5e4a85bdb56d224f412d9c98ae4cbd032cc4f3161818f692cd81766eee65a", size = 1264616 }, + { url = "https://files.pythonhosted.org/packages/0c/20/70ce17764b685ca8f5bf4d568881b4e1f1f4ea5e8170f512fdb1a33859d2/aiohttp-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b606353da03edcc71130b52388d25f9a30a126e04caef1fd637e31683033abd", size = 1298402 }, + { url = "https://files.pythonhosted.org/packages/d1/d1/5248225ccc687f498d06c3bca5af2647a361c3687a85eb3aedcc247ee1aa/aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026", size = 1222205 }, + { url = "https://files.pythonhosted.org/packages/f2/a3/9296b27cc5d4feadf970a14d0694902a49a985f3fae71b8322a5f77b0baa/aiohttp-3.10.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578a4b875af3e0daaf1ac6fa983d93e0bbfec3ead753b6d6f33d467100cdc67b", size = 1193804 }, + { url = "https://files.pythonhosted.org/packages/d9/07/f3760160feb12ac51a6168a6da251a4a8f2a70733d49e6ceb9b3e6ee2f03/aiohttp-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8105fd8a890df77b76dd3054cddf01a879fc13e8af576805d667e0fa0224c35d", size = 1193544 }, + { url = "https://files.pythonhosted.org/packages/7e/4c/93a70f9a4ba1c30183a6dd68bfa79cddbf9a674f162f9c62e823a74a5515/aiohttp-3.10.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3bcd391d083f636c06a68715e69467963d1f9600f85ef556ea82e9ef25f043f7", size = 1193047 }, + { url = "https://files.pythonhosted.org/packages/ff/a3/36a1e23ff00c7a0cd696c5a28db05db25dc42bfc78c508bd78623ff62a4a/aiohttp-3.10.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fbc6264158392bad9df19537e872d476f7c57adf718944cc1e4495cbabf38e2a", size = 1247201 }, + { url = "https://files.pythonhosted.org/packages/55/ae/95399848557b98bb2c402d640b2276ce3a542b94dba202de5a5a1fe29abe/aiohttp-3.10.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e48d5021a84d341bcaf95c8460b152cfbad770d28e5fe14a768988c461b821bc", size = 1264102 }, + { url = "https://files.pythonhosted.org/packages/38/f5/02e5c72c1b60d7cceb30b982679a26167e84ac029fd35a93dd4da52c50a3/aiohttp-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2609e9ab08474702cc67b7702dbb8a80e392c54613ebe80db7e8dbdb79837c68", size = 1215760 }, + { url = "https://files.pythonhosted.org/packages/30/17/1463840bad10d02d0439068f37ce5af0b383884b0d5838f46fb027e233bf/aiohttp-3.10.10-cp310-cp310-win32.whl", hash = "sha256:84afcdea18eda514c25bc68b9af2a2b1adea7c08899175a51fe7c4fb6d551257", size = 362678 }, + { url = "https://files.pythonhosted.org/packages/dd/01/a0ef707d93e867a43abbffee3a2cdf30559910750b9176b891628c7ad074/aiohttp-3.10.10-cp310-cp310-win_amd64.whl", hash = "sha256:9c72109213eb9d3874f7ac8c0c5fa90e072d678e117d9061c06e30c85b4cf0e6", size = 381097 }, + { url = "https://files.pythonhosted.org/packages/72/31/3c351d17596194e5a38ef169a4da76458952b2497b4b54645b9d483cbbb0/aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", size = 586501 }, + { url = "https://files.pythonhosted.org/packages/a4/a8/a559d09eb08478cdead6b7ce05b0c4a133ba27fcdfa91e05d2e62867300d/aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", size = 398993 }, + { url = "https://files.pythonhosted.org/packages/c5/47/7736d4174613feef61d25332c3bd1a4f8ff5591fbd7331988238a7299485/aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", size = 390647 }, + { url = "https://files.pythonhosted.org/packages/27/21/e9ba192a04b7160f5a8952c98a1de7cf8072ad150fa3abd454ead1ab1d7f/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", size = 1306481 }, + { url = "https://files.pythonhosted.org/packages/cf/50/f364c01c8d0def1dc34747b2470969e216f5a37c7ece00fe558810f37013/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", size = 1344652 }, + { url = "https://files.pythonhosted.org/packages/1d/c2/74f608e984e9b585649e2e83883facad6fa3fc1d021de87b20cc67e8e5ae/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", size = 1378498 }, + { url = "https://files.pythonhosted.org/packages/9f/a7/05a48c7c0a7a80a5591b1203bf1b64ca2ed6a2050af918d09c05852dc42b/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", size = 1292718 }, + { url = "https://files.pythonhosted.org/packages/7d/78/a925655018747e9790350180330032e27d6e0d7ed30bde545fae42f8c49c/aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", size = 1251776 }, + { url = "https://files.pythonhosted.org/packages/47/9d/85c6b69f702351d1236594745a4fdc042fc43f494c247a98dac17e004026/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", size = 1271716 }, + { url = "https://files.pythonhosted.org/packages/7f/a7/55fc805ff9b14af818903882ece08e2235b12b73b867b521b92994c52b14/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", size = 1266263 }, + { url = "https://files.pythonhosted.org/packages/1f/ec/d2be2ca7b063e4f91519d550dbc9c1cb43040174a322470deed90b3d3333/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", size = 1321617 }, + { url = "https://files.pythonhosted.org/packages/c9/a3/b29f7920e1cd0a9a68a45dd3eb16140074d2efb1518d2e1f3e140357dc37/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", size = 1339227 }, + { url = "https://files.pythonhosted.org/packages/8a/81/34b67235c47e232d807b4bbc42ba9b927c7ce9476872372fddcfd1e41b3d/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", size = 1299068 }, + { url = "https://files.pythonhosted.org/packages/04/1f/26a7fe11b6ad3184f214733428353c89ae9fe3e4f605a657f5245c5e720c/aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", size = 362223 }, + { url = "https://files.pythonhosted.org/packages/10/91/85dcd93f64011434359ce2666bece981f08d31bc49df33261e625b28595d/aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", size = 381576 }, + { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, + { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, + { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, + { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, + { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, + { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, + { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, + { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, + { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, + { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, + { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, + { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, + { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, + { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, + { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, + { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, + { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, + { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, + { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, + { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, + { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, + { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, + { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, + { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, + { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, + { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, + { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, + { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, + { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, + { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, ] [[package]] @@ -579,6 +582,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] @@ -718,57 +736,57 @@ version = "7.6.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/52/12/3669b6382792783e92046730ad3327f53b2726f0603f4c311c4da4824222/coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", size = 798716 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/61/eb7ce5ed62bacf21beca4937a90fe32545c91a3c8a42a30c6616d48fc70d/coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", size = 206690 }, - { url = "https://files.pythonhosted.org/packages/7d/73/041928e434442bd3afde5584bdc3f932fb4562b1597629f537387cec6f3d/coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", size = 207127 }, - { url = "https://files.pythonhosted.org/packages/c7/c8/6ca52b5147828e45ad0242388477fdb90df2c6cbb9a441701a12b3c71bc8/coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", size = 235654 }, - { url = "https://files.pythonhosted.org/packages/d5/da/9ac2b62557f4340270942011d6efeab9833648380109e897d48ab7c1035d/coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc", size = 233598 }, - { url = "https://files.pythonhosted.org/packages/53/23/9e2c114d0178abc42b6d8d5281f651a8e6519abfa0ef460a00a91f80879d/coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", size = 234732 }, - { url = "https://files.pythonhosted.org/packages/0f/7e/a0230756fb133343a52716e8b855045f13342b70e48e8ad41d8a0d60ab98/coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", size = 233816 }, - { url = "https://files.pythonhosted.org/packages/28/7c/3753c8b40d232b1e5eeaed798c875537cf3cb183fb5041017c1fdb7ec14e/coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", size = 232325 }, - { url = "https://files.pythonhosted.org/packages/57/e3/818a2b2af5b7573b4b82cf3e9f137ab158c90ea750a8f053716a32f20f06/coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", size = 233418 }, - { url = "https://files.pythonhosted.org/packages/c8/fb/4532b0b0cefb3f06d201648715e03b0feb822907edab3935112b61b885e2/coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", size = 209343 }, - { url = "https://files.pythonhosted.org/packages/5a/25/af337cc7421eca1c187cc9c315f0a755d48e755d2853715bfe8c418a45fa/coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", size = 210136 }, - { url = "https://files.pythonhosted.org/packages/ad/5f/67af7d60d7e8ce61a4e2ddcd1bd5fb787180c8d0ae0fbd073f903b3dd95d/coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", size = 206796 }, - { url = "https://files.pythonhosted.org/packages/e1/0e/e52332389e057daa2e03be1fbfef25bb4d626b37d12ed42ae6281d0a274c/coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", size = 207244 }, - { url = "https://files.pythonhosted.org/packages/aa/cd/766b45fb6e090f20f8927d9c7cb34237d41c73a939358bc881883fd3a40d/coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", size = 239279 }, - { url = "https://files.pythonhosted.org/packages/70/6c/a9ccd6fe50ddaf13442a1e2dd519ca805cbe0f1fcd377fba6d8339b98ccb/coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", size = 236859 }, - { url = "https://files.pythonhosted.org/packages/14/6f/8351b465febb4dbc1ca9929505202db909c5a635c6fdf33e089bbc3d7d85/coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", size = 238549 }, - { url = "https://files.pythonhosted.org/packages/68/3c/289b81fa18ad72138e6d78c4c11a82b5378a312c0e467e2f6b495c260907/coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", size = 237477 }, - { url = "https://files.pythonhosted.org/packages/ed/1c/aa1efa6459d822bd72c4abc0b9418cf268de3f60eeccd65dc4988553bd8d/coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", size = 236134 }, - { url = "https://files.pythonhosted.org/packages/fb/c8/521c698f2d2796565fe9c789c2ee1ccdae610b3aa20b9b2ef980cc253640/coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", size = 236910 }, - { url = "https://files.pythonhosted.org/packages/7d/30/033e663399ff17dca90d793ee8a2ea2890e7fdf085da58d82468b4220bf7/coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", size = 209348 }, - { url = "https://files.pythonhosted.org/packages/20/05/0d1ccbb52727ccdadaa3ff37e4d2dc1cd4d47f0c3df9eb58d9ec8508ca88/coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", size = 210230 }, - { url = "https://files.pythonhosted.org/packages/7e/d4/300fc921dff243cd518c7db3a4c614b7e4b2431b0d1145c1e274fd99bd70/coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", size = 206983 }, - { url = "https://files.pythonhosted.org/packages/e1/ab/6bf00de5327ecb8db205f9ae596885417a31535eeda6e7b99463108782e1/coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", size = 207221 }, - { url = "https://files.pythonhosted.org/packages/92/8f/2ead05e735022d1a7f3a0a683ac7f737de14850395a826192f0288703472/coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", size = 240342 }, - { url = "https://files.pythonhosted.org/packages/0f/ef/94043e478201ffa85b8ae2d2c79b4081e5a1b73438aafafccf3e9bafb6b5/coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", size = 237371 }, - { url = "https://files.pythonhosted.org/packages/1f/0f/c890339dd605f3ebc269543247bdd43b703cce6825b5ed42ff5f2d6122c7/coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", size = 239455 }, - { url = "https://files.pythonhosted.org/packages/d1/04/7fd7b39ec7372a04efb0f70c70e35857a99b6a9188b5205efb4c77d6a57a/coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", size = 238924 }, - { url = "https://files.pythonhosted.org/packages/ed/bf/73ce346a9d32a09cf369f14d2a06651329c984e106f5992c89579d25b27e/coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", size = 237252 }, - { url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 }, - { url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 }, - { url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 }, - { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, - { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, - { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, - { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, - { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, - { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, - { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, - { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, - { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, - { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, - { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, - { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, - { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, - { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, - { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, - { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, - { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, - { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, - { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, - { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, - { url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 }, + { url = "https://files.pythonhosted.org/packages/a5/93/4ad92f71e28ece5c0326e5f4a6630aa4928a8846654a65cfff69b49b95b9/coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07", size = 206713 }, + { url = "https://files.pythonhosted.org/packages/01/ae/747a580b1eda3f2e431d87de48f0604bd7bc92e52a1a95185a4aa585bc47/coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0", size = 207149 }, + { url = "https://files.pythonhosted.org/packages/07/1a/1f573f8a6145f6d4c9130bbc120e0024daf1b24cf2a78d7393fa6eb6aba7/coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72", size = 235584 }, + { url = "https://files.pythonhosted.org/packages/40/42/c8523f2e4db34aa9389caee0d3688b6ada7a84fcc782e943a868a7f302bd/coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51", size = 233486 }, + { url = "https://files.pythonhosted.org/packages/8d/95/565c310fffa16ede1a042e9ea1ca3962af0d8eb5543bc72df6b91dc0c3d5/coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491", size = 234649 }, + { url = "https://files.pythonhosted.org/packages/d5/81/3b550674d98968ec29c92e3e8650682be6c8b1fa7581a059e7e12e74c431/coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b", size = 233744 }, + { url = "https://files.pythonhosted.org/packages/0d/70/d66c7f51b3e33aabc5ea9f9624c1c9d9655472962270eb5e7b0d32707224/coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea", size = 232204 }, + { url = "https://files.pythonhosted.org/packages/23/2d/2b3a2dbed7a5f40693404c8a09e779d7c1a5fbed089d3e7224c002129ec8/coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a", size = 233335 }, + { url = "https://files.pythonhosted.org/packages/5a/4f/92d1d2ad720d698a4e71c176eacf531bfb8e0721d5ad560556f2c484a513/coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa", size = 209435 }, + { url = "https://files.pythonhosted.org/packages/c7/b9/cdf158e7991e2287bcf9082670928badb73d310047facac203ff8dcd5ff3/coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172", size = 210243 }, + { url = "https://files.pythonhosted.org/packages/87/31/9c0cf84f0dfcbe4215b7eb95c31777cdc0483c13390e69584c8150c85175/coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b", size = 206819 }, + { url = "https://files.pythonhosted.org/packages/53/ed/a38401079ad320ad6e054a01ec2b61d270511aeb3c201c80e99c841229d5/coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25", size = 207263 }, + { url = "https://files.pythonhosted.org/packages/20/e7/c3ad33b179ab4213f0d70da25a9c214d52464efa11caeab438592eb1d837/coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546", size = 239205 }, + { url = "https://files.pythonhosted.org/packages/36/91/fc02e8d8e694f557752120487fd982f654ba1421bbaa5560debf96ddceda/coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b", size = 236612 }, + { url = "https://files.pythonhosted.org/packages/cc/57/cb08f0eda0389a9a8aaa4fc1f9fec7ac361c3e2d68efd5890d7042c18aa3/coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e", size = 238479 }, + { url = "https://files.pythonhosted.org/packages/d5/c9/2c7681a9b3ca6e6f43d489c2e6653a53278ed857fd6e7010490c307b0a47/coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718", size = 237405 }, + { url = "https://files.pythonhosted.org/packages/b5/4e/ebfc6944b96317df8b537ae875d2e57c27b84eb98820bc0a1055f358f056/coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db", size = 236038 }, + { url = "https://files.pythonhosted.org/packages/13/f2/3a0bf1841a97c0654905e2ef531170f02c89fad2555879db8fe41a097871/coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522", size = 236812 }, + { url = "https://files.pythonhosted.org/packages/b9/9c/66bf59226b52ce6ed9541b02d33e80a6e816a832558fbdc1111a7bd3abd4/coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf", size = 209400 }, + { url = "https://files.pythonhosted.org/packages/2a/a0/b0790934c04dfc8d658d4a62acb8f7ca0efdf3818456fcad757b11c6479d/coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19", size = 210243 }, + { url = "https://files.pythonhosted.org/packages/7d/e7/9291de916d084f41adddfd4b82246e68d61d6a75747f075f7e64628998d2/coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", size = 207013 }, + { url = "https://files.pythonhosted.org/packages/27/03/932c2c5717a7fa80cd43c6a07d3177076d97b79f12f40f882f9916db0063/coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", size = 207251 }, + { url = "https://files.pythonhosted.org/packages/d5/3f/0af47dcb9327f65a45455fbca846fe96eb57c153af46c4754a3ba678938a/coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", size = 240268 }, + { url = "https://files.pythonhosted.org/packages/8a/3c/37a9d81bbd4b23bc7d46ca820e16174c613579c66342faa390a271d2e18b/coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", size = 237298 }, + { url = "https://files.pythonhosted.org/packages/c0/70/6b0627e5bd68204ee580126ed3513140b2298995c1233bd67404b4e44d0e/coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", size = 239367 }, + { url = "https://files.pythonhosted.org/packages/3c/eb/634d7dfab24ac3b790bebaf9da0f4a5352cbc125ce6a9d5c6cf4c6cae3c7/coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", size = 238853 }, + { url = "https://files.pythonhosted.org/packages/d9/0d/8e3ed00f1266ef7472a4e33458f42e39492e01a64281084fb3043553d3f1/coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", size = 237160 }, + { url = "https://files.pythonhosted.org/packages/ce/9c/4337f468ef0ab7a2e0887a9c9da0e58e2eada6fc6cbee637a4acd5dfd8a9/coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", size = 238824 }, + { url = "https://files.pythonhosted.org/packages/5e/09/3e94912b8dd37251377bb02727a33a67ee96b84bbbe092f132b401ca5dd9/coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", size = 209639 }, + { url = "https://files.pythonhosted.org/packages/01/69/d4f3a4101171f32bc5b3caec8ff94c2c60f700107a6aaef7244b2c166793/coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", size = 210428 }, + { url = "https://files.pythonhosted.org/packages/c2/4d/2dede4f7cb5a70fb0bb40a57627fddf1dbdc6b9c1db81f7c4dcdcb19e2f4/coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", size = 207039 }, + { url = "https://files.pythonhosted.org/packages/3f/f9/d86368ae8c79e28f1fb458ebc76ae9ff3e8bd8069adc24e8f2fed03c58b7/coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", size = 207298 }, + { url = "https://files.pythonhosted.org/packages/64/c5/b4cc3c3f64622c58fbfd4d8b9a7a8ce9d355f172f91fcabbba1f026852f6/coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", size = 239813 }, + { url = "https://files.pythonhosted.org/packages/8a/86/14c42e60b70a79b26099e4d289ccdfefbc68624d096f4481163085aa614c/coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", size = 236959 }, + { url = "https://files.pythonhosted.org/packages/7f/f8/4436a643631a2fbab4b44d54f515028f6099bfb1cd95b13cfbf701e7f2f2/coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", size = 238950 }, + { url = "https://files.pythonhosted.org/packages/49/50/1571810ddd01f99a0a8be464a4ac8b147f322cd1e8e296a1528984fc560b/coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", size = 238610 }, + { url = "https://files.pythonhosted.org/packages/f3/8c/6312d241fe7cbd1f0cade34a62fea6f333d1a261255d76b9a87074d8703c/coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", size = 236697 }, + { url = "https://files.pythonhosted.org/packages/ce/5f/fef33dfd05d87ee9030f614c857deb6df6556b8f6a1c51bbbb41e24ee5ac/coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", size = 238541 }, + { url = "https://files.pythonhosted.org/packages/a9/64/6a984b6e92e1ea1353b7ffa08e27f707a5e29b044622445859200f541e8c/coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", size = 209707 }, + { url = "https://files.pythonhosted.org/packages/5c/60/ce5a9e942e9543783b3db5d942e0578b391c25cdd5e7f342d854ea83d6b7/coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", size = 210439 }, + { url = "https://files.pythonhosted.org/packages/78/53/6719677e92c308207e7f10561a1b16ab8b5c00e9328efc9af7cfd6fb703e/coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", size = 207784 }, + { url = "https://files.pythonhosted.org/packages/fa/dd/7054928930671fcb39ae6a83bb71d9ab5f0afb733172543ced4b09a115ca/coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", size = 208058 }, + { url = "https://files.pythonhosted.org/packages/b5/7d/fd656ddc2b38301927b9eb3aae3fe827e7aa82e691923ed43721fd9423c9/coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", size = 250772 }, + { url = "https://files.pythonhosted.org/packages/90/d0/eb9a3cc2100b83064bb086f18aedde3afffd7de6ead28f69736c00b7f302/coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", size = 246490 }, + { url = "https://files.pythonhosted.org/packages/45/44/3f64f38f6faab8a0cfd2c6bc6eb4c6daead246b97cf5f8fc23bf3788f841/coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", size = 248848 }, + { url = "https://files.pythonhosted.org/packages/5d/11/4c465a5f98656821e499f4b4619929bd5a34639c466021740ecdca42aa30/coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", size = 248340 }, + { url = "https://files.pythonhosted.org/packages/f1/96/ebecda2d016cce9da812f404f720ca5df83c6b29f65dc80d2000d0078741/coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", size = 246229 }, + { url = "https://files.pythonhosted.org/packages/16/d9/3d820c00066ae55d69e6d0eae11d6149a5ca7546de469ba9d597f01bf2d7/coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", size = 247510 }, + { url = "https://files.pythonhosted.org/packages/8f/c3/4fa1eb412bb288ff6bfcc163c11700ff06e02c5fad8513817186e460ed43/coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", size = 210353 }, + { url = "https://files.pythonhosted.org/packages/7e/77/03fc2979d1538884d921c2013075917fc927f41cd8526909852fe4494112/coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", size = 211502 }, + { url = "https://files.pythonhosted.org/packages/cc/56/e1d75e8981a2a92c2a777e67c26efa96c66da59d645423146eb9ff3a851b/coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e", size = 198954 }, ] [package.optional-dependencies] @@ -826,6 +844,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/44/7f728f4985a173edd70436f07a1a8a4a3d2d71ff4664d1d5cfe93bcafb9e/dapr-1.14.0-py3-none-any.whl", hash = "sha256:31bfa9587b58d410a575dd46e568cd731e790e235d7b61b18cb17420977e9c84", size = 131503 }, ] +[[package]] +name = "dapr-ext-fastapi" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dapr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "fastapi", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "uvicorn", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/1a/3aada04990820a271a0c65a6c2bb883f8298a531238145a26baac9547ed4/dapr-ext-fastapi-1.14.0.tar.gz", hash = "sha256:162320f55bec3037534a0066f89924593abf8e6d58233b15990eb4d515aef3ce", size = 8781 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/3f/94cff4e36962b843a78a831770b9b44e476a5f9c76c0d53f7cf92053a1b4/dapr_ext_fastapi-1.14.0-py3-none-any.whl", hash = "sha256:88df67d6af33fd5adcf97d8799fa43373774b13cb9a1091ac4dd47e18a009ca0", size = 10458 }, +] + [[package]] name = "debugpy" version = "1.8.7" @@ -844,6 +876,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/79/8bba39190d2ea17840925d287f1c6c3a7c60b58f5090444e9ecf176c540f/debugpy-1.8.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c1fd62ae0356e194f3e7b7a92acd931f71fe81c4b3be2c17a7b8a4b546ec2", size = 4170911 }, { url = "https://files.pythonhosted.org/packages/3b/19/5b3d312936db8eb281310fa27903459328ed722d845d594ba5feaeb2f0b3/debugpy-1.8.7-cp312-cp312-win32.whl", hash = "sha256:2f729228430ef191c1e4df72a75ac94e9bf77413ce5f3f900018712c9da0aaca", size = 5195476 }, { url = "https://files.pythonhosted.org/packages/9f/49/ad20b29f8c921fd5124530d3d39b8f2077efd51b71339a2eff02bba693e9/debugpy-1.8.7-cp312-cp312-win_amd64.whl", hash = "sha256:45c30aaefb3e1975e8a0258f5bbd26cd40cde9bfe71e9e5a7ac82e79bad64e39", size = 5235031 }, + { url = "https://files.pythonhosted.org/packages/41/95/29b247518d0a6afdb5249f5d05743c9c5bfaf4bd13a85b81cb5e1dc65837/debugpy-1.8.7-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:d050a1ec7e925f514f0f6594a1e522580317da31fbda1af71d1530d6ea1f2b40", size = 2517557 }, + { url = "https://files.pythonhosted.org/packages/4d/93/026e2000a0740e2f54b198f8dc317accf3a70b6524b2b15fa8e6eca74414/debugpy-1.8.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f4349a28e3228a42958f8ddaa6333d6f8282d5edaea456070e48609c5983b7", size = 4162703 }, + { url = "https://files.pythonhosted.org/packages/c3/92/a48e653b19a171434290ecdc5935b7a292a65488139c5271d6d0eceeb0f1/debugpy-1.8.7-cp313-cp313-win32.whl", hash = "sha256:11ad72eb9ddb436afb8337891a986302e14944f0f755fd94e90d0d71e9100bba", size = 5195220 }, + { url = "https://files.pythonhosted.org/packages/4e/b3/dc3c5527edafcd1a6d0f8c4ecc6c5c9bc431f77340cf4193328e98f0ac38/debugpy-1.8.7-cp313-cp313-win_amd64.whl", hash = "sha256:2efb84d6789352d7950b03d7f866e6d180284bc02c7e12cb37b489b7083d81aa", size = 5235333 }, { url = "https://files.pythonhosted.org/packages/51/b1/a0866521c71a6ae3d3ca320e74835163a4671b1367ba360a55a0a51e5a91/debugpy-1.8.7-py2.py3-none-any.whl", hash = "sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae", size = 5210683 }, ] @@ -1066,6 +1102,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, + { url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 }, + { url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 }, + { url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 }, + { url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 }, + { url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 }, + { url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 }, + { url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 }, + { url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 }, + { url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 }, + { url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 }, + { url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 }, + { url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 }, + { url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 }, + { url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 }, { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] @@ -1364,6 +1415,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/94/16550ad6b3f13b96f0856ee5dfc2554efac28539ee84a51d7b14526da985/grpcio-1.67.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38", size = 6149369 }, { url = "https://files.pythonhosted.org/packages/33/0d/4c3b2587e8ad7f121b597329e6c2620374fccbc2e4e1aa3c73ccc670fde4/grpcio-1.67.1-cp312-cp312-win32.whl", hash = "sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78", size = 3599176 }, { url = "https://files.pythonhosted.org/packages/7d/36/0c03e2d80db69e2472cf81c6123aa7d14741de7cf790117291a703ae6ae1/grpcio-1.67.1-cp312-cp312-win_amd64.whl", hash = "sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc", size = 4346574 }, + { url = "https://files.pythonhosted.org/packages/12/d2/2f032b7a153c7723ea3dea08bffa4bcaca9e0e5bdf643ce565b76da87461/grpcio-1.67.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:aa0162e56fd10a5547fac8774c4899fc3e18c1aa4a4759d0ce2cd00d3696ea6b", size = 5091487 }, + { url = "https://files.pythonhosted.org/packages/d0/ae/ea2ff6bd2475a082eb97db1104a903cf5fc57c88c87c10b3c3f41a184fc0/grpcio-1.67.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:beee96c8c0b1a75d556fe57b92b58b4347c77a65781ee2ac749d550f2a365dc1", size = 10943530 }, + { url = "https://files.pythonhosted.org/packages/07/62/646be83d1a78edf8d69b56647327c9afc223e3140a744c59b25fbb279c3b/grpcio-1.67.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:a93deda571a1bf94ec1f6fcda2872dad3ae538700d94dc283c672a3b508ba3af", size = 5589079 }, + { url = "https://files.pythonhosted.org/packages/d0/25/71513d0a1b2072ce80d7f5909a93596b7ed10348b2ea4fdcbad23f6017bf/grpcio-1.67.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e6f255980afef598a9e64a24efce87b625e3e3c80a45162d111a461a9f92955", size = 6213542 }, + { url = "https://files.pythonhosted.org/packages/76/9a/d21236297111052dcb5dc85cd77dc7bf25ba67a0f55ae028b2af19a704bc/grpcio-1.67.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e838cad2176ebd5d4a8bb03955138d6589ce9e2ce5d51c3ada34396dbd2dba8", size = 5850211 }, + { url = "https://files.pythonhosted.org/packages/2d/fe/70b1da9037f5055be14f359026c238821b9bcf6ca38a8d760f59a589aacd/grpcio-1.67.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a6703916c43b1d468d0756c8077b12017a9fcb6a1ef13faf49e67d20d7ebda62", size = 6572129 }, + { url = "https://files.pythonhosted.org/packages/74/0d/7df509a2cd2a54814598caf2fb759f3e0b93764431ff410f2175a6efb9e4/grpcio-1.67.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:917e8d8994eed1d86b907ba2a61b9f0aef27a2155bca6cbb322430fc7135b7bb", size = 6149819 }, + { url = "https://files.pythonhosted.org/packages/0a/08/bc3b0155600898fd10f16b79054e1cca6cb644fa3c250c0fe59385df5e6f/grpcio-1.67.1-cp313-cp313-win32.whl", hash = "sha256:e279330bef1744040db8fc432becc8a727b84f456ab62b744d3fdb83f327e121", size = 3596561 }, + { url = "https://files.pythonhosted.org/packages/5a/96/44759eca966720d0f3e1b105c43f8ad4590c97bf8eb3cd489656e9590baa/grpcio-1.67.1-cp313-cp313-win_amd64.whl", hash = "sha256:fa0c739ad8b1996bd24823950e3cb5152ae91fca1c09cc791190bf1627ffefba", size = 4346042 }, ] [[package]] @@ -1431,6 +1491,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/0d/a5d703214fe49d261b4b8f0a64140a4dc1f88560724a38ad937120b899ad/grpcio_tools-1.67.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:db9e87f6ea4b0ce99b2651203480585fd9e8dd0dd122a19e46836e93e3a1b749", size = 2870421 }, { url = "https://files.pythonhosted.org/packages/ac/af/41d79cb87eae99c0348e8f1fb3dbed9e40a6f63548b216e99f4d1165fa5c/grpcio_tools-1.67.1-cp312-cp312-win32.whl", hash = "sha256:6a595a872fb720dde924c4e8200f41d5418dd6baab8cc1a3c1e540f8f4596351", size = 940542 }, { url = "https://files.pythonhosted.org/packages/66/e5/096e12f5319835aa2bcb746d49ae62220bb48313ca649e89bdbef605c11d/grpcio_tools-1.67.1-cp312-cp312-win_amd64.whl", hash = "sha256:92eebb9b31031604ae97ea7657ae2e43149b0394af7117ad7e15894b6cc136dc", size = 1090425 }, + { url = "https://files.pythonhosted.org/packages/62/b3/91c88440c978740752d39f1abae83f21408048b98b93652ebd84f974ad3d/grpcio_tools-1.67.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:9a3b9510cc87b6458b05ad49a6dee38df6af37f9ee6aa027aa086537798c3d4a", size = 2307453 }, + { url = "https://files.pythonhosted.org/packages/05/33/faf3330825463c0409fa3891bc1459bf86a00055b19790211365279538d7/grpcio_tools-1.67.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e4c9b9fa9b905f15d414cb7bd007ba7499f8907bdd21231ab287a86b27da81a", size = 5517975 }, + { url = "https://files.pythonhosted.org/packages/bd/78/461ab34cadbd0b5b9a0b6efedda96b58e0de471e3fa91d8e4a4e31924e1b/grpcio_tools-1.67.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:e11a98b41af4bc88b7a738232b8fa0306ad82c79fa5d7090bb607f183a57856f", size = 2281081 }, + { url = "https://files.pythonhosted.org/packages/5f/0c/b30bdbcab1795b12e05adf30c20981c14f66198e22044edb15b3c1d9f0bc/grpcio_tools-1.67.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de0fcfe61c26679d64b1710746f2891f359593f76894fcf492c37148d5694f00", size = 2616929 }, + { url = "https://files.pythonhosted.org/packages/d3/c2/a77ca68ae768f8d5f1d070ea4afc42fda40401083e7c4f5c08211e84de38/grpcio_tools-1.67.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae3b3e2ee5aad59dece65a613624c46a84c9582fc3642686537c6dfae8e47dc", size = 2414633 }, + { url = "https://files.pythonhosted.org/packages/39/70/8d7131dccfe4d7b739c96ada7ea9acde631f58f013eae773791fb490a3eb/grpcio_tools-1.67.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:9a630f83505b6471a3094a7a372a1240de18d0cd3e64f4fbf46b361bac2be65b", size = 3224328 }, + { url = "https://files.pythonhosted.org/packages/2a/28/2d24b933ccf0d6877035aa3d5f8b64aad18c953657dd43c682b5701dc127/grpcio_tools-1.67.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d85a1fcbacd3e08dc2b3d1d46b749351a9a50899fa35cf2ff040e1faf7d405ad", size = 2869640 }, + { url = "https://files.pythonhosted.org/packages/37/77/ddd2b4cc896639fb0f85fc21d5684f25080ee28845c5a4031e3dd65fdc92/grpcio_tools-1.67.1-cp313-cp313-win32.whl", hash = "sha256:778470f025f25a1fca5a48c93c0a18af395b46b12dd8df7fca63736b85181f41", size = 939997 }, + { url = "https://files.pythonhosted.org/packages/96/d0/f0855a0ccb26ffeb41e6db68b5cbb25d7e9ba1f8f19151eef36210e64efc/grpcio_tools-1.67.1-cp313-cp313-win_amd64.whl", hash = "sha256:6961da86e9856b4ddee0bf51ef6636b4bf9c29c0715aa71f3c8f027c45d42654", size = 1089819 }, ] [[package]] @@ -1575,6 +1644,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 }, { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 }, { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 }, + { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 }, + { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 }, + { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 }, + { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 }, + { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 }, + { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 }, + { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 }, ] [[package]] @@ -1806,6 +1882,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/9d/816d2d7f19070b72cf0133437cbacf99a9202f6fbbc2cfa2111fb686b0e0/jiter-0.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15cf691ebd8693b70c94627d6b748f01e6d697d9a6e9f2bc310934fcfb7cf25e", size = 498050 }, { url = "https://files.pythonhosted.org/packages/3e/a5/d0afb758c02d2d3c8ac3214a5be26579594d790944eaee7a47af06915e0e/jiter-0.7.0-cp312-none-win32.whl", hash = "sha256:9dcd54fa422fb66ca398bec296fed5f58e756aa0589496011cfea2abb5be38a5", size = 198912 }, { url = "https://files.pythonhosted.org/packages/d0/8e/80b2afd0391a3530966d8fc2f9c104955ba41093b3c319ae40b25e68e323/jiter-0.7.0-cp312-none-win_amd64.whl", hash = "sha256:cc989951f73f9375b8eacd571baaa057f3d7d11b7ce6f67b9d54642e7475bfad", size = 199942 }, + { url = "https://files.pythonhosted.org/packages/50/bb/82c7180dc126687ddcc25386727b3a1688ab8eff496afe7838b69886fcc7/jiter-0.7.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:24cecd18df540963cd27c08ca5ce1d0179f229ff78066d9eecbe5add29361340", size = 292624 }, + { url = "https://files.pythonhosted.org/packages/11/c2/3b6d4596eab2ff81ebfe5bab779f457433cc2ffb8a2d1d6ab5ac187f26f6/jiter-0.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d41b46236b90b043cca73785674c23d2a67d16f226394079d0953f94e765ed76", size = 304723 }, + { url = "https://files.pythonhosted.org/packages/49/65/56f78dfccfb22e43815cad4a468b4360f8cfebecc024edb5e2a625b83a04/jiter-0.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b160db0987171365c153e406a45dcab0ee613ae3508a77bfff42515cb4ce4d6e", size = 328319 }, + { url = "https://files.pythonhosted.org/packages/fd/f2/9e3ed9ac0b122dd65250fc83cd0f0979da82f055ef6041411191f6301284/jiter-0.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1c8d91e0f0bd78602eaa081332e8ee4f512c000716f5bc54e9a037306d693a7", size = 347323 }, + { url = "https://files.pythonhosted.org/packages/42/18/24517f9f8575daf36fdac9dd53fcecde3d4c5bdd9f7b97a55e26ed2555b5/jiter-0.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997706c683195eeff192d2e5285ce64d2a610414f37da3a3f2625dcf8517cf90", size = 374073 }, + { url = "https://files.pythonhosted.org/packages/a1/b1/b368ccdeff3eabb4b293a21a94317a6f717ecc5bfbfca4eecd12ff39da3f/jiter-0.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ea52a8a0ff0229ab2920284079becd2bae0688d432fca94857ece83bb49c541", size = 388224 }, + { url = "https://files.pythonhosted.org/packages/92/1e/cc3d0655bcbc026e4b7746cb1ccab10d6eb2c29ffa64e574072db4d55f73/jiter-0.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d77449d2738cf74752bb35d75ee431af457e741124d1db5e112890023572c7c", size = 326145 }, + { url = "https://files.pythonhosted.org/packages/bb/24/d410c732326738d4f392689621ff14e10d3717efe7de9ecb97c44d8765a3/jiter-0.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8203519907a1d81d6cb00902c98e27c2d0bf25ce0323c50ca594d30f5f1fbcf", size = 366857 }, + { url = "https://files.pythonhosted.org/packages/14/a1/53df95b8248968936e7ba9eb5839918e3cfd183e56356d2961b9b29a49fc/jiter-0.7.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41d15ccc53931c822dd7f1aebf09faa3cda2d7b48a76ef304c7dbc19d1302e51", size = 514972 }, + { url = "https://files.pythonhosted.org/packages/97/c8/1876add533606ff1204450dd2564638cac7f164ff90844cb921cdf25cf68/jiter-0.7.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:febf3179b2fabf71fbd2fd52acb8594163bb173348b388649567a548f356dbf6", size = 497728 }, + { url = "https://files.pythonhosted.org/packages/94/31/1e59f246e264414b004864b63783e54aa3397be88f53dda3b01db3ae4251/jiter-0.7.0-cp313-none-win32.whl", hash = "sha256:4a8e2d866e7eda19f012444e01b55079d8e1c4c30346aaac4b97e80c54e2d6d3", size = 198660 }, + { url = "https://files.pythonhosted.org/packages/ca/96/58b3d260e212add0087563672931b1176e70bef1225839a4470ec66157a5/jiter-0.7.0-cp313-none-win_amd64.whl", hash = "sha256:7417c2b928062c496f381fb0cb50412eee5ad1d8b53dbc0e011ce45bb2de522c", size = 199305 }, ] [[package]] @@ -2007,6 +2095,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, ] [[package]] @@ -2095,70 +2203,70 @@ version = "5.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e2/08/04ad6419f072ea3f51f9a0f429dd30f5f0a0b02ead7ca11a831117b6f9e8/mmh3-5.0.1.tar.gz", hash = "sha256:7dab080061aeb31a6069a181f27c473a1f67933854e36a3464931f2716508896", size = 32008 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/de/19c97460492496ed5e21d8d7cffb86e26e27424e594992da7e111abf289d/mmh3-5.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e65e16c9de793bfa334355c60fccc859faf1c0b707d847252841cee72b5309df", size = 48553 }, - { url = "https://files.pythonhosted.org/packages/fa/89/d52316cf1565374a33318009edccc92d0d81d2e8ac141924d4827e58fc2d/mmh3-5.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:66d5423c65aebe94f244e8204cc8b39a4b970e342fb619621376af90c5f9a421", size = 34034 }, - { url = "https://files.pythonhosted.org/packages/bc/05/35e048b5e77c989a16a225e915c6ad28db231ffcc43e6562774ec5e49195/mmh3-5.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5bfc15d11bcc5ce96254f5399582104c566a1eeeb91072ff0a0de92b24f704ff", size = 33896 }, - { url = "https://files.pythonhosted.org/packages/04/e6/22b1a7f1ecae2fab2ad58cfe0980521db6f26d6f0bc4e12149dde8128fed/mmh3-5.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1616cb621cab3bc5b58dba9605311c346b45e732818f12f943a803b9a641f09c", size = 89190 }, - { url = "https://files.pythonhosted.org/packages/ad/3e/9e14a3c742dbc9c584aef304c1c563754f18293369e615a2e8f724f13e23/mmh3-5.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3e3d94553b321b26952d507dace15509463604ead98fece710237ca8cb5983d", size = 94082 }, - { url = "https://files.pythonhosted.org/packages/cb/f7/94f1988fef130ce1ac4aad243c7952fb2620c312613a0ca7178a148451e0/mmh3-5.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b46b6d5c0fcd2620ebc699099fed6fda0101805d7d4c274fa2b2c384e8b9e8b9", size = 93741 }, - { url = "https://files.pythonhosted.org/packages/72/ba/7ad763b950a68c070fe10e02a6a7d5e4e7d23f6802fb950bb26203a731e7/mmh3-5.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a2a9cd368f2a15f06f2749db764e410b7dc260822319f169a52c649da078bf6", size = 82005 }, - { url = "https://files.pythonhosted.org/packages/94/64/436925da3a70fed754e4636d84d4c0251e7d3751108f3f91c88aaa81beb8/mmh3-5.0.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:903cdb66f8d8de26a0a6c737a13664388b5ed14813f84793bccbba44ffa09fa2", size = 88921 }, - { url = "https://files.pythonhosted.org/packages/d4/2c/c6a4adba7edf8a4c8f3af1d0bea9f882bb290fd74f7d601eb702b33e2840/mmh3-5.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7653d8177e4241a5f7913a675636ccc701722741b153b0a43c82464a4a865752", size = 89282 }, - { url = "https://files.pythonhosted.org/packages/8a/66/0e9ecf5f860864a3524ddb6bbe8b317f7593340e5e0cc24c9d93c985ef7d/mmh3-5.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a9154a0a32de54b812d178541468cce4c73b112fbd8b5b0a4add92cfda69c390", size = 84123 }, - { url = "https://files.pythonhosted.org/packages/3e/04/f73fe2bbde831e78b4d6f5d9905aa195de7fb8115d8bc8a4f22c0e5e1145/mmh3-5.0.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5f814a621fd0e567a121ace724ad57f28fb9972acfd54c854749ee91d5c4905c", size = 95029 }, - { url = "https://files.pythonhosted.org/packages/22/06/bc22a7c776c2f19349dc6675d2da33d24d62c2bbcfab90947aad0e615322/mmh3-5.0.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:333057bcf12804a8cae12adb2a5cef3bc50fc8de044ad6a01ae1918a342d6f0e", size = 89633 }, - { url = "https://files.pythonhosted.org/packages/d6/04/c20c2b285b0f0de6cdad691153fb634b17b192bee1e3dbd92cc0f3dd4a28/mmh3-5.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e713afe276481af7ea0330f40214c71c11486b28754aa2d1cb286b5ee9571dee", size = 88484 }, - { url = "https://files.pythonhosted.org/packages/1c/7b/c3de7359af41670a181fae919a6e1fee095aada20d3173942464f12174d4/mmh3-5.0.0-cp310-cp310-win32.whl", hash = "sha256:917b72bc8b238286d7e2c586c19d604b3b3e5a93f054020cd15530324b868e6e", size = 34836 }, - { url = "https://files.pythonhosted.org/packages/8e/50/4e629064bc48c17a970b6897bb799b2fd1774cc136231ab34ab9471c0e2d/mmh3-5.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a8bcaa5c0fd9c4679639c830b46e52fcc3b84502faa2aa5f3ca1dacb7cdbb1f", size = 35421 }, - { url = "https://files.pythonhosted.org/packages/b9/59/1e767bbea3b68205e78c963107932fb7e87046f78f4a74f5394aaea131cd/mmh3-5.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:341ad4f902ebb7fc14751fab67fb4eedf800a1744bc9dc214a56e11b62d0bfdd", size = 32190 }, - { url = "https://files.pythonhosted.org/packages/28/b8/27d06956add5f882c7120ade726f6e772325a267a4bb0f1589397d75163d/mmh3-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:690cb4b36ed7c863680029c2370b4f3a0c3dc8900320eb5ce79a867eb8b37151", size = 48554 }, - { url = "https://files.pythonhosted.org/packages/60/da/135b43806e59b1fcc7a6c27a029922c60785353c84c4bd4915b603725b4f/mmh3-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5580c7bf9570458d8096a016f7012453306a14d2e3e4ef1267b9c9c9f506d8a4", size = 34036 }, - { url = "https://files.pythonhosted.org/packages/29/99/98d47eb4d18556a7fd13bfa4d7a358faef1ba08981c1d7cdc21642fd1bfe/mmh3-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f271a043545c86cce51c35e5bb6f52dceb535dcd2d46c2129a9c869b80ec2eaa", size = 33897 }, - { url = "https://files.pythonhosted.org/packages/85/7e/1da6f2c77a2db61fe73c5832f51ed604f07dd989b03027308030e09f8714/mmh3-5.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2400e805018e04718c9367e85d694c036d21a41b37024d5b0dc8ef80cb984cf0", size = 90792 }, - { url = "https://files.pythonhosted.org/packages/a1/7e/ee067c17df65f3b30f1dbfe75b9f87ff114a04125286f55912fb5b1c5691/mmh3-5.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3d75183b7d5df178bf01f0d9ac366525fd54e828d799fe3892882b83c13454b", size = 95739 }, - { url = "https://files.pythonhosted.org/packages/94/d1/d197e47e9a28e6d4faaad7ee4cab0c2c79a246a0995a0609e9a8db9fe2e4/mmh3-5.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec24039151e67c5fc026ce5be8788e3e8093d9ce3e114d7a6175f453521bacc9", size = 95361 }, - { url = "https://files.pythonhosted.org/packages/4d/0d/2849b96caf2bad20f9af4a27d11a1cd6a62018b28e7f333875b15d468cce/mmh3-5.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88513eb686937b26d33fe7ded7ed1a68ede490d326eea2344447c0cc42fb7f97", size = 83235 }, - { url = "https://files.pythonhosted.org/packages/a7/3c/756620970d575c66677c9c13ca871d52b8b23f8f13cb6c81cc85caeb0658/mmh3-5.0.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a015a90951b31d45a01c8f92703c028d8d759f71dc31727581c916f31cacbade", size = 90467 }, - { url = "https://files.pythonhosted.org/packages/2e/63/b6a45319059855fbcb20a02bc5803deb10327842846d98d559cf1c35e89f/mmh3-5.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:337f747eaf6ab78d0be9cbbb763781ae76eb2e4c0e6523e74582877fe827ec51", size = 86122 }, - { url = "https://files.pythonhosted.org/packages/53/55/0269256d61783a783a82c189e165a00dcc5499f0670049e5c408e2162f6a/mmh3-5.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01636d74df6371f192dc5a112f4afc43cb4119a9ea6de704469161fd4ab9e86b", size = 85142 }, - { url = "https://files.pythonhosted.org/packages/01/a7/9f68185843ba171c52b04db3ab5a39f991fbeedb89da85c2a0d533995c00/mmh3-5.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3d969f1813b27bd4caac359e0ea0f6b711d252e872c0723124b58d7ac275cb0e", size = 90393 }, - { url = "https://files.pythonhosted.org/packages/8c/61/04d196fb38d79c11f4858122844916d55fd061b6650902c74f3268ce8016/mmh3-5.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f699f2232efe3907a6a05d9661edd2f4045a0e05161dc1087f72957d752a47a", size = 86743 }, - { url = "https://files.pythonhosted.org/packages/51/43/564b427dc2a3c9d90ae4946a25a14926ff3bf71625ebd944967ed0a7005d/mmh3-5.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:16f46dc1774bf3e8305fa33207a502317cd7a592cb79b0d65c84f0fbcf9d9ffa", size = 85260 }, - { url = "https://files.pythonhosted.org/packages/b8/74/f7201c1e5ef5cd84f210ba0f6a5810e2726dfdc22c1ddc5c81363b286997/mmh3-5.0.0-cp311-cp311-win32.whl", hash = "sha256:2d039b32f4194ac345c0f52441b7ff0a55735a896303a3eb9054e5f8512d84c8", size = 34838 }, - { url = "https://files.pythonhosted.org/packages/77/c1/dac0e65e482c9f6205020c06d5db20397745211d162be7dcd98e0f2cec30/mmh3-5.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:47b3823a88c5f7859580688016bff13437fd866f6132e4770b306f0c6edb01a7", size = 35417 }, - { url = "https://files.pythonhosted.org/packages/6f/29/35110041e065bacbdd6440eb29e6d9b0bb6b396d221515ffed14a10c3fd0/mmh3-5.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:2ee87816b838709bd0fc623e3277736e9465a941d27b14f35d0df1c2006e4438", size = 32190 }, - { url = "https://files.pythonhosted.org/packages/4a/46/e3bdf55ddadb6174414df98c64d0045d2142efc8657c9bb0686aaba3ba88/mmh3-5.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed23a89a6daeb9b0d4db9fa865b125300516e8d6961f771b2dd97965bf888bce", size = 48598 }, - { url = "https://files.pythonhosted.org/packages/8f/50/a2ab4155fa338acfdc020b752057c164a3350495747f02cde4d73127d8e8/mmh3-5.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b020012e30ba0e4b002a150ca1c1d590a7387fac50dfd9b6b5dc66d9d0e61257", size = 34076 }, - { url = "https://files.pythonhosted.org/packages/57/64/6682b31df93c46b4a55ea3de1b328d6a2d651e0b01a0709b2f92ae05d26d/mmh3-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e86246d036da05d54e833cdc342ad9c62f38f2507b14f2c58ce2c271f22d7251", size = 33894 }, - { url = "https://files.pythonhosted.org/packages/fd/9e/6866f4cb9be5908eff335369f8d214a04718fda6ab3821f13e1069344dfb/mmh3-5.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f50535009c1aaa44f9702ad14551d12d1755b537fc25a5bd7d46c493ec4bcfaa", size = 90779 }, - { url = "https://files.pythonhosted.org/packages/0d/2c/00fded897ff8a05f6241b2e3f396094c122868d9cd6508d59ffd35faa2b6/mmh3-5.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a567a87026f103778b70f2b19637fb490d9c29dc7d3af9cd46185d48efbd49dc", size = 95742 }, - { url = "https://files.pythonhosted.org/packages/ee/f2/0bfc0434845034e3afe9d38775cbd91d9d8b1e0858ac1b3cdd49ff522f4e/mmh3-5.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4405f231032b8f8ae93d9a558ddc04b9aa94a59c309cb265ebe1e79ced920e", size = 95453 }, - { url = "https://files.pythonhosted.org/packages/44/42/e3fa4bd3222a87e7f8fe6444d903024efd6cc901f4ba30a02913a64824a5/mmh3-5.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d630fe75ef7d4ab1a95eb824d81dee15ed73020703bf030515f03283cb8f086f", size = 83332 }, - { url = "https://files.pythonhosted.org/packages/d4/d3/82a119f7a079cac3e07ae50756d85df89ed9d915856168035d1f0572f647/mmh3-5.0.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:361f9d611debc10992888cbace09dbc47391ae8b84b50c995a6d97e6314bb422", size = 90665 }, - { url = "https://files.pythonhosted.org/packages/92/3a/743c53d584acf07a8e9a78f2fc2815996d01f63acd05f57b66b8428475f0/mmh3-5.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:11e29156edb1990600cb4b91bcb371a2adf20a0fcb818837fb78408be19e9117", size = 86172 }, - { url = "https://files.pythonhosted.org/packages/6a/34/27cf51e7a4697b4a0ac2fde1cbea3ebe5ed0899645cdcfdd741d1183f0a2/mmh3-5.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e70c4fc340509f6554a1748fe6f539a846fbacf147255048d1702def820a1520", size = 85242 }, - { url = "https://files.pythonhosted.org/packages/b5/26/b6c6b713341674200d10b6b39d9523a54afbad305c226f14019e1505410a/mmh3-5.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:aa790a46370eeedb474c462820be78597452f54c5fffe1f810fc8e847faf42a1", size = 90558 }, - { url = "https://files.pythonhosted.org/packages/6e/2c/916c881e5ec5920ea1f26ea749329b195a850628e2bdc5e5dd76b74b9714/mmh3-5.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce678ac7d31e83fecc817ab630cc7254c7826de11fd2b3e8c31a8a5b0b762884", size = 87016 }, - { url = "https://files.pythonhosted.org/packages/03/8c/3f2c216f16f05da7f48893144a63f88466f8c7dbb8f6b955d3714e8e833f/mmh3-5.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee22cd4cad4fc7d4e5282b2729899460b03c388cde0290d411e877249f78a373", size = 85496 }, - { url = "https://files.pythonhosted.org/packages/8e/0c/f30776ad91410d35148fcd7595ca2489e6f9c8cead8350ac976fc2ccf162/mmh3-5.0.0-cp312-cp312-win32.whl", hash = "sha256:cb1a96488dc8fccf843ccdbdd10faf1939e6e18cd928c2beff17e70c2ab09ec1", size = 34857 }, - { url = "https://files.pythonhosted.org/packages/86/6b/24c9c618993a5d5612a12c156aa30b6a58e9123d9798642ed8d9608ef6f2/mmh3-5.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:897ebafa83bbbbb1958ee30cda78c7ad4b12f2b9360f96b22e488eb127b2cb4f", size = 35456 }, - { url = "https://files.pythonhosted.org/packages/88/a1/e8f896aa6a61c8655e5ba708004700c142f2c34d02222d3e1afdcf2aaead/mmh3-5.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:e6e3334985865ec3bdfcc4ae8df4a1939be048c5ae3ce1c8c309744400f8e4de", size = 32189 }, - { url = "https://files.pythonhosted.org/packages/1f/1d/621df14c109a53148717a6e9aceef93b1a65bb46938cfc176eb5fb8664b4/mmh3-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:05b09d98cbdb6ad03eb9c701e87cea005ececd4fd7d2968ff0f5a86af1ef340d", size = 48594 }, - { url = "https://files.pythonhosted.org/packages/1a/90/f3f4fe3fea68d949fbe554841e036c33d571756ae4a9921d27e8fdb5e3e8/mmh3-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d4ac0b8d48ce1e7561cf330ec73b9582f6773e40aaf8a771dd51a0bb483ec94f", size = 34084 }, - { url = "https://files.pythonhosted.org/packages/77/eb/f6f734766113017a9d76bf25f83a8bc7b09a3798b92d357ad0418ed18bbc/mmh3-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5a1c056b65be3077496ed655731eff1f65ee67f2b31f40a027f3171ba0ac20d1", size = 33893 }, - { url = "https://files.pythonhosted.org/packages/65/24/e52443fb243a479513b7c1811798dd29d285b4d5edd2ef412aa77d0637bb/mmh3-5.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a572adb41cf831d79b3b38c7994e5a5bc1a8ea8d7b574ce0c24272fc5abb52df", size = 90675 }, - { url = "https://files.pythonhosted.org/packages/99/ad/9f1e0d11d4ed095b0c02a424b414b51596a18dacfb8f06912d042d597bb6/mmh3-5.0.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0be4d14ab3a690bac6c127733490493b8698f84eadb9d667be7eb952281c51e4", size = 95656 }, - { url = "https://files.pythonhosted.org/packages/f2/12/a7a3b84645106ad5c64e16557a97ab305673bbb6fe14ab55c1fc23083939/mmh3-5.0.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b65b6eabd9e78e2b8eee2b8d4db34d4d2f5b540f2ac06ec0a76a1f1566f0ff7", size = 95353 }, - { url = "https://files.pythonhosted.org/packages/68/66/6ccf44dc2adcde5bfd30a642880a51cf78712fd74195d88e103b8d10d084/mmh3-5.0.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b433656f371af5edf44cf00862e288e08327bb9e90c8aaa5e4e60dfebc62039", size = 83291 }, - { url = "https://files.pythonhosted.org/packages/43/55/a924e81867406bb0d1bf59039732e927a05a5c56b08e7b894687fda71881/mmh3-5.0.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1b12073a58be5e6408c6bd8366bbf6253defe042cdec25ee51f123c944e5a8f", size = 90524 }, - { url = "https://files.pythonhosted.org/packages/a0/c4/aa8f8527dfeff955e7be85901fde840df407a26b7f52e2a114e094c08422/mmh3-5.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:29b2c8eb7a473f6f235c2d9905912a76350dd11b42058364de984264fa4f74ca", size = 86180 }, - { url = "https://files.pythonhosted.org/packages/96/84/16a2a0a196c151d5d3d5513c5a5042b9c1cef428f68f2668337924b04fad/mmh3-5.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b178b744685de956ff84b3b2531271824a2e4372aff199ab805e1fdd7f996f5c", size = 85283 }, - { url = "https://files.pythonhosted.org/packages/e4/84/07584c6fbf82981359e3f702ed56a1e42657f4d670ae8e505c62df55a0cf/mmh3-5.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fcac7a75846aec7bd168c05576dc8c9448a9705165dfa0986d0f48952eca62a4", size = 90621 }, - { url = "https://files.pythonhosted.org/packages/c9/1b/cefb28385f8bfa24c058caf106a5cf7a28a238d06a7ce27a41b50a7b06bf/mmh3-5.0.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cc0caa0d2800d54384cc048e49e6c2b4a90cba1afff0597d7c2a5006c42b5536", size = 87006 }, - { url = "https://files.pythonhosted.org/packages/7b/cb/9da22a15b73ae5346fb51c7fab665adb9b4cf79038299c6eaea9b68b4f55/mmh3-5.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:05b10476fd5cfb0fd63ceebf7430612423e7f79e9732e0b344225aa642e12be4", size = 85546 }, - { url = "https://files.pythonhosted.org/packages/e4/03/249dc33217095088c9519ddda809e728d18a8cf1eefa2619c2586224eb2c/mmh3-5.0.0-cp313-cp313-win32.whl", hash = "sha256:7101a12a2a4b39d7748d2d83310d5e0415950ccf6b9ec8da1d35af3f50b3ef0e", size = 34852 }, - { url = "https://files.pythonhosted.org/packages/a2/b5/cb5b2fa2ceb34a65367afef283126c79f15e8f864bea50742f7184f6acf2/mmh3-5.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:47d9a9c1c48accaf78ddb77669c40c837e90be2ecddd39bf7ef2f8dacff85ca6", size = 35462 }, - { url = "https://files.pythonhosted.org/packages/8c/df/c070cf4dd4425f1c2abbff9b922ffb7a5161667a39cf32c618422406d78b/mmh3-5.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9126155ad1a9418920360497a0b44906dce32f0732cb44378ace08c62751dd1e", size = 32193 }, + { url = "https://files.pythonhosted.org/packages/fa/b9/9a91b0a0e330557cdbf51fc43ca0ba306633f2ec6d2b15e871e288592a32/mmh3-5.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f0a4b4bf05778ed77d820d6e7d0e9bd6beb0c01af10e1ce9233f5d2f814fcafa", size = 52867 }, + { url = "https://files.pythonhosted.org/packages/da/28/6b37f0d6707872764e1af49f327b0940b6a3ad995d91b3839b90ba35f559/mmh3-5.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac7a391039aeab95810c2d020b69a94eb6b4b37d4e2374831e92db3a0cdf71c6", size = 38352 }, + { url = "https://files.pythonhosted.org/packages/76/84/a98f59a620b522f218876a0630b02fc345ecf078f6393595756ddb3aa0b5/mmh3-5.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3a2583b5521ca49756d8d8bceba80627a9cc295f255dcab4e3df7ccc2f09679a", size = 38214 }, + { url = "https://files.pythonhosted.org/packages/35/cb/4980c7eb6cd31f49d1913a4066562bc9e0af28526750f1232be9688a9cd4/mmh3-5.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:081a8423fe53c1ac94f87165f3e4c500125d343410c1a0c5f1703e898a3ef038", size = 93502 }, + { url = "https://files.pythonhosted.org/packages/65/f3/29726296fadeaf06134a6978f7c453dfa562cf2f0f1faf9ae28b9b8ef76e/mmh3-5.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8b4d72713799755dc8954a7d36d5c20a6c8de7b233c82404d122c7c7c1707cc", size = 98394 }, + { url = "https://files.pythonhosted.org/packages/35/fd/e181f4f4b250f7b63ee27a7d65e5e290a3ea0e26cc633f4bfd906f04558b/mmh3-5.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:389a6fd51efc76d3182d36ec306448559c1244f11227d2bb771bdd0e6cc91321", size = 98052 }, + { url = "https://files.pythonhosted.org/packages/61/5c/8a5d838da3eb3fb91035ef5eaaea469abab4e8e3fae55607c27a1a07d162/mmh3-5.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39f4128edaa074bff721b1d31a72508cba4d2887ee7867f22082e1fe9d4edea0", size = 86320 }, + { url = "https://files.pythonhosted.org/packages/10/80/3f33a8f4de12cea322607da1a84d001513affb741b3c3cc1277ecb85d34b/mmh3-5.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5d23a94d91aabba3386b3769048d5f4210fdfef80393fece2f34ba5a7b466c", size = 93232 }, + { url = "https://files.pythonhosted.org/packages/9e/1c/d0ce5f498493be4de2e7e7596e1cbf63315a4c0bb8bb94e3c37c4fad965d/mmh3-5.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:16347d038361f8b8f24fd2b7ef378c9b68ddee9f7706e46269b6e0d322814713", size = 93590 }, + { url = "https://files.pythonhosted.org/packages/d9/66/770b5ad35b5a2eb7965f3fcaeaa76148e59543575d2e27b80690c1b0795c/mmh3-5.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6e299408565af7d61f2d20a5ffdd77cf2ed902460fe4e6726839d59ba4b72316", size = 88433 }, + { url = "https://files.pythonhosted.org/packages/14/58/e0d258b18749d8640233976493716a40aa27352dcb1cea941836357dac24/mmh3-5.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42050af21ddfc5445ee5a66e73a8fc758c71790305e3ee9e4a85a8e69e810f94", size = 99339 }, + { url = "https://files.pythonhosted.org/packages/38/26/7267146122deb584cf377975b994d80c6d72c4c8d0e8eedff4d0cc5cd4c8/mmh3-5.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2ae9b1f5ef27ec54659920f0404b7ceb39966e28867c461bfe83a05e8d18ddb0", size = 93944 }, + { url = "https://files.pythonhosted.org/packages/8d/6b/df60b14a2dd383d8848f6f35496c86c7003be3ffb236789e98d002c542c6/mmh3-5.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:50c2495a02045f3047d71d4ae9cdd7a15efc0bcbb7ff17a18346834a8e2d1d19", size = 92798 }, + { url = "https://files.pythonhosted.org/packages/0a/3f/d5fecf13915163a15b449e5cc89232a4df90e836ecad1c38121318119d27/mmh3-5.0.1-cp310-cp310-win32.whl", hash = "sha256:c028fa77cddf351ca13b4a56d43c1775652cde0764cadb39120b68f02a23ecf6", size = 39185 }, + { url = "https://files.pythonhosted.org/packages/74/8e/4bb5ade332a87de633cda21dae09d6002d69601f2b93e9f40302ab2d9acf/mmh3-5.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c5e741e421ec14400c4aae30890515c201f518403bdef29ae1e00d375bb4bbb5", size = 39766 }, + { url = "https://files.pythonhosted.org/packages/16/2b/cd5cfa4d7ad40a37655af491f9270909d63fc27bcf0558ec36000ee5347f/mmh3-5.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:b17156d56fabc73dbf41bca677ceb6faed435cc8544f6566d72ea77d8a17e9d0", size = 36540 }, + { url = "https://files.pythonhosted.org/packages/fb/8a/f3b9cf8b7110fef0f130158d7602af6f5b09f2cf568130814b7c92e2507b/mmh3-5.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a6d5a9b1b923f1643559ba1fc0bf7a5076c90cbb558878d3bf3641ce458f25d", size = 52867 }, + { url = "https://files.pythonhosted.org/packages/bf/06/f466e0da3c5bd6fbb1e047f70fd4e9e9563d0268aa56de511f363478dbf2/mmh3-5.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3349b968be555f7334bbcce839da98f50e1e80b1c615d8e2aa847ea4a964a012", size = 38349 }, + { url = "https://files.pythonhosted.org/packages/13/f0/2d3daca276a4673f82af859e4b0b18befd4e6e54f1017ba48ea9735b2f1b/mmh3-5.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1bd3c94b110e55db02ab9b605029f48a2f7f677c6e58c09d44e42402d438b7e1", size = 38211 }, + { url = "https://files.pythonhosted.org/packages/e3/56/a2d203ca97702d4e045ac1a46a608393da1a1dddb24f81de664dae940518/mmh3-5.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ba84d48608f79adbb10bb09986b6dc33eeda5c2d1bd75d00820081b73bde9", size = 95104 }, + { url = "https://files.pythonhosted.org/packages/ec/45/c7c8ae64e3ae024776a0ce5377c16c6741a3359f3e9505fc35fc5012beb2/mmh3-5.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0217987a8b8525c8d9170f66d036dec4ab45cfbd53d47e8d76125791ceb155e", size = 100049 }, + { url = "https://files.pythonhosted.org/packages/d5/74/681113776fe406c09870ab2152ffbd214a15bbc8f1d1da9ad73ce594b878/mmh3-5.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2797063a34e78d1b61639a98b0edec1c856fa86ab80c7ec859f1796d10ba429", size = 99671 }, + { url = "https://files.pythonhosted.org/packages/bf/4f/dbb8be18ce9b6ff8df14bc14348c0404b3091fb51df9c673ebfcf5877db3/mmh3-5.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8bba16340adcbd47853a2fbe5afdb397549e8f2e79324ff1dced69a3f8afe7c3", size = 87549 }, + { url = "https://files.pythonhosted.org/packages/5f/82/274d646f3f604c35b7e3d4eb7f3ff08b3bdc6a2c87d797709bb6f084a611/mmh3-5.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:282797957c9f60b51b9d768a602c25f579420cc9af46feb77d457a27823d270a", size = 94780 }, + { url = "https://files.pythonhosted.org/packages/c9/a1/f094ca8b8fb5e2ac53201070bda42b0fee80ceb92c153eb99a1453e3aed3/mmh3-5.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e4fb670c29e63f954f9e7a2cdcd57b36a854c2538f579ef62681ccbaa1de2b69", size = 90430 }, + { url = "https://files.pythonhosted.org/packages/d9/23/4732ba68c6ef7242b69bb53b9e1bcb2ef065d68ed85fd26e829fb911ab5a/mmh3-5.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ee7d85438dc6aff328e19ab052086a3c29e8a9b632998a49e5c4b0034e9e8d6", size = 89451 }, + { url = "https://files.pythonhosted.org/packages/3c/c5/daea5d534fcf20b2399c2a7b1cd00a8d29d4d474247c15c2c94548a1a272/mmh3-5.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7fb5db231f3092444bc13901e6a8d299667126b00636ffbad4a7b45e1051e2f", size = 94703 }, + { url = "https://files.pythonhosted.org/packages/5e/4a/34d5691e7be7c63c34181387bc69bdcc0005ca93c8b562d68cb5775e0e78/mmh3-5.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c100dd441703da5ec136b1d9003ed4a041d8a1136234c9acd887499796df6ad8", size = 91054 }, + { url = "https://files.pythonhosted.org/packages/5c/3a/ab31bb5e9e1a19a4a997593cbe6ce56710308218ff36c7f76d40ff9c8d2e/mmh3-5.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71f3b765138260fd7a7a2dba0ea5727dabcd18c1f80323c9cfef97a7e86e01d0", size = 89571 }, + { url = "https://files.pythonhosted.org/packages/0b/79/b986bb067dbfcba6879afe6e723aad1bd53f223450532dd9a4606d0af389/mmh3-5.0.1-cp311-cp311-win32.whl", hash = "sha256:9a76518336247fd17689ce3ae5b16883fd86a490947d46a0193d47fb913e26e3", size = 39187 }, + { url = "https://files.pythonhosted.org/packages/48/69/97029eda3df0f84edde16a496a2e71bac508fc5d1f0a31e163da071e2670/mmh3-5.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:336bc4df2e44271f1c302d289cc3d78bd52d3eed8d306c7e4bff8361a12bf148", size = 39766 }, + { url = "https://files.pythonhosted.org/packages/c7/51/538f2b8412303281d8ce2a9a5c4ea84ff81f06de98af0b7c72059727a3bb/mmh3-5.0.1-cp311-cp311-win_arm64.whl", hash = "sha256:af6522722fbbc5999aa66f7244d0986767a46f1fb05accc5200f75b72428a508", size = 36540 }, + { url = "https://files.pythonhosted.org/packages/75/c7/5b52d0882e7c0dccfaf8786a648e2b26c5307c594abe5cbe98c092607c97/mmh3-5.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f2730bb263ed9c388e8860438b057a53e3cc701134a6ea140f90443c4c11aa40", size = 52907 }, + { url = "https://files.pythonhosted.org/packages/01/b5/9609fa353c27188292748db033323c206f3fc6fbfa124bccf6a42af0da08/mmh3-5.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6246927bc293f6d56724536400b85fb85f5be26101fa77d5f97dd5e2a4c69bf2", size = 38389 }, + { url = "https://files.pythonhosted.org/packages/33/99/49bf3c86244857b3b250c2f54aff22a5a78ef12258af556fa39bb1e80699/mmh3-5.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbca322519a6e6e25b6abf43e940e1667cf8ea12510e07fb4919b48a0cd1c411", size = 38204 }, + { url = "https://files.pythonhosted.org/packages/f8/04/8860cab35b48aaefe40cf88344437e79ddc93cf7ff745dacd1cd56a2be1e/mmh3-5.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae8c19903ed8a1724ad9e67e86f15d198a7a1271a4f9be83d47e38f312ed672", size = 95091 }, + { url = "https://files.pythonhosted.org/packages/fa/e9/4ac56001a5bab6d26aa3dfabeddea6d7f037fd2972c76803259f51a5af75/mmh3-5.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09fd6cc72c07c0c07c3357714234b646d78052487c4a3bd5f7f6e08408cff60", size = 100055 }, + { url = "https://files.pythonhosted.org/packages/18/e8/7d5fd73f559c423ed5b72f940130c27803a406ee0ffc32ef5422f733df67/mmh3-5.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ff8551fee7ae3b11c5d986b6347ade0dccaadd4670ffdb2b944dee120ffcc84", size = 99764 }, + { url = "https://files.pythonhosted.org/packages/54/d8/c0d89da6c729feec997a9b3b68698894cef12359ade0da95eba9e03b1d5d/mmh3-5.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e39694c73a5a20c8bf36dfd8676ed351e5234d55751ba4f7562d85449b21ef3f", size = 87650 }, + { url = "https://files.pythonhosted.org/packages/dd/41/ec0ee3fd5124c83cb767dcea8569bb326f8981cc88c991e3e4e948a31e24/mmh3-5.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eba6001989a92f72a89c7cf382fda831678bd780707a66b4f8ca90239fdf2123", size = 94976 }, + { url = "https://files.pythonhosted.org/packages/8e/fa/e8059199fe6fbb2fd6494302904cb1209b2f8b6899d58059858a280e89a5/mmh3-5.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0771f90c9911811cc606a5c7b7b58f33501c9ee896ed68a6ac22c7d55878ecc0", size = 90485 }, + { url = "https://files.pythonhosted.org/packages/3a/a0/eb9da5f93dea3f44b8e970f013279d1543ab210ccf63bb030830968682aa/mmh3-5.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:09b31ed0c0c0920363e96641fac4efde65b1ab62b8df86293142f35a254e72b4", size = 89554 }, + { url = "https://files.pythonhosted.org/packages/e7/e8/5803181eac4e015b4caf307af22fea74292dca48e580d93afe402dcdc138/mmh3-5.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5cf4a8deda0235312db12075331cb417c4ba163770edfe789bde71d08a24b692", size = 94872 }, + { url = "https://files.pythonhosted.org/packages/ed/f9/4d55063f9dcaed41524f078a85989efdf1d335159af5e70af29942ebae67/mmh3-5.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41f7090a95185ef20ac018581a99337f0cbc84a2135171ee3290a9c0d9519585", size = 91326 }, + { url = "https://files.pythonhosted.org/packages/80/75/0a5acab5291480acd939db80e94448ac937fc7fbfddc0a67b3e721ebfc9c/mmh3-5.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b97b5b368fb7ff22194ec5854f5b12d8de9ab67a0f304728c7f16e5d12135b76", size = 89810 }, + { url = "https://files.pythonhosted.org/packages/9b/fd/eb1a3573cda74d4c2381d10ded62c128e869954ced1881c15e2bcd97a48f/mmh3-5.0.1-cp312-cp312-win32.whl", hash = "sha256:842516acf04da546f94fad52db125ee619ccbdcada179da51c326a22c4578cb9", size = 39206 }, + { url = "https://files.pythonhosted.org/packages/66/e8/542ed252924002b84c43a68a080cfd4facbea0d5df361e4f59637638d3c7/mmh3-5.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:d963be0dbfd9fca209c17172f6110787ebf78934af25e3694fe2ba40e55c1e2b", size = 39799 }, + { url = "https://files.pythonhosted.org/packages/bd/25/ff2cd36c82a23afa57a05cdb52ab467a911fb12c055c8a8238c0d426cbf0/mmh3-5.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:a5da292ceeed8ce8e32b68847261a462d30fd7b478c3f55daae841404f433c15", size = 36537 }, + { url = "https://files.pythonhosted.org/packages/09/e0/fb19c46265c18311b422ba5ce3e18046ad45c48cfb213fd6dbec23ae6b51/mmh3-5.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:673e3f1c8d4231d6fb0271484ee34cb7146a6499fc0df80788adb56fd76842da", size = 52909 }, + { url = "https://files.pythonhosted.org/packages/c3/94/54fc591e7a24c7ce2c531ecfc5715cff932f9d320c2936550cc33d67304d/mmh3-5.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f795a306bd16a52ad578b663462cc8e95500b3925d64118ae63453485d67282b", size = 38396 }, + { url = "https://files.pythonhosted.org/packages/1f/9a/142bcc9d0d28fc8ae45bbfb83926adc069f984cdf3495a71534cc22b8e27/mmh3-5.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5ed57a5e28e502a1d60436cc25c76c3a5ba57545f250f2969af231dc1221e0a5", size = 38207 }, + { url = "https://files.pythonhosted.org/packages/f8/5b/f1c9110aa70321bb1ee713f17851b9534586c63bc25e0110e4fc03ae2450/mmh3-5.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:632c28e7612e909dbb6cbe2fe496201ada4695b7715584005689c5dc038e59ad", size = 94988 }, + { url = "https://files.pythonhosted.org/packages/87/e5/4dc67e7e0e716c641ab0a5875a659e37258417439590feff5c3bd3ff4538/mmh3-5.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53fd6bd525a5985e391c43384672d9d6b317fcb36726447347c7fc75bfed34ec", size = 99969 }, + { url = "https://files.pythonhosted.org/packages/ac/68/d148327337687c53f04ad9ceaedfa9ad155ee0111d0cb06220f044d66720/mmh3-5.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dceacf6b0b961a0e499836af3aa62d60633265607aef551b2a3e3c48cdaa5edd", size = 99662 }, + { url = "https://files.pythonhosted.org/packages/13/79/782adb6df6397947c1097b1e94b7f8d95629a4a73df05cf7207bd5148c1f/mmh3-5.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f0738d478fdfb5d920f6aff5452c78f2c35b0eff72caa2a97dfe38e82f93da2", size = 87606 }, + { url = "https://files.pythonhosted.org/packages/f2/c2/0404383281df049d0e4ccf07fabd659fc1f3da834df6708d934116cbf45d/mmh3-5.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e70285e7391ab88b872e5bef632bad16b9d99a6d3ca0590656a4753d55988af", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/c8/33/fda67c5f28e4c2131891cf8cbc3513cfc55881e3cfe26e49328e38ffacb3/mmh3-5.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:27e5fc6360aa6b828546a4318da1a7da6bf6e5474ccb053c3a6aa8ef19ff97bd", size = 90492 }, + { url = "https://files.pythonhosted.org/packages/64/2f/0ed38aefe2a87f30bb1b12e5b75dc69fcffdc16def40d1752d6fc7cbbf96/mmh3-5.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7989530c3c1e2c17bf5a0ec2bba09fd19819078ba90beedabb1c3885f5040b0d", size = 89594 }, + { url = "https://files.pythonhosted.org/packages/95/ab/6e7a5e765fc78e3dbd0a04a04cfdf72e91eb8e31976228e69d82c741a5b4/mmh3-5.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cdad7bee649950da7ecd3cbbbd12fb81f1161072ecbdb5acfa0018338c5cb9cf", size = 94929 }, + { url = "https://files.pythonhosted.org/packages/74/51/f748f00c072006f4a093d9b08853a0e2e3cd5aeaa91343d4e2d942851978/mmh3-5.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e143b8f184c1bb58cecd85ab4a4fd6dc65a2d71aee74157392c3fddac2a4a331", size = 91317 }, + { url = "https://files.pythonhosted.org/packages/df/a1/21ee8017a7feb0270c49f756ff56da9f99bd150dcfe3b3f6f0d4b243423d/mmh3-5.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5eb12e886f3646dd636f16b76eb23fc0c27e8ff3c1ae73d4391e50ef60b40f6", size = 89861 }, + { url = "https://files.pythonhosted.org/packages/c2/d2/46a6d070de4659bdf91cd6a62d659f8cc547dadee52b6d02bcbacb3262ed/mmh3-5.0.1-cp313-cp313-win32.whl", hash = "sha256:16e6dddfa98e1c2d021268e72c78951234186deb4df6630e984ac82df63d0a5d", size = 39201 }, + { url = "https://files.pythonhosted.org/packages/ed/07/316c062f09019b99b248a4183c5333f8eeebe638345484774908a8f2c9c0/mmh3-5.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:d3ffb792d70b8c4a2382af3598dad6ae0c5bd9cee5b7ffcc99aa2f5fd2c1bf70", size = 39807 }, + { url = "https://files.pythonhosted.org/packages/9d/d3/f7e6d7d062b8d7072c3989a528d9d47486ee5d5ae75250f6e26b4976d098/mmh3-5.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:122fa9ec148383f9124292962bda745f192b47bfd470b2af5fe7bb3982b17896", size = 36539 }, ] [[package]] @@ -2325,6 +2433,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 }, { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 }, { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 }, + { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 }, + { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 }, + { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 }, + { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 }, + { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 }, { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 }, ] @@ -2426,58 +2539,58 @@ version = "2.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4b/d1/8a730ea07f4a37d94f9172f4ce1d81064b7a64766b460378be278952de75/numpy-2.1.2.tar.gz", hash = "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c", size = 18878063 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/37/e3de47233b3ba458b1021a6f95029198b2f68a83eb886a862640b6ec3e9a/numpy-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8a0e34993b510fc19b9a2ce7f31cb8e94ecf6e924a40c0c9dd4f62d0aac47d9", size = 21150738 }, - { url = "https://files.pythonhosted.org/packages/69/30/f41c9b6dab4e1ec56b40d1daa81ce9f9f8d26da6d02af18768a883676bd5/numpy-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7dd86dfaf7c900c0bbdcb8b16e2f6ddf1eb1fe39c6c8cca6e94844ed3152a8fd", size = 13758247 }, - { url = "https://files.pythonhosted.org/packages/e1/30/d2f71d3419ada3b3735e2ce9cea7dfe22c268ac9fbb24e0b5ac5fc222633/numpy-2.1.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:5889dd24f03ca5a5b1e8a90a33b5a0846d8977565e4ae003a63d22ecddf6782f", size = 5353756 }, - { url = "https://files.pythonhosted.org/packages/84/64/879bd6877488441cfaa578c96bdc4b43710d7e3ae4f8260fbd04821da395/numpy-2.1.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:59ca673ad11d4b84ceb385290ed0ebe60266e356641428c845b39cd9df6713ab", size = 6886809 }, - { url = "https://files.pythonhosted.org/packages/cd/c4/869f8db87f5c9df86b93ca42036f58911ff162dd091a41e617977ab50d1f/numpy-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13ce49a34c44b6de5241f0b38b07e44c1b2dcacd9e36c30f9c2fcb1bb5135db7", size = 13977367 }, - { url = "https://files.pythonhosted.org/packages/7d/4b/a509d346fffede6120cc17610cc500819417ee9c3da7f08d9aaf15cab2a3/numpy-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913cc1d311060b1d409e609947fa1b9753701dac96e6581b58afc36b7ee35af6", size = 16326516 }, - { url = "https://files.pythonhosted.org/packages/4a/0c/fdba41b2ddeb7a052f84d85fb17d5e168af0e8034b3a2d6e369b7cc2966f/numpy-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:caf5d284ddea7462c32b8d4a6b8af030b6c9fd5332afb70e7414d7fdded4bfd0", size = 16702642 }, - { url = "https://files.pythonhosted.org/packages/bf/8d/a8da065a46515efdbcf81a92535b816ea17194ce5b767df1f13815c32179/numpy-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57eb525e7c2a8fdee02d731f647146ff54ea8c973364f3b850069ffb42799647", size = 14475522 }, - { url = "https://files.pythonhosted.org/packages/b9/d2/5b7cf5851af48c35a73b85750b41f9b622760ee11659665a688e6b3f7cb7/numpy-2.1.1-cp310-cp310-win32.whl", hash = "sha256:9a8e06c7a980869ea67bbf551283bbed2856915f0a792dc32dd0f9dd2fb56728", size = 6535211 }, - { url = "https://files.pythonhosted.org/packages/e5/6a/b1f7d73fec1942ded4b474a78c3fdd11c4fad5232143f41dd7e6ae166080/numpy-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d10c39947a2d351d6d466b4ae83dad4c37cd6c3cdd6d5d0fa797da56f710a6ae", size = 12865289 }, - { url = "https://files.pythonhosted.org/packages/f7/86/2c01070424a42b286ea0271203682c3d3e81e10ce695545b35768307b383/numpy-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d07841fd284718feffe7dd17a63a2e6c78679b2d386d3e82f44f0108c905550", size = 21154850 }, - { url = "https://files.pythonhosted.org/packages/ef/4e/d3426d9e620a18bbb979f28e4dc7f9a2c35eb7cf726ffcb33545ebdd3e6a/numpy-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5613cfeb1adfe791e8e681128f5f49f22f3fcaa942255a6124d58ca59d9528f", size = 13789477 }, - { url = "https://files.pythonhosted.org/packages/c6/6e/fb6b1b2da9f4c757f55b202f10b6af0fe4fee87ace6e830228a12ab8ae5d/numpy-2.1.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0b8cc2715a84b7c3b161f9ebbd942740aaed913584cae9cdc7f8ad5ad41943d0", size = 5351769 }, - { url = "https://files.pythonhosted.org/packages/58/9a/07c8a9dc7254f3265ae014e33768d1cfd8eb73ee6cf215f4ec3b497e4255/numpy-2.1.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b49742cdb85f1f81e4dc1b39dcf328244f4d8d1ded95dea725b316bd2cf18c95", size = 6890872 }, - { url = "https://files.pythonhosted.org/packages/08/4e/3b50fa3b1e045793056ed5a1fc6f89dd897ff9cb00900ca6377fe552d442/numpy-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d5f8a8e3bc87334f025194c6193e408903d21ebaeb10952264943a985066ca", size = 13984256 }, - { url = "https://files.pythonhosted.org/packages/d9/37/108d692f7e2544b9ae972c7bfa06c26717871c273ccec86470bc3132b04d/numpy-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d51fc141ddbe3f919e91a096ec739f49d686df8af254b2053ba21a910ae518bf", size = 16337778 }, - { url = "https://files.pythonhosted.org/packages/95/2d/df81a1be3be6d3a92fd12dfd6c26a0dc026b276136ec1056562342a484a2/numpy-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:98ce7fb5b8063cfdd86596b9c762bf2b5e35a2cdd7e967494ab78a1fa7f8b86e", size = 16710448 }, - { url = "https://files.pythonhosted.org/packages/8f/34/4b2e604c5c44bd64b6c85e89d88871b41e60233b3ddf97419b37ae5b0c72/numpy-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24c2ad697bd8593887b019817ddd9974a7f429c14a5469d7fad413f28340a6d2", size = 14489002 }, - { url = "https://files.pythonhosted.org/packages/9f/0d/67c04b6bfefd0abbe7f60f7e4f11e3aca15d688faec1d1df089966105a9a/numpy-2.1.1-cp311-cp311-win32.whl", hash = "sha256:397bc5ce62d3fb73f304bec332171535c187e0643e176a6e9421a6e3eacef06d", size = 6533215 }, - { url = "https://files.pythonhosted.org/packages/94/7a/4c00332a3ca79702bbc86228afd0e84e6f91b47222ec8cdf00677dd16481/numpy-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:ae8ce252404cdd4de56dcfce8b11eac3c594a9c16c231d081fb705cf23bd4d9e", size = 12870550 }, - { url = "https://files.pythonhosted.org/packages/36/11/c573ef66c004f991989c2c6218229d9003164525549409aec5ec9afc0285/numpy-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c803b7934a7f59563db459292e6aa078bb38b7ab1446ca38dd138646a38203e", size = 20884403 }, - { url = "https://files.pythonhosted.org/packages/6b/6c/a9fbef5fd2f9685212af2a9e47485cde9357c3e303e079ccf85127516f2d/numpy-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6435c48250c12f001920f0751fe50c0348f5f240852cfddc5e2f97e007544cbe", size = 13493375 }, - { url = "https://files.pythonhosted.org/packages/34/f2/1316a6b08ad4c161d793abe81ff7181e9ae2e357a5b06352a383b9f8e800/numpy-2.1.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3269c9eb8745e8d975980b3a7411a98976824e1fdef11f0aacf76147f662b15f", size = 5088823 }, - { url = "https://files.pythonhosted.org/packages/be/15/fabf78a6d4a10c250e87daf1cd901af05e71501380532ac508879cc46a7e/numpy-2.1.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fac6e277a41163d27dfab5f4ec1f7a83fac94e170665a4a50191b545721c6521", size = 6619825 }, - { url = "https://files.pythonhosted.org/packages/9f/8a/76ddef3e621541ddd6984bc24d256a4e3422d036790cbbe449e6cad439ee/numpy-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd8f556cdc8cfe35e70efb92463082b7f43dd7e547eb071ffc36abc0ca4699b", size = 13696705 }, - { url = "https://files.pythonhosted.org/packages/cb/22/2b840d297183916a95847c11f82ae11e248fa98113490b2357f774651e1d/numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b9cd92c8f8e7b313b80e93cedc12c0112088541dcedd9197b5dee3738c1201", size = 16041649 }, - { url = "https://files.pythonhosted.org/packages/c7/e8/6f4825d8f576cfd5e4d6515b9eec22bd618868bdafc8a8c08b446dcb65f0/numpy-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:afd9c680df4de71cd58582b51e88a61feed4abcc7530bcd3d48483f20fc76f2a", size = 16409358 }, - { url = "https://files.pythonhosted.org/packages/bf/f8/5edf1105b0dc24fd66fc3e9e7f3bca3d920cde571caaa4375ec1566073c3/numpy-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8661c94e3aad18e1ea17a11f60f843a4933ccaf1a25a7c6a9182af70610b2313", size = 14172488 }, - { url = "https://files.pythonhosted.org/packages/f4/c2/dddca3e69a024d2f249a5b68698328163cbdafb7e65fbf6d36373bbabf12/numpy-2.1.1-cp312-cp312-win32.whl", hash = "sha256:950802d17a33c07cba7fd7c3dcfa7d64705509206be1606f196d179e539111ed", size = 6237195 }, - { url = "https://files.pythonhosted.org/packages/b7/98/5640a09daa3abf0caeaefa6e7bf0d10c0aa28a77c84e507d6a716e0e23df/numpy-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fc5eabfc720db95d68e6646e88f8b399bfedd235994016351b1d9e062c4b270", size = 12568082 }, - { url = "https://files.pythonhosted.org/packages/6b/9e/8bc6f133bc6d359ccc9ec051853aded45504d217685191f31f46d36b7065/numpy-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:046356b19d7ad1890c751b99acad5e82dc4a02232013bd9a9a712fddf8eb60f5", size = 20834810 }, - { url = "https://files.pythonhosted.org/packages/32/1b/429519a2fa28681814c511574017d35f3aab7136d554cc65f4c1526dfbf5/numpy-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5a9cb2be39350ae6c8f79410744e80154df658d5bea06e06e0ac5bb75480d5", size = 13507739 }, - { url = "https://files.pythonhosted.org/packages/25/18/c732d7dd9896d11e4afcd487ac65e62f9fa0495563b7614eb850765361fa/numpy-2.1.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:d4c57b68c8ef5e1ebf47238e99bf27657511ec3f071c465f6b1bccbef12d4136", size = 5074465 }, - { url = "https://files.pythonhosted.org/packages/3e/37/838b7ae9262c370ab25312bab365492016f11810ffc03ebebbd54670b669/numpy-2.1.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8ae0fd135e0b157365ac7cc31fff27f07a5572bdfc38f9c2d43b2aff416cc8b0", size = 6606418 }, - { url = "https://files.pythonhosted.org/packages/8b/b9/7ff3bfb71e316a5b43a124c4b7a5881ab12f3c32636014bef1f757f19dbd/numpy-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981707f6b31b59c0c24bcda52e5605f9701cb46da4b86c2e8023656ad3e833cb", size = 13692464 }, - { url = "https://files.pythonhosted.org/packages/42/78/75bcf16e6737cd196ff7ecf0e1fd3f953293a34dff4fd93fb488e8308536/numpy-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca4b53e1e0b279142113b8c5eb7d7a877e967c306edc34f3b58e9be12fda8df", size = 16037763 }, - { url = "https://files.pythonhosted.org/packages/23/99/36bf5ffe034d06df307bc783e25cf164775863166dcd878879559fe0379f/numpy-2.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e097507396c0be4e547ff15b13dc3866f45f3680f789c1a1301b07dadd3fbc78", size = 16410374 }, - { url = "https://files.pythonhosted.org/packages/7f/16/04c5dab564887d4cd31a9ed30e51467fa70d52a4425f5a9bd1eed5b3d34c/numpy-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7506387e191fe8cdb267f912469a3cccc538ab108471291636a96a54e599556", size = 14169873 }, - { url = "https://files.pythonhosted.org/packages/09/e0/d1b5adbf1731886c4186c59a9fa208585df9452a43a2b60e79af7c649717/numpy-2.1.1-cp313-cp313-win32.whl", hash = "sha256:251105b7c42abe40e3a689881e1793370cc9724ad50d64b30b358bbb3a97553b", size = 6234118 }, - { url = "https://files.pythonhosted.org/packages/d0/9c/2391ee6e9ebe77232ddcab29d92662b545e99d78c3eb3b4e26d59b9ca1ca/numpy-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:f212d4f46b67ff604d11fff7cc62d36b3e8714edf68e44e9760e19be38c03eb0", size = 12561742 }, - { url = "https://files.pythonhosted.org/packages/38/0e/c4f754f9e73f9bb520e8bf418c646f2c4f70c5d5f2bc561e90f884593193/numpy-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:920b0911bb2e4414c50e55bd658baeb78281a47feeb064ab40c2b66ecba85553", size = 20858403 }, - { url = "https://files.pythonhosted.org/packages/32/fc/d69092b9171efa0cb8079577e71ce0cac0e08f917d33f6e99c916ed51d44/numpy-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bab7c09454460a487e631ffc0c42057e3d8f2a9ddccd1e60c7bb8ed774992480", size = 13519851 }, - { url = "https://files.pythonhosted.org/packages/14/2a/d7cf2cd9f15b23f623075546ea64a2c367cab703338ca22aaaecf7e704df/numpy-2.1.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:cea427d1350f3fd0d2818ce7350095c1a2ee33e30961d2f0fef48576ddbbe90f", size = 5115444 }, - { url = "https://files.pythonhosted.org/packages/8e/00/e87b2cb4afcecca3b678deefb8fa53005d7054f3b5c39596e5554e5d98f8/numpy-2.1.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:e30356d530528a42eeba51420ae8bf6c6c09559051887196599d96ee5f536468", size = 6628903 }, - { url = "https://files.pythonhosted.org/packages/ab/9d/337ae8721b3beec48c3413d71f2d44b2defbf3c6f7a85184fc18b7b61f4a/numpy-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8dfa9e94fc127c40979c3eacbae1e61fda4fe71d84869cc129e2721973231ef", size = 13665945 }, - { url = "https://files.pythonhosted.org/packages/c0/90/ee8668e84c5d5cc080ef3beb622c016adf19ca3aa51afe9dbdcc6a9baf59/numpy-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910b47a6d0635ec1bd53b88f86120a52bf56dcc27b51f18c7b4a2e2224c29f0f", size = 16023473 }, - { url = "https://files.pythonhosted.org/packages/38/a0/57c24b2131879183051dc698fbb53fd43b77c3fa85b6e6311014f2bc2973/numpy-2.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:13cc11c00000848702322af4de0147ced365c81d66053a67c2e962a485b3717c", size = 16400624 }, - { url = "https://files.pythonhosted.org/packages/bb/4c/14a41eb5c9548c6cee6af0936eabfd985c69230ffa2f2598321431a9aa0a/numpy-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53e27293b3a2b661c03f79aa51c3987492bd4641ef933e366e0f9f6c9bf257ec", size = 14155072 }, - { url = "https://files.pythonhosted.org/packages/94/9a/d6a5d138b53ccdc002fdf07f0d1a960326c510e66cbfff7180c88d37c482/numpy-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7be6a07520b88214ea85d8ac8b7d6d8a1839b0b5cb87412ac9f49fa934eb15d5", size = 20982055 }, - { url = "https://files.pythonhosted.org/packages/40/b5/78d8b5481aeef6d2aad3724c6aa5398045d2657038dfe54c055cae1fcf75/numpy-2.1.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:52ac2e48f5ad847cd43c4755520a2317f3380213493b9d8a4c5e37f3b87df504", size = 6750222 }, - { url = "https://files.pythonhosted.org/packages/eb/9a/59a548ad57df8c432bfac4556504a9fae5c082ffea53d108fcf7ce2956e4/numpy-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a95ca3560a6058d6ea91d4629a83a897ee27c00630aed9d933dff191f170cd", size = 16141236 }, - { url = "https://files.pythonhosted.org/packages/02/31/3cbba87e998748b2e33ca5bc6fcc5662c867037f980918e302aebdf139a2/numpy-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:99f4a9ee60eed1385a86e82288971a51e71df052ed0b2900ed30bc840c0f2e39", size = 12789681 }, + { url = "https://files.pythonhosted.org/packages/1c/a2/40a76d357f168e9f9f06d6cc2c8e22dd5fb2bfbe63fe2c433057258c145a/numpy-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee", size = 21150947 }, + { url = "https://files.pythonhosted.org/packages/b5/d0/ba271ea9108d7278d3889a7eb38d77370a88713fb94339964e71ac184d4a/numpy-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884", size = 13758184 }, + { url = "https://files.pythonhosted.org/packages/7c/b9/5c6507439cd756201010f7937bf90712c2469052ae094584af14557dd64f/numpy-2.1.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648", size = 5354091 }, + { url = "https://files.pythonhosted.org/packages/60/21/7938cf724d9e84e45fb886f3fc794ab431d71facfebc261e3e9f19f3233a/numpy-2.1.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d", size = 6887169 }, + { url = "https://files.pythonhosted.org/packages/09/8d/42a124657f5d31902fca73921b25a0d022cead2b32ce7e6975762cd2995a/numpy-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86", size = 13888165 }, + { url = "https://files.pythonhosted.org/packages/fb/25/ba023652a39a2c127200e85aed975fc6119b421e2c348e5d0171e2046edb/numpy-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7", size = 16326954 }, + { url = "https://files.pythonhosted.org/packages/34/58/23e6b07fad492b7c47cf09cd8bad6983658f0f925b6c535fd008e3e86274/numpy-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03", size = 16702916 }, + { url = "https://files.pythonhosted.org/packages/91/24/37b5cf2dc7d385ac97f7b7fe50cba312abb70a2a5eac74c23af028811f73/numpy-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466", size = 14384372 }, + { url = "https://files.pythonhosted.org/packages/ea/ec/0f6d471058a01d1a05a50d2793898de1549280fa715a8537987ee866b5d9/numpy-2.1.2-cp310-cp310-win32.whl", hash = "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb", size = 6535361 }, + { url = "https://files.pythonhosted.org/packages/c2/3d/293cc5927f916a7bc6bf74da8f6defab63d1b13f0959d7e21878ad8a20d8/numpy-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2", size = 12865501 }, + { url = "https://files.pythonhosted.org/packages/aa/9c/9a6ec3ae89cd0648d419781284308f2956d2a61d932b5ac9682c956a171b/numpy-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe", size = 21154845 }, + { url = "https://files.pythonhosted.org/packages/02/69/9f05c4ecc75fabf297b17743996371b4c3dfc4d92e15c5c38d8bb3db8d74/numpy-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1", size = 13789409 }, + { url = "https://files.pythonhosted.org/packages/34/4e/f95c99217bf77bbfaaf660d693c10bd0dc03b6032d19316d316088c9e479/numpy-2.1.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f", size = 5352097 }, + { url = "https://files.pythonhosted.org/packages/06/13/f5d87a497c16658e9af8920449b0b5692b469586b8231340c672962071c5/numpy-2.1.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4", size = 6891195 }, + { url = "https://files.pythonhosted.org/packages/6c/89/691ac07429ac061b344d5e37fa8e94be51a6017734aea15f2d9d7c6d119a/numpy-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a", size = 13895153 }, + { url = "https://files.pythonhosted.org/packages/23/69/538317f0d925095537745f12aced33be1570bbdc4acde49b33748669af96/numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1", size = 16338306 }, + { url = "https://files.pythonhosted.org/packages/af/03/863fe7062c2106d3c151f7df9353f2ae2237c1dd6900f127a3eb1f24cb1b/numpy-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2", size = 16710893 }, + { url = "https://files.pythonhosted.org/packages/70/77/0ad9efe25482009873f9660d29a40a8c41a6f0e8b541195e3c95c70684c5/numpy-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146", size = 14398048 }, + { url = "https://files.pythonhosted.org/packages/3e/0f/e785fe75544db9f2b0bb1c181e13ceff349ce49753d807fd9672916aa06d/numpy-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c", size = 6533458 }, + { url = "https://files.pythonhosted.org/packages/d4/96/450054662295125af861d48d2c4bc081dadcf1974a879b2104613157aa62/numpy-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9", size = 12870896 }, + { url = "https://files.pythonhosted.org/packages/a0/7d/554a6838f37f3ada5a55f25173c619d556ae98092a6e01afb6e710501d70/numpy-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b", size = 20848077 }, + { url = "https://files.pythonhosted.org/packages/b0/29/cb48a402ea879e645b16218718f3f7d9588a77d674a9dcf22e4c43487636/numpy-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db", size = 13493242 }, + { url = "https://files.pythonhosted.org/packages/56/44/f899b0581766c230da42f751b7b8896d096640b19b312164c267e48d36cb/numpy-2.1.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1", size = 5089219 }, + { url = "https://files.pythonhosted.org/packages/79/8f/b987070d45161a7a4504afc67ed38544ed2c0ed5576263599a0402204a9c/numpy-2.1.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426", size = 6620167 }, + { url = "https://files.pythonhosted.org/packages/c4/a7/af3329fda3c3ec31d9b650e42bbcd3422fc62a765cbb1405fde4177a0996/numpy-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0", size = 13604905 }, + { url = "https://files.pythonhosted.org/packages/9b/b4/e3c7e6fab0f77fff6194afa173d1f2342073d91b1d3b4b30b17c3fb4407a/numpy-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df", size = 16041825 }, + { url = "https://files.pythonhosted.org/packages/e9/50/6828e66a78aa03147c111f84d55f33ce2dde547cb578d6744a3b06a0124b/numpy-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366", size = 16409541 }, + { url = "https://files.pythonhosted.org/packages/bf/72/66af7916d9c3c6dbfbc8acdd4930c65461e1953374a2bc43d00f948f004a/numpy-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142", size = 14081134 }, + { url = "https://files.pythonhosted.org/packages/dc/5a/59a67d84f33fe00ae74f0b5b69dd4f93a586a4aba7f7e19b54b2133db038/numpy-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550", size = 6237784 }, + { url = "https://files.pythonhosted.org/packages/4c/79/73735a6a5dad6059c085f240a4e74c9270feccd2bc66e4d31b5ca01d329c/numpy-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e", size = 12568254 }, + { url = "https://files.pythonhosted.org/packages/16/72/716fa1dbe92395a9a623d5049203ff8ddb0cfce65b9df9117c3696ccc011/numpy-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d", size = 20834690 }, + { url = "https://files.pythonhosted.org/packages/1e/fb/3e85a39511586053b5c6a59a643879e376fae22230ebfef9cfabb0e032e2/numpy-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf", size = 13507474 }, + { url = "https://files.pythonhosted.org/packages/35/eb/5677556d9ba13436dab51e129f98d4829d95cd1b6bd0e199c14485a4bdb9/numpy-2.1.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e", size = 5074742 }, + { url = "https://files.pythonhosted.org/packages/3e/c5/6c5ef5ba41b65a7e51bed50dbf3e1483eb578055633dd013e811a28e96a1/numpy-2.1.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3", size = 6606787 }, + { url = "https://files.pythonhosted.org/packages/08/ac/f2f29dd4fd325b379c7dc932a0ebab22f0e031dbe80b2f6019b291a3a544/numpy-2.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8", size = 13601333 }, + { url = "https://files.pythonhosted.org/packages/44/26/63f5f4e5089654dfb858f4892215ed968cd1a68e6f4a83f9961f84f855cb/numpy-2.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a", size = 16038090 }, + { url = "https://files.pythonhosted.org/packages/1d/21/015e0594de9c3a8d5edd24943d2bd23f102ec71aec026083f822f86497e2/numpy-2.1.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98", size = 16410865 }, + { url = "https://files.pythonhosted.org/packages/df/01/c1bcf9e6025d79077fbf3f3ee503b50aa7bfabfcd8f4b54f5829f4c00f3f/numpy-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe", size = 14078077 }, + { url = "https://files.pythonhosted.org/packages/ba/06/db9d127d63bd11591770ba9f3d960f8041e0f895184b9351d4b1b5b56983/numpy-2.1.2-cp313-cp313-win32.whl", hash = "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a", size = 6234904 }, + { url = "https://files.pythonhosted.org/packages/a9/96/9f61f8f95b6e0ea0aa08633b704c75d1882bdcb331bdf8bfd63263b25b00/numpy-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445", size = 12561910 }, + { url = "https://files.pythonhosted.org/packages/36/b8/033f627821784a48e8f75c218033471eebbaacdd933f8979c79637a1b44b/numpy-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5", size = 20857719 }, + { url = "https://files.pythonhosted.org/packages/96/46/af5726fde5b74ed83f2f17a73386d399319b7ed4d51279fb23b721d0816d/numpy-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0", size = 13518826 }, + { url = "https://files.pythonhosted.org/packages/db/6e/8ce677edf36da1c4dae80afe5529f47690697eb55b4864673af260ccea7b/numpy-2.1.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17", size = 5115036 }, + { url = "https://files.pythonhosted.org/packages/6a/ba/3cce44fb1b8438042c11847048812a776f75ee0e7070179c22e4cfbf420c/numpy-2.1.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6", size = 6628641 }, + { url = "https://files.pythonhosted.org/packages/59/c8/e722998720ccbd35ffbcf1d1b8ed0aa2304af88d3f1c38e06ebf983599b3/numpy-2.1.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8", size = 13574803 }, + { url = "https://files.pythonhosted.org/packages/7c/8e/fc1fdd83a55476765329ac2913321c4aed5b082a7915095628c4ca30ea72/numpy-2.1.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35", size = 16021174 }, + { url = "https://files.pythonhosted.org/packages/2a/b6/a790742aa88067adb4bd6c89a946778c1417d4deaeafce3ca928f26d4c52/numpy-2.1.2-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62", size = 16400117 }, + { url = "https://files.pythonhosted.org/packages/48/6f/129e3c17e3befe7fefdeaa6890f4c4df3f3cf0831aa053802c3862da67aa/numpy-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a", size = 14066202 }, + { url = "https://files.pythonhosted.org/packages/73/c9/3e1d6bbe6d3d2e2c5a9483b24b2f29a229b323f62054278a3bba7fee11e5/numpy-2.1.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952", size = 20981945 }, + { url = "https://files.pythonhosted.org/packages/6e/62/989c4988bde1a8e08117fccc3bab73d2886421fb98cde597168714f3c54e/numpy-2.1.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5", size = 6750558 }, + { url = "https://files.pythonhosted.org/packages/53/b1/00ef9f30975f1312a53257f68e57b4513d14d537e03d507e2773a684b1e8/numpy-2.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7", size = 16141552 }, + { url = "https://files.pythonhosted.org/packages/c0/ec/0c04903b48dfea6be1d7b47ba70f98709fb7198fd970784a1400c391d522/numpy-2.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e", size = 12789924 }, ] [[package]] @@ -2867,42 +2980,43 @@ version = "3.10.10" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/80/44/d36e86b33fc84f224b5f2cdf525adf3b8f9f475753e721c402b1ddef731e/orjson-3.10.10.tar.gz", hash = "sha256:37949383c4df7b4337ce82ee35b6d7471e55195efa7dcb45ab8226ceadb0fe3b", size = 5404170 } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/12/60931cf808b9334f26210ab496442f4a7a3d66e29d1cf12e0a01857e756f/orjson-3.10.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:74f4544f5a6405b90da8ea724d15ac9c36da4d72a738c64685003337401f5c12", size = 251312 }, - { url = "https://files.pythonhosted.org/packages/fe/0e/efbd0a2d25f8e82b230eb20b6b8424be6dd95b6811b669be9af16234b6db/orjson-3.10.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34a566f22c28222b08875b18b0dfbf8a947e69df21a9ed5c51a6bf91cfb944ac", size = 148124 }, - { url = "https://files.pythonhosted.org/packages/dd/47/1ddff6e23fe5f4aeaaed996a3cde422b3eaac4558c03751723e106184c68/orjson-3.10.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf6ba8ebc8ef5792e2337fb0419f8009729335bb400ece005606336b7fd7bab7", size = 147277 }, - { url = "https://files.pythonhosted.org/packages/04/da/d03d72b54bdd60d05de372114abfbd9f05050946895140c6ff5f27ab8f49/orjson-3.10.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac7cf6222b29fbda9e3a472b41e6a5538b48f2c8f99261eecd60aafbdb60690c", size = 152955 }, - { url = "https://files.pythonhosted.org/packages/7f/7e/ef8522dbba112af6cc52227dcc746dd3447c7d53ea8cea35740239b547ee/orjson-3.10.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de817e2f5fc75a9e7dd350c4b0f54617b280e26d1631811a43e7e968fa71e3e9", size = 163955 }, - { url = "https://files.pythonhosted.org/packages/b6/bc/fbd345d771a73cacc5b0e774d034cd081590b336754c511f4ead9fdc4cf1/orjson-3.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:348bdd16b32556cf8d7257b17cf2bdb7ab7976af4af41ebe79f9796c218f7e91", size = 141896 }, - { url = "https://files.pythonhosted.org/packages/82/0a/1f09c12d15b1e83156b7f3f621561d38650fe5b8f39f38f04a64de1a87fc/orjson-3.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:479fd0844ddc3ca77e0fd99644c7fe2de8e8be1efcd57705b5c92e5186e8a250", size = 170166 }, - { url = "https://files.pythonhosted.org/packages/a6/d8/eee30caba21a8d6a9df06d2519bb0ecd0adbcd57f2e79d360de5570031cf/orjson-3.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fdf5197a21dd660cf19dfd2a3ce79574588f8f5e2dbf21bda9ee2d2b46924d84", size = 167804 }, - { url = "https://files.pythonhosted.org/packages/44/fe/d1d89d3f15e343511417195f6ccd2bdeb7ebc5a48a882a79ab3bbcdf5fc7/orjson-3.10.7-cp310-none-win32.whl", hash = "sha256:d374d36726746c81a49f3ff8daa2898dccab6596864ebe43d50733275c629175", size = 143010 }, - { url = "https://files.pythonhosted.org/packages/88/8c/0e7b8d5a523927774758ac4ce2de4d8ca5dda569955ba3aeb5e208344eda/orjson-3.10.7-cp310-none-win_amd64.whl", hash = "sha256:cb61938aec8b0ffb6eef484d480188a1777e67b05d58e41b435c74b9d84e0b9c", size = 137306 }, - { url = "https://files.pythonhosted.org/packages/89/c9/dd286c97c2f478d43839bd859ca4d9820e2177d4e07a64c516dc3e018062/orjson-3.10.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7db8539039698ddfb9a524b4dd19508256107568cdad24f3682d5773e60504a2", size = 251312 }, - { url = "https://files.pythonhosted.org/packages/b9/72/d90bd11e83a0e9623b3803b079478a93de8ec4316c98fa66110d594de5fa/orjson-3.10.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:480f455222cb7a1dea35c57a67578848537d2602b46c464472c995297117fa09", size = 148125 }, - { url = "https://files.pythonhosted.org/packages/9d/b6/ed61e87f327a4cbb2075ed0716e32ba68cb029aa654a68c3eb27803050d8/orjson-3.10.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8a9c9b168b3a19e37fe2778c0003359f07822c90fdff8f98d9d2a91b3144d8e0", size = 147278 }, - { url = "https://files.pythonhosted.org/packages/66/9f/e6a11b5d1ad11e9dc869d938707ef93ff5ed20b53d6cda8b5e2ac532a9d2/orjson-3.10.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8de062de550f63185e4c1c54151bdddfc5625e37daf0aa1e75d2a1293e3b7d9a", size = 152954 }, - { url = "https://files.pythonhosted.org/packages/92/ee/702d5e8ccd42dc2b9d1043f22daa1ba75165616aa021dc19fb0c5a726ce8/orjson-3.10.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6b0dd04483499d1de9c8f6203f8975caf17a6000b9c0c54630cef02e44ee624e", size = 163953 }, - { url = "https://files.pythonhosted.org/packages/d3/cb/55205f3f1ee6ba80c0a9a18ca07423003ca8de99192b18be30f1f31b4cdd/orjson-3.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b58d3795dafa334fc8fd46f7c5dc013e6ad06fd5b9a4cc98cb1456e7d3558bd6", size = 141895 }, - { url = "https://files.pythonhosted.org/packages/bb/ab/1185e472f15c00d37d09c395e478803ed0eae7a3a3d055a5f3885e1ea136/orjson-3.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:33cfb96c24034a878d83d1a9415799a73dc77480e6c40417e5dda0710d559ee6", size = 170169 }, - { url = "https://files.pythonhosted.org/packages/53/b9/10abe9089bdb08cd4218cc45eb7abfd787c82cf301cecbfe7f141542d7f4/orjson-3.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e724cebe1fadc2b23c6f7415bad5ee6239e00a69f30ee423f319c6af70e2a5c0", size = 167808 }, - { url = "https://files.pythonhosted.org/packages/8a/ad/26b40ccef119dcb0f4a39745ffd7d2d319152c1a52859b1ebbd114eca19c/orjson-3.10.7-cp311-none-win32.whl", hash = "sha256:82763b46053727a7168d29c772ed5c870fdae2f61aa8a25994c7984a19b1021f", size = 143010 }, - { url = "https://files.pythonhosted.org/packages/e7/63/5f4101e4895b78ada568f4cf8f870dd594139ca2e75e654e373da78b03b0/orjson-3.10.7-cp311-none-win_amd64.whl", hash = "sha256:eb8d384a24778abf29afb8e41d68fdd9a156cf6e5390c04cc07bbc24b89e98b5", size = 137307 }, - { url = "https://files.pythonhosted.org/packages/14/7c/b4ecc2069210489696a36e42862ccccef7e49e1454a3422030ef52881b01/orjson-3.10.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44a96f2d4c3af51bfac6bc4ef7b182aa33f2f054fd7f34cc0ee9a320d051d41f", size = 251409 }, - { url = "https://files.pythonhosted.org/packages/60/84/e495edb919ef0c98d054a9b6d05f2700fdeba3886edd58f1c4dfb25d514a/orjson-3.10.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ac14cd57df0572453543f8f2575e2d01ae9e790c21f57627803f5e79b0d3c3", size = 147913 }, - { url = "https://files.pythonhosted.org/packages/c5/27/e40bc7d79c4afb7e9264f22320c285d06d2c9574c9c682ba0f1be3012833/orjson-3.10.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bdbb61dcc365dd9be94e8f7df91975edc9364d6a78c8f7adb69c1cdff318ec93", size = 147390 }, - { url = "https://files.pythonhosted.org/packages/30/be/fd646fb1a461de4958a6eacf4ecf064b8d5479c023e0e71cc89b28fa91ac/orjson-3.10.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b48b3db6bb6e0a08fa8c83b47bc169623f801e5cc4f24442ab2b6617da3b5313", size = 152973 }, - { url = "https://files.pythonhosted.org/packages/b1/00/414f8d4bc5ec3447e27b5c26b4e996e4ef08594d599e79b3648f64da060c/orjson-3.10.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23820a1563a1d386414fef15c249040042b8e5d07b40ab3fe3efbfbbcbcb8864", size = 164039 }, - { url = "https://files.pythonhosted.org/packages/a0/6b/34e6904ac99df811a06e42d8461d47b6e0c9b86e2fe7ee84934df6e35f0d/orjson-3.10.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0c6a008e91d10a2564edbb6ee5069a9e66df3fbe11c9a005cb411f441fd2c09", size = 142035 }, - { url = "https://files.pythonhosted.org/packages/17/7e/254189d9b6df89660f65aec878d5eeaa5b1ae371bd2c458f85940445d36f/orjson-3.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d352ee8ac1926d6193f602cbe36b1643bbd1bbcb25e3c1a657a4390f3000c9a5", size = 169941 }, - { url = "https://files.pythonhosted.org/packages/02/1a/d11805670c29d3a1b29fc4bd048dc90b094784779690592efe8c9f71249a/orjson-3.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2d9f990623f15c0ae7ac608103c33dfe1486d2ed974ac3f40b693bad1a22a7b", size = 167994 }, - { url = "https://files.pythonhosted.org/packages/20/5f/03d89b007f9d6733dc11bc35d64812101c85d6c4e9c53af9fa7e7689cb11/orjson-3.10.7-cp312-none-win32.whl", hash = "sha256:7c4c17f8157bd520cdb7195f75ddbd31671997cbe10aee559c2d613592e7d7eb", size = 143130 }, - { url = "https://files.pythonhosted.org/packages/c6/9d/9b9fb6c60b8a0e04031ba85414915e19ecea484ebb625402d968ea45b8d5/orjson-3.10.7-cp312-none-win_amd64.whl", hash = "sha256:1d9c0e733e02ada3ed6098a10a8ee0052dd55774de3d9110d29868d24b17faa1", size = 137326 }, - { url = "https://files.pythonhosted.org/packages/15/05/121af8a87513c56745d01ad7cf215c30d08356da9ad882ebe2ba890824cd/orjson-3.10.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:77d325ed866876c0fa6492598ec01fe30e803272a6e8b10e992288b009cbe149", size = 251331 }, - { url = "https://files.pythonhosted.org/packages/73/7f/8d6ccd64a6f8bdbfe6c9be7c58aeb8094aa52a01fbbb2cda42ff7e312bd7/orjson-3.10.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea2c232deedcb605e853ae1db2cc94f7390ac776743b699b50b071b02bea6fe", size = 142012 }, - { url = "https://files.pythonhosted.org/packages/04/65/f2a03fd1d4f0308f01d372e004c049f7eb9bc5676763a15f20f383fa9c01/orjson-3.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3dcfbede6737fdbef3ce9c37af3fb6142e8e1ebc10336daa05872bfb1d87839c", size = 169920 }, - { url = "https://files.pythonhosted.org/packages/e2/1c/3ef8d83d7c6a619ad3d69a4d5318591b4ce5862e6eda7c26bbe8208652ca/orjson-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11748c135f281203f4ee695b7f80bb1358a82a63905f9f0b794769483ea854ad", size = 167916 }, - { url = "https://files.pythonhosted.org/packages/f2/0d/820a640e5a7dfbe525e789c70871ebb82aff73b0c7bf80082653f86b9431/orjson-3.10.7-cp313-none-win32.whl", hash = "sha256:a7e19150d215c7a13f39eb787d84db274298d3f83d85463e61d277bbd7f401d2", size = 143089 }, - { url = "https://files.pythonhosted.org/packages/1a/72/a424db9116c7cad2950a8f9e4aeb655a7b57de988eb015acd0fcd1b4609b/orjson-3.10.7-cp313-none-win_amd64.whl", hash = "sha256:eef44224729e9525d5261cc8d28d6b11cafc90e6bd0be2157bde69a52ec83024", size = 137081 }, + { url = "https://files.pythonhosted.org/packages/98/c7/07ca73c32d49550490572235e5000aa0d75e333997cbb3a221890ef0fa04/orjson-3.10.10-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b788a579b113acf1c57e0a68e558be71d5d09aa67f62ca1f68e01117e550a998", size = 270718 }, + { url = "https://files.pythonhosted.org/packages/4d/6e/eaefdfe4b11fd64b38f6663c71a3c9063054c8c643a52555c5b6d4350446/orjson-3.10.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:804b18e2b88022c8905bb79bd2cbe59c0cd014b9328f43da8d3b28441995cda4", size = 153292 }, + { url = "https://files.pythonhosted.org/packages/cf/87/94474cbf63306f196a0a85a2f3ea6cea261328b4141a260b7ec5e7145bc5/orjson-3.10.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9972572a1d042ec9ee421b6da69f7cc823da5962237563fa548ab17f152f0b9b", size = 168625 }, + { url = "https://files.pythonhosted.org/packages/0a/67/1a6bd763282bc89fcc0269e3a44a8ecbb236a1e4b6f5a6320301726b36a1/orjson-3.10.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc6993ab1c2ae7dd0711161e303f1db69062955ac2668181bfdf2dd410e65258", size = 155845 }, + { url = "https://files.pythonhosted.org/packages/ae/28/bb2dd7a988159896be9fa59ef4c991dca8cca9af85ebdc27164234929008/orjson-3.10.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d78e4cacced5781b01d9bc0f0cd8b70b906a0e109825cb41c1b03f9c41e4ce86", size = 166406 }, + { url = "https://files.pythonhosted.org/packages/e3/88/42199849c791b4b5b92fcace0e8ef178d5ae1ea9865dfd4d5809e650d652/orjson-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6eb2598df518281ba0cbc30d24c5b06124ccf7e19169e883c14e0831217a0bc", size = 144518 }, + { url = "https://files.pythonhosted.org/packages/c7/77/e684fe4ed34e73149bc0e7320b91a459386693279cd62efab6e82da072a3/orjson-3.10.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23776265c5215ec532de6238a52707048401a568f0fa0d938008e92a147fe2c7", size = 172184 }, + { url = "https://files.pythonhosted.org/packages/fa/b2/9dc2ed13121b27b9f99acba077c821ad2c0deff9feeb617efef4699fad35/orjson-3.10.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cc2a654c08755cef90b468ff17c102e2def0edd62898b2486767204a7f5cc9c", size = 170148 }, + { url = "https://files.pythonhosted.org/packages/86/0a/b06967f9374856f491f297a914c588eae97ef9490a77ec0e146a2e4bfe7f/orjson-3.10.10-cp310-none-win32.whl", hash = "sha256:081b3fc6a86d72efeb67c13d0ea7c030017bd95f9868b1e329a376edc456153b", size = 145116 }, + { url = "https://files.pythonhosted.org/packages/1f/c7/1aecf5e320828261ece0683e472ee77c520f4e6c52c468486862e2257962/orjson-3.10.10-cp310-none-win_amd64.whl", hash = "sha256:ff38c5fb749347768a603be1fb8a31856458af839f31f064c5aa74aca5be9efe", size = 139307 }, + { url = "https://files.pythonhosted.org/packages/79/bc/2a0eb0029729f1e466d5a595261446e5c5b6ed9213759ee56b6202f99417/orjson-3.10.10-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:879e99486c0fbb256266c7c6a67ff84f46035e4f8749ac6317cc83dacd7f993a", size = 270717 }, + { url = "https://files.pythonhosted.org/packages/3d/2b/5af226f183ce264bf64f15afe58647b09263dc1bde06aaadae6bbeca17f1/orjson-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:019481fa9ea5ff13b5d5d95e6fd5ab25ded0810c80b150c2c7b1cc8660b662a7", size = 153294 }, + { url = "https://files.pythonhosted.org/packages/1d/95/d6a68ab51ed76e3794669dabb51bf7fa6ec2f4745f66e4af4518aeab4b73/orjson-3.10.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0dd57eff09894938b4c86d4b871a479260f9e156fa7f12f8cad4b39ea8028bb5", size = 168628 }, + { url = "https://files.pythonhosted.org/packages/c0/c9/1bbe5262f5e9df3e1aeec44ca8cc86846c7afb2746fa76bf668a7d0979e9/orjson-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbde6d70cd95ab4d11ea8ac5e738e30764e510fc54d777336eec09bb93b8576c", size = 155845 }, + { url = "https://files.pythonhosted.org/packages/bf/22/e17b14ff74646e6c080dccb2859686a820bc6468f6b62ea3fe29a8bd3b05/orjson-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2625cb37b8fb42e2147404e5ff7ef08712099197a9cd38895006d7053e69d6", size = 166406 }, + { url = "https://files.pythonhosted.org/packages/8a/1e/b3abbe352f648f96a418acd1e602b1c77ffcc60cf801a57033da990b2c49/orjson-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbf3c20c6a7db69df58672a0d5815647ecf78c8e62a4d9bd284e8621c1fe5ccb", size = 144518 }, + { url = "https://files.pythonhosted.org/packages/0e/5e/28f521ee0950d279489db1522e7a2460d0596df7c5ca452e242ff1509cfe/orjson-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:75c38f5647e02d423807d252ce4528bf6a95bd776af999cb1fb48867ed01d1f6", size = 172187 }, + { url = "https://files.pythonhosted.org/packages/04/b4/538bf6f42eb0fd5a485abbe61e488d401a23fd6d6a758daefcf7811b6807/orjson-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23458d31fa50ec18e0ec4b0b4343730928296b11111df5f547c75913714116b2", size = 170152 }, + { url = "https://files.pythonhosted.org/packages/94/5c/a1a326a58452f9261972ad326ae3bb46d7945681239b7062a1b85d8811e2/orjson-3.10.10-cp311-none-win32.whl", hash = "sha256:2787cd9dedc591c989f3facd7e3e86508eafdc9536a26ec277699c0aa63c685b", size = 145116 }, + { url = "https://files.pythonhosted.org/packages/df/12/a02965df75f5a247091306d6cf40a77d20bf6c0490d0a5cb8719551ee815/orjson-3.10.10-cp311-none-win_amd64.whl", hash = "sha256:6514449d2c202a75183f807bc755167713297c69f1db57a89a1ef4a0170ee269", size = 139307 }, + { url = "https://files.pythonhosted.org/packages/21/c6/f1d2ec3ffe9d6a23a62af0477cd11dd2926762e0186a1fad8658a4f48117/orjson-3.10.10-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8564f48f3620861f5ef1e080ce7cd122ee89d7d6dacf25fcae675ff63b4d6e05", size = 270801 }, + { url = "https://files.pythonhosted.org/packages/52/01/eba0226efaa4d4be8e44d9685750428503a3803648878fa5607100a74f81/orjson-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bf161a32b479034098c5b81f2608f09167ad2fa1c06abd4e527ea6bf4837a9", size = 153221 }, + { url = "https://files.pythonhosted.org/packages/da/4b/a705f9d3ae4786955ee0ac840b20960add357e612f1b0a54883d1811fe1a/orjson-3.10.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b65c93617bcafa7f04b74ae8bc2cc214bd5cb45168a953256ff83015c6747d", size = 168590 }, + { url = "https://files.pythonhosted.org/packages/de/6c/eb405252e7d9ae9905a12bad582cfe37ef8ef18fdfee941549cb5834c7b2/orjson-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8e28406f97fc2ea0c6150f4c1b6e8261453318930b334abc419214c82314f85", size = 156052 }, + { url = "https://files.pythonhosted.org/packages/9f/e7/65a0461574078a38f204575153524876350f0865162faa6e6e300ecaa199/orjson-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4d0d9fe174cc7a5bdce2e6c378bcdb4c49b2bf522a8f996aa586020e1b96cee", size = 166562 }, + { url = "https://files.pythonhosted.org/packages/dd/99/85780be173e7014428859ba0211e6f2a8f8038ea6ebabe344b42d5daa277/orjson-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3be81c42f1242cbed03cbb3973501fcaa2675a0af638f8be494eaf37143d999", size = 144892 }, + { url = "https://files.pythonhosted.org/packages/ed/c0/c7c42a2daeb262da417f70064746b700786ee0811b9a5821d9d37543b29d/orjson-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65f9886d3bae65be026219c0a5f32dbbe91a9e6272f56d092ab22561ad0ea33b", size = 172093 }, + { url = "https://files.pythonhosted.org/packages/ad/9b/be8b3d3aec42aa47f6058482ace0d2ca3023477a46643d766e96281d5d31/orjson-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:730ed5350147db7beb23ddaf072f490329e90a1d059711d364b49fe352ec987b", size = 170424 }, + { url = "https://files.pythonhosted.org/packages/1b/15/a4cc61e23c39b9dec4620cb95817c83c84078be1771d602f6d03f0e5c696/orjson-3.10.10-cp312-none-win32.whl", hash = "sha256:a8f4bf5f1c85bea2170800020d53a8877812892697f9c2de73d576c9307a8a5f", size = 145132 }, + { url = "https://files.pythonhosted.org/packages/9f/8a/ce7c28e4ea337f6d95261345d7c61322f8561c52f57b263a3ad7025984f4/orjson-3.10.10-cp312-none-win_amd64.whl", hash = "sha256:384cd13579a1b4cd689d218e329f459eb9ddc504fa48c5a83ef4889db7fd7a4f", size = 139389 }, + { url = "https://files.pythonhosted.org/packages/0c/69/f1c4382cd44bdaf10006c4e82cb85d2bcae735369f84031e203c4e5d87de/orjson-3.10.10-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44bffae68c291f94ff5a9b4149fe9d1bdd4cd0ff0fb575bcea8351d48db629a1", size = 270695 }, + { url = "https://files.pythonhosted.org/packages/61/29/aeb5153271d4953872b06ed239eb54993a5f344353727c42d3aabb2046f6/orjson-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e27b4c6437315df3024f0835887127dac2a0a3ff643500ec27088d2588fa5ae1", size = 141632 }, + { url = "https://files.pythonhosted.org/packages/bc/a2/c8ac38d8fb461a9b717c766fbe1f7d3acf9bde2f12488eb13194960782e4/orjson-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca84df16d6b49325a4084fd8b2fe2229cb415e15c46c529f868c3387bb1339d", size = 144854 }, + { url = "https://files.pythonhosted.org/packages/79/51/e7698fdb28bdec633888cc667edc29fd5376fce9ade0a5b3e22f5ebe0343/orjson-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c14ce70e8f39bd71f9f80423801b5d10bf93d1dceffdecd04df0f64d2c69bc01", size = 172023 }, + { url = "https://files.pythonhosted.org/packages/02/2d/0d99c20878658c7e33b90e6a4bb75cf2924d6ff29c2365262cff3c26589a/orjson-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:24ac62336da9bda1bd93c0491eff0613003b48d3cb5d01470842e7b52a40d5b4", size = 170429 }, + { url = "https://files.pythonhosted.org/packages/cd/45/6a4a446f4fb29bb4703c3537d5c6a2bf7fed768cb4d7b7dce9d71b72fc93/orjson-3.10.10-cp313-none-win32.whl", hash = "sha256:eb0a42831372ec2b05acc9ee45af77bcaccbd91257345f93780a8e654efc75db", size = 145099 }, + { url = "https://files.pythonhosted.org/packages/72/6e/4631fe219a4203aa111e9bb763ad2e2e0cdd1a03805029e4da124d96863f/orjson-3.10.10-cp313-none-win_amd64.whl", hash = "sha256:f0c4f37f8bf3f1075c6cc8dd8a9f843689a4b618628f8812d0a71e6968b95ffd", size = 139176 }, ] [[package]] @@ -3025,57 +3139,65 @@ version = "11.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, - { url = "https://files.pythonhosted.org/packages/a7/62/c9449f9c3043c37f73e7487ec4ef0c03eb9c9afc91a92b977a67b3c0bbc5/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c", size = 3509265 }, - { url = "https://files.pythonhosted.org/packages/f4/5f/491dafc7bbf5a3cc1845dc0430872e8096eb9e2b6f8161509d124594ec2d/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be", size = 3375655 }, - { url = "https://files.pythonhosted.org/packages/73/d5/c4011a76f4207a3c151134cd22a1415741e42fa5ddecec7c0182887deb3d/pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3", size = 4340304 }, - { url = "https://files.pythonhosted.org/packages/ac/10/c67e20445a707f7a610699bba4fe050583b688d8cd2d202572b257f46600/pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6", size = 4452804 }, - { url = "https://files.pythonhosted.org/packages/a9/83/6523837906d1da2b269dee787e31df3b0acb12e3d08f024965a3e7f64665/pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe", size = 4365126 }, - { url = "https://files.pythonhosted.org/packages/ba/e5/8c68ff608a4203085158cff5cc2a3c534ec384536d9438c405ed6370d080/pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319", size = 4533541 }, - { url = "https://files.pythonhosted.org/packages/f4/7c/01b8dbdca5bc6785573f4cee96e2358b0918b7b2c7b60d8b6f3abf87a070/pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d", size = 4471616 }, - { url = "https://files.pythonhosted.org/packages/c8/57/2899b82394a35a0fbfd352e290945440e3b3785655a03365c0ca8279f351/pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696", size = 4600802 }, - { url = "https://files.pythonhosted.org/packages/4d/d7/a44f193d4c26e58ee5d2d9db3d4854b2cfb5b5e08d360a5e03fe987c0086/pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496", size = 2235213 }, - { url = "https://files.pythonhosted.org/packages/c1/d0/5866318eec2b801cdb8c82abf190c8343d8a1cd8bf5a0c17444a6f268291/pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91", size = 2554498 }, - { url = "https://files.pythonhosted.org/packages/d4/c8/310ac16ac2b97e902d9eb438688de0d961660a87703ad1561fd3dfbd2aa0/pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22", size = 2243219 }, - { url = "https://files.pythonhosted.org/packages/05/cb/0353013dc30c02a8be34eb91d25e4e4cf594b59e5a55ea1128fde1e5f8ea/pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", size = 3509350 }, - { url = "https://files.pythonhosted.org/packages/e7/cf/5c558a0f247e0bf9cec92bff9b46ae6474dd736f6d906315e60e4075f737/pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", size = 3374980 }, - { url = "https://files.pythonhosted.org/packages/84/48/6e394b86369a4eb68b8a1382c78dc092245af517385c086c5094e3b34428/pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", size = 4343799 }, - { url = "https://files.pythonhosted.org/packages/3b/f3/a8c6c11fa84b59b9df0cd5694492da8c039a24cd159f0f6918690105c3be/pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", size = 4459973 }, - { url = "https://files.pythonhosted.org/packages/7d/1b/c14b4197b80150fb64453585247e6fb2e1d93761fa0fa9cf63b102fde822/pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", size = 4370054 }, - { url = "https://files.pythonhosted.org/packages/55/77/40daddf677897a923d5d33329acd52a2144d54a9644f2a5422c028c6bf2d/pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", size = 4539484 }, - { url = "https://files.pythonhosted.org/packages/40/54/90de3e4256b1207300fb2b1d7168dd912a2fb4b2401e439ba23c2b2cabde/pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", size = 4477375 }, - { url = "https://files.pythonhosted.org/packages/13/24/1bfba52f44193860918ff7c93d03d95e3f8748ca1de3ceaf11157a14cf16/pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", size = 4608773 }, - { url = "https://files.pythonhosted.org/packages/55/04/5e6de6e6120451ec0c24516c41dbaf80cce1b6451f96561235ef2429da2e/pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", size = 2235690 }, - { url = "https://files.pythonhosted.org/packages/74/0a/d4ce3c44bca8635bd29a2eab5aa181b654a734a29b263ca8efe013beea98/pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", size = 2554951 }, - { url = "https://files.pythonhosted.org/packages/b5/ca/184349ee40f2e92439be9b3502ae6cfc43ac4b50bc4fc6b3de7957563894/pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", size = 2243427 }, - { url = "https://files.pythonhosted.org/packages/c3/00/706cebe7c2c12a6318aabe5d354836f54adff7156fd9e1bd6c89f4ba0e98/pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3", size = 3525685 }, - { url = "https://files.pythonhosted.org/packages/cf/76/f658cbfa49405e5ecbfb9ba42d07074ad9792031267e782d409fd8fe7c69/pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb", size = 3374883 }, - { url = "https://files.pythonhosted.org/packages/46/2b/99c28c4379a85e65378211971c0b430d9c7234b1ec4d59b2668f6299e011/pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70", size = 4339837 }, - { url = "https://files.pythonhosted.org/packages/f1/74/b1ec314f624c0c43711fdf0d8076f82d9d802afd58f1d62c2a86878e8615/pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be", size = 4455562 }, - { url = "https://files.pythonhosted.org/packages/4a/2a/4b04157cb7b9c74372fa867096a1607e6fedad93a44deeff553ccd307868/pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0", size = 4366761 }, - { url = "https://files.pythonhosted.org/packages/ac/7b/8f1d815c1a6a268fe90481232c98dd0e5fa8c75e341a75f060037bd5ceae/pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc", size = 4536767 }, - { url = "https://files.pythonhosted.org/packages/e5/77/05fa64d1f45d12c22c314e7b97398ffb28ef2813a485465017b7978b3ce7/pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a", size = 4477989 }, - { url = "https://files.pythonhosted.org/packages/12/63/b0397cfc2caae05c3fb2f4ed1b4fc4fc878f0243510a7a6034ca59726494/pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309", size = 4610255 }, - { url = "https://files.pythonhosted.org/packages/7b/f9/cfaa5082ca9bc4a6de66ffe1c12c2d90bf09c309a5f52b27759a596900e7/pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060", size = 2235603 }, - { url = "https://files.pythonhosted.org/packages/01/6a/30ff0eef6e0c0e71e55ded56a38d4859bf9d3634a94a88743897b5f96936/pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea", size = 2554972 }, - { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375 }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, + { url = "https://files.pythonhosted.org/packages/98/fb/a6ce6836bd7fd93fbf9144bf54789e02babc27403b50a9e1583ee877d6da/pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947", size = 3154708 }, + { url = "https://files.pythonhosted.org/packages/6a/1d/1f51e6e912d8ff316bb3935a8cda617c801783e0b998bf7a894e91d3bd4c/pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba", size = 2979223 }, + { url = "https://files.pythonhosted.org/packages/90/83/e2077b0192ca8a9ef794dbb74700c7e48384706467067976c2a95a0f40a1/pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086", size = 4183167 }, + { url = "https://files.pythonhosted.org/packages/0e/74/467af0146970a98349cdf39e9b79a6cc8a2e7558f2c01c28a7b6b85c5bda/pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9", size = 4283912 }, + { url = "https://files.pythonhosted.org/packages/85/b1/d95d4f7ca3a6c1ae120959605875a31a3c209c4e50f0029dc1a87566cf46/pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488", size = 4195815 }, + { url = "https://files.pythonhosted.org/packages/41/c3/94f33af0762ed76b5a237c5797e088aa57f2b7fa8ee7932d399087be66a8/pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f", size = 4366117 }, + { url = "https://files.pythonhosted.org/packages/ba/3c/443e7ef01f597497268899e1cca95c0de947c9bbf77a8f18b3c126681e5d/pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb", size = 4278607 }, + { url = "https://files.pythonhosted.org/packages/26/95/1495304448b0081e60c0c5d63f928ef48bb290acee7385804426fa395a21/pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97", size = 4410685 }, + { url = "https://files.pythonhosted.org/packages/45/da/861e1df971ef0de9870720cb309ca4d553b26a9483ec9be3a7bf1de4a095/pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50", size = 2249185 }, + { url = "https://files.pythonhosted.org/packages/d5/4e/78f7c5202ea2a772a5ab05069c1b82503e6353cd79c7e474d4945f4b82c3/pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c", size = 2566726 }, + { url = "https://files.pythonhosted.org/packages/77/e4/6e84eada35cbcc646fc1870f72ccfd4afacb0fae0c37ffbffe7f5dc24bf1/pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1", size = 2254585 }, + { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, + { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, + { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, + { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, + { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, + { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, + { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, + { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, + { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, + { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, + { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, + { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, + { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, + { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, + { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, + { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, + { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, + { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, + { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, + { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, + { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, + { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, + { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, + { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, + { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, + { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, + { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, + { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, + { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, + { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, + { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, + { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, + { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, + { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, + { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, + { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, + { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, + { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, + { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, + { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, + { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, + { url = "https://files.pythonhosted.org/packages/36/57/42a4dd825eab762ba9e690d696d894ba366e06791936056e26e099398cda/pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2", size = 3119239 }, + { url = "https://files.pythonhosted.org/packages/98/f7/25f9f9e368226a1d6cf3507081a1a7944eddd3ca7821023377043f5a83c8/pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2", size = 2950803 }, + { url = "https://files.pythonhosted.org/packages/59/01/98ead48a6c2e31e6185d4c16c978a67fe3ccb5da5c2ff2ba8475379bb693/pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b", size = 3281098 }, + { url = "https://files.pythonhosted.org/packages/51/c0/570255b2866a0e4d500a14f950803a2ec273bac7badc43320120b9262450/pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2", size = 3323665 }, + { url = "https://files.pythonhosted.org/packages/0e/75/689b4ec0483c42bfc7d1aacd32ade7a226db4f4fac57c6fdcdf90c0731e3/pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830", size = 3310533 }, + { url = "https://files.pythonhosted.org/packages/3d/30/38bd6149cf53da1db4bad304c543ade775d225961c4310f30425995cb9ec/pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734", size = 3414886 }, + { url = "https://files.pythonhosted.org/packages/ec/3d/c32a51d848401bd94cabb8767a39621496491ee7cd5199856b77da9b18ad/pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316", size = 2567508 }, ] [[package]] @@ -3260,6 +3382,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 }, { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 }, { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 }, + { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 }, + { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 }, + { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 }, + { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 }, + { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 }, + { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 }, + { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 }, + { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 }, + { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 }, + { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 }, + { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 }, + { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 }, + { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 }, + { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 }, + { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 }, + { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 }, { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 }, ] @@ -3295,15 +3433,13 @@ version = "6.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/66/78c9c3020f573c58101dc43a44f6855d01bbbd747e24da2f0c4491200ea3/psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35", size = 249766 }, - { url = "https://files.pythonhosted.org/packages/e1/3f/2403aa9558bea4d3854b0e5e567bc3dd8e9fbc1fc4453c0aa9aafeb75467/psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1", size = 253024 }, - { url = "https://files.pythonhosted.org/packages/0b/37/f8da2fbd29690b3557cca414c1949f92162981920699cd62095a984983bf/psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0", size = 250961 }, - { url = "https://files.pythonhosted.org/packages/35/56/72f86175e81c656a01c4401cd3b1c923f891b31fbcebe98985894176d7c9/psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0", size = 287478 }, - { url = "https://files.pythonhosted.org/packages/19/74/f59e7e0d392bc1070e9a70e2f9190d652487ac115bb16e2eff6b22ad1d24/psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd", size = 290455 }, - { url = "https://files.pythonhosted.org/packages/cd/5f/60038e277ff0a9cc8f0c9ea3d0c5eb6ee1d2470ea3f9389d776432888e47/psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132", size = 292046 }, - { url = "https://files.pythonhosted.org/packages/8b/20/2ff69ad9c35c3df1858ac4e094f20bd2374d33c8643cf41da8fd7cdcb78b/psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d", size = 253560 }, - { url = "https://files.pythonhosted.org/packages/73/44/561092313ae925f3acfaace6f9ddc4f6a9c748704317bad9c8c8f8a36a79/psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3", size = 257399 }, - { url = "https://files.pythonhosted.org/packages/7c/06/63872a64c312a24fb9b4af123ee7007a306617da63ff13bcc1432386ead7/psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0", size = 251988 }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, ] [[package]] @@ -3332,50 +3468,50 @@ name = "psycopg-binary" version = "3.2.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/42/f5a181d07c0ae5c8091449fda45d562d3b0861c127b94d7009eaea45c61f/psycopg_binary-3.2.2-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:8eacbf58d4f8d7bc82e0a60476afa2622b5a58f639a3cc2710e3e37b72aff3cb", size = 3381668 }, - { url = "https://files.pythonhosted.org/packages/ce/fb/66d2e3e5d550ba3b9d33e30bf6d5beb871a85eb95553c851fce7f09f8a1e/psycopg_binary-3.2.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:d07e62476ee8c54853b2b8cfdf3858a574218103b4cd213211f64326c7812437", size = 3502272 }, - { url = "https://files.pythonhosted.org/packages/f0/8d/758da39eca57f046ee712ad4c310840bcc08d889042d1b297cd28c78e909/psycopg_binary-3.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c22e615ee0ecfc6687bb8a39a4ed9d6bac030b5e72ac15e7324fd6e48979af71", size = 4467251 }, - { url = "https://files.pythonhosted.org/packages/91/bb/1abb1ccc318eb878acf9637479334de7406529516126e4af48b16dd85426/psycopg_binary-3.2.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec29c7ec136263628e3f09a53e51d0a4b1ad765a6e45135707bfa848b39113f9", size = 4268614 }, - { url = "https://files.pythonhosted.org/packages/f5/1a/14b4ae68f1c7cfba543883987d2f134eca31b0983bb684a52e0f51f3ac21/psycopg_binary-3.2.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:035753f80cbbf6aceca6386f53e139df70c7aca057b0592711047b5a8cfef8bb", size = 4512352 }, - { url = "https://files.pythonhosted.org/packages/12/44/53df01c7c7cffb351cafa88c58692fab0ab962edd89f22974cbfc38b6677/psycopg_binary-3.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9ee99336151ff7c30682f2ef9cb1174d235bc1471322faabba97f9db1398167", size = 4212477 }, - { url = "https://files.pythonhosted.org/packages/b7/31/c918927692fc5a9c4db0a7c454e1595e9d40378d5c526d26505f310e4068/psycopg_binary-3.2.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a60674dff4a4194e88312b463fb84ac80924c2b9e25d0e0460f3176bf1af4a6b", size = 3137907 }, - { url = "https://files.pythonhosted.org/packages/cb/65/538aa057b3e8245a31ea8baac93df9947ee1b2ebf4c02014a556cddd875e/psycopg_binary-3.2.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3c701507a49340de422d77a6ce95918a0019990bbf27daec35aa40050c6eadb6", size = 3113363 }, - { url = "https://files.pythonhosted.org/packages/dc/81/eaee4f05bcba19984615e90319c429d125d07e5f0fe8c8ec3025901de4df/psycopg_binary-3.2.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1b3c5a04eaf8866e399315cff2e810260cce10b797437a9f49fd71b5f4b94d0a", size = 3220512 }, - { url = "https://files.pythonhosted.org/packages/48/cc/1d0f82a47216f925e36be6f6d7be61984a5168ff8c0496c57f468cc0e219/psycopg_binary-3.2.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0ad9c09de4c262f516ae6891d042a4325649b18efa39dd82bbe0f7bc95c37bfb", size = 3255023 }, - { url = "https://files.pythonhosted.org/packages/d0/29/c45760ba6218eae37474aa5f46c1f55b290a6d4b86c0c59e60fa5613257a/psycopg_binary-3.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:bf1d3582185cb43ecc27403bee2f5405b7a45ccaab46c8508d9a9327341574fc", size = 2921688 }, - { url = "https://files.pythonhosted.org/packages/1f/1a/76299ad86a01f57a67961c4a45ce06c6eb8e76b8bc7bfb92548c62a6fa72/psycopg_binary-3.2.2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:554d208757129d34fa47b7c890f9ef922f754e99c6b089cb3a209aa0fe282682", size = 3390336 }, - { url = "https://files.pythonhosted.org/packages/c2/1d/04fbcadd568eb0ee04b0d99286fe4ffd6c76c9cdd130e58d477617b77941/psycopg_binary-3.2.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:71dc3cc10d1fd7d26a3079d0a5b4a8e8ad0d7b89a702ceb7605a52e4395be122", size = 3507406 }, - { url = "https://files.pythonhosted.org/packages/60/00/094a437f68d83fef4dd139630dfb0e060fcf2a7ac68fffdb63b2f3eaa43a/psycopg_binary-3.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86f578d63f2e1fdf87c9adaed4ff23d7919bda8791cf1380fa4cf3a857ccb8b", size = 4463745 }, - { url = "https://files.pythonhosted.org/packages/ea/de/0303e807a33251dec41aec709c3041b9ffd86b67d997088c504a24e90ba3/psycopg_binary-3.2.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a4eb737682c02a602a12aa85a492608066f77793dab681b1c4e885fedc160b1", size = 4263212 }, - { url = "https://files.pythonhosted.org/packages/3f/0d/8fa059bd936bb8e95164cc549d2eaaeaeb7df3a069bbb0ea01b48fab10a4/psycopg_binary-3.2.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e120a576e74e4e612c48f4b021e322e320ca102534d78a0ca4db2ffd058ae8d", size = 4513242 }, - { url = "https://files.pythonhosted.org/packages/1f/a5/9904c4ae040eef6cdb81c04e43b834302cfd3e47ee7cab8878d114abb168/psycopg_binary-3.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:849d518e7d4c6186e1e48ea2ac2671912edf7e732fffe6f01dfed61cf0245de4", size = 4207852 }, - { url = "https://files.pythonhosted.org/packages/07/b7/24438b2ecb3ae8ceea44cf6e2bb92baac6be9b3d92c2940c89b3aa8e520e/psycopg_binary-3.2.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ee2b19152bcec8f356f989c31768702be5f139b4d51094273c4a9ddc8c55380", size = 3134053 }, - { url = "https://files.pythonhosted.org/packages/83/e3/d0157858ad814cdc6cf9f9b7543c736f6b56ab9d8dc1b4ca56908ec03586/psycopg_binary-3.2.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:00273dd011892e8216fcef76b42f775ddaa6348664a7fffae2a27c9557f45bfa", size = 3110817 }, - { url = "https://files.pythonhosted.org/packages/9f/fc/8554c822a80a08cd17b9e2a4e8fc098c940e972e01bc9e3f3774b9e02d54/psycopg_binary-3.2.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4bcb489615d7e56d1de42937e6a0fc13f766505729afdb54c2947a52db295220", size = 3214760 }, - { url = "https://files.pythonhosted.org/packages/6a/4d/a12d8a301fbd4416ebdb3f019c777a17edea0452278f630f83237cbcc3d4/psycopg_binary-3.2.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:06963f88916a177df95aaed27101af0989ba206654743b1a0e050b9d8e734686", size = 3253951 }, - { url = "https://files.pythonhosted.org/packages/09/0f/120b190ddaf6afed1eaa2fbc89e29ec810d8af44ff3599521f69f89b64b3/psycopg_binary-3.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:ed1ad836a0c21890c7f84e73c7ef1ed0950e0e4b0d8e49b609b6fd9c13f2ca21", size = 2924949 }, - { url = "https://files.pythonhosted.org/packages/1e/9a/68b76a795fe620c8848c758d12860b8b94998f374882dbf8ea4bc343b9e1/psycopg_binary-3.2.2-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:0dd314229885a81f9497875295d8788e651b78945627540f1e78ed71595e614a", size = 3361334 }, - { url = "https://files.pythonhosted.org/packages/0d/0c/f91242672c58bce7c290e11128569fe66ed27552388499cd80d75a5d4d0d/psycopg_binary-3.2.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:989acbe2f552769cdb780346cea32d86e7c117044238d5172ac10b025fe47194", size = 3504380 }, - { url = "https://files.pythonhosted.org/packages/e4/45/5fa47240357dea3646f3492d20141a5869cfaedcd5c64499622db7b17a8f/psycopg_binary-3.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566b1c530898590f0ac9d949cf94351c08d73c89f8800c74c0a63ffd89a383c8", size = 4443783 }, - { url = "https://files.pythonhosted.org/packages/ee/e5/9da098d1f7c1b064b39a2499cb4dfebe8fa5a48a132c3f544dab994199c4/psycopg_binary-3.2.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68d03efab7e2830a0df3aa4c29a708930e3f6b9fd98774ff9c4fd1f33deafecc", size = 4247070 }, - { url = "https://files.pythonhosted.org/packages/ba/44/c905a0ce2c66c0250a4ddce8eef41edc728bd2055ecaf8bd23468110c3f4/psycopg_binary-3.2.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e1f013bfb744023df23750fde51edcb606def8328473361db3c192c392c6060", size = 4483735 }, - { url = "https://files.pythonhosted.org/packages/30/2d/9f6bfcff78b643d220e088d91103fde70d193b9745d8999c7654ad45cd65/psycopg_binary-3.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a06136aab55a2de7dd4e2555badae276846827cfb023e6ba1b22f7a7b88e3f1b", size = 4186284 }, - { url = "https://files.pythonhosted.org/packages/44/48/79e7886a28818fdb4d5d39a86b5769bb33681ac23efe23accdaab42514c6/psycopg_binary-3.2.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:020c5154be144a1440cf87eae012b9004fb414ae4b9e7b1b9fb808fe39e96e83", size = 3110593 }, - { url = "https://files.pythonhosted.org/packages/5c/93/83d5610d259feb1d4d2d37cc0e1781f0d1632c885f5e2f85808b5b196552/psycopg_binary-3.2.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ef341c556aeaa43a2729b07b04e20bfffdcf3d96c4a96e728ca94fe4ce632d8c", size = 3095074 }, - { url = "https://files.pythonhosted.org/packages/b6/94/3126db7a06fa9fe2ab3b1d6dd7a4add6bc1596b6864e01a77239702827b4/psycopg_binary-3.2.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66de2dd7d37bf66eb234ca9d907f5cd8caca43ff8d8a50dd5c15844d1cf0390c", size = 3184181 }, - { url = "https://files.pythonhosted.org/packages/6c/0e/6cce5ffaa25a25ede5ff08e757232bb425cacafe622627f29d286774073b/psycopg_binary-3.2.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2eb6f8f410dbbb71b8c633f283b8588b63bee0a7321f00ab76e9c800c593f732", size = 3229942 }, - { url = "https://files.pythonhosted.org/packages/10/31/951247b07205711115307f36ec3dbf6726101e086562febf6f989cbd6b95/psycopg_binary-3.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:b45553c6b614d02e1486585980afdfd18f0000aac668e2e87c6e32da1adb051a", size = 2912528 }, - { url = "https://files.pythonhosted.org/packages/87/e5/245f749abdfc33b42ec2bc4d89fe2cdb29cd40dca7156d0e09308c33f933/psycopg_binary-3.2.2-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:1ee891287c2da57e7fee31fbe2fbcdf57125768133d811b02e9523d5a052eb28", size = 3358682 }, - { url = "https://files.pythonhosted.org/packages/93/dc/047a90e2bfd80a8414f5a203c7ff1747e3b3f43231c3c8059e8be91849cc/psycopg_binary-3.2.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5e95e4a8076ac7611e571623e1113fa84fd48c0459601969ffbf534d7aa236e7", size = 3500354 }, - { url = "https://files.pythonhosted.org/packages/df/72/b905dec41c30a8aad21f7767b21d3e5d3b9a7e92c1844678e4083d79257b/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6269d79a3d7d76b6fcf0fafae8444da00e83777a6c68c43851351a571ad37155", size = 4445322 }, - { url = "https://files.pythonhosted.org/packages/aa/41/aef11d4cda1af4a8181fbd578af39d6920232624fc6222f6b2f9758cc0e0/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6dd5d21a298c3c53af20ced8da4ae4cd038c6fe88c80842a8888fa3660b2094", size = 4248626 }, - { url = "https://files.pythonhosted.org/packages/6c/75/39ed8598f44188e4985f31f2639aa9894851fdfbf061bf926744b08b5790/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cf64e41e238620f05aad862f06bc8424f8f320d8075f1499bd85a225d18bd57", size = 4485767 }, - { url = "https://files.pythonhosted.org/packages/00/5a/ecdc4cf957d0658f77cc6fa61f6ee2e5118c914e5f93497375023389a1e5/psycopg_binary-3.2.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c482c3236ded54add31136a91d5223b233ec301f297fa2db79747404222dca6", size = 4188840 }, - { url = "https://files.pythonhosted.org/packages/2d/71/af4c47a665d13d2477085f77fb64195da5d6463dd54fc3a8bdfd5c082d24/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0718be095cefdad712542169d16fa58b3bd9200a3de1b0217ae761cdec1cf569", size = 3114998 }, - { url = "https://files.pythonhosted.org/packages/38/8f/6d56168d2ce7e7d802e09a4288faceb52f28bd4023cde72ede9e848c9f9b/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fb303b03c243a9041e1873b596e246f7caaf01710b312fafa65b1db5cd77dd6f", size = 3095882 }, - { url = "https://files.pythonhosted.org/packages/8b/76/c77643d97292673d8a5e3eea643812d585993155658f840c86bfa855e077/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:705da5bc4364bd7529473225fca02b795653bc5bd824dbe43e1df0b1a40fe691", size = 3189435 }, - { url = "https://files.pythonhosted.org/packages/30/31/b4ea793bdf44acca51e3fa6f68cc80d03725e8ef87fc2ee2b332c49fa521/psycopg_binary-3.2.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:05406b96139912574571b1c56bb023839a9146cf4b57c4548f36251dd5909fa1", size = 3233951 }, - { url = "https://files.pythonhosted.org/packages/49/e3/633d6d05e40651acb30458e296c90e878fa4caf3b3c21bb9e6adc912b811/psycopg_binary-3.2.2-cp313-cp313-win_amd64.whl", hash = "sha256:7c357cf87e8d7612cfe781225be7669f35038a765d1b53ec9605f6c5aef9ee85", size = 2913412 }, + { url = "https://files.pythonhosted.org/packages/64/1c/1fc9d53844c15059b98b27d7037a8af87e43832e367c88c8ee43b8bb650f/psycopg_binary-3.2.3-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:965455eac8547f32b3181d5ec9ad8b9be500c10fe06193543efaaebe3e4ce70c", size = 3383146 }, + { url = "https://files.pythonhosted.org/packages/fb/80/0d0eca43756578738a14f747b3d27e8e22ba468765071eaf61cd517c52a3/psycopg_binary-3.2.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:71adcc8bc80a65b776510bc39992edf942ace35b153ed7a9c6c573a6849ce308", size = 3504185 }, + { url = "https://files.pythonhosted.org/packages/7c/02/1db86752a2a663cf59d410374e9aced220d1a883a64b7256ed1171685a27/psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f73adc05452fb85e7a12ed3f69c81540a8875960739082e6ea5e28c373a30774", size = 4469268 }, + { url = "https://files.pythonhosted.org/packages/59/04/b8cbc84f494247fa887dcc5cba15f99d261dc44b94fbb10fdaa44c4d6dac/psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8630943143c6d6ca9aefc88bbe5e76c90553f4e1a3b2dc339e67dc34aa86f7e", size = 4270625 }, + { url = "https://files.pythonhosted.org/packages/74/94/851a58aeab1e2aa30a564133f84229242b2fc774eabb3fc5c164b2423dcd/psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bffb61e198a91f712cc3d7f2d176a697cb05b284b2ad150fb8edb308eba9002", size = 4515573 }, + { url = "https://files.pythonhosted.org/packages/5a/95/e3e600687e59df7d5214e81d9aa2d324f2c5dece32068d66b03a4fd6edf6/psycopg_binary-3.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc4fa2240c9fceddaa815a58f29212826fafe43ce80ff666d38c4a03fb036955", size = 4214078 }, + { url = "https://files.pythonhosted.org/packages/2e/1e/4b50e1a2c35a7ee1fc65f8a5fed36026c16b05c9549dc4247914dfbfa2f5/psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:192a5f8496e6e1243fdd9ac20e117e667c0712f148c5f9343483b84435854c78", size = 3139319 }, + { url = "https://files.pythonhosted.org/packages/a0/bb/fc88304a7b759d87ad79f538f1b605c23802f36963d207b6e8e9062a57bd/psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64dc6e9ec64f592f19dc01a784e87267a64a743d34f68488924251253da3c818", size = 3118977 }, + { url = "https://files.pythonhosted.org/packages/92/19/88e14b615291b472b616bb3078206eac63dd6cb806c79b12119b7c39e519/psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:79498df398970abcee3d326edd1d4655de7d77aa9aecd578154f8af35ce7bbd2", size = 3224533 }, + { url = "https://files.pythonhosted.org/packages/98/cd/6cedff641f1ffb7008b6c511233814d2934df8caf2ec93c50412c37e5f91/psycopg_binary-3.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:949551752930d5e478817e0b49956350d866b26578ced0042a61967e3fcccdea", size = 3258089 }, + { url = "https://files.pythonhosted.org/packages/31/2c/8059fbcd513d4b7c9e25dd93c438ab174e8ce389b85d8432b4ce3c0e8958/psycopg_binary-3.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:80a2337e2dfb26950894c8301358961430a0304f7bfe729d34cc036474e9c9b1", size = 2921689 }, + { url = "https://files.pythonhosted.org/packages/3d/78/8e8b4063b5cd1cc91cc100fc3e9296b96f52c9a709750b24ade6cfa8021b/psycopg_binary-3.2.3-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:6d8f2144e0d5808c2e2aed40fbebe13869cd00c2ae745aca4b3b16a435edb056", size = 3391535 }, + { url = "https://files.pythonhosted.org/packages/36/7f/04eed0c415d158a0fb1c196957b9c7faec43c7b50d20db05c62e5bd22c93/psycopg_binary-3.2.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94253be2b57ef2fea7ffe08996067aabf56a1eb9648342c9e3bad9e10c46e045", size = 3509175 }, + { url = "https://files.pythonhosted.org/packages/0d/91/042fe504220a6e1a423e6a26d24f198da976b9cce11bc9ab7e9415bac08f/psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fda0162b0dbfa5eaed6cdc708179fa27e148cb8490c7d62e5cf30713909658ea", size = 4465647 }, + { url = "https://files.pythonhosted.org/packages/35/7c/4cf02ee263431b306453b7b086ec8e91dcbd5008382d711e82afa829f73e/psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c0419cdad8c70eaeb3116bb28e7b42d546f91baf5179d7556f230d40942dc78", size = 4267051 }, + { url = "https://files.pythonhosted.org/packages/f5/9b/cea713d8d75621481ece2dfc7edae6e4f05dfbcaab28fac0dbff9b96fc3a/psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74fbf5dd3ef09beafd3557631e282f00f8af4e7a78fbfce8ab06d9cd5a789aae", size = 4517398 }, + { url = "https://files.pythonhosted.org/packages/56/65/cd4165c45359f4117147b861c16c7b85afbd93cc9efac6116b13f62bc725/psycopg_binary-3.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d784f614e4d53050cbe8abf2ae9d1aaacf8ed31ce57b42ce3bf2a48a66c3a5c", size = 4210644 }, + { url = "https://files.pythonhosted.org/packages/f3/80/14e7bf67613c4344e74fe6ac5c9876a7acb4ddc15e5455c54e24cdc087f8/psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4e76ce2475ed4885fe13b8254058be710ec0de74ebd8ef8224cf44a9a3358e5f", size = 3138032 }, + { url = "https://files.pythonhosted.org/packages/7e/81/e18c36de78e0f7a491a754dc74c1bb6b16469d8c240b2add1e856801d567/psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5938b257b04c851c2d1e6cb2f8c18318f06017f35be9a5fe761ee1e2e344dfb7", size = 3114329 }, + { url = "https://files.pythonhosted.org/packages/48/39/07b0bf8355cb535ccdd58261a18fb6e786e175492363f5255b446fff6427/psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:257c4aea6f70a9aef39b2a77d0658a41bf05c243e2bf41895eb02220ac6306f3", size = 3219579 }, + { url = "https://files.pythonhosted.org/packages/64/ea/92c700989b5bdeb8e8e59732191547e32da732692d6c016830c82f9b4ac7/psycopg_binary-3.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:06b5cc915e57621eebf2393f4173793ed7e3387295f07fed93ed3fb6a6ccf585", size = 3257145 }, + { url = "https://files.pythonhosted.org/packages/84/49/39f0875fd32a6d77cd22b44887df39eb470039b389c388cee4ba75c0bda7/psycopg_binary-3.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:09baa041856b35598d335b1a74e19a49da8500acedf78164600694c0ba8ce21b", size = 2924948 }, + { url = "https://files.pythonhosted.org/packages/55/6b/9805a5c743c1d54dcd035bd5c069202fde21b4cf69857ca40c2a55e69f8c/psycopg_binary-3.2.3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:48f8ca6ee8939bab760225b2ab82934d54330eec10afe4394a92d3f2a0c37dd6", size = 3363376 }, + { url = "https://files.pythonhosted.org/packages/a8/82/45ac156b20e08e8f556a323c9568a011c71cf6e734e49667a398719ce0e4/psycopg_binary-3.2.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5361ea13c241d4f0ec3f95e0bf976c15e2e451e9cc7ef2e5ccfc9d170b197a40", size = 3506449 }, + { url = "https://files.pythonhosted.org/packages/e4/be/760cef50e1adfbc87dab2b05b30f544d7297040cce495835df9016556517/psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb987f14af7da7c24f803111dbc7392f5070fd350146af3345103f76ea82e339", size = 4445757 }, + { url = "https://files.pythonhosted.org/packages/b4/9c/bae6a9c6949aac577cc93f58705f649b50c62827038903bd75ff8956e63e/psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0463a11b1cace5a6aeffaf167920707b912b8986a9c7920341c75e3686277920", size = 4248376 }, + { url = "https://files.pythonhosted.org/packages/e5/0e/9db06ef94e4a156f3ed06043ee4f370e21866b0e3b7959691c8c4abfb698/psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b7be9a6c06518967b641fb15032b1ed682fd3b0443f64078899c61034a0bca6", size = 4487765 }, + { url = "https://files.pythonhosted.org/packages/9f/5f/8afc32b60ee8bc5c4af51e7cf6c42d93a989a09609524d0a393106e300cd/psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64a607e630d9f4b2797f641884e52b9f8e239d35943f51bef817a384ec1678fe", size = 4188374 }, + { url = "https://files.pythonhosted.org/packages/ed/5d/210cb75aff0296dc5c09bcf67babf8679905412d7a11357b983f0d877360/psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fa33ead69ed133210d96af0c63448b1385df48b9c0247eda735c5896b9e6dbbf", size = 3113180 }, + { url = "https://files.pythonhosted.org/packages/40/ec/46b1a5cdb2fe995b8ec0376f0695003e97fed9ac077e090a3165ea15f735/psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1f8b0d0e99d8e19923e6e07379fa00570be5182c201a8c0b5aaa9a4d4a4ea20b", size = 3099455 }, + { url = "https://files.pythonhosted.org/packages/11/68/eaf85b3421b3f01b638dd6b16f4e9bc8de42eb1d000da62964fb29f8c823/psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:709447bd7203b0b2debab1acec23123eb80b386f6c29e7604a5d4326a11e5bd6", size = 3189977 }, + { url = "https://files.pythonhosted.org/packages/83/5a/cf94c3ba87ea6c8331aa0aba36a18a837a3231764457780661968804673e/psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5e37d5027e297a627da3551a1e962316d0f88ee4ada74c768f6c9234e26346d9", size = 3232263 }, + { url = "https://files.pythonhosted.org/packages/0e/3a/9d912b16059e87b04e3eb4fca457f079d78d6468f627d5622fbda80e9378/psycopg_binary-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:261f0031ee6074765096a19b27ed0f75498a8338c3dcd7f4f0d831e38adf12d1", size = 2912530 }, + { url = "https://files.pythonhosted.org/packages/c6/bf/717c5e51c68e2498b60a6e9f1476cc47953013275a54bf8e23fd5082a72d/psycopg_binary-3.2.3-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:41fdec0182efac66b27478ac15ef54c9ebcecf0e26ed467eb7d6f262a913318b", size = 3360874 }, + { url = "https://files.pythonhosted.org/packages/31/d5/6f9ad6fe5ef80ca9172bc3d028ebae8e9a1ee8aebd917c95c747a5efd85f/psycopg_binary-3.2.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:07d019a786eb020c0f984691aa1b994cb79430061065a694cf6f94056c603d26", size = 3502320 }, + { url = "https://files.pythonhosted.org/packages/fb/7b/c58dd26c27fe7a491141ca765c103e702872ff1c174ebd669d73d7fb0b5d/psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c57615791a337378fe5381143259a6c432cdcbb1d3e6428bfb7ce59fff3fb5c", size = 4446950 }, + { url = "https://files.pythonhosted.org/packages/ed/75/acf6a81c788007b7bc0a43b02c22eff7cb19a6ace9e84c32838e86083a3f/psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8eb9a4e394926b93ad919cad1b0a918e9b4c846609e8c1cfb6b743683f64da0", size = 4252409 }, + { url = "https://files.pythonhosted.org/packages/83/a5/8a01b923fe42acd185d53f24fb98ead717725ede76a4cd183ff293daf1f1/psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5905729668ef1418bd36fbe876322dcb0f90b46811bba96d505af89e6fbdce2f", size = 4488121 }, + { url = "https://files.pythonhosted.org/packages/14/8f/b00e65e204340ab1259ecc8d4cc4c1f72c386be5ca7bfb90ae898a058d68/psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd65774ed7d65101b314808b6893e1a75b7664f680c3ef18d2e5c84d570fa393", size = 4190653 }, + { url = "https://files.pythonhosted.org/packages/ce/fc/ba830fc6c9b02b66d1e2fb420736df4d78369760144169a9046f04d72ac6/psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:700679c02f9348a0d0a2adcd33a0275717cd0d0aee9d4482b47d935023629505", size = 3118074 }, + { url = "https://files.pythonhosted.org/packages/b8/75/b62d06930a615435e909e05de126aa3d49f6ec2993d1aa6a99e7faab5570/psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96334bb64d054e36fed346c50c4190bad9d7c586376204f50bede21a913bf942", size = 3100457 }, + { url = "https://files.pythonhosted.org/packages/57/e5/32dc7518325d0010813853a87b19c784d8b11fdb17f5c0e0c148c5ac77af/psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9099e443d4cc24ac6872e6a05f93205ba1a231b1a8917317b07c9ef2b955f1f4", size = 3192788 }, + { url = "https://files.pythonhosted.org/packages/23/a3/d1aa04329253c024a2323051774446770d47b43073874a3de8cca797ed8e/psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1985ab05e9abebfbdf3163a16ebb37fbc5d49aff2bf5b3d7375ff0920bbb54cd", size = 3234247 }, + { url = "https://files.pythonhosted.org/packages/03/20/b675af723b9a61d48abd6a3d64cbb9797697d330255d1f8105713d54ed8e/psycopg_binary-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:e90352d7b610b4693fad0feea48549d4315d10f1eba5605421c92bb834e90170", size = 2913413 }, ] [[package]] @@ -3795,6 +3931,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, + { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, + { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, + { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, ] [[package]] @@ -4091,70 +4230,70 @@ version = "0.20.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/25/cb/8e919951f55d109d658f81c9b49d0cc3b48637c50792c5d2e77032b8c5da/rpds_py-0.20.1.tar.gz", hash = "sha256:e1791c4aabd117653530dccd24108fa03cc6baf21f58b950d0a73c3b3b29a350", size = 25931 } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/2d/a7e60483b72b91909e18f29a5c5ae847bac4e2ae95b77bb77e1f41819a58/rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2", size = 318432 }, - { url = "https://files.pythonhosted.org/packages/b5/b4/f15b0c55a6d880ce74170e7e28c3ed6c5acdbbd118df50b91d1dabf86008/rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f", size = 311333 }, - { url = "https://files.pythonhosted.org/packages/36/10/3f4e490fe6eb069c07c22357d0b4804cd94cb9f8d01345ef9b1d93482b9d/rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150", size = 366697 }, - { url = "https://files.pythonhosted.org/packages/f5/c8/cd6ab31b4424c7fab3b17e153b6ea7d1bb0d7cabea5c1ef683cc8adb8bc2/rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e", size = 368386 }, - { url = "https://files.pythonhosted.org/packages/60/5e/642a44fda6dda90b5237af7a0ef1d088159c30a504852b94b0396eb62125/rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2", size = 395374 }, - { url = "https://files.pythonhosted.org/packages/7c/b5/ff18c093c9e72630f6d6242e5ccb0728ef8265ba0a154b5972f89d23790a/rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3", size = 433189 }, - { url = "https://files.pythonhosted.org/packages/4a/6d/1166a157b227f2333f8e8ae320b6b7ea2a6a38fbe7a3563ad76dffc8608d/rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf", size = 354849 }, - { url = "https://files.pythonhosted.org/packages/70/a4/70ea49863ea09ae4c2971f2eef58e80b757e3c0f2f618c5815bb751f7847/rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140", size = 373233 }, - { url = "https://files.pythonhosted.org/packages/3b/d3/822a28152a1e7e2ba0dc5d06cf8736f4cd64b191bb6ec47fb51d1c3c5ccf/rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f", size = 541852 }, - { url = "https://files.pythonhosted.org/packages/c6/a5/6ef91e4425dc8b3445ff77d292fc4c5e37046462434a0423c4e0a596a8bd/rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce", size = 547630 }, - { url = "https://files.pythonhosted.org/packages/72/f8/d5625ee05c4e5c478954a16d9359069c66fe8ac8cd5ddf28f80d3b321837/rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94", size = 525766 }, - { url = "https://files.pythonhosted.org/packages/94/3c/1ff1ed6ae323b3e16fdfcdae0f0a67f373a6c3d991229dc32b499edeffb7/rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee", size = 199174 }, - { url = "https://files.pythonhosted.org/packages/ec/ba/5762c0aee2403dfea14ed74b0f8a2415cfdbb21cf745d600d9a8ac952c5b/rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399", size = 213543 }, - { url = "https://files.pythonhosted.org/packages/ab/2a/191374c52d7be0b056cc2a04d718d2244c152f915d4a8d2db2aacc526189/rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489", size = 318369 }, - { url = "https://files.pythonhosted.org/packages/0e/6a/2c9fdcc6d235ac0d61ec4fd9981184689c3e682abd05e3caa49bccb9c298/rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318", size = 311303 }, - { url = "https://files.pythonhosted.org/packages/d2/b2/725487d29633f64ef8f9cbf4729111a0b61702c8f8e94db1653930f52cce/rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db", size = 366424 }, - { url = "https://files.pythonhosted.org/packages/7a/8c/668195ab9226d01b7cf7cd9e59c1c0be1df05d602df7ec0cf46f857dcf59/rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5", size = 368359 }, - { url = "https://files.pythonhosted.org/packages/52/28/356f6a39c1adeb02cf3e5dd526f5e8e54e17899bef045397abcfbf50dffa/rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5", size = 394886 }, - { url = "https://files.pythonhosted.org/packages/a2/65/640fb1a89080a8fb6f4bebd3dafb65a2edba82e2e44c33e6eb0f3e7956f1/rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6", size = 432416 }, - { url = "https://files.pythonhosted.org/packages/a7/e8/85835077b782555d6b3416874b702ea6ebd7db1f145283c9252968670dd5/rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209", size = 354819 }, - { url = "https://files.pythonhosted.org/packages/4f/87/1ac631e923d65cbf36fbcfc6eaa702a169496de1311e54be142f178e53ee/rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3", size = 373282 }, - { url = "https://files.pythonhosted.org/packages/e4/ce/cb316f7970189e217b998191c7cf0da2ede3d5437932c86a7210dc1e9994/rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272", size = 541540 }, - { url = "https://files.pythonhosted.org/packages/90/d7/4112d7655ec8aff168ecc91d4ceb51c557336edde7e6ccf6463691a2f253/rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad", size = 547640 }, - { url = "https://files.pythonhosted.org/packages/ab/44/4f61d64dfed98cc71623f3a7fcb612df636a208b4b2c6611eaa985e130a9/rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58", size = 525555 }, - { url = "https://files.pythonhosted.org/packages/35/f2/a862d81eacb21f340d584cd1c749c289979f9a60e9229f78bffc0418a199/rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0", size = 199338 }, - { url = "https://files.pythonhosted.org/packages/cc/ec/77d0674f9af4872919f3738018558dd9d37ad3f7ad792d062eadd4af7cba/rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c", size = 213585 }, - { url = "https://files.pythonhosted.org/packages/89/b7/f9682c5cc37fcc035f4a0fc33c1fe92ec9cbfdee0cdfd071cf948f53e0df/rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6", size = 321468 }, - { url = "https://files.pythonhosted.org/packages/b8/ad/fc82be4eaceb8d444cb6fc1956ce972b3a0795104279de05e0e4131d0a47/rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b", size = 313062 }, - { url = "https://files.pythonhosted.org/packages/0e/1c/6039e80b13a08569a304dc13476dc986352dca4598e909384db043b4e2bb/rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739", size = 370168 }, - { url = "https://files.pythonhosted.org/packages/dc/c9/5b9aa35acfb58946b4b785bc8e700ac313669e02fb100f3efa6176a83e81/rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c", size = 371376 }, - { url = "https://files.pythonhosted.org/packages/7b/dd/0e0dbeb70d8a5357d2814764d467ded98d81d90d3570de4fb05ec7224f6b/rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee", size = 397200 }, - { url = "https://files.pythonhosted.org/packages/e4/da/a47d931eb688ccfd77a7389e45935c79c41e8098d984d87335004baccb1d/rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96", size = 426824 }, - { url = "https://files.pythonhosted.org/packages/0f/f7/a59a673594e6c2ff2dbc44b00fd4ecdec2fc399bb6a7bd82d612699a0121/rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4", size = 357967 }, - { url = "https://files.pythonhosted.org/packages/5f/61/3ba1905396b2cb7088f9503a460b87da33452da54d478cb9241f6ad16d00/rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef", size = 378905 }, - { url = "https://files.pythonhosted.org/packages/08/31/6d0df9356b4edb0a3a077f1ef714e25ad21f9f5382fc490c2383691885ea/rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821", size = 546348 }, - { url = "https://files.pythonhosted.org/packages/ae/15/d33c021de5cb793101df9961c3c746dfc476953dbbf5db337d8010dffd4e/rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940", size = 553152 }, - { url = "https://files.pythonhosted.org/packages/70/2d/5536d28c507a4679179ab15aa0049440e4d3dd6752050fa0843ed11e9354/rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174", size = 528807 }, - { url = "https://files.pythonhosted.org/packages/e3/62/7ebe6ec0d3dd6130921f8cffb7e34afb7f71b3819aa0446a24c5e81245ec/rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139", size = 200993 }, - { url = "https://files.pythonhosted.org/packages/ec/2f/b938864d66b86a6e4acadefdc56de75ef56f7cafdfd568a6464605457bd5/rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585", size = 214458 }, - { url = "https://files.pythonhosted.org/packages/99/32/43b919a0a423c270a838ac2726b1c7168b946f2563fd99a51aaa9692d00f/rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29", size = 321465 }, - { url = "https://files.pythonhosted.org/packages/58/a9/c4d899cb28e9e47b0ff12462e8f827381f243176036f17bef9c1604667f2/rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91", size = 312900 }, - { url = "https://files.pythonhosted.org/packages/8f/90/9e51670575b5dfaa8c823369ef7d943087bfb73d4f124a99ad6ef19a2b26/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24", size = 370973 }, - { url = "https://files.pythonhosted.org/packages/fc/c1/523f2a03f853fc0d4c1acbef161747e9ab7df0a8abf6236106e333540921/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7", size = 370890 }, - { url = "https://files.pythonhosted.org/packages/51/ca/2458a771f16b0931de4d384decbe43016710bc948036c8f4562d6e063437/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9", size = 397174 }, - { url = "https://files.pythonhosted.org/packages/00/7d/6e06807f6305ea2408b364efb0eef83a6e21b5e7b5267ad6b473b9a7e416/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8", size = 426449 }, - { url = "https://files.pythonhosted.org/packages/8c/d1/6c9e65260a819a1714510a7d69ac1d68aa23ee9ce8a2d9da12187263c8fc/rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879", size = 357698 }, - { url = "https://files.pythonhosted.org/packages/5d/fb/ecea8b5286d2f03eec922be7173a03ed17278944f7c124348f535116db15/rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f", size = 378530 }, - { url = "https://files.pythonhosted.org/packages/e3/e3/ac72f858957f52a109c588589b73bd2fad4a0fc82387fb55fb34aeb0f9cd/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c", size = 545753 }, - { url = "https://files.pythonhosted.org/packages/b2/a4/a27683b519d5fc98e4390a3b130117d80fd475c67aeda8aac83c0e8e326a/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2", size = 552443 }, - { url = "https://files.pythonhosted.org/packages/a1/ed/c074d248409b4432b1ccb2056974175fa0af2d1bc1f9c21121f80a358fa3/rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57", size = 528380 }, - { url = "https://files.pythonhosted.org/packages/d5/bd/04caf938895d2d78201e89c0c8a94dfd9990c34a19ff52fb01d0912343e3/rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a", size = 200540 }, - { url = "https://files.pythonhosted.org/packages/95/cc/109eb8b9863680411ae703664abacaa035820c7755acc9686d5dd02cdd2e/rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2", size = 214111 }, - { url = "https://files.pythonhosted.org/packages/06/39/bf1f664c347c946ef56cecaa896e3693d91acc741afa78ebb3fdb7aba08b/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045", size = 319444 }, - { url = "https://files.pythonhosted.org/packages/c1/71/876135d3cb90d62468540b84e8e83ff4dc92052ab309bfdea7ea0b9221ad/rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc", size = 311699 }, - { url = "https://files.pythonhosted.org/packages/f7/da/8ccaeba6a3dda7467aebaf893de9eafd56275e2c90773c83bf15fb0b8374/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02", size = 367825 }, - { url = "https://files.pythonhosted.org/packages/04/b6/02a54c47c178d180395b3c9a8bfb3b93906e08f9acf7b4a1067d27c3fae0/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92", size = 369046 }, - { url = "https://files.pythonhosted.org/packages/a7/64/df4966743aa4def8727dc13d06527c8b13eb7412c1429def2d4701bee520/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d", size = 395896 }, - { url = "https://files.pythonhosted.org/packages/6f/d9/7ff03ff3642c600f27ff94512bb158a8d815fea5ed4162c75a7e850d6003/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855", size = 432427 }, - { url = "https://files.pythonhosted.org/packages/b8/c6/e1b886f7277b3454e55e85332e165091c19114eecb5377b88d892fd36ccf/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511", size = 355403 }, - { url = "https://files.pythonhosted.org/packages/e2/62/e26bd5b944e547c7bfd0b6ca7e306bfa430f8bd298ab72a1217976a7ca8d/rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51", size = 374491 }, - { url = "https://files.pythonhosted.org/packages/c3/92/93c5a530898d3a5d1ce087455071ba714b77806ed9ffee4070d0c7a53b7e/rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075", size = 543622 }, - { url = "https://files.pythonhosted.org/packages/01/9e/d68fba289625b5d3c9d1925825d7da716fbf812bda2133ac409021d5db13/rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60", size = 548558 }, - { url = "https://files.pythonhosted.org/packages/bf/d6/4b2fad4898154365f0f2bd72ffd190349274a4c1d6a6f94f02a83bb2b8f1/rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344", size = 525753 }, - { url = "https://files.pythonhosted.org/packages/d2/ea/6f121d1802f3adae1981aea4209ea66f9d3c7f2f6d6b85ef4f13a61d17ef/rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989", size = 213529 }, + { url = "https://files.pythonhosted.org/packages/ae/0e/d7e7e9280988a7bc56fd326042baca27f4f55fad27dc8aa64e5e0e894e5d/rpds_py-0.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a649dfd735fff086e8a9d0503a9f0c7d01b7912a333c7ae77e1515c08c146dad", size = 327335 }, + { url = "https://files.pythonhosted.org/packages/4c/72/027185f213d53ae66765c575229829b202fbacf3d55fe2bd9ff4e29bb157/rpds_py-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f16bc1334853e91ddaaa1217045dd7be166170beec337576818461268a3de67f", size = 318250 }, + { url = "https://files.pythonhosted.org/packages/2b/e7/b4eb3e6ff541c83d3b46f45f855547e412ab60c45bef64520fafb00b9b42/rpds_py-0.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14511a539afee6f9ab492b543060c7491c99924314977a55c98bfa2ee29ce78c", size = 361206 }, + { url = "https://files.pythonhosted.org/packages/e7/80/cb9a4b4cad31bcaa37f38dae7a8be861f767eb2ca4f07a146b5ffcfbee09/rpds_py-0.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3ccb8ac2d3c71cda472b75af42818981bdacf48d2e21c36331b50b4f16930163", size = 369921 }, + { url = "https://files.pythonhosted.org/packages/95/1b/463b11e7039e18f9e778568dbf7338c29bbc1f8996381115201c668eb8c8/rpds_py-0.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c142b88039b92e7e0cb2552e8967077e3179b22359e945574f5e2764c3953dcf", size = 403673 }, + { url = "https://files.pythonhosted.org/packages/86/98/1ef4028e9d5b76470bf7f8f2459be07ac5c9621270a2a5e093f8d8a8cc2c/rpds_py-0.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f19169781dddae7478a32301b499b2858bc52fc45a112955e798ee307e294977", size = 430267 }, + { url = "https://files.pythonhosted.org/packages/25/8e/41d7e3e6d3a4a6c94375020477705a3fbb6515717901ab8f94821cf0a0d9/rpds_py-0.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13c56de6518e14b9bf6edde23c4c39dac5b48dcf04160ea7bce8fca8397cdf86", size = 360569 }, + { url = "https://files.pythonhosted.org/packages/4f/6a/8839340464d4e1bbfaf0482e9d9165a2309c2c17427e4dcb72ce3e5cc5d6/rpds_py-0.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:925d176a549f4832c6f69fa6026071294ab5910e82a0fe6c6228fce17b0706bd", size = 382584 }, + { url = "https://files.pythonhosted.org/packages/64/96/7a7f938d3796a6a3ec08ed0e8a5ecd436fbd516a3684ab1fa22d46d6f6cc/rpds_py-0.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:78f0b6877bfce7a3d1ff150391354a410c55d3cdce386f862926a4958ad5ab7e", size = 546560 }, + { url = "https://files.pythonhosted.org/packages/15/c7/19fb4f1247a3c90a99eca62909bf76ee988f9b663e47878a673d9854ec5c/rpds_py-0.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3dd645e2b0dcb0fd05bf58e2e54c13875847687d0b71941ad2e757e5d89d4356", size = 549359 }, + { url = "https://files.pythonhosted.org/packages/d2/4c/445eb597a39a883368ea2f341dd6e48a9d9681b12ebf32f38a827b30529b/rpds_py-0.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4f676e21db2f8c72ff0936f895271e7a700aa1f8d31b40e4e43442ba94973899", size = 527567 }, + { url = "https://files.pythonhosted.org/packages/4f/71/4c44643bffbcb37311fc7fe221bcf139c8d660bc78f746dd3a05741372c8/rpds_py-0.20.1-cp310-none-win32.whl", hash = "sha256:648386ddd1e19b4a6abab69139b002bc49ebf065b596119f8f37c38e9ecee8ff", size = 200412 }, + { url = "https://files.pythonhosted.org/packages/f4/33/9d0529d74099e090ec9ab15eb0a049c56cca599eaaca71bfedbdbca656a9/rpds_py-0.20.1-cp310-none-win_amd64.whl", hash = "sha256:d9ecb51120de61e4604650666d1f2b68444d46ae18fd492245a08f53ad2b7711", size = 218563 }, + { url = "https://files.pythonhosted.org/packages/a0/2e/a6ded84019a05b8f23e0fe6a632f62ae438a8c5e5932d3dfc90c73418414/rpds_py-0.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:762703bdd2b30983c1d9e62b4c88664df4a8a4d5ec0e9253b0231171f18f6d75", size = 327194 }, + { url = "https://files.pythonhosted.org/packages/68/11/d3f84c69de2b2086be3d6bd5e9d172825c096b13842ab7e5f8f39f06035b/rpds_py-0.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0b581f47257a9fce535c4567782a8976002d6b8afa2c39ff616edf87cbeff712", size = 318126 }, + { url = "https://files.pythonhosted.org/packages/18/c0/13f1bce9c901511e5e4c0b77a99dbb946bb9a177ca88c6b480e9cb53e304/rpds_py-0.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842c19a6ce894493563c3bd00d81d5100e8e57d70209e84d5491940fdb8b9e3a", size = 361119 }, + { url = "https://files.pythonhosted.org/packages/06/31/3bd721575671f22a37476c2d7b9e34bfa5185bdcee09f7fedde3b29f3adb/rpds_py-0.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42cbde7789f5c0bcd6816cb29808e36c01b960fb5d29f11e052215aa85497c93", size = 369532 }, + { url = "https://files.pythonhosted.org/packages/20/22/3eeb0385f33251b4fd0f728e6a3801dc8acc05e714eb7867cefe635bf4ab/rpds_py-0.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c8e9340ce5a52f95fa7d3b552b35c7e8f3874d74a03a8a69279fd5fca5dc751", size = 403703 }, + { url = "https://files.pythonhosted.org/packages/10/e1/8dde6174e7ac5b9acd3269afca2e17719bc7e5088c68f44874d2ad9e4560/rpds_py-0.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ba6f89cac95c0900d932c9efb7f0fb6ca47f6687feec41abcb1bd5e2bd45535", size = 429868 }, + { url = "https://files.pythonhosted.org/packages/19/51/a3cc1a5238acfc2582033e8934d034301f9d4931b9bf7c7ccfabc4ca0880/rpds_py-0.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a916087371afd9648e1962e67403c53f9c49ca47b9680adbeef79da3a7811b0", size = 360539 }, + { url = "https://files.pythonhosted.org/packages/cd/8c/3c87471a44bd4114e2b0aec90f298f6caaac4e8db6af904d5dd2279f5c61/rpds_py-0.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:200a23239781f46149e6a415f1e870c5ef1e712939fe8fa63035cd053ac2638e", size = 382467 }, + { url = "https://files.pythonhosted.org/packages/d0/9b/95073fe3e0f130e6d561e106818b6568ef1f2df3352e7f162ab912da837c/rpds_py-0.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:58b1d5dd591973d426cbb2da5e27ba0339209832b2f3315928c9790e13f159e8", size = 546669 }, + { url = "https://files.pythonhosted.org/packages/de/4c/7ab3669e02bb06fedebcfd64d361b7168ba39dfdf385e4109440f2e7927b/rpds_py-0.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6b73c67850ca7cae0f6c56f71e356d7e9fa25958d3e18a64927c2d930859b8e4", size = 549304 }, + { url = "https://files.pythonhosted.org/packages/f1/e8/ad5da336cd42adbdafe0ecd40dcecdae01fd3d703c621c7637615a008d3a/rpds_py-0.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d8761c3c891cc51e90bc9926d6d2f59b27beaf86c74622c8979380a29cc23ac3", size = 527637 }, + { url = "https://files.pythonhosted.org/packages/02/f1/1b47b9e5b941c2659c9b7e4ef41b6f07385a6500c638fa10c066e4616ecb/rpds_py-0.20.1-cp311-none-win32.whl", hash = "sha256:cd945871335a639275eee904caef90041568ce3b42f402c6959b460d25ae8732", size = 200488 }, + { url = "https://files.pythonhosted.org/packages/85/f6/c751c1adfa31610055acfa1cc667cf2c2d7011a73070679c448cf5856905/rpds_py-0.20.1-cp311-none-win_amd64.whl", hash = "sha256:7e21b7031e17c6b0e445f42ccc77f79a97e2687023c5746bfb7a9e45e0921b84", size = 218475 }, + { url = "https://files.pythonhosted.org/packages/e7/10/4e8dcc08b58a548098dbcee67a4888751a25be7a6dde0a83d4300df48bfa/rpds_py-0.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:36785be22066966a27348444b40389f8444671630063edfb1a2eb04318721e17", size = 329749 }, + { url = "https://files.pythonhosted.org/packages/d2/e4/61144f3790e12fd89e6153d77f7915ad26779735fef8ee9c099cba6dfb4a/rpds_py-0.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:142c0a5124d9bd0e2976089484af5c74f47bd3298f2ed651ef54ea728d2ea42c", size = 321032 }, + { url = "https://files.pythonhosted.org/packages/fa/e0/99205aabbf3be29ef6c58ef9b08feed51ba6532fdd47461245cb58dd9897/rpds_py-0.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbddc10776ca7ebf2a299c41a4dde8ea0d8e3547bfd731cb87af2e8f5bf8962d", size = 363931 }, + { url = "https://files.pythonhosted.org/packages/ac/bd/bce2dddb518b13a7e77eed4be234c9af0c9c6d403d01c5e6ae8eb447ab62/rpds_py-0.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15a842bb369e00295392e7ce192de9dcbf136954614124a667f9f9f17d6a216f", size = 373343 }, + { url = "https://files.pythonhosted.org/packages/43/15/112b7c553066cb91264691ba7fb119579c440a0ae889da222fa6fc0d411a/rpds_py-0.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be5ef2f1fc586a7372bfc355986226484e06d1dc4f9402539872c8bb99e34b01", size = 406304 }, + { url = "https://files.pythonhosted.org/packages/af/8d/2da52aef8ae5494a382b0c0025ba5b68f2952db0f2a4c7534580e8ca83cc/rpds_py-0.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbcf360c9e3399b056a238523146ea77eeb2a596ce263b8814c900263e46031a", size = 423022 }, + { url = "https://files.pythonhosted.org/packages/c8/1b/f23015cb293927c93bdb4b94a48bfe77ad9d57359c75db51f0ff0cf482ff/rpds_py-0.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd27a66740ffd621d20b9a2f2b5ee4129a56e27bfb9458a3bcc2e45794c96cb", size = 364937 }, + { url = "https://files.pythonhosted.org/packages/7b/8b/6da8636b2ea2e2f709e56656e663b6a71ecd9a9f9d9dc21488aade122026/rpds_py-0.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0b937b2a1988f184a3e9e577adaa8aede21ec0b38320d6009e02bd026db04fa", size = 386301 }, + { url = "https://files.pythonhosted.org/packages/20/af/2ae192797bffd0d6d558145b5a36e7245346ff3e44f6ddcb82f0eb8512d4/rpds_py-0.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6889469bfdc1eddf489729b471303739bf04555bb151fe8875931f8564309afc", size = 549452 }, + { url = "https://files.pythonhosted.org/packages/07/dd/9f6520712a5108cd7d407c9db44a3d59011b385c58e320d58ebf67757a9e/rpds_py-0.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:19b73643c802f4eaf13d97f7855d0fb527fbc92ab7013c4ad0e13a6ae0ed23bd", size = 554370 }, + { url = "https://files.pythonhosted.org/packages/5e/0e/b1bdc7ea0db0946d640ab8965146099093391bb5d265832994c47461e3c5/rpds_py-0.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c6afcf2338e7f374e8edc765c79fbcb4061d02b15dd5f8f314a4af2bdc7feb5", size = 530940 }, + { url = "https://files.pythonhosted.org/packages/ae/d3/ffe907084299484fab60a7955f7c0e8a295c04249090218c59437010f9f4/rpds_py-0.20.1-cp312-none-win32.whl", hash = "sha256:dc73505153798c6f74854aba69cc75953888cf9866465196889c7cdd351e720c", size = 203164 }, + { url = "https://files.pythonhosted.org/packages/1f/ba/9cbb57423c4bfbd81c473913bebaed151ad4158ee2590a4e4b3e70238b48/rpds_py-0.20.1-cp312-none-win_amd64.whl", hash = "sha256:8bbe951244a838a51289ee53a6bae3a07f26d4e179b96fc7ddd3301caf0518eb", size = 220750 }, + { url = "https://files.pythonhosted.org/packages/b5/01/fee2e1d1274c92fff04aa47d805a28d62c2aa971d1f49f5baea1c6e670d9/rpds_py-0.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6ca91093a4a8da4afae7fe6a222c3b53ee4eef433ebfee4d54978a103435159e", size = 329359 }, + { url = "https://files.pythonhosted.org/packages/b0/cf/4aeffb02b7090029d7aeecbffb9a10e1c80f6f56d7e9a30e15481dc4099c/rpds_py-0.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b9c2fe36d1f758b28121bef29ed1dee9b7a2453e997528e7d1ac99b94892527c", size = 320543 }, + { url = "https://files.pythonhosted.org/packages/17/69/85cf3429e9ccda684ba63ff36b5866d5f9451e921cc99819341e19880334/rpds_py-0.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f009c69bc8c53db5dfab72ac760895dc1f2bc1b62ab7408b253c8d1ec52459fc", size = 363107 }, + { url = "https://files.pythonhosted.org/packages/ef/de/7df88dea9c3eeb832196d23b41f0f6fc5f9a2ee9b2080bbb1db8731ead9c/rpds_py-0.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6740a3e8d43a32629bb9b009017ea5b9e713b7210ba48ac8d4cb6d99d86c8ee8", size = 372027 }, + { url = "https://files.pythonhosted.org/packages/d1/b8/88675399d2038580743c570a809c43a900e7090edc6553f8ffb66b23c965/rpds_py-0.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32b922e13d4c0080d03e7b62991ad7f5007d9cd74e239c4b16bc85ae8b70252d", size = 405031 }, + { url = "https://files.pythonhosted.org/packages/e1/aa/cca639f6d17caf00bab51bdc70fcc0bdda3063e5662665c4fdf60443c474/rpds_py-0.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe00a9057d100e69b4ae4a094203a708d65b0f345ed546fdef86498bf5390982", size = 422271 }, + { url = "https://files.pythonhosted.org/packages/c4/07/bf8a949d2ec4626c285579c9d6b356c692325f1a4126e947736b416e1fc4/rpds_py-0.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fe9b04b6fa685bd39237d45fad89ba19e9163a1ccaa16611a812e682913496", size = 363625 }, + { url = "https://files.pythonhosted.org/packages/11/f0/06675c6a58d6ce34547879138810eb9aab0c10e5607ea6c2e4dc56b703c8/rpds_py-0.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa7ac11e294304e615b43f8c441fee5d40094275ed7311f3420d805fde9b07b4", size = 385906 }, + { url = "https://files.pythonhosted.org/packages/bf/ac/2d1f50374eb8e41030fad4e87f81751e1c39e3b5d4bee8c5618830d8a6ac/rpds_py-0.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aa97af1558a9bef4025f8f5d8c60d712e0a3b13a2fe875511defc6ee77a1ab7", size = 549021 }, + { url = "https://files.pythonhosted.org/packages/f7/d4/a7d70a7cc71df772eeadf4bce05e32e780a9fe44a511a5b091c7a85cb767/rpds_py-0.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:483b29f6f7ffa6af845107d4efe2e3fa8fb2693de8657bc1849f674296ff6a5a", size = 553800 }, + { url = "https://files.pythonhosted.org/packages/87/81/dc30bc449ccba63ad23a0f6633486d4e0e6955f45f3715a130dacabd6ad0/rpds_py-0.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37fe0f12aebb6a0e3e17bb4cd356b1286d2d18d2e93b2d39fe647138458b4bcb", size = 531076 }, + { url = "https://files.pythonhosted.org/packages/50/80/fb62ab48f3b5cfe704ead6ad372da1922ddaa76397055e02eb507054c979/rpds_py-0.20.1-cp313-none-win32.whl", hash = "sha256:a624cc00ef2158e04188df5e3016385b9353638139a06fb77057b3498f794782", size = 202804 }, + { url = "https://files.pythonhosted.org/packages/d9/30/a3391e76d0b3313f33bdedd394a519decae3a953d2943e3dabf80ae32447/rpds_py-0.20.1-cp313-none-win_amd64.whl", hash = "sha256:b71b8666eeea69d6363248822078c075bac6ed135faa9216aa85f295ff009b1e", size = 220502 }, + { url = "https://files.pythonhosted.org/packages/b6/fa/7959429e69569d0f6e7d27f80451402da0409349dd2b07f6bcbdd5fad2d3/rpds_py-0.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a07ced2b22f0cf0b55a6a510078174c31b6d8544f3bc00c2bcee52b3d613f74", size = 328209 }, + { url = "https://files.pythonhosted.org/packages/25/97/5dfdb091c30267ff404d2fd9e70c7a6d6ffc65ca77fffe9456e13b719066/rpds_py-0.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:68cb0a499f2c4a088fd2f521453e22ed3527154136a855c62e148b7883b99f9a", size = 319499 }, + { url = "https://files.pythonhosted.org/packages/7c/98/cf2608722400f5f9bb4c82aa5ac09026f3ac2ebea9d4059d3533589ed0b6/rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa3060d885657abc549b2a0f8e1b79699290e5d83845141717c6c90c2df38311", size = 361795 }, + { url = "https://files.pythonhosted.org/packages/89/de/0e13dd43c785c60e63933e96fbddda0b019df6862f4d3019bb49c3861131/rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95f3b65d2392e1c5cec27cff08fdc0080270d5a1a4b2ea1d51d5f4a2620ff08d", size = 370604 }, + { url = "https://files.pythonhosted.org/packages/8a/fc/fe3c83c77f82b8059eeec4e998064913d66212b69b3653df48f58ad33d3d/rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2cc3712a4b0b76a1d45a9302dd2f53ff339614b1c29603a911318f2357b04dd2", size = 404177 }, + { url = "https://files.pythonhosted.org/packages/94/30/5189518bfb80a41f664daf32b46645c7fbdcc89028a0f1bfa82e806e0fbb/rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d4eea0761e37485c9b81400437adb11c40e13ef513375bbd6973e34100aeb06", size = 430108 }, + { url = "https://files.pythonhosted.org/packages/67/0e/6f069feaff5c298375cd8c55e00ecd9bd79c792ce0893d39448dc0097857/rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f5179583d7a6cdb981151dd349786cbc318bab54963a192692d945dd3f6435d", size = 361184 }, + { url = "https://files.pythonhosted.org/packages/27/9f/ce3e2ae36f392c3ef1988c06e9e0b4c74f64267dad7c223003c34da11adb/rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fbb0ffc754490aff6dabbf28064be47f0f9ca0b9755976f945214965b3ace7e", size = 384140 }, + { url = "https://files.pythonhosted.org/packages/5f/d5/89d44504d0bc7a1135062cb520a17903ff002f458371b8d9160af3b71e52/rpds_py-0.20.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a94e52537a0e0a85429eda9e49f272ada715506d3b2431f64b8a3e34eb5f3e75", size = 546589 }, + { url = "https://files.pythonhosted.org/packages/8f/8f/e1c2db4fcca3947d9a28ec9553700b4dc8038f0eff575f579e75885b0661/rpds_py-0.20.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:92b68b79c0da2a980b1c4197e56ac3dd0c8a149b4603747c4378914a68706979", size = 550059 }, + { url = "https://files.pythonhosted.org/packages/67/29/00a9e986df36721b5def82fff60995c1ee8827a7d909a6ec8929fb4cc668/rpds_py-0.20.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:93da1d3db08a827eda74356f9f58884adb254e59b6664f64cc04cdff2cc19b0d", size = 529131 }, + { url = "https://files.pythonhosted.org/packages/a3/32/95364440560ec476b19c6a2704259e710c223bf767632ebaa72cc2a1760f/rpds_py-0.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:754bbed1a4ca48479e9d4182a561d001bbf81543876cdded6f695ec3d465846b", size = 219677 }, ] [[package]] @@ -4211,6 +4350,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/d5/a659ca6f503b9379b930f13bc6b130c9f176469b73b9834296822a83a132/ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680", size = 745831 }, { url = "https://files.pythonhosted.org/packages/b1/82/85cb92f15a4231c89b95dfe08b09eb6adca929ef7df7e17ab59902b6f589/ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5", size = 98777 }, { url = "https://files.pythonhosted.org/packages/d7/8f/c3654f6f1ddb75daf3922c3d8fc6005b1ab56671ad56ffb874d908bfa668/ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", size = 115523 }, + { url = "https://files.pythonhosted.org/packages/29/00/4864119668d71a5fa45678f380b5923ff410701565821925c69780356ffa/ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a", size = 132011 }, + { url = "https://files.pythonhosted.org/packages/7f/5e/212f473a93ae78c669ffa0cb051e3fee1139cb2d385d2ae1653d64281507/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475", size = 642488 }, + { url = "https://files.pythonhosted.org/packages/1f/8f/ecfbe2123ade605c49ef769788f79c38ddb1c8fa81e01f4dbf5cf1a44b16/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef", size = 745066 }, + { url = "https://files.pythonhosted.org/packages/e2/a9/28f60726d29dfc01b8decdb385de4ced2ced9faeb37a847bd5cf26836815/ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6", size = 701785 }, + { url = "https://files.pythonhosted.org/packages/84/7e/8e7ec45920daa7f76046578e4f677a3215fe8f18ee30a9cb7627a19d9b4c/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf", size = 693017 }, + { url = "https://files.pythonhosted.org/packages/c5/b3/d650eaade4ca225f02a648321e1ab835b9d361c60d51150bac49063b83fa/ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1", size = 741270 }, + { url = "https://files.pythonhosted.org/packages/30/8c/ed73f047a73638257aa9377ad356bea4d96125b305c34a28766f4445cc0f/ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6", size = 98583 }, + { url = "https://files.pythonhosted.org/packages/b0/85/e8e751d8791564dd333d5d9a4eab0a7a115f7e349595417fd50ecae3395c/ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3", size = 115190 }, ] [[package]] @@ -4390,7 +4537,7 @@ wheels = [ [[package]] name = "semantic-kernel" -version = "1.11.0" +version = "1.14.0" source = { editable = "." } dependencies = [ { name = "aiohttp", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -4428,6 +4575,7 @@ chroma = [ ] dapr = [ { name = "dapr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "dapr-ext-fastapi", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] google = [ { name = "google-cloud-aiplatform", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -4510,6 +4658,7 @@ requires-dist = [ { name = "chromadb", marker = "extra == 'chroma'", specifier = ">=0.5,<0.6" }, { name = "cloudevents", specifier = "~=1.0" }, { name = "dapr", marker = "extra == 'dapr'", specifier = ">=1.14.0" }, + { name = "dapr-ext-fastapi", marker = "extra == 'dapr'", specifier = ">=1.14.0" }, { name = "defusedxml", specifier = "~=0.7" }, { name = "google-cloud-aiplatform", marker = "extra == 'google'", specifier = "~=1.60" }, { name = "google-generativeai", marker = "extra == 'google'", specifier = "~=0.7" }, @@ -4904,6 +5053,7 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6d/69/d8ada8b6e0a4257556d5b4ddeb4345ea8eeaaef3c98b60d1cca197c7ad8e/torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:3f4b7f10a247e0dcd7ea97dc2d3bfbfc90302ed36d7f3952b0008d0df264e697", size = 91811673 }, { url = "https://files.pythonhosted.org/packages/5f/ba/607d013b55b9fd805db2a5c2662ec7551f1910b4eef39653eeaba182c5b2/torch-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:73e58e78f7d220917c5dbfad1a40e09df9929d3b95d25e57d9f8558f84c9a11c", size = 203046841 }, { url = "https://files.pythonhosted.org/packages/57/6c/bf52ff061da33deb9f94f4121fde7ff3058812cb7d2036c97bc167793bd1/torch-2.5.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:8c712df61101964eb11910a846514011f0b6f5920c55dbf567bff8a34163d5b1", size = 63858109 }, + { url = "https://files.pythonhosted.org/packages/69/72/20cb30f3b39a9face296491a86adb6ff8f1a47a897e4d14667e6cf89d5c3/torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:9b61edf3b4f6e3b0e0adda8b3960266b9009d02b37555971f4d1c8f7a05afed7", size = 906393265 }, ] [[package]] @@ -5234,6 +5384,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 }, { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 }, { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 }, + { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 }, + { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 }, + { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 }, + { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 }, + { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 }, + { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 }, ] [[package]] @@ -5376,57 +5532,57 @@ version = "13.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/bd/224fd6c4c0d60645444bb77cabf3633a6c14a47e2d03cdbc2136486c51f7/websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f", size = 150946 }, - { url = "https://files.pythonhosted.org/packages/44/5b/16f06fa678432d0cdbc55477bb6f0215c42b31615948bd63a884c294e0a5/websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c", size = 148600 }, - { url = "https://files.pythonhosted.org/packages/5a/33/c57b4ecdd26510ffcda37d30073097f1e9015b316fe21b513360bf2d8ee2/websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f", size = 148853 }, - { url = "https://files.pythonhosted.org/packages/71/a3/6a8a0e86c44fc39fab83fc6b946f9f7d53e5be6824916450dac637937086/websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543", size = 157935 }, - { url = "https://files.pythonhosted.org/packages/a0/58/ba14373234d2b7cce48031f7bd05ab2d23a11ffa0d35c3348d5729fa0527/websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d", size = 156949 }, - { url = "https://files.pythonhosted.org/packages/7d/8a/8e2319207bae70156d0505bf91e192de015ee91ccc5b1afb406bb7db3819/websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f", size = 157260 }, - { url = "https://files.pythonhosted.org/packages/03/cd/31ff415c4b0dc3c185bd87c412affdc5fab42c700b04d02b380bfb789310/websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8", size = 157661 }, - { url = "https://files.pythonhosted.org/packages/e8/58/a95d1dc6f589cbbfca0918d160ff27c920ab2e94637b750591c6f226cf27/websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b", size = 157078 }, - { url = "https://files.pythonhosted.org/packages/ce/02/207f49e1c22c8fad9e6353815de698e778d365609801dc2387e01e0f94a2/websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448", size = 157027 }, - { url = "https://files.pythonhosted.org/packages/3b/aa/e59d994712635e9e6bc883471e12cc493e3a704e4e22e9d4a59ff1491161/websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3", size = 151776 }, - { url = "https://files.pythonhosted.org/packages/7b/f9/83bc78788d6ce5492fa44133708584a885080aa7c790be2532f326948115/websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0", size = 152206 }, - { url = "https://files.pythonhosted.org/packages/20/95/e002ec55688b751d3c9cc131c1960af7e440d95e1954c441535b9da2bf36/websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7", size = 150948 }, - { url = "https://files.pythonhosted.org/packages/62/6b/85fb8c13b278db7d45e27ff6ee0db3009b0fadef7c37c85e6cb4a0fbf08e/websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4", size = 148599 }, - { url = "https://files.pythonhosted.org/packages/e8/2e/c80cafbab86f8c399ba8323efff298b7062055724146391443d266e9c49b/websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2", size = 148851 }, - { url = "https://files.pythonhosted.org/packages/2e/67/631d4b1f28fef6f12730c0cbe982203a9d6814768c2ab1e0a352d9a07a97/websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0", size = 158509 }, - { url = "https://files.pythonhosted.org/packages/9b/e8/ba740eab2a9c5b903ea94d9a2a448db63f0a296265aee976d17abf734758/websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e", size = 157507 }, - { url = "https://files.pythonhosted.org/packages/f8/4e/ffa2f1aad2da67e483fb7bad6c69f80c786f4e85d1942a39d7b275b084ed/websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462", size = 157881 }, - { url = "https://files.pythonhosted.org/packages/c0/85/0cbfe7b0e0dd3d885cd87b0523c6690ae7369feaf3aab5a23e95bdb4fefa/websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501", size = 158187 }, - { url = "https://files.pythonhosted.org/packages/39/29/d9df0a1daedebefaeea88fb8071539604df09fd0f1bfb73bf58333aa3eb6/websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418", size = 157626 }, - { url = "https://files.pythonhosted.org/packages/7d/9a/f88e186059f6b89f8bb08461d9fda7a26940b7b8897c7d7f02aead40b7e4/websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df", size = 157575 }, - { url = "https://files.pythonhosted.org/packages/cf/e4/ecdb8352ebab2e44c10b9d6f50008f95e30bb0a7ef0e6b66cb475d539d74/websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f", size = 151779 }, - { url = "https://files.pythonhosted.org/packages/12/40/46967d00640e6c3231b73d310617927a11c91bcc044dd5a0860a3c457c33/websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075", size = 152206 }, - { url = "https://files.pythonhosted.org/packages/4e/51/23ed2d239f1c3087c1431d41cfd159865df0bc35bb0c89973e3b6a0fff9b/websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a", size = 150953 }, - { url = "https://files.pythonhosted.org/packages/57/8d/814a7ef62b916b0f39108ad2e4d9b4cb0f8c640f8c30202fb63041598ada/websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956", size = 148610 }, - { url = "https://files.pythonhosted.org/packages/ad/8b/a378d21124011737e0e490a8a6ef778914b03e50c8d938de2f2170a20dbd/websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af", size = 148849 }, - { url = "https://files.pythonhosted.org/packages/46/d2/814a61226af313c1bc289cfe3a10f87bf426b6f2d9df0f927c47afab7612/websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf", size = 158772 }, - { url = "https://files.pythonhosted.org/packages/a1/7e/5987299eb7e131216c9027b05a65f149cbc2bde7c582e694d9eed6ec3d40/websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c", size = 157724 }, - { url = "https://files.pythonhosted.org/packages/94/6e/eaf95894042ba8a05a125fe8bcf9ee3572fef6edbcbf49478f4991c027cc/websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4", size = 158152 }, - { url = "https://files.pythonhosted.org/packages/ce/ba/a1315d569cc2dadaafda74a9cea16ab5d68142525937f1994442d969b306/websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab", size = 158442 }, - { url = "https://files.pythonhosted.org/packages/90/9b/59866695cfd05e785c90932fef3dae4682eb4e06e7076b7c53478f25faad/websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d", size = 157823 }, - { url = "https://files.pythonhosted.org/packages/9b/47/20af68a313b6453d2d094ccc497b7232e8475175d234e3e5bef5088521e5/websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237", size = 157818 }, - { url = "https://files.pythonhosted.org/packages/f8/bb/60aaedc80e388e978617dda1ff38788780c6b0f6e462b85368cb934131a5/websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185", size = 151785 }, - { url = "https://files.pythonhosted.org/packages/16/2e/e47692f569e1be2e66c1dbc5e85ea4d2cc93b80027fbafa28ae8b0dee52c/websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99", size = 152214 }, - { url = "https://files.pythonhosted.org/packages/46/37/d8ef4b68684d1fa368a5c64be466db07fc58b68163bc2496db2d4cc208ff/websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa", size = 150962 }, - { url = "https://files.pythonhosted.org/packages/95/49/78aeb3af08ec9887a9065e85cef9d7e199d6c6261fcd39eec087f3a62328/websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231", size = 148621 }, - { url = "https://files.pythonhosted.org/packages/31/0d/dc9b7cec8deaee452092a631ccda894bd7098859f71dd7639b4b5b9c615c/websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9", size = 148853 }, - { url = "https://files.pythonhosted.org/packages/16/bf/734cbd815d7bc94cffe35c934f4e08b619bf3b47df1c6c7af21c1d35bcfe/websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75", size = 158741 }, - { url = "https://files.pythonhosted.org/packages/af/9b/756f89b12fee8931785531a314e6f087b21774a7f8c60878e597c684f91b/websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553", size = 157690 }, - { url = "https://files.pythonhosted.org/packages/d3/37/31f97132d2262e666b797e250879ca833eab55115f88043b3952a2840eb8/websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920", size = 158132 }, - { url = "https://files.pythonhosted.org/packages/41/ce/59c8d44e148c002fec506a9527504fb4281676e2e75c2ee5a58180f1b99a/websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329", size = 158490 }, - { url = "https://files.pythonhosted.org/packages/1a/74/5b31ce0f318b902c0d70c031f8e1228ba1a4d95a46b2a24a2a5ac17f9cf0/websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7", size = 157879 }, - { url = "https://files.pythonhosted.org/packages/0d/a7/6eac4f04177644bbc98deb98d11770cc7fbc216f6f67ab187c150540fd52/websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2", size = 157873 }, - { url = "https://files.pythonhosted.org/packages/72/f6/b8b30a3b134dfdb4ccd1694befa48fddd43783957c988a1dab175732af33/websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb", size = 151782 }, - { url = "https://files.pythonhosted.org/packages/3e/88/d94ccc006c69583168aa9dd73b3f1885c8931f2c676f4bdd8cbfae91c7b6/websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b", size = 152212 }, - { url = "https://files.pythonhosted.org/packages/ae/d8/9d0e5c836f89147aa769b72e2d82217ae1c17ffd5f375de8d785e1e16870/websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89", size = 148629 }, - { url = "https://files.pythonhosted.org/packages/9c/ff/005a440db101d298b42cc7565579ed55a7e12ccc0c6ea0491e53bb073930/websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad", size = 148863 }, - { url = "https://files.pythonhosted.org/packages/9f/06/44d7c7d48e0beaecbacaf0020eafccd490741e496622da6b2a5626fe6689/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e", size = 150226 }, - { url = "https://files.pythonhosted.org/packages/48/6f/861ba99aa3c5cb54412c3870d5549e466d82d2f7c440b435e23ca6496865/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc", size = 149833 }, - { url = "https://files.pythonhosted.org/packages/8d/a0/9fb50648f69ed341e30096356a815c89c4f9daef24a32e9754dbdc3de8a8/websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333", size = 149778 }, - { url = "https://files.pythonhosted.org/packages/f1/ba/48b5b8343e6f62a8a809ffe987d4d7c911cedcb1b8353f3da615f2609893/websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32", size = 152259 }, - { url = "https://files.pythonhosted.org/packages/fd/bd/d34c4b7918453506d2149208b175368738148ffc4ba256d7fd8708956732/websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817", size = 145262 }, + { url = "https://files.pythonhosted.org/packages/0a/94/d15dbfc6a5eb636dbc754303fba18208f2e88cf97e733e1d64fb9cb5c89e/websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee", size = 157815 }, + { url = "https://files.pythonhosted.org/packages/30/02/c04af33f4663945a26f5e8cf561eb140c35452b50af47a83c3fbcfe62ae1/websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7", size = 155466 }, + { url = "https://files.pythonhosted.org/packages/35/e8/719f08d12303ea643655e52d9e9851b2dadbb1991d4926d9ce8862efa2f5/websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6", size = 155716 }, + { url = "https://files.pythonhosted.org/packages/91/e1/14963ae0252a8925f7434065d25dcd4701d5e281a0b4b460a3b5963d2594/websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b", size = 164806 }, + { url = "https://files.pythonhosted.org/packages/ec/fa/ab28441bae5e682a0f7ddf3d03440c0c352f930da419301f4a717f675ef3/websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa", size = 163810 }, + { url = "https://files.pythonhosted.org/packages/44/77/dea187bd9d16d4b91566a2832be31f99a40d0f5bfa55eeb638eb2c3bc33d/websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700", size = 164125 }, + { url = "https://files.pythonhosted.org/packages/cf/d9/3af14544e83f1437eb684b399e6ba0fa769438e869bf5d83d74bc197fae8/websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c", size = 164532 }, + { url = "https://files.pythonhosted.org/packages/1c/8a/6d332eabe7d59dfefe4b8ba6f46c8c5fabb15b71c8a8bc3d2b65de19a7b6/websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0", size = 163948 }, + { url = "https://files.pythonhosted.org/packages/1a/91/a0aeadbaf3017467a1ee03f8fb67accdae233fe2d5ad4b038c0a84e357b0/websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f", size = 163898 }, + { url = "https://files.pythonhosted.org/packages/71/31/a90fb47c63e0ae605be914b0b969d7c6e6ffe2038cd744798e4b3fbce53b/websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe", size = 158706 }, + { url = "https://files.pythonhosted.org/packages/93/ca/9540a9ba80da04dc7f36d790c30cae4252589dbd52ccdc92e75b0be22437/websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a", size = 159141 }, + { url = "https://files.pythonhosted.org/packages/b2/f0/cf0b8a30d86b49e267ac84addbebbc7a48a6e7bb7c19db80f62411452311/websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19", size = 157813 }, + { url = "https://files.pythonhosted.org/packages/bf/e7/22285852502e33071a8cf0ac814f8988480ec6db4754e067b8b9d0e92498/websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5", size = 155469 }, + { url = "https://files.pythonhosted.org/packages/68/d4/c8c7c1e5b40ee03c5cc235955b0fb1ec90e7e37685a5f69229ad4708dcde/websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd", size = 155717 }, + { url = "https://files.pythonhosted.org/packages/c9/e4/c50999b9b848b1332b07c7fd8886179ac395cb766fda62725d1539e7bc6c/websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02", size = 165379 }, + { url = "https://files.pythonhosted.org/packages/bc/49/4a4ad8c072f18fd79ab127650e47b160571aacfc30b110ee305ba25fffc9/websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7", size = 164376 }, + { url = "https://files.pythonhosted.org/packages/af/9b/8c06d425a1d5a74fd764dd793edd02be18cf6fc3b1ccd1f29244ba132dc0/websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096", size = 164753 }, + { url = "https://files.pythonhosted.org/packages/d5/5b/0acb5815095ff800b579ffc38b13ab1b915b317915023748812d24e0c1ac/websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084", size = 165051 }, + { url = "https://files.pythonhosted.org/packages/30/93/c3891c20114eacb1af09dedfcc620c65c397f4fd80a7009cd12d9457f7f5/websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3", size = 164489 }, + { url = "https://files.pythonhosted.org/packages/28/09/af9e19885539759efa2e2cd29b8b3f9eecef7ecefea40d46612f12138b36/websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9", size = 164438 }, + { url = "https://files.pythonhosted.org/packages/b6/08/6f38b8e625b3d93de731f1d248cc1493327f16cb45b9645b3e791782cff0/websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f", size = 158710 }, + { url = "https://files.pythonhosted.org/packages/fb/39/ec8832ecb9bb04a8d318149005ed8cee0ba4e0205835da99e0aa497a091f/websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557", size = 159137 }, + { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 }, + { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 }, + { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 }, + { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 }, + { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 }, + { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 }, + { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 }, + { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 }, + { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 }, + { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 }, + { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 }, + { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 }, + { url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 }, + { url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 }, + { url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 }, + { url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 }, + { url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 }, + { url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 }, + { url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 }, + { url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 }, + { url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 }, + { url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 }, + { url = "https://files.pythonhosted.org/packages/2d/75/6da22cb3ad5b8c606963f9a5f9f88656256fecc29d420b4b2bf9e0c7d56f/websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238", size = 155499 }, + { url = "https://files.pythonhosted.org/packages/c0/ba/22833d58629088fcb2ccccedfae725ac0bbcd713319629e97125b52ac681/websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5", size = 155737 }, + { url = "https://files.pythonhosted.org/packages/95/54/61684fe22bdb831e9e1843d972adadf359cf04ab8613285282baea6a24bb/websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9", size = 157095 }, + { url = "https://files.pythonhosted.org/packages/fc/f5/6652fb82440813822022a9301a30afde85e5ff3fb2aebb77f34aabe2b4e8/websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6", size = 156701 }, + { url = "https://files.pythonhosted.org/packages/67/33/ae82a7b860fa8a08aba68818bdf7ff61f04598aa5ab96df4cd5a3e418ca4/websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a", size = 156654 }, + { url = "https://files.pythonhosted.org/packages/63/0b/a1b528d36934f833e20f6da1032b995bf093d55cb416b9f2266f229fb237/websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23", size = 159192 }, + { url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 }, ] [[package]] @@ -5491,67 +5647,71 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/54/9c/9c0a9bfa683fc1be7fdcd9687635151544d992cccd48892dc5e0a5885a29/yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47", size = 178163 } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/a3/4e67b1463c12ba178aace33b62468377473c77b33a95bcb12b67b2b93817/yarl-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00", size = 188473 }, - { url = "https://files.pythonhosted.org/packages/f3/86/c0c76e69a390fb43533783582714e8a58003f443b81cac1605ce71cade00/yarl-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d", size = 114362 }, - { url = "https://files.pythonhosted.org/packages/07/ef/e6bee78c1bf432de839148fe9fdc1cf5e7fbd6402d8b0b7d7a1522fb9733/yarl-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e", size = 112537 }, - { url = "https://files.pythonhosted.org/packages/37/f4/3406e76ed71e4d3023dbae4514513a387e2e753cb8a4cadd6ff9ba08a046/yarl-1.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc", size = 442573 }, - { url = "https://files.pythonhosted.org/packages/37/15/98b4951271a693142e551fea24bca1e96be71b5256b3091dbe8433532a45/yarl-1.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec", size = 468046 }, - { url = "https://files.pythonhosted.org/packages/88/1a/f10b88c4d8200708cbc799aad978a37a0ab15a4a72511c60bed11ee585c4/yarl-1.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf", size = 462124 }, - { url = "https://files.pythonhosted.org/packages/02/a3/97b527b5c4551c3b17fd095fe019435664330060b3879c8c1ae80985d4bc/yarl-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49", size = 446807 }, - { url = "https://files.pythonhosted.org/packages/40/06/da47aae54f1bb8ac0668d68bbdde40ba761643f253b2c16fdb4362af8ca3/yarl-1.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff", size = 431778 }, - { url = "https://files.pythonhosted.org/packages/ba/a1/54992cd68f61c11d975184f4c8a4c7f43a838e7c6ce183030a3fc0a257a6/yarl-1.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad", size = 443702 }, - { url = "https://files.pythonhosted.org/packages/5c/8b/adf290dc272a1a30a0e9dc04e2e62486be80f371bd9da2e9899f8e6181f3/yarl-1.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145", size = 448289 }, - { url = "https://files.pythonhosted.org/packages/fc/98/e6ad935fa009890b9ef2769266dc9dceaeee5a7f9a57bc7daf50b5b6c305/yarl-1.11.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd", size = 471660 }, - { url = "https://files.pythonhosted.org/packages/91/5d/1ad82849ce3c02661395f5097878c58ecabc4dac5d2d98e4f85949386448/yarl-1.11.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26", size = 469830 }, - { url = "https://files.pythonhosted.org/packages/e0/70/376046a7f69cfec814b97fb8bf1af6f16dcbe37fd0ef89a9f87b04156923/yarl-1.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46", size = 457671 }, - { url = "https://files.pythonhosted.org/packages/33/49/825f84f9a5d26d26fbf82531cee3923f356e2d8efc1819b85ada508fa91f/yarl-1.11.1-cp310-cp310-win32.whl", hash = "sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91", size = 101184 }, - { url = "https://files.pythonhosted.org/packages/b0/29/2a08a45b9f2eddd1b840813698ee655256f43b507c12f7f86df947cf5f8f/yarl-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998", size = 110175 }, - { url = "https://files.pythonhosted.org/packages/af/f1/f3e6be722461cab1e7c6aea657685897956d6e4743940d685d167914e31c/yarl-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68", size = 188410 }, - { url = "https://files.pythonhosted.org/packages/4b/c1/21cc66b263fdc2ec10b6459aed5b239f07eed91a77438d88f0e1bd70e202/yarl-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe", size = 114293 }, - { url = "https://files.pythonhosted.org/packages/31/7a/0ecab63a166a22357772f4a2852c859e2d5a7b02a5c58803458dd516e6b4/yarl-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675", size = 112548 }, - { url = "https://files.pythonhosted.org/packages/57/5d/78152026864475e841fdae816499345364c8e364b45ea6accd0814a295f0/yarl-1.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63", size = 485002 }, - { url = "https://files.pythonhosted.org/packages/d3/70/2e880d74aeb4908d45c6403e46bbd4aa866ae31ddb432318d9b8042fe0f6/yarl-1.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27", size = 504850 }, - { url = "https://files.pythonhosted.org/packages/06/58/5676a47b6d2751853f89d1d68b6a54d725366da6a58482f2410fa7eb38af/yarl-1.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5", size = 499291 }, - { url = "https://files.pythonhosted.org/packages/4d/e5/b56d535703a63a8d86ac82059e630e5ba9c0d5626d9c5ac6af53eed815c2/yarl-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92", size = 487818 }, - { url = "https://files.pythonhosted.org/packages/f3/b4/6b95e1e0983593f4145518980b07126a27e2a4938cb6afb8b592ce6fc2c9/yarl-1.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b", size = 470447 }, - { url = "https://files.pythonhosted.org/packages/a8/e5/5d349b7b04ed4247d4f717f271fce601a79d10e2ac81166c13f97c4973a9/yarl-1.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a", size = 484544 }, - { url = "https://files.pythonhosted.org/packages/fa/dc/ce90e9d85ef2233e81148a9658e4ea8372c6de070ce96c5c8bd3ff365144/yarl-1.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83", size = 482409 }, - { url = "https://files.pythonhosted.org/packages/4c/a1/17c0a03615b0cd213aee2e318a0fbd3d07259c37976d85af9eec6184c589/yarl-1.11.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff", size = 512970 }, - { url = "https://files.pythonhosted.org/packages/6c/ed/1e317799d54c79a3e4846db597510f5c84fb7643bb8703a3848136d40809/yarl-1.11.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c", size = 515203 }, - { url = "https://files.pythonhosted.org/packages/7a/37/9a4e2d73953956fa686fa0f0c4a0881245f39423fa75875d981b4f680611/yarl-1.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e", size = 497323 }, - { url = "https://files.pythonhosted.org/packages/a3/c3/a25ae9c85c0e50a8722aecc486ac5ba53b28d1384548df99b2145cb69862/yarl-1.11.1-cp311-cp311-win32.whl", hash = "sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6", size = 101226 }, - { url = "https://files.pythonhosted.org/packages/90/6d/c62ba0ae0232a0b0012706a7735a16b44a03216fedfb6ea0bcda79d1e12c/yarl-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b", size = 110471 }, - { url = "https://files.pythonhosted.org/packages/3b/05/379002019a0c9d5dc0c4cc6f71e324ea43461ae6f58e94ee87e07b8ffa90/yarl-1.11.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0", size = 189044 }, - { url = "https://files.pythonhosted.org/packages/23/d5/e62cfba5ceaaf92ee4f9af6f9c9ab2f2b47d8ad48687fa69570a93b0872c/yarl-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265", size = 114867 }, - { url = "https://files.pythonhosted.org/packages/b1/10/6abc0bd7e7fe7c6b9b9e9ce0ff558912c9ecae65a798f5442020ef9e4177/yarl-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867", size = 112737 }, - { url = "https://files.pythonhosted.org/packages/37/a5/ad026afde5efe1849f4f55bd9f9a2cb5b006511b324db430ae5336104fb3/yarl-1.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd", size = 482887 }, - { url = "https://files.pythonhosted.org/packages/f8/82/b8bee972617b800319b4364cfcd69bfaf7326db052e91a56e63986cc3e05/yarl-1.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef", size = 498635 }, - { url = "https://files.pythonhosted.org/packages/af/ad/ac688503b134e02e8505415f0b8e94dc8e92a97e82abdd9736658389b5ae/yarl-1.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8", size = 496198 }, - { url = "https://files.pythonhosted.org/packages/ce/f2/b6cae0ad1afed6e95f82ab2cb9eb5b63e41f1463ece2a80c39d80cf6167a/yarl-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870", size = 489068 }, - { url = "https://files.pythonhosted.org/packages/c8/f4/355e69b5563154b40550233ffba8f6099eac0c99788600191967763046cf/yarl-1.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2", size = 468286 }, - { url = "https://files.pythonhosted.org/packages/26/3d/3c37f3f150faf87b086f7915724f2fcb9ff2f7c9d3f6c0f42b7722bd9b77/yarl-1.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/94/ee/d591abbaea3b14e0f68bdec5cbcb75f27107190c51889d518bafe5d8f120/yarl-1.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa", size = 484947 }, - { url = "https://files.pythonhosted.org/packages/57/70/ad1c65a13315f03ff0c63fd6359dd40d8198e2a42e61bf86507602a0364f/yarl-1.11.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff", size = 505610 }, - { url = "https://files.pythonhosted.org/packages/4c/8c/6086dec0f8d7df16d136b38f373c49cf3d2fb94464e5a10bf788b36f3f54/yarl-1.11.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239", size = 515951 }, - { url = "https://files.pythonhosted.org/packages/49/79/e0479e9a3bbb7bdcb82779d89711b97cea30902a4bfe28d681463b7071ce/yarl-1.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45", size = 501273 }, - { url = "https://files.pythonhosted.org/packages/8e/85/eab962453e81073276b22f3d1503dffe6bfc3eb9cd0f31899970de05d490/yarl-1.11.1-cp312-cp312-win32.whl", hash = "sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447", size = 101139 }, - { url = "https://files.pythonhosted.org/packages/5d/de/618b3e5cab10af8a2ed3eb625dac61c1d16eb155d1f56f9fdb3500786c12/yarl-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639", size = 110504 }, - { url = "https://files.pythonhosted.org/packages/07/b7/948e4f427817e0178f3737adf6712fea83f76921e11e2092f403a8a9dc4a/yarl-1.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c", size = 185061 }, - { url = "https://files.pythonhosted.org/packages/f3/67/8d91ad79a3b907b4fef27fafa912350554443ba53364fff3c347b41105cb/yarl-1.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e", size = 113056 }, - { url = "https://files.pythonhosted.org/packages/a1/77/6b2348a753702fa87f435cc33dcec21981aaca8ef98a46566a7b29940b4a/yarl-1.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93", size = 110958 }, - { url = "https://files.pythonhosted.org/packages/8e/3e/6eadf32656741549041f549a392f3b15245d3a0a0b12a9bc22bd6b69621f/yarl-1.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d", size = 470326 }, - { url = "https://files.pythonhosted.org/packages/3d/a4/1b641a8c7899eeaceec45ff105a2e7206ec0eb0fb9d86403963cc8521c5e/yarl-1.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7", size = 484778 }, - { url = "https://files.pythonhosted.org/packages/8a/f5/80c142f34779a5c26002b2bf1f73b9a9229aa9e019ee6f9fd9d3e9704e78/yarl-1.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089", size = 485568 }, - { url = "https://files.pythonhosted.org/packages/f8/f2/6b40ffea2d5d3a11f514ab23c30d14f52600c36a3210786f5974b6701bb8/yarl-1.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5", size = 477801 }, - { url = "https://files.pythonhosted.org/packages/4c/1a/e60c116f3241e4842ed43c104eb2751abe02f6bac0301cdae69e4fda9c3a/yarl-1.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5", size = 455361 }, - { url = "https://files.pythonhosted.org/packages/b9/98/fe0aeee425a4bc5cd3ed86e867661d2bfa782544fa07a8e3dcd97d51ae3d/yarl-1.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786", size = 473893 }, - { url = "https://files.pythonhosted.org/packages/6b/9b/677455d146bd3cecd350673f0e4bb28854af66726493ace3b640e9c5552b/yarl-1.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318", size = 476407 }, - { url = "https://files.pythonhosted.org/packages/33/ca/ce85766247a9a9b56654428fb78a3e14ea6947a580a9c4e891b3aa7da322/yarl-1.11.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82", size = 490848 }, - { url = "https://files.pythonhosted.org/packages/6d/d6/717f0f19bcf2c4705ad95550b4b6319a0d8d1d4f137ea5e223207f00df50/yarl-1.11.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a", size = 501084 }, - { url = "https://files.pythonhosted.org/packages/14/b5/b93c70d9a462b802c8df65c64b85f49d86b4ba70c393fbad95cf7ec053cb/yarl-1.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da", size = 491776 }, - { url = "https://files.pythonhosted.org/packages/03/0f/5a52eaa402a6a93265ba82f42c6f6085ccbe483e1b058ad34207e75812b1/yarl-1.11.1-cp313-cp313-win32.whl", hash = "sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979", size = 485250 }, - { url = "https://files.pythonhosted.org/packages/dd/97/946d26a5d82706a6769399cabd472c59f9a3227ce1432afb4739b9c29572/yarl-1.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367", size = 492590 }, - { url = "https://files.pythonhosted.org/packages/5b/b3/841f7d706137bdc8b741c6826106b6f703155076d58f1830f244da857451/yarl-1.11.1-py3-none-any.whl", hash = "sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38", size = 38648 }, + { url = "https://files.pythonhosted.org/packages/97/63/0e1e3626a323f366a8ff8eeb4d2835d403cb505393c2fce00c68c2be9d1a/yarl-1.17.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1794853124e2f663f0ea54efb0340b457f08d40a1cef78edfa086576179c91", size = 140627 }, + { url = "https://files.pythonhosted.org/packages/ff/ef/80c92e43f5ca5dfe964f42080252b669097fdd37d40e8c174e5a10d67d2c/yarl-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fbea1751729afe607d84acfd01efd95e3b31db148a181a441984ce9b3d3469da", size = 93563 }, + { url = "https://files.pythonhosted.org/packages/05/43/add866f8c7e99af126a3ff4a673165537617995a5ae90e86cb95f9a1d4ad/yarl-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ee427208c675f1b6e344a1f89376a9613fc30b52646a04ac0c1f6587c7e46ec", size = 91400 }, + { url = "https://files.pythonhosted.org/packages/b9/44/464aba5761fb7ab448d8854520d98355217481746d2421231b8d07d2de8c/yarl-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b74ff4767d3ef47ffe0cd1d89379dc4d828d4873e5528976ced3b44fe5b0a21", size = 313746 }, + { url = "https://files.pythonhosted.org/packages/c1/0f/3a08d81f1e4ff88b07d62f3bb271603c0e2d063cea12239e500defa800d3/yarl-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62a91aefff3d11bf60e5956d340eb507a983a7ec802b19072bb989ce120cd948", size = 329234 }, + { url = "https://files.pythonhosted.org/packages/7d/0f/98f29b8637cf13d7589bb7a1fdc4357bcfc0cfc3f20bc65a6970b71a22ec/yarl-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:846dd2e1243407133d3195d2d7e4ceefcaa5f5bf7278f0a9bda00967e6326b04", size = 325776 }, + { url = "https://files.pythonhosted.org/packages/3c/8c/f383fc542a3d2a1837fb0543ce698653f1760cc18954c29e6d6d49713376/yarl-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e844be8d536afa129366d9af76ed7cb8dfefec99f5f1c9e4f8ae542279a6dc3", size = 318659 }, + { url = "https://files.pythonhosted.org/packages/2b/35/742b4a03ca90e116f70a44b24a36d2138f1b1d776a532ddfece4d60cd93d/yarl-1.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc7c92c1baa629cb03ecb0c3d12564f172218fb1739f54bf5f3881844daadc6d", size = 310172 }, + { url = "https://files.pythonhosted.org/packages/9b/fc/f1aba4194861f44673d9b432310cbee2e7c3ffa8ff9bdf165c7eaa9c6e38/yarl-1.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae3476e934b9d714aa8000d2e4c01eb2590eee10b9d8cd03e7983ad65dfbfcba", size = 318283 }, + { url = "https://files.pythonhosted.org/packages/27/0f/2b20100839064d1c75fb85fa6b5cbd68249d96a4b06a5cf25f9eaaf9b32a/yarl-1.17.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c7e177c619342e407415d4f35dec63d2d134d951e24b5166afcdfd1362828e17", size = 317599 }, + { url = "https://files.pythonhosted.org/packages/7b/da/3f2d6643d8cf3003c72587f28a9d9c76829a5b45186cae8f978bac113fc5/yarl-1.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64cc6e97f14cf8a275d79c5002281f3040c12e2e4220623b5759ea7f9868d6a5", size = 323398 }, + { url = "https://files.pythonhosted.org/packages/9e/f8/881c97cc35603ec63b48875d47e36e1b984648826b36ce7affac16e08261/yarl-1.17.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:84c063af19ef5130084db70ada40ce63a84f6c1ef4d3dbc34e5e8c4febb20822", size = 337601 }, + { url = "https://files.pythonhosted.org/packages/81/da/049b354e00b33019c32126f2a40ecbcc320859f619c4304c556cf23a5dc3/yarl-1.17.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:482c122b72e3c5ec98f11457aeb436ae4aecca75de19b3d1de7cf88bc40db82f", size = 338975 }, + { url = "https://files.pythonhosted.org/packages/26/64/e36e808b249d64cfc33caca7e9ef2d7e636e4f9e8529e4fe5ed4813ac5b0/yarl-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:380e6c38ef692b8fd5a0f6d1fa8774d81ebc08cfbd624b1bca62a4d4af2f9931", size = 331078 }, + { url = "https://files.pythonhosted.org/packages/82/cb/6fe205b528cc889f8e13d6d180adbc8721a21a6aac67fc3158294575add3/yarl-1.17.1-cp310-cp310-win32.whl", hash = "sha256:16bca6678a83657dd48df84b51bd56a6c6bd401853aef6d09dc2506a78484c7b", size = 83573 }, + { url = "https://files.pythonhosted.org/packages/55/96/4dcb7110ae4cd53768254fb50ace7bca00e110459e6eff1d16983c513219/yarl-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:561c87fea99545ef7d692403c110b2f99dced6dff93056d6e04384ad3bc46243", size = 89761 }, + { url = "https://files.pythonhosted.org/packages/ec/0f/ce6a2c8aab9946446fb27f1e28f0fd89ce84ae913ab18a92d18078a1c7ed/yarl-1.17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217", size = 140727 }, + { url = "https://files.pythonhosted.org/packages/9d/df/204f7a502bdc3973cd9fc29e7dfad18ae48b3acafdaaf1ae07c0f41025aa/yarl-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988", size = 93560 }, + { url = "https://files.pythonhosted.org/packages/a2/e1/f4d522ae0560c91a4ea31113a50f00f85083be885e1092fc6e74eb43cb1d/yarl-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75", size = 91497 }, + { url = "https://files.pythonhosted.org/packages/f1/82/783d97bf4a226f1a2e59b1966f2752244c2bf4dc89bc36f61d597b8e34e5/yarl-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca", size = 339446 }, + { url = "https://files.pythonhosted.org/packages/e5/ff/615600647048d81289c80907165de713fbc566d1e024789863a2f6563ba3/yarl-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74", size = 354616 }, + { url = "https://files.pythonhosted.org/packages/a5/04/bfb7adb452bd19dfe0c35354ffce8ebc3086e028e5f8270e409d17da5466/yarl-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f", size = 351801 }, + { url = "https://files.pythonhosted.org/packages/10/e0/efe21edacdc4a638ce911f8cabf1c77cac3f60e9819ba7d891b9ceb6e1d4/yarl-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d", size = 343381 }, + { url = "https://files.pythonhosted.org/packages/63/f9/7bc7e69857d6fc3920ecd173592f921d5701f4a0dd3f2ae293b386cfa3bf/yarl-1.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11", size = 337093 }, + { url = "https://files.pythonhosted.org/packages/93/52/99da61947466275ff17d7bc04b0ac31dfb7ec699bd8d8985dffc34c3a913/yarl-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0", size = 346619 }, + { url = "https://files.pythonhosted.org/packages/91/8a/8aaad86a35a16e485ba0e5de0d2ae55bf8dd0c9f1cccac12be4c91366b1d/yarl-1.17.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3", size = 344347 }, + { url = "https://files.pythonhosted.org/packages/af/b6/97f29f626b4a1768ffc4b9b489533612cfcb8905c90f745aade7b2eaf75e/yarl-1.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe", size = 350316 }, + { url = "https://files.pythonhosted.org/packages/d7/98/8e0e8b812479569bdc34d66dd3e2471176ca33be4ff5c272a01333c4b269/yarl-1.17.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860", size = 361336 }, + { url = "https://files.pythonhosted.org/packages/9e/d3/d1507efa0a85c25285f8eb51df9afa1ba1b6e446dda781d074d775b6a9af/yarl-1.17.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4", size = 365350 }, + { url = "https://files.pythonhosted.org/packages/22/ba/ee7f1830449c96bae6f33210b7d89e8aaf3079fbdaf78ac398e50a9da404/yarl-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4", size = 357689 }, + { url = "https://files.pythonhosted.org/packages/a0/85/321c563dc5afe1661108831b965c512d185c61785400f5606006507d2e18/yarl-1.17.1-cp311-cp311-win32.whl", hash = "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7", size = 83635 }, + { url = "https://files.pythonhosted.org/packages/bc/da/543a32c00860588ff1235315b68f858cea30769099c32cd22b7bb266411b/yarl-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3", size = 90218 }, + { url = "https://files.pythonhosted.org/packages/5d/af/e25615c7920396219b943b9ff8b34636ae3e1ad30777649371317d7f05f8/yarl-1.17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61", size = 141839 }, + { url = "https://files.pythonhosted.org/packages/83/5e/363d9de3495c7c66592523f05d21576a811015579e0c87dd38c7b5788afd/yarl-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d", size = 94125 }, + { url = "https://files.pythonhosted.org/packages/e3/a2/b65447626227ebe36f18f63ac551790068bf42c69bb22dfa3ae986170728/yarl-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139", size = 92048 }, + { url = "https://files.pythonhosted.org/packages/a1/f5/2ef86458446f85cde10582054fd5113495ef8ce8477da35aaaf26d2970ef/yarl-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5", size = 331472 }, + { url = "https://files.pythonhosted.org/packages/f3/6b/1ba79758ba352cdf2ad4c20cab1b982dd369aa595bb0d7601fc89bf82bee/yarl-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac", size = 341260 }, + { url = "https://files.pythonhosted.org/packages/2d/41/4e07c2afca3f9ed3da5b0e38d43d0280d9b624a3d5c478c425e5ce17775c/yarl-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463", size = 340882 }, + { url = "https://files.pythonhosted.org/packages/c3/c0/cd8e94618983c1b811af082e1a7ad7764edb3a6af2bc6b468e0e686238ba/yarl-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147", size = 336648 }, + { url = "https://files.pythonhosted.org/packages/ac/fc/73ec4340d391ffbb8f34eb4c55429784ec9f5bd37973ce86d52d67135418/yarl-1.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7", size = 325019 }, + { url = "https://files.pythonhosted.org/packages/57/48/da3ebf418fc239d0a156b3bdec6b17a5446f8d2dea752299c6e47b143a85/yarl-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685", size = 342841 }, + { url = "https://files.pythonhosted.org/packages/5d/79/107272745a470a8167924e353a5312eb52b5a9bb58e22686adc46c94f7ec/yarl-1.17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172", size = 341433 }, + { url = "https://files.pythonhosted.org/packages/30/9c/6459668b3b8dcc11cd061fc53e12737e740fb6b1575b49c84cbffb387b3a/yarl-1.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7", size = 344927 }, + { url = "https://files.pythonhosted.org/packages/c5/0b/93a17ed733aca8164fc3a01cb7d47b3f08854ce4f957cce67a6afdb388a0/yarl-1.17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da", size = 355732 }, + { url = "https://files.pythonhosted.org/packages/9a/63/ead2ed6aec3c59397e135cadc66572330325a0c24cd353cd5c94f5e63463/yarl-1.17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c", size = 362123 }, + { url = "https://files.pythonhosted.org/packages/89/bf/f6b75b4c2fcf0e7bb56edc0ed74e33f37fac45dc40e5a52a3be66b02587a/yarl-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199", size = 356355 }, + { url = "https://files.pythonhosted.org/packages/45/1f/50a0257cd07eef65c8c65ad6a21f5fb230012d659e021aeb6ac8a7897bf6/yarl-1.17.1-cp312-cp312-win32.whl", hash = "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96", size = 83279 }, + { url = "https://files.pythonhosted.org/packages/bc/82/fafb2c1268d63d54ec08b3a254fbe51f4ef098211501df646026717abee3/yarl-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df", size = 89590 }, + { url = "https://files.pythonhosted.org/packages/06/1e/5a93e3743c20eefbc68bd89334d9c9f04f3f2334380f7bbf5e950f29511b/yarl-1.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488", size = 139974 }, + { url = "https://files.pythonhosted.org/packages/a1/be/4e0f6919013c7c5eaea5c31811c551ccd599d2fc80aa3dd6962f1bbdcddd/yarl-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374", size = 93364 }, + { url = "https://files.pythonhosted.org/packages/73/f0/650f994bc491d0cb85df8bb45392780b90eab1e175f103a5edc61445ff67/yarl-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac", size = 91177 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/9945ed555d14b43ede3ae8b1bd73e31068a694cad2b9d3cad0a28486c2eb/yarl-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170", size = 333086 }, + { url = "https://files.pythonhosted.org/packages/a6/c0/7d167e48e14d26639ca066825af8da7df1d2fcdba827e3fd6341aaf22a3b/yarl-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8", size = 343661 }, + { url = "https://files.pythonhosted.org/packages/fa/81/80a266517531d4e3553aecd141800dbf48d02e23ebd52909e63598a80134/yarl-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938", size = 345196 }, + { url = "https://files.pythonhosted.org/packages/b0/77/6adc482ba7f2dc6c0d9b3b492e7cd100edfac4cfc3849c7ffa26fd7beb1a/yarl-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e", size = 338743 }, + { url = "https://files.pythonhosted.org/packages/6d/cc/f0c4c0b92ff3ada517ffde2b127406c001504b225692216d969879ada89a/yarl-1.17.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556", size = 326719 }, + { url = "https://files.pythonhosted.org/packages/18/3b/7bfc80d3376b5fa162189993a87a5a6a58057f88315bd0ea00610055b57a/yarl-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67", size = 345826 }, + { url = "https://files.pythonhosted.org/packages/2e/66/cf0b0338107a5c370205c1a572432af08f36ca12ecce127f5b558398b4fd/yarl-1.17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8", size = 340335 }, + { url = "https://files.pythonhosted.org/packages/2f/52/b084b0eec0fd4d2490e1d33ace3320fad704c5f1f3deaa709f929d2d87fc/yarl-1.17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3", size = 345301 }, + { url = "https://files.pythonhosted.org/packages/ef/38/9e2036d948efd3bafcdb4976cb212166fded76615f0dfc6c1492c4ce4784/yarl-1.17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0", size = 354205 }, + { url = "https://files.pythonhosted.org/packages/81/c1/13dfe1e70b86811733316221c696580725ceb1c46d4e4db852807e134310/yarl-1.17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299", size = 360501 }, + { url = "https://files.pythonhosted.org/packages/91/87/756e05c74cd8bf9e71537df4a2cae7e8211a9ebe0d2350a3e26949e1e41c/yarl-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258", size = 359452 }, + { url = "https://files.pythonhosted.org/packages/06/b2/b2bb09c1e6d59e1c9b1b36a86caa473e22c3dbf26d1032c030e9bfb554dc/yarl-1.17.1-cp313-cp313-win32.whl", hash = "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2", size = 308904 }, + { url = "https://files.pythonhosted.org/packages/f3/27/f084d9a5668853c1f3b246620269b14ee871ef3c3cc4f3a1dd53645b68ec/yarl-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda", size = 314637 }, + { url = "https://files.pythonhosted.org/packages/52/ad/1fe7ff5f3e8869d4c5070f47b96bac2b4d15e67c100a8278d8e7876329fc/yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06", size = 44352 }, ] [[package]] From ed3bed7b51f9c055f9ad757a875375536d8c511b Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Sat, 9 Nov 2024 09:32:41 -0500 Subject: [PATCH 06/16] Fix mypy errors --- python/samples/demos/process_with_dapr/app.py | 2 +- .../dapr_runtime/actors/actor_state_key.py | 3 + .../dapr_runtime/actors/event_buffer_actor.py | 4 +- .../actors/external_event_buffer_actor.py | 6 +- .../actors/message_buffer_actor.py | 9 +- .../dapr_runtime/actors/process_actor.py | 90 +++++++++++++------ .../dapr_runtime/actors/step_actor.py | 71 +++++++++------ .../dapr_kernel_process_context.py | 6 +- .../dapr_runtime/dapr_process_info.py | 7 +- .../processes/dapr_runtime/dapr_step_info.py | 4 +- .../dapr_runtime/interfaces/__init__.py | 0 .../event_buffer_interface.py | 13 ++- .../external_event_buffer_interface.py | 13 ++- .../message_buffer_interface.py | 13 ++- .../{ => interfaces}/process_interface.py | 24 +++-- .../{ => interfaces}/step_interface.py | 35 +++++--- .../semantic_kernel/processes/step_utils.py | 3 +- python/uv.lock | 4 +- 18 files changed, 205 insertions(+), 102 deletions(-) create mode 100644 python/semantic_kernel/processes/dapr_runtime/interfaces/__init__.py rename python/semantic_kernel/processes/dapr_runtime/{ => interfaces}/event_buffer_interface.py (72%) rename python/semantic_kernel/processes/dapr_runtime/{ => interfaces}/external_event_buffer_interface.py (73%) rename python/semantic_kernel/processes/dapr_runtime/{ => interfaces}/message_buffer_interface.py (73%) rename python/semantic_kernel/processes/dapr_runtime/{ => interfaces}/process_interface.py (84%) rename python/semantic_kernel/processes/dapr_runtime/{ => interfaces}/step_interface.py (50%) diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index c837c33ba19c..818475d50fe7 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -130,7 +130,7 @@ async def activate(self, state: KernelProcessStepState[CStepState]): async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str): self.state.current_cycle += 1 print(f"CStep Current Cycle: {self.state.current_cycle}") - if self.state.current_cycle == 3: + if self.state.current_cycle >= 3: print("CStep Exit Requested") await context.emit_event(process_event=CommonEvents.ExitRequested.value) return diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py b/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py index 86ee082daa91..f1701c338184 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/actor_state_key.py @@ -2,7 +2,10 @@ from enum import Enum +from semantic_kernel.utils.experimental_decorator import experimental_class + +@experimental_class class ActorStateKeys(Enum): """Keys used to store actor state in Dapr.""" diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py index e166f3beb5c7..1a5f235e0628 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/event_buffer_actor.py @@ -7,11 +7,13 @@ from dapr.actor import Actor from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys -from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.message_buffer_interface import MessageBufferInterface +from semantic_kernel.utils.experimental_decorator import experimental_class logger = logging.getLogger(__name__) +@experimental_class class EventBufferActor(Actor, MessageBufferInterface): """Represents a message buffer actor that manages a queue of JSON strings representing events.""" diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py index c37fb1007137..1938056b4f23 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/external_event_buffer_actor.py @@ -8,11 +8,15 @@ from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys -from semantic_kernel.processes.dapr_runtime.external_event_buffer_interface import ExternalEventBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.external_event_buffer_interface import ( + ExternalEventBufferInterface, +) +from semantic_kernel.utils.experimental_decorator import experimental_class logger = logging.getLogger(__name__) +@experimental_class class ExternalEventBufferActor(Actor, ExternalEventBufferInterface): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py index 8c2e626b872b..cf28f868b619 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py @@ -8,11 +8,13 @@ from dapr.actor.runtime.context import ActorRuntimeContext from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys -from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.message_buffer_interface import MessageBufferInterface +from semantic_kernel.utils.experimental_decorator import experimental_class logger: logging.Logger = logging.getLogger(__name__) +@experimental_class class MessageBufferActor(Actor, MessageBufferInterface): """Represents a message buffer actor that follows the MessageBuffer abstract class.""" @@ -54,8 +56,6 @@ async def dequeue_all(self) -> list[str]: raise Exception(error_message) async def _on_activate(self) -> None: - from semantic_kernel.processes.process_message import ProcessMessage - try: logger.info(f"Activating actor with ID: {self.id.id}") @@ -63,8 +63,7 @@ async def _on_activate(self) -> None: if has_value and queue_list: self.queue = Queue() for item_dict in queue_list: - message_obj = ProcessMessage(**item_dict) - self.queue.put(message_obj) + self.queue.put(item_dict) else: self.queue = Queue() except Exception as e: diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py index 9e0e46123bea..11e80bfac09e 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py @@ -21,22 +21,27 @@ from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo -from semantic_kernel.processes.dapr_runtime.event_buffer_interface import EventBufferInterface -from semantic_kernel.processes.dapr_runtime.external_event_buffer_interface import ExternalEventBufferInterface -from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface -from semantic_kernel.processes.dapr_runtime.process_interface import ProcessInterface -from semantic_kernel.processes.dapr_runtime.step_interface import StepInterface +from semantic_kernel.processes.dapr_runtime.interfaces.event_buffer_interface import EventBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.external_event_buffer_interface import ( + ExternalEventBufferInterface, +) +from semantic_kernel.processes.dapr_runtime.interfaces.message_buffer_interface import MessageBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.process_interface import ProcessInterface +from semantic_kernel.processes.dapr_runtime.interfaces.step_interface import StepInterface from semantic_kernel.processes.kernel_process.kernel_process_event import ( KernelProcessEvent, KernelProcessEventVisibility, ) +from semantic_kernel.processes.kernel_process.kernel_process_state import KernelProcessState from semantic_kernel.processes.process_event import ProcessEvent from semantic_kernel.processes.process_message import ProcessMessage from semantic_kernel.processes.process_message_factory import ProcessMessageFactory +from semantic_kernel.utils.experimental_decorator import experimental_class logger: logging.Logger = logging.getLogger(__name__) +@experimental_class class ProcessActor(StepActor, ProcessInterface): """A local process that contains a collection of steps.""" @@ -50,7 +55,7 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): """ super().__init__(ctx, actor_id, kernel) self.kernel = kernel - self.steps: list[StepActor] = [] + self.steps: list[StepInterface] = [] self.step_infos: list[DaprStepInfo] = [] self.initialize_task: bool | None = False self.external_event_queue: Queue = Queue() @@ -60,11 +65,12 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): @property def name(self) -> str: """Gets the name of the step.""" - if self.process.state.name is None: - raise KernelException("The process must be initialized before accessing the name property.") - return self.step_info.state.name + if self.process is None or self.process.state is None or self.process.state.name is None: + error_message = "The process must be initialized before accessing the name property." + logger.error(error_message) + raise KernelException(error_message) + return self.process.state.name - # async def initialize_process(self, process_info: dict[str, Any], parent_process_id: str | None = None) -> None: async def initialize_process(self, input: dict) -> None: """Initializes the process.""" process_info_dict = input.get("process_info") @@ -95,6 +101,8 @@ async def initialize_process(self, input: dict) -> None: ) await self._state_manager.try_add_state(ActorStateKeys.StepActivatedState.value, True) await self._state_manager.save_state() + + logger.info(f"Initialized process for: {dapr_process_info} and parent process ID: {parent_process_id}") except Exception as ex: error_message = str(ex) logger.error(f"Error in initialize_process: {error_message}") @@ -118,13 +126,16 @@ async def run_once(self, process_event: str) -> None: if process_event is None: raise ProcessEventUndefinedException("The process event must be specified.") - external_event_queue: ExternalEventBufferActor = ActorProxy.create( + external_event_queue: ExternalEventBufferActor = ActorProxy.create( # type: ignore actor_type=f"{ExternalEventBufferActor.__name__}", actor_id=ActorId(self.id.id), actor_interface=ExternalEventBufferInterface, ) try: await external_event_queue.enqueue(process_event) + + logger.info(f"Run once for process event: {process_event}") + await self.start(keep_alive=False) if self.process_task: try: @@ -161,7 +172,7 @@ async def _on_activate(self) -> None: has_value, parent_process_id = await self._state_manager.try_get_state( ActorStateKeys.StepParentProcessId.value ) - combined_input = {**existing_process_info, **parent_process_id} + combined_input = {**existing_process_info, **parent_process_id} # type: ignore await self.initialize_process(combined_input) except Exception as e: error_message = str(e) @@ -180,11 +191,16 @@ async def get_process_info(self): async def to_dapr_process_info(self) -> DaprProcessInfo: """Converts the process to a Dapr process info.""" - process_state = DaprProcessInfo(self.name, self.id.id) + if self.process is None: + raise ValueError("The process must be initialized before converting to DaprProcessInfo.") + if self.inner_step_type is None: + raise ValueError("The inner step type must be defined before converting to DaprProcessInfo.") + + process_state = KernelProcessState(self.name, self.id.id) step_tasks = [step.to_dapr_step_info() for step in self.steps] steps = await asyncio.gather(*step_tasks) return DaprProcessInfo( - inner_step_dotnet_type=self.inner_step_type, edges=self.process.edges, state=process_state, steps=steps + inner_step_python_type=self.inner_step_type, edges=self.process.edges, state=process_state, steps=steps ) async def handle_message(self, message: ProcessMessage) -> None: @@ -200,7 +216,7 @@ async def handle_message(self, message: ProcessMessage) -> None: nested_event = KernelProcessEvent( id=event_id, data=message.target_event_data, visibility=KernelProcessEventVisibility.Internal ) - await self.run_once(nested_event) + await self.run_once(nested_event.model_dump_json()) async def _initialize_process_actor( self, process_info: DaprProcessInfo, parent_process_id: str | None = None @@ -218,7 +234,7 @@ async def _initialize_process_actor( self.output_edges = {kvp[0]: list(kvp[1]) for kvp in self.process.edges.items()} for step in self.step_infos: - step_actor: StepInterface = None + step_actor = None # The current step should already have a name. assert step.state and step.state.name is not None # nosec @@ -230,14 +246,14 @@ async def _initialize_process_actor( # Initialize the step as a process scoped_process_id = self._scoped_actor_id(ActorId(step.state.id)) - process_actor: ProcessInterface = ActorProxy.create( + process_actor: ProcessInterface = ActorProxy.create( # type: ignore actor_type=f"{ProcessActor.__name__}", actor_id=scoped_process_id, actor_interface=ProcessInterface, ) payload = {"process_info": step.model_dump(), "parent_process_id": self.id.id} await process_actor.initialize_process(payload) - step_actor = ActorProxy.create( + step_actor = ActorProxy.create( # type: ignore actor_type=f"{ProcessActor.__name__}", actor_id=scoped_process_id, actor_interface=StepInterface, @@ -247,7 +263,7 @@ async def _initialize_process_actor( assert step.state and step.state.id is not None # nosec scoped_step_id = self._scoped_actor_id(ActorId(step.state.id)) - step_actor = ActorProxy.create( + step_actor = ActorProxy.create( # type: ignore actor_type=f"{StepActor.__name__}", actor_id=scoped_step_id, actor_interface=StepInterface, @@ -261,7 +277,7 @@ async def _initialize_process_actor( raise ex # Add the local step to the list of steps - self.steps.append(step_actor) + self.steps.append(step_actor) # type: ignore self.initialize_task = True @@ -308,20 +324,25 @@ def _scoped_event(self, dapr_event: ProcessEvent): if dapr_event is None: raise ValueError("The Dapr event must be specified.") + if self.process is None or self.process.state is None: + raise ValueError("The process must be initialized before scoping the event.") + dapr_event.namespace = f"{self.name}_{self.process.state.id}" return dapr_event async def send_outgoing_public_events(self) -> None: """Sends outgoing public events.""" if self.parent_process_id is not None: - event_queue: EventBufferActor = ActorProxy.create( + event_queue: EventBufferActor = ActorProxy.create( # type: ignore actor_type=f"{EventBufferActor.__name__}", actor_id=ActorId(self.id.id), actor_interface=EventBufferInterface, ) - all_events: list[ProcessEvent] = await event_queue.dequeue_all() + all_events: list[str] = await event_queue.dequeue_all() - for e in all_events: + process_events = [ProcessEvent.model_validate(json.loads(e)) for e in all_events] + + for e in process_events: scoped_event = self._scoped_event(e) if scoped_event.id in self.output_edges and self.output_edges[scoped_event.id] is not None: for edge in self.output_edges[scoped_event.id]: @@ -329,27 +350,35 @@ async def send_outgoing_public_events(self) -> None: scoped_message_buffer_id = self._scoped_actor_id( ActorId(edge.output_target.step_id), scope_to_parent=True ) - message_queue: MessageBufferActor = ActorProxy.create( + message_queue: MessageBufferActor = ActorProxy.create( # type: ignore actor_id=scoped_message_buffer_id, actor_type=f"{MessageBufferActor.__name__}", actor_interface=MessageBufferInterface, ) - await message_queue.enqueue(message.model_dump_json()) + + message_json = json.dumps(message.model_dump()) + + logger.info(f"Enqueueing message: {message_json}") + + await message_queue.enqueue(message_json) async def _is_end_message_sent(self) -> bool: """Checks if the end message has been sent.""" scoped_message_buffer_id = self._scoped_actor_id(ActorId(END_PROCESS_ID)) - end_message_queue: MessageBufferActor = ActorProxy.create( + end_message_queue: MessageBufferActor = ActorProxy.create( # type: ignore actor_type=f"{MessageBufferActor.__name__}", actor_id=scoped_message_buffer_id, actor_interface=MessageBufferInterface, ) messages: list[str] = await end_message_queue.dequeue_all() + + logger.info(f"End message sent: {len(messages) > 0}") + return len(messages) > 0 async def _enqueue_external_messages(self) -> None: """Enqueues external messages into the process.""" - external_event_queue: ExternalEventBufferActor = ActorProxy.create( + external_event_queue: ExternalEventBufferActor = ActorProxy.create( # type: ignore actor_type=f"{ExternalEventBufferActor.__name__}", actor_id=ActorId(self.id.id), actor_interface=ExternalEventBufferInterface, @@ -357,6 +386,8 @@ async def _enqueue_external_messages(self) -> None: external_events_json = await external_event_queue.dequeue_all() + logger.info(f"External events dequeued: {len(external_events_json)} with json: {external_events_json}") + external_events = [KernelProcessEvent.model_validate(json.loads(e)) for e in external_events_json] for external_event in external_events: @@ -364,10 +395,13 @@ async def _enqueue_external_messages(self) -> None: for edge in self.output_edges[external_event.id]: message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, external_event.data) scoped_message_buffer_id = self._scoped_actor_id(ActorId(edge.output_target.step_id)) - message_queue: MessageBufferActor = ActorProxy.create( + message_queue: MessageBufferActor = ActorProxy.create( # type: ignore actor_type=f"{MessageBufferActor.__name__}", actor_id=scoped_message_buffer_id, actor_interface=MessageBufferInterface, ) message_json = json.dumps(message.model_dump()) + + logger.info(f"Enqueueing message: {message_json}") + await message_queue.enqueue(message_json) diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py index e4bb14363417..c5ee2eaa62d1 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -21,9 +21,9 @@ from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo -from semantic_kernel.processes.dapr_runtime.event_buffer_interface import EventBufferInterface -from semantic_kernel.processes.dapr_runtime.message_buffer_interface import MessageBufferInterface -from semantic_kernel.processes.dapr_runtime.step_interface import StepInterface +from semantic_kernel.processes.dapr_runtime.interfaces.event_buffer_interface import EventBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.message_buffer_interface import MessageBufferInterface +from semantic_kernel.processes.dapr_runtime.interfaces.step_interface import StepInterface from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge from semantic_kernel.processes.kernel_process.kernel_process_event import ( KernelProcessEvent, @@ -60,7 +60,7 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): self.step_info: DaprStepInfo | None = None self.initialize_task: bool | None = False self.event_namespace: str | None = None - self.inner_step_type: type | None = None + self.inner_step_type: str | None = None self.incoming_messages: Queue = Queue() self.step_state: KernelProcessStepState | None = None self.step_state_type: type | None = None @@ -74,38 +74,37 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId, kernel: Kernel): @property def name(self) -> str: """Gets the name of the step.""" + if self.step_info is None or self.step_info.state is None or self.step_info.state.name is None: + error_message = "The step must be initialized before accessing the name property." + logger.error(error_message) + raise KernelException(error_message) return self.step_info.state.name - async def initialize_step(self, input: dict) -> None: + async def initialize_step(self, input: str) -> None: """Initializes the step with the provided step information.""" if input is None: raise ValueError("step_info must not be None") try: - input = json.loads(input) + input_dict: dict[str, Any] = json.loads(input) except (json.JSONDecodeError, TypeError): raise ValueError("Input must be a valid JSON string representing a dictionary") - step_info = DaprStepInfo.model_validate(input.get("step_info")) + step_info = DaprStepInfo.model_validate(input_dict.get("step_info")) if self.initialize_task: return - await self._int_initialize_step(step_info, input.get("parent_process_id")) + await self._int_initialize_step(step_info, input_dict.get("parent_process_id")) try: await self._state_manager.try_add_state(ActorStateKeys.StepInfoState.value, step_info) await self._state_manager.try_add_state( - ActorStateKeys.StepParentProcessId.value, input.get("parent_process_id") + ActorStateKeys.StepParentProcessId.value, input_dict.get("parent_process_id") ) await self._state_manager.save_state() except Exception as ex: - try: - current_state = await self._state_manager.get_state(ActorStateKeys.StepInfoState.value) - except Exception as ex: - print(ex) - print(current_state) - print(f"Error in Step {self.name}: {ex!s}") + logger.error(f"Error in Step {self.name}: {ex!s}") raise ex async def _int_initialize_step(self, step_info: DaprStepInfo, parent_process_id: str | None = None) -> None: @@ -128,7 +127,7 @@ async def _int_initialize_step(self, step_info: DaprStepInfo, parent_process_id: async def prepare_incoming_messages(self) -> int: """Prepares the incoming messages for processing.""" try: - message_queue: MessageBufferInterface = ActorProxy.create( + message_queue: MessageBufferInterface = ActorProxy.create( # type: ignore actor_type=f"{MessageBufferActor.__name__}", actor_id=ActorId(self.id.id), actor_interface=MessageBufferInterface, @@ -157,8 +156,11 @@ async def prepare_incoming_messages(self) -> int: async def process_incoming_messages(self) -> None: """Triggers the step to process all prepared messages.""" + logger.info(f"Processing incoming messages for step {self.name}.") + while not self.incoming_messages.empty(): message = self.incoming_messages.get() + logger.info(f"Processing message {message}.") await self.handle_message(message) await self._state_manager.try_add_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) @@ -254,6 +256,8 @@ async def handle_message(self, message: ProcessMessage): if message is None: raise ValueError("The message is None.") + logger.info(f"Received message from `{message.source_id}` targeting function `{message.function_name}`.") + if not self.step_activated: async with self.init_lock: # Second check to ensure that initialization happens only once @@ -264,6 +268,7 @@ async def handle_message(self, message: ProcessMessage): self.step_activated = True if self.functions is None or self.inputs is None or self.initial_inputs is None: + logger.error(f"The step `{self.name}` has not been initialized.") raise ValueError("The step has not been initialized.") message_log_parameters = ", ".join(f"{k}: {v}" for k, v in message.values.items()) @@ -332,9 +337,10 @@ async def handle_message(self, message: ProcessMessage): event_name = f"{target_function}.OnResult" event_value = invoke_result.value - state_dict = self.step_state.model_dump() - await self._state_manager.set_state(ActorStateKeys.StepStateJson.value, json.dumps(state_dict)) - await self._state_manager.save_state() + if self.step_state is not None: + state_dict = self.step_state.model_dump() + await self._state_manager.set_state(ActorStateKeys.StepStateJson.value, json.dumps(state_dict)) + await self._state_manager.save_state() except Exception as ex: logger.error(f"Error in Step {self.name}: {ex!s}") event_name = f"{target_function}.OnError" @@ -351,12 +357,15 @@ async def invoke_function(self, function: "KernelFunction", kernel: "Kernel", ar async def emit_event(self, process_event: KernelProcessEvent): """Emits an event from the step.""" + if self.event_namespace is None: + raise ValueError("The event namespace must be initialized before emitting an event.") + await self.emit_process_event(ProcessEvent.from_kernel_process_event(process_event, self.event_namespace)) async def emit_process_event(self, dapr_event: ProcessEvent): """Emits an event from the step.""" if dapr_event.visibility == KernelProcessEventVisibility.Public and self.parent_process_id is not None: - parent_process: EventBufferActor = ActorProxy.create( + parent_process: EventBufferActor = ActorProxy.create( # type: ignore actor_type=f"{EventBufferActor.__name__}", actor_id=ActorId(self.parent_process_id), actor_interface=EventBufferInterface, @@ -366,14 +375,14 @@ async def emit_process_event(self, dapr_event: ProcessEvent): for edge in self.get_edge_for_event(dapr_event.id): message: ProcessMessage = ProcessMessageFactory.create_from_edge(edge, dapr_event.data) scoped_step_id = self._scoped_actor_id(ActorId(edge.output_target.step_id)) - target_step: MessageBufferInterface = ActorProxy.create( + target_step: MessageBufferInterface = ActorProxy.create( # type: ignore actor_type=f"{MessageBufferActor.__name__}", actor_id=scoped_step_id, actor_interface=MessageBufferInterface, ) await target_step.enqueue(message.model_dump_json()) - async def to_dapr_step_info(self) -> DaprStepInfo: + async def to_dapr_step_info(self) -> str: """Converts the step to a DaprStepInfo object.""" if not self.step_activated: async with self.init_lock: @@ -384,10 +393,18 @@ async def to_dapr_step_info(self) -> DaprStepInfo: await self.activate_step() self.step_activated = True - return DaprStepInfo( + if self.step_info is None: + raise ValueError("The step must be initialized before converting to DaprStepInfo.") + + if self.inner_step_type is None: + raise ValueError("The inner step type must be initialized before converting to DaprStepInfo.") + + step_info = DaprStepInfo( inner_step_python_type=self.inner_step_type, state=self.step_info.state, edges=self.step_info.edges ) + return step_info.model_dump_json() + async def _on_activate(self) -> None: """Override the Actor's on_activate method.""" try: @@ -397,14 +414,18 @@ async def _on_activate(self) -> None: raise ex if has_value: parent_process_id = await self._state_manager.get_state(ActorStateKeys.StepParentProcessId.value) - await self._int_initialize_step(existing_step_info, parent_process_id=parent_process_id) + step_info = DaprStepInfo.model_validate(json.loads(existing_step_info)) # type: ignore + await self._int_initialize_step(step_info, parent_process_id=parent_process_id) # Load persisted incoming messages has_value, incoming_messages = await self._state_manager.try_get_state( ActorStateKeys.StepIncomingMessagesState.value ) if has_value: - self.incoming_messages = incoming_messages + messages = json.loads(incoming_messages) # type: ignore + for msg in messages: + process_message = ProcessMessage.model_validate(json.loads(msg)) + self.incoming_messages.put(process_message) def scoped_event(self, dapr_event: "ProcessEvent") -> "ProcessEvent": """Generates a scoped event for the step.""" diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py index ed6b6ad3bb28..1486713f163f 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -6,15 +6,17 @@ from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo -from semantic_kernel.processes.dapr_runtime.process_interface import ProcessInterface +from semantic_kernel.processes.dapr_runtime.interfaces.process_interface import ProcessInterface from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.utils.experimental_decorator import experimental_class +@experimental_class class DaprKernelProcessContext: """A Dapr kernel process context.""" - dapr_process: ProcessInterface + dapr_process: ActorProxy process: KernelProcess def __init__(self, process: KernelProcess): diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py index 0d3b5b5fc0eb..71cb2ea3a6b5 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py @@ -7,14 +7,13 @@ from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess from semantic_kernel.processes.kernel_process.kernel_process_state import KernelProcessState from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo +from semantic_kernel.utils.experimental_decorator import experimental_class +@experimental_class class DaprProcessInfo(DaprStepInfo): """A Dapr process info.""" - # info: KernelProcessEdge | KernelProcessState | KernelProcessStepState | KernelProcessStepState[TState] = Field( - # discriminator="type" - # ) steps: list[DaprStepInfo] = Field(default_factory=list) def to_kernel_process(self) -> KernelProcess: @@ -38,7 +37,7 @@ def from_kernel_process(cls, kernel_process: KernelProcess) -> "DaprProcessInfo" raise ValueError("Kernel process must be provided") dapr_step_info = DaprStepInfo.from_kernel_step_info(kernel_process) - dapr_steps = [] + dapr_steps: list[DaprProcessInfo | DaprStepInfo] = [] for step in kernel_process.steps: if isinstance(step, KernelProcess): diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py index 74060c6918ce..f94cc1a4d601 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py @@ -10,8 +10,10 @@ from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState from semantic_kernel.processes.step_utils import get_fully_qualified_name +from semantic_kernel.utils.experimental_decorator import experimental_class +@experimental_class class DaprStepInfo(KernelBaseModel): """A Dapr step info.""" @@ -26,7 +28,7 @@ def to_kernel_process_step_info(self) -> KernelProcessStepInfo: raise KernelException( f"Unable to create inner step type from assembly qualified name `{self.inner_step_python_type}`" ) - return KernelProcessStepInfo(inner_step_type=inner_step_type, state=self.state, edges=self.edges) + return KernelProcessStepInfo(inner_step_type=inner_step_type, state=self.state, output_edges=self.edges) @classmethod def from_kernel_step_info(cls, kernel_step_info: KernelProcessStepInfo) -> "DaprStepInfo": diff --git a/python/semantic_kernel/processes/dapr_runtime/interfaces/__init__.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/event_buffer_interface.py similarity index 72% rename from python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py rename to python/semantic_kernel/processes/dapr_runtime/interfaces/event_buffer_interface.py index 2c537aa3654f..3f6312b7ff37 100644 --- a/python/semantic_kernel/processes/dapr_runtime/event_buffer_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/interfaces/event_buffer_interface.py @@ -1,11 +1,17 @@ # Copyright (c) Microsoft. All rights reserved. +from abc import ABC, abstractmethod + from dapr.actor import ActorInterface, actormethod +from semantic_kernel.utils.experimental_decorator import experimental_class + -class EventBufferInterface(ActorInterface): +@experimental_class +class EventBufferInterface(ActorInterface, ABC): """Abstract base class for an event buffer that follows the ActorInterface.""" + @abstractmethod @actormethod(name="enqueue") async def enqueue(self, step_event: str) -> None: """Enqueues a `ProcessEvent` step event into the buffer. @@ -13,8 +19,9 @@ async def enqueue(self, step_event: str) -> None: Args: step_event: The step event to enqueue. """ - pass + ... + @abstractmethod @actormethod(name="dequeue_all") async def dequeue_all(self) -> list[str]: """Dequeues a step event from the buffer. @@ -22,4 +29,4 @@ async def dequeue_all(self) -> list[str]: Returns: The dequeued step event as a list of `ProcessEvent`. """ - pass + ... diff --git a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/external_event_buffer_interface.py similarity index 73% rename from python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py rename to python/semantic_kernel/processes/dapr_runtime/interfaces/external_event_buffer_interface.py index 8023f94bc6fd..af1bb8686d01 100644 --- a/python/semantic_kernel/processes/dapr_runtime/external_event_buffer_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/interfaces/external_event_buffer_interface.py @@ -1,12 +1,18 @@ # Copyright (c) Microsoft. All rights reserved. +from abc import ABC, abstractmethod + from dapr.actor import ActorInterface, actormethod +from semantic_kernel.utils.experimental_decorator import experimental_class + -class ExternalEventBufferInterface(ActorInterface): +@experimental_class +class ExternalEventBufferInterface(ActorInterface, ABC): """Abstract base class for an external event buffer that follows the ActorInterface.""" + @abstractmethod @actormethod(name="enqueue") async def enqueue(self, external_event: str) -> None: """Enqueues an external event into the buffer. @@ -14,8 +20,9 @@ async def enqueue(self, external_event: str) -> None: Args: external_event: The external event to enqueue. """ - pass + ... + @abstractmethod @actormethod(name="dequeue_all") async def dequeue_all(self) -> list[str]: """Dequeues all external events from the buffer as. @@ -25,4 +32,4 @@ async def dequeue_all(self) -> list[str]: Returns: The dequeued external event. """ - pass + ... diff --git a/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/message_buffer_interface.py similarity index 73% rename from python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py rename to python/semantic_kernel/processes/dapr_runtime/interfaces/message_buffer_interface.py index a1c3fcb2cadb..c1591c219b85 100644 --- a/python/semantic_kernel/processes/dapr_runtime/message_buffer_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/interfaces/message_buffer_interface.py @@ -1,11 +1,17 @@ # Copyright (c) Microsoft. All rights reserved. +from abc import ABC, abstractmethod + from dapr.actor import ActorInterface, actormethod +from semantic_kernel.utils.experimental_decorator import experimental_class + -class MessageBufferInterface(ActorInterface): +@experimental_class +class MessageBufferInterface(ActorInterface, ABC): """Abstract base class for a message event buffer that follows the ActorInterface.""" + @abstractmethod @actormethod(name="enqueue") async def enqueue(self, message: str) -> None: """Enqueues a message event into the buffer. @@ -13,8 +19,9 @@ async def enqueue(self, message: str) -> None: Args: message: The message event to enqueue. """ - pass + ... + @abstractmethod @actormethod(name="dequeue_all") async def dequeue_all(self) -> list[str]: """Dequeues all process events from the buffer. @@ -23,4 +30,4 @@ async def dequeue_all(self) -> list[str]: The dequeued message event as a list of string representing a ProcessEvent. """ - pass + ... diff --git a/python/semantic_kernel/processes/dapr_runtime/process_interface.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py similarity index 84% rename from python/semantic_kernel/processes/dapr_runtime/process_interface.py rename to python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py index 92add53bb779..f477d31e3950 100644 --- a/python/semantic_kernel/processes/dapr_runtime/process_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py @@ -1,15 +1,20 @@ # Copyright (c) Microsoft. All rights reserved. +from abc import ABC, abstractmethod + from dapr.actor import ActorInterface, actormethod from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.utils.experimental_decorator import experimental_class -class ProcessInterface(ActorInterface): +@experimental_class +class ProcessInterface(ActorInterface, ABC): """Abstract base class for a process that follows the ActorInterface.""" + @abstractmethod @actormethod(name="initialize_process") # async def initialize_process(self, process_info: "DaprProcessInfo", parent_process_id: str | None = None) -> None: async def initialize_process(self, input: dict) -> None: @@ -18,41 +23,46 @@ async def initialize_process(self, input: dict) -> None: :param process_info: Used to initialize the process. :param parent_process_id: The parent ID of the process if one exists. """ - pass + ... + @abstractmethod @actormethod(name="start") async def start(self, keep_alive: bool) -> None: """Starts an initialized process. :param keep_alive: Indicates if the process should wait for external events after it's finished processing. """ - pass + ... + @abstractmethod @actormethod(name="run_once") async def run_once(self, process_event: KernelProcessEvent) -> None: """Starts the process with an initial event and then waits for the process to finish. :param process_event: Required. The KernelProcessEvent to start the process with. """ - pass + ... + @abstractmethod @actormethod(name="stop") async def stop(self) -> None: """Stops a running process, canceling and waiting for it to complete before returning.""" - pass + ... + @abstractmethod @actormethod(name="send_message") async def send_message(self, process_event: "KernelProcessEvent") -> None: """Sends a message to the process without starting it if it is not already running. :param process_event: Required. The KernelProcessEvent to queue for the process. """ - pass + ... + @abstractmethod @actormethod(name="get_process_info") async def get_process_info(self) -> "DaprProcessInfo": """Retrieves the process information. :return: An instance of DaprProcessInfo. """ - pass + ... diff --git a/python/semantic_kernel/processes/dapr_runtime/step_interface.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/step_interface.py similarity index 50% rename from python/semantic_kernel/processes/dapr_runtime/step_interface.py rename to python/semantic_kernel/processes/dapr_runtime/interfaces/step_interface.py index 97d31467b00f..987e52103cb1 100644 --- a/python/semantic_kernel/processes/dapr_runtime/step_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/interfaces/step_interface.py @@ -1,42 +1,49 @@ # Copyright (c) Microsoft. All rights reserved. +from abc import ABC, abstractmethod + from dapr.actor import ActorInterface, actormethod -from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.utils.experimental_decorator import experimental_class -class StepInterface(ActorInterface): +@experimental_class +class StepInterface(ActorInterface, ABC): """Abstract base class for a step in the process workflow.""" + @abstractmethod @actormethod(name="initialize_step") - # async def initialize_step(self, step_info: "DaprStepInfo", parent_process_id: str | None = None) -> None: - async def initialize_step(self, input: dict) -> None: + async def initialize_step(self, input: str) -> None: """Initializes the step with the provided step information. - :param step_info: The DaprStepInfo object to initialize the step with. - :param parent_process_id: Optional parent process ID if one exists. - :raises KernelException: If an error occurs during initialization. + Args: + input: the DaprStepinfo and ParentProcessId dictionary as a str """ - pass + ... + @abstractmethod @actormethod(name="prepare_incoming_messages") async def prepare_incoming_messages(self) -> int: """Triggers the step to dequeue all pending messages and prepare for processing. - :return: An integer indicating the number of messages prepared for processing. + Returns: + The number of messages that were dequeued. """ - pass + ... + @abstractmethod @actormethod(name="process_incoming_messages") async def process_incoming_messages(self) -> None: """Triggers the step to process all prepared messages.""" - pass + ... + @abstractmethod @actormethod(name="to_dapr_step_info") - async def to_dapr_step_info(self) -> "DaprStepInfo": + async def to_dapr_step_info(self) -> str: """Builds the current state of the step into a DaprStepInfo. - :return: An instance of DaprStepInfo representing the step's current state. + Returns: + The DaprStepInfo representing the current state of the step. """ - pass + ... diff --git a/python/semantic_kernel/processes/step_utils.py b/python/semantic_kernel/processes/step_utils.py index 74d4be1abcd5..e964dfb18e81 100644 --- a/python/semantic_kernel/processes/step_utils.py +++ b/python/semantic_kernel/processes/step_utils.py @@ -31,7 +31,6 @@ def find_input_channels( return inputs -@staticmethod -def get_fully_qualified_name(cls): +def get_fully_qualified_name(cls) -> str: """Gets the fully qualified name of a class.""" return f"{cls.__module__}.{cls.__name__}" diff --git a/python/uv.lock b/python/uv.lock index f1a1e59c04ad..30107f985873 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -4685,7 +4685,7 @@ requires-dist = [ { name = "pydantic", specifier = "~=2.0" }, { name = "pydantic-settings", specifier = "~=2.0" }, { name = "pymilvus", marker = "extra == 'milvus'", specifier = ">=2.3,<2.5" }, - { name = "pymongo", marker = "extra == 'mongo'", specifier = ">=4.8.0,<4.9" }, + { name = "pymongo", marker = "extra == 'mongo'", specifier = ">=4.8.0,<4.11" }, { name = "qdrant-client", marker = "extra == 'qdrant'", specifier = "~=1.9" }, { name = "redis", extras = ["hiredis"], marker = "extra == 'redis'", specifier = "~=5.0" }, { name = "sentence-transformers", marker = "extra == 'hugging-face'", specifier = ">=2.2,<4.0" }, @@ -5127,7 +5127,7 @@ name = "triton" version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "filelock", marker = "(python_full_version < '3.13' and sys_platform == 'darwin') or (python_full_version < '3.13' and sys_platform == 'linux') or (python_full_version < '3.13' and sys_platform == 'win32')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/98/29/69aa56dc0b2eb2602b553881e34243475ea2afd9699be042316842788ff5/triton-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0dd10a925263abbe9fa37dcde67a5e9b2383fc269fdf59f5657cac38c5d1d8", size = 209460013 }, From c7fb53239d4e58962075a1f51f497ec2b593ea23 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Mon, 11 Nov 2024 10:03:10 -0500 Subject: [PATCH 07/16] Clean up sample, add sample README, add unit tests for Dapr runtime. --- .../samples/demos/process_with_dapr/README.md | 163 +++++++++++++++++ python/samples/demos/process_with_dapr/app.py | 21 ++- .../actors/message_buffer_actor.py | 9 +- .../dapr_runtime/actors/step_actor.py | 10 +- .../dapr_runtime/dapr_kernel_process.py | 7 +- .../dapr_kernel_process_context.py | 5 - .../processes/dapr_runtime/dapr_step_info.py | 1 - .../interfaces/process_interface.py | 1 - .../dapr_runtime/test_dapr_kernel_process.py | 117 +++++++++++++ .../test_dapr_kernel_process_context.py | 98 +++++++++++ .../dapr_runtime/test_event_buffer_actor.py | 64 +++++++ .../test_external_event_buffer_actor.py | 100 +++++++++++ .../dapr_runtime/test_message_buffer_actor.py | 97 +++++++++++ .../dapr_runtime/test_process_actor.py | 164 ++++++++++++++++++ .../processes/dapr_runtime/test_step_actor.py | 102 +++++++++++ .../test_kernel_process_event.py | 2 +- .../local_runtime/test_local_process.py | 2 +- .../processes/test_process_message_factory.py | 18 ++ .../tests/unit/processes/test_step_utils.py | 133 ++++++++++++++ 19 files changed, 1087 insertions(+), 27 deletions(-) create mode 100644 python/samples/demos/process_with_dapr/README.md create mode 100644 python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py create mode 100644 python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py create mode 100644 python/tests/unit/processes/dapr_runtime/test_event_buffer_actor.py create mode 100644 python/tests/unit/processes/dapr_runtime/test_external_event_buffer_actor.py create mode 100644 python/tests/unit/processes/dapr_runtime/test_message_buffer_actor.py create mode 100644 python/tests/unit/processes/dapr_runtime/test_process_actor.py create mode 100644 python/tests/unit/processes/dapr_runtime/test_step_actor.py create mode 100644 python/tests/unit/processes/test_process_message_factory.py create mode 100644 python/tests/unit/processes/test_step_utils.py diff --git a/python/samples/demos/process_with_dapr/README.md b/python/samples/demos/process_with_dapr/README.md new file mode 100644 index 000000000000..6a10f6d533d2 --- /dev/null +++ b/python/samples/demos/process_with_dapr/README.md @@ -0,0 +1,163 @@ +# Semantic Kernel Processes in Dapr + +This demo contains a FastAPI app that uses Dapr to run a Semantic Kernel Process. Dapr is a portable, event-driven runtime that can simplify the process of building resilient, stateful application that run in the cloud and/or edge. Dapr is a natural fit for hosting Semantic Kernel Processes and allows you to scale your processes in size and quantity without sacrificing performance, or reliability. + +For more information about Semantic Kernel Processes and Dapr, see the following documentation: + +#### Semantic Kernel Processes + +- [Overview of the Process Framework (docs)](https://learn.microsoft.com/semantic-kernel/frameworks/process/process-framework) +- [Getting Started with Processes (samples)](../../getting_started_with_processes/) + +#### Dapr + +- [Dapr documentation](https://docs.dapr.io/) +- [Dapr Actor documentation](https://v1-10.docs.dapr.io/developing-applications/building-blocks/actors/) +- [Dapr local development](https://docs.dapr.io/getting-started/install-dapr-selfhost/) + +## Running the Demo + +Before running this Demo, make sure to configure Dapr for local development following the links above. The Dapr containers must be running for this demo application to run. + +```mermaid +flowchart LR + Kickoff --> A + Kickoff --> B + A --> C + B --> C + + C -->|Count < 3| Kickoff + C -->|Count >= 3| End + + classDef kickoffClass fill:#f9f,stroke:#333,stroke-width:2px; + class Kickoff kickoffClass; + + End((End)) +``` + +1. Build and run the sample. Running the Dapr service locally can be done using the Dapr Cli or with the Dapr VS Code extension. The VS Code extension is the recommended approach if you want to debug the code as it runs. + - If using VSCode to debug, select the `Pythonapp with Dapr` option from the Run and Debug dropdown list. +1. When the service is up and running, it will expose a single API in localhost port 5001. + +#### Invoking the process: + +1. Open a web browser and point it to [http://localhost:5001/processes/1234](http://localhost:5001/processes/1234) to invoke a new process with `Id = "1234"` +1. When the process is complete, you should see `{"processId":"1234"}` in the web browser. +1. You should also see console output from the running service with logs that match the following: + +```text +##### Kickoff ran. +##### AStep ran. +##### BStep ran. +##### CStep activated with Cycle = '1'. +##### CStep run cycle 2. +##### Kickoff ran. +##### AStep ran. +##### BStep ran. +##### CStep run cycle 3 - exiting. +``` + +Now refresh the page in your browser to run the same processes instance again. Now the logs should look like this: + +```text +##### Kickoff ran. +##### AStep ran. +##### BStep ran. +##### CStep run cycle 4 - exiting. +``` + +Notice that the logs from the two runs are not the same. In the first run, the processes has not been run before and so it's initial +state came from what we defined in the process: + +**_First Run_** + +- `CState` is initialized with `Cycle = 1` which is the initial state that we specified while building the process. +- `CState` is invoked a total of two times before the terminal condition of `Cycle >= 3` is reached. + +In the second run however, the process has persisted state from the first run: + +**_Second Run_** + +- `CState` is initialized with `Cycle = 3` which is the final state from the first run of the process. +- `CState` is invoked only once and is already in the terminal condition of `Cycle >= 3`. + +If you create a new instance of the process with `Id = "ABCD"` by pointing your browser to [http://localhost:5001/processes/ABCD](http://localhost:5001/processes/ABCD), you will see the it will start with the initial state as expected. + +## Understanding the Code + +Below are the key aspects of the code that show how Dapr and Semantic Kernel Processes can be integrated into a FastAPI app: + +- Create a new Dapr FastAPI app. +- Add the required Semantic Kernel and Dapr packages to your project: + +**_General Imports and Dapr Packages_** + +```python +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import logging +from contextlib import asynccontextmanager +from enum import Enum +from typing import TYPE_CHECKING, ClassVar + +import uvicorn +from dapr.actor import ActorId +from dapr.actor.runtime.context import ActorRuntimeContext +from dapr.ext.fastapi import DaprActor, DaprApp +from fastapi import FastAPI +from fastapi.responses import JSONResponse +from pydantic import Field +``` + +**_Semantic Kernel Process Imports_** + +```python +from semantic_kernel import Kernel +from semantic_kernel.functions import kernel_function +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor +from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor +from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor +from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start +from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep +from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState +from semantic_kernel.processes.process_builder import ProcessBuilder +``` + +**_Define the FastAPI app, Dapr App, and the DaprActor_** + +```python +kernel = Kernel() + + +def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: + """Factory function to create ProcessActor instances with dependencies.""" + return ProcessActor(ctx, actor_id, kernel) + + +def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor: + """Factory function to create StepActor instances with dependencies.""" + return StepActor(ctx, actor_id, kernel=kernel) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + print("## actor startup ##") + await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) + await actor.register_actor(StepActor, actor_factory=step_actor_factory) + await actor.register_actor(EventBufferActor) + await actor.register_actor(MessageBufferActor) + await actor.register_actor(ExternalEventBufferActor) + yield + + +app = FastAPI(title="SKProcess", lifespan=lifespan) +dapr_app = DaprApp(app) +actor = DaprActor(app) +``` + +- Build and run a Process as you normally would. For this Demo we run a simple example process from with a FastAPI method in response to a GET request. [See the FastAPI app here](./app.py). diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index 818475d50fe7..f89a042a0c93 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -31,7 +31,7 @@ if TYPE_CHECKING: from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess -logging.basicConfig(level=logging.DEBUG) +logging.basicConfig(level=logging.ERROR) kernel = Kernel() @@ -49,7 +49,7 @@ def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor @asynccontextmanager async def lifespan(app: FastAPI): - print("~~ actor startup") + print("## actor startup ##") await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) await actor.register_actor(StepActor, actor_factory=step_actor_factory) await actor.register_actor(EventBufferActor) @@ -90,6 +90,7 @@ class KickOffStep(KernelProcessStep): @kernel_function(name=KICK_OFF_FUNCTION) async def print_welcome_message(self, context: KernelProcessStepContext): + print("##### Kickoff ran.") await context.emit_event(process_event=CommonEvents.StartARequested.value, data="Get Going A") await context.emit_event(process_event=CommonEvents.StartBRequested.value, data="Get Going B") @@ -99,6 +100,7 @@ async def print_welcome_message(self, context: KernelProcessStepContext): class AStep(KernelProcessStep): @kernel_function() async def do_it(self, context: KernelProcessStepContext): + print("##### AStep ran.") await asyncio.sleep(1) await context.emit_event(process_event=CommonEvents.AStepDone.value, data="I did A") @@ -108,13 +110,14 @@ async def do_it(self, context: KernelProcessStepContext): class BStep(KernelProcessStep): @kernel_function() async def do_it(self, context: KernelProcessStepContext): + print("##### BStep ran.") await asyncio.sleep(2) await context.emit_event(process_event=CommonEvents.BStepDone.value, data="I did B") # Define a sample `CStepState` that will keep track of the current cycle. class CStepState(KernelBaseModel): - current_cycle: int = 0 + current_cycle: int = 1 # Define a sample `CStep` step that will emit an `ExitRequested` event after 3 cycles. @@ -124,16 +127,18 @@ class CStep(KernelProcessStep[CStepState]): # The activate method overrides the base class method to set the state in the step. async def activate(self, state: KernelProcessStepState[CStepState]): """Activates the step and sets the state.""" + step_state = CStepState.model_validate(state.state) + print(f"##### CStep activated with Cycle = '{step_state.current_cycle}'.") self.state = state.state @kernel_function() async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str): self.state.current_cycle += 1 - print(f"CStep Current Cycle: {self.state.current_cycle}") if self.state.current_cycle >= 3: - print("CStep Exit Requested") + print("##### CStep run cycle 3 - exiting.") await context.emit_event(process_event=CommonEvents.ExitRequested.value) return + print(f"##### CStep run cycle {self.state.current_cycle}") await context.emit_event(process_event=CommonEvents.CStepDone.value) @@ -148,7 +153,9 @@ def get_process() -> "KernelProcess": kickoff_step = process.add_step(step_type=KickOffStep) myAStep = process.add_step(step_type=AStep) myBStep = process.add_step(step_type=BStep) - myCStep = process.add_step(step_type=CStep) + + # Intialize the CStep with an initial state and the state's current cycle set to 1 + myCStep = process.add_step(step_type=CStep, initial_state=CStepState(current_cycle=1)) # Define the input event and where to send it to process.on_input_event(event_id=CommonEvents.StartProcess.value).send_event_to(target=kickoff_step) @@ -180,4 +187,4 @@ async def start_process(process_id: str): if __name__ == "__main__": - uvicorn.run(app, host="0.0.0.0", port=5001) # nosec + uvicorn.run(app, host="0.0.0.0", port=5001, log_level="error") # nosec diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py index cf28f868b619..b94616a7ec6e 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/message_buffer_actor.py @@ -24,7 +24,11 @@ def __init__(self, ctx: ActorRuntimeContext, actor_id: ActorId): self.queue: Queue[str] = Queue() async def enqueue(self, message: str) -> None: - """Enqueues a message event into the buffer and updates the state.""" + """Enqueues a message event into the buffer and updates the state. + + Args: + message (str): The message to enqueue. + """ try: self.queue.put(message) @@ -45,7 +49,7 @@ async def dequeue_all(self) -> list[str]: while not self.queue.empty(): items.append(self.queue.get()) - await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, json.dumps(items)) + await self._state_manager.try_add_state(ActorStateKeys.MessageQueueState.value, json.dumps([])) await self._state_manager.save_state() return items @@ -56,6 +60,7 @@ async def dequeue_all(self) -> list[str]: raise Exception(error_message) async def _on_activate(self) -> None: + """Called when the actor is activated.""" try: logger.info(f"Activating actor with ID: {self.id.id}") diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py index c5ee2eaa62d1..0d50b831b5ba 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -154,16 +154,14 @@ async def prepare_incoming_messages(self) -> int: logger.error(f"Error in prepare_incoming_messages: {error_message}") raise Exception(error_message) - async def process_incoming_messages(self) -> None: - """Triggers the step to process all prepared messages.""" - logger.info(f"Processing incoming messages for step {self.name}.") - + async def process_incoming_messages(self): + """Processes the incoming messages for the step.""" while not self.incoming_messages.empty(): message = self.incoming_messages.get() - logger.info(f"Processing message {message}.") await self.handle_message(message) - await self._state_manager.try_add_state(ActorStateKeys.StepIncomingMessagesState.value, self.incoming_messages) + messages_to_save = [json.dumps(msg.model_dump()) for msg in list(self.incoming_messages.queue)] + await self._state_manager.try_add_state(ActorStateKeys.StepIncomingMessagesState.value, messages_to_save) await self._state_manager.save_state() def _get_class_from_string(self, full_class_name: str): diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py index 2390e40c089c..99373933fbea 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py @@ -1,4 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. + from typing import TYPE_CHECKING from semantic_kernel.exceptions.process_exceptions import ProcessInvalidConfigurationException @@ -22,15 +23,15 @@ async def start( """Start the kernel process.""" if process is None: raise ProcessInvalidConfigurationException("process cannot be None") - if process.state is None or not process.state.name: - raise ProcessInvalidConfigurationException("process state name cannot be empty") + if process.state is None: + raise ProcessInvalidConfigurationException("process state cannot be empty") if kernel is None: raise ProcessInvalidConfigurationException("kernel cannot be None") if initial_event is None: raise ProcessInvalidConfigurationException("initial_event cannot be None") if isinstance(initial_event, str): - initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data", None)) + initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data")) if process_id is not None: process.state.id = process_id diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py index 1486713f163f..ef46d1c8026a 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -39,19 +39,14 @@ async def start_with_event(self, initial_event: KernelProcessEvent) -> None: dapr_process = DaprProcessInfo.from_kernel_process(self.process) dapr_process_dict = dapr_process.model_dump() - # Prepare the payload with the serialized DaprProcessInfo payload = { "process_info": dapr_process_dict, "parent_process_id": None, } - # Send the payload to the actor method await self.dapr_process.initialize_process(payload) - - # Serialize the initial event initial_event_json = initial_event.model_dump_json() - # Start the process with the initial event await self.dapr_process.run_once(initial_event_json) async def send_event(self, event: KernelProcessEvent) -> None: diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py index f94cc1a4d601..68e40229bd63 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py @@ -36,7 +36,6 @@ def from_kernel_step_info(cls, kernel_step_info: KernelProcessStepInfo) -> "Dapr if kernel_step_info is None: raise KernelException("Kernel step info must be provided") - # Get the fully qualified name of the inner step type inner_step_type = get_fully_qualified_name(kernel_step_info.inner_step_type) return DaprStepInfo( diff --git a/python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py b/python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py index f477d31e3950..63268ed58fbc 100644 --- a/python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py +++ b/python/semantic_kernel/processes/dapr_runtime/interfaces/process_interface.py @@ -16,7 +16,6 @@ class ProcessInterface(ActorInterface, ABC): @abstractmethod @actormethod(name="initialize_process") - # async def initialize_process(self, process_info: "DaprProcessInfo", parent_process_id: str | None = None) -> None: async def initialize_process(self, input: dict) -> None: """Initializes the process with the specified instance of DaprProcessInfo. diff --git a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py new file mode 100644 index 000000000000..701a49b25f7d --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py @@ -0,0 +1,117 @@ +# Copyright (c) Microsoft. All rights reserved. + +from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch + +import pytest + +from semantic_kernel.exceptions.process_exceptions import ProcessInvalidConfigurationException +from semantic_kernel.kernel import Kernel +from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start +from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.processes.kernel_process.kernel_process_state import KernelProcessState +from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo + + +# Define a fake DaprKernelProcessContext with only the needed method +class FakeDaprKernelProcessContext: + def __init__(self, process): + self.process = process + self.start_with_event = AsyncMock() + print("FakeDaprKernelProcessContext initialized") # Diagnostic print to confirm usage + + +@pytest.mark.asyncio +async def test_start_with_valid_parameters(): + # Arrange + state = MagicMock(spec=KernelProcessState) + state.name = "valid_state" + state.id = "state_1" + + mock_step = MagicMock(spec=KernelProcessStepInfo) + process = KernelProcess(state=state, steps=[mock_step]) + + kernel = MagicMock(spec=Kernel) + initial_event = KernelProcessEvent(id="event_1", data="data_1") + + with patch( + "semantic_kernel.processes.dapr_runtime.dapr_kernel_process.DaprKernelProcessContext", + new=FakeDaprKernelProcessContext, + ): + # Act + result = await start(process=process, kernel=kernel, initial_event=initial_event) + + # Assert + assert isinstance(result, FakeDaprKernelProcessContext) + assert result.process == process + result.start_with_event.assert_called_once_with(initial_event) + + +@pytest.mark.asyncio +async def test_start_with_invalid_process(): + # Arrange + kernel = MagicMock(spec=Kernel) + initial_event = KernelProcessEvent(id="event_1", data="data_1") + + # Act & Assert + with pytest.raises(ProcessInvalidConfigurationException, match="process cannot be None"): + await start(process=None, kernel=kernel, initial_event=initial_event) + + +@pytest.mark.asyncio +async def test_start_with_invalid_kernel(): + # Arrange + state = MagicMock(spec=KernelProcessState) + type(state).name = PropertyMock(return_value="valid_state") + mock_step = MagicMock(spec=KernelProcessStepInfo) + process = KernelProcess(state=state, steps=[mock_step]) + initial_event = KernelProcessEvent(id="event_1", data="data_1") + + # Act & Assert + with pytest.raises(ProcessInvalidConfigurationException, match="kernel cannot be None"): + await start(process=process, kernel=None, initial_event=initial_event) + + +@pytest.mark.asyncio +async def test_start_with_invalid_initial_event(): + # Arrange + state = MagicMock(spec=KernelProcessState) + type(state).name = PropertyMock(return_value="valid_state") + mock_step = MagicMock(spec=KernelProcessStepInfo) + process = KernelProcess(state=state, steps=[mock_step]) + kernel = MagicMock(spec=Kernel) + + # Act & Assert + with pytest.raises(ProcessInvalidConfigurationException, match="initial_event cannot be None"): + await start(process=process, kernel=kernel, initial_event=None) + + +@pytest.mark.asyncio +async def test_start_with_initial_event_as_string(): + # Arrange + state = MagicMock(spec=KernelProcessState) + type(state).name = PropertyMock(return_value="valid_state") + mock_step = MagicMock(spec=KernelProcessStepInfo) + process = KernelProcess(state=state, steps=[mock_step]) + kernel = MagicMock(spec=Kernel) + initial_event = "start_event" + + # Mock DaprKernelProcessContext and its start_with_event method + with patch( + "semantic_kernel.processes.dapr_runtime.dapr_kernel_process.DaprKernelProcessContext", new=MagicMock() + ) as mock_process_context_class: + mock_process_context_instance = mock_process_context_class.return_value + mock_process_context_instance.start_with_event = AsyncMock() + + # Act + result = await start(process=process, kernel=kernel, initial_event=initial_event, data="event_data") + + # Assert + assert result == mock_process_context_instance + # Verify that the initial event was correctly converted to a KernelProcessEvent + mock_process_context_instance.start_with_event.assert_called_once() + args, _ = mock_process_context_instance.start_with_event.call_args + actual_event = args[0] + assert isinstance(actual_event, KernelProcessEvent) + assert actual_event.id == "start_event" + assert actual_event.data == "event_data" diff --git a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py new file mode 100644 index 000000000000..89469355375e --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py @@ -0,0 +1,98 @@ +# Copyright (c) Microsoft. All rights reserved. + +import uuid +from unittest.mock import AsyncMock, patch + +import pytest + +from semantic_kernel.processes.dapr_runtime.dapr_kernel_process_context import DaprKernelProcessContext +from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo +from semantic_kernel.processes.dapr_runtime.interfaces.process_interface import ProcessInterface +from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess +from semantic_kernel.processes.kernel_process.kernel_process_event import KernelProcessEvent +from semantic_kernel.processes.kernel_process.kernel_process_state import KernelProcessState +from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState + + +class DummyInnerStepType: + pass + + +@pytest.fixture +def process_context(): + state = KernelProcessState(name="TestProcess", id=str(uuid.uuid4())) + + step_state = KernelProcessStepState(name="TestStep", id="step1") + + step = KernelProcessStepInfo( + state=step_state, + inner_step_type=DummyInnerStepType, + output_edges={}, + ) + + steps = [step] + process = KernelProcess(state=state, steps=steps) + + with patch("dapr.actor.ActorProxy.create") as mock_actor_proxy_create: + mock_dapr_process = AsyncMock(spec=ProcessInterface) + mock_actor_proxy_create.return_value = mock_dapr_process + + context = DaprKernelProcessContext(process=process) + + yield context, mock_dapr_process + + +@pytest.mark.asyncio +async def test_start_with_event(process_context): + context, mock_dapr_process = process_context + + initial_event = KernelProcessEvent(id="event1", data="some data") + + await context.start_with_event(initial_event) + + dapr_process_info = DaprProcessInfo.from_kernel_process(context.process) + expected_payload = { + "process_info": dapr_process_info.model_dump(), + "parent_process_id": None, + } + mock_dapr_process.initialize_process.assert_awaited_once_with(expected_payload) + + initial_event_json = initial_event.model_dump_json() + mock_dapr_process.run_once.assert_awaited_once_with(initial_event_json) + + +@pytest.mark.asyncio +async def test_send_event(process_context): + context, mock_dapr_process = process_context + + event = KernelProcessEvent(id="event2", data="event data") + + await context.send_event(event) + + mock_dapr_process.send_message.assert_awaited_once_with(event) + + +@pytest.mark.asyncio +async def test_stop(process_context): + context, mock_dapr_process = process_context + + await context.stop() + + mock_dapr_process.stop.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_get_state(process_context): + context, mock_dapr_process = process_context + + dapr_process_info = DaprProcessInfo.from_kernel_process(context.process) + mock_dapr_process.get_process_info.return_value = dapr_process_info + + result = await context.get_state() + + mock_dapr_process.get_process_info.assert_awaited_once() + + assert isinstance(result, KernelProcess) + assert result.state.id == context.process.state.id + assert result.state.name == context.process.state.name diff --git a/python/tests/unit/processes/dapr_runtime/test_event_buffer_actor.py b/python/tests/unit/processes/dapr_runtime/test_event_buffer_actor.py new file mode 100644 index 000000000000..db15aaf262b8 --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_event_buffer_actor.py @@ -0,0 +1,64 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +from unittest.mock import AsyncMock + +import pytest +from dapr.actor.id import ActorId +from dapr.actor.runtime._type_information import ActorTypeInformation +from dapr.actor.runtime.context import ActorRuntimeContext +from dapr.serializers import DefaultJSONSerializer + +from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor + + +def _run(coro): + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop.run_until_complete(coro) + + +@pytest.fixture +def actor_context(): + actor_id = ActorId("test_actor") + actor_type_info = ActorTypeInformation.create(EventBufferActor) + + message_serializer = DefaultJSONSerializer() + state_serializer = DefaultJSONSerializer() + + mock_actor_client = AsyncMock() + + runtime_context = ActorRuntimeContext( + actor_type_info=actor_type_info, + message_serializer=message_serializer, + state_serializer=state_serializer, + actor_client=mock_actor_client, + ) + + actor = EventBufferActor(runtime_context, actor_id) + + _run(actor._on_activate()) + return actor + + +def test_enqueue(actor_context): + _run(actor_context.enqueue('{"event": "test_event"}')) + queue_list = list(actor_context.queue.queue) + assert queue_list == ['{"event": "test_event"}'] + + +def test_dequeue_all(actor_context): + _run(actor_context.enqueue('{"event": "event1"}')) + _run(actor_context.enqueue('{"event": "event2"}')) + messages = _run(actor_context.dequeue_all()) + assert messages == ['{"event": "event1"}', '{"event": "event2"}'] + assert actor_context.queue.empty() + + +def test_on_activate(actor_context): + new_actor = EventBufferActor(actor_context.runtime_ctx, actor_context.id) + _run(new_actor._on_activate()) + assert new_actor.queue.empty() diff --git a/python/tests/unit/processes/dapr_runtime/test_external_event_buffer_actor.py b/python/tests/unit/processes/dapr_runtime/test_external_event_buffer_actor.py new file mode 100644 index 000000000000..2eb24eaa1a0f --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_external_event_buffer_actor.py @@ -0,0 +1,100 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import json +from unittest.mock import AsyncMock + +import pytest +from dapr.actor.id import ActorId +from dapr.actor.runtime._type_information import ActorTypeInformation +from dapr.actor.runtime.context import ActorRuntimeContext +from dapr.serializers import DefaultJSONSerializer + +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor + + +def _run(coro): + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop.run_until_complete(coro) + + +@pytest.fixture +def actor_context(): + actor_id = ActorId("test_actor") + actor_type_info = ActorTypeInformation.create(ExternalEventBufferActor) + + message_serializer = DefaultJSONSerializer() + state_serializer = DefaultJSONSerializer() + + mock_actor_client = AsyncMock() + + mock_state_manager = AsyncMock() + mock_state_manager.try_get_state.return_value = (True, json.dumps([])) + mock_state_manager.try_add_state = AsyncMock() + mock_state_manager.save_state = AsyncMock() + + runtime_context = ActorRuntimeContext( + actor_type_info=actor_type_info, + message_serializer=message_serializer, + state_serializer=state_serializer, + actor_client=mock_actor_client, + ) + + actor = ExternalEventBufferActor(runtime_context, actor_id) + actor._state_manager = mock_state_manager + + _run(actor._on_activate()) + return actor + + +def test_enqueue(actor_context): + _run(actor_context.enqueue('{"event": "test_event"}')) + queue_list = list(actor_context.queue.queue) + assert queue_list == ['{"event": "test_event"}'] + + actor_context._state_manager.try_add_state.assert_called_with( + ActorStateKeys.ExternalEventQueueState.value, json.dumps(['{"event": "test_event"}']) + ) + actor_context._state_manager.save_state.assert_called_once() + + +def test_dequeue_all(actor_context): + _run(actor_context.enqueue('{"event": "event1"}')) + _run(actor_context.enqueue('{"event": "event2"}')) + messages = _run(actor_context.dequeue_all()) + assert messages == ['{"event": "event1"}', '{"event": "event2"}'] + assert actor_context.queue.empty() + + actor_context._state_manager.try_add_state.assert_called_with( + ActorStateKeys.ExternalEventQueueState.value, json.dumps([]) + ) + actor_context._state_manager.save_state.assert_called() + + +def test_on_activate_with_existing_state(actor_context): + actor_context._state_manager.try_get_state.return_value = ( + True, + json.dumps(['{"event": "event1"}', '{"event": "event2"}']), + ) + + new_actor = ExternalEventBufferActor(actor_context.runtime_ctx, actor_context.id) + new_actor._state_manager = actor_context._state_manager + _run(new_actor._on_activate()) + + queue_list = list(new_actor.queue.queue) + assert queue_list == ['{"event": "event1"}', '{"event": "event2"}'] + + +def test_on_activate_with_no_existing_state(actor_context): + actor_context._state_manager.try_get_state.return_value = (False, None) + + new_actor = ExternalEventBufferActor(actor_context.runtime_ctx, actor_context.id) + new_actor._state_manager = actor_context._state_manager + _run(new_actor._on_activate()) + + assert new_actor.queue.empty() diff --git a/python/tests/unit/processes/dapr_runtime/test_message_buffer_actor.py b/python/tests/unit/processes/dapr_runtime/test_message_buffer_actor.py new file mode 100644 index 000000000000..85956ee49389 --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_message_buffer_actor.py @@ -0,0 +1,97 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +from unittest.mock import AsyncMock + +import pytest +from dapr.actor.id import ActorId +from dapr.actor.runtime._type_information import ActorTypeInformation +from dapr.actor.runtime.context import ActorRuntimeContext +from dapr.serializers import DefaultJSONSerializer + +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor + + +def _run(coro): + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop.run_until_complete(coro) + + +@pytest.fixture +def actor_context(): + actor_id = ActorId("test_actor") + actor_type_info = ActorTypeInformation.create(MessageBufferActor) + + message_serializer = DefaultJSONSerializer() + state_serializer = DefaultJSONSerializer() + + mock_actor_client = AsyncMock() + + mock_state_manager = AsyncMock() + mock_state_manager.try_get_state.return_value = (True, []) + mock_state_manager.try_add_state = AsyncMock() + mock_state_manager.save_state = AsyncMock() + + runtime_context = ActorRuntimeContext( + actor_type_info=actor_type_info, + message_serializer=message_serializer, + state_serializer=state_serializer, + actor_client=mock_actor_client, + ) + + actor = MessageBufferActor(runtime_context, actor_id) + actor._state_manager = mock_state_manager + + _run(actor._on_activate()) + return actor + + +def test_enqueue(actor_context): + _run(actor_context.enqueue('{"event": "test_event"}')) + queue_list = list(actor_context.queue.queue) + assert queue_list == ['{"event": "test_event"}'] + + actor_context._state_manager.try_add_state.assert_called_with( + ActorStateKeys.MessageQueueState.value, ['{"event": "test_event"}'] + ) + actor_context._state_manager.save_state.assert_called_once() + + +def test_dequeue_all(actor_context): + _run(actor_context.enqueue('{"event": "event1"}')) + _run(actor_context.enqueue('{"event": "event2"}')) + + actor_context._state_manager.reset_mock() + + messages = _run(actor_context.dequeue_all()) + assert messages == ['{"event": "event1"}', '{"event": "event2"}'] + assert actor_context.queue.empty() + + actor_context._state_manager.try_add_state.assert_called_with(ActorStateKeys.MessageQueueState.value, "[]") + actor_context._state_manager.save_state.assert_called_once() + + +def test_on_activate_with_existing_state(actor_context): + actor_context._state_manager.try_get_state.return_value = (True, ['{"event": "event1"}', '{"event": "event2"}']) + + new_actor = MessageBufferActor(actor_context.runtime_ctx, actor_context.id) + new_actor._state_manager = actor_context._state_manager + _run(new_actor._on_activate()) + + queue_list = list(new_actor.queue.queue) + assert queue_list == ['{"event": "event1"}', '{"event": "event2"}'] + + +def test_on_activate_with_no_existing_state(actor_context): + actor_context._state_manager.try_get_state.return_value = (False, None) + + new_actor = MessageBufferActor(actor_context.runtime_ctx, actor_context.id) + new_actor._state_manager = actor_context._state_manager + _run(new_actor._on_activate()) + + assert new_actor.queue.empty() diff --git a/python/tests/unit/processes/dapr_runtime/test_process_actor.py b/python/tests/unit/processes/dapr_runtime/test_process_actor.py new file mode 100644 index 000000000000..ff2e5a30b199 --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_process_actor.py @@ -0,0 +1,164 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import json +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest +from dapr.actor.id import ActorId +from dapr.actor.runtime._type_information import ActorTypeInformation +from dapr.actor.runtime.context import ActorRuntimeContext + +from semantic_kernel.processes.dapr_runtime.actors.actor_state_key import ActorStateKeys +from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor +from semantic_kernel.processes.dapr_runtime.dapr_process_info import DaprProcessInfo +from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState + + +@pytest.fixture +def actor_context(): + actor_id = ActorId("test_actor") + actor_type_info = ActorTypeInformation.create(ProcessActor) + runtime_context = ActorRuntimeContext( + actor_type_info=actor_type_info, + message_serializer=MagicMock(), + state_serializer=MagicMock(), + actor_client=MagicMock(), + ) + kernel_mock = MagicMock() + actor = ProcessActor(runtime_context, actor_id, kernel=kernel_mock) + + actor._state_manager = AsyncMock() + actor._state_manager.try_add_state = AsyncMock(return_value=True) + actor._state_manager.try_get_state = AsyncMock(return_value=(True, {})) + actor._state_manager.save_state = AsyncMock() + + asyncio.run(actor._on_activate()) + return actor + + +def clean_structure(data): + """Recursively remove null values and empty dictionaries for direct comparison.""" + if isinstance(data, dict): + return {k: clean_structure(v) for k, v in data.items() if v not in [None, {}]} + if isinstance(data, list): + return [clean_structure(item) for item in data] + return data + + +@pytest.mark.asyncio +async def test_initialize_process(actor_context): + input_data = { + "process_info": { + "state": {"name": "Test Process", "id": "proc_123"}, + "steps": [ + { + "state": {"name": "Step1", "id": "step_123"}, + "inner_step_python_type": "SomeStepType", + } + ], + "inner_step_python_type": "SomeProcessType", + "edges": {}, + }, + "parent_process_id": "parent_123", + } + + expected_process_info = clean_structure(input_data["process_info"]) + + # Convert input data into the expected DaprProcessInfo instance + dapr_process_info_instance = DaprProcessInfo( + inner_step_python_type="SomeProcessType", + state=KernelProcessStepState(name="Test Process", id="proc_123"), + edges={}, + steps=[ + DaprStepInfo( + inner_step_python_type="SomeStepType", + state=KernelProcessStepState(name="Step1", id="step_123"), + edges={}, + ) + ], + ) + + with ( + patch.multiple( + actor_context, + _initialize_process_actor=AsyncMock(), + _state_manager=actor_context._state_manager, + ), + patch.object(actor_context._state_manager, "save_state", new=AsyncMock()) as mock_save_state, + ): + await actor_context.initialize_process(input_data) + + actual_calls = actor_context._state_manager.try_add_state.call_args_list + actual_process_info_call = next( + (call for call in actual_calls if call[0][0] == ActorStateKeys.ProcessInfoState.value), None + ) + + assert actual_process_info_call is not None, "ProcessInfoState call was not found." + + actual_process_info = clean_structure(actual_process_info_call[0][1]) + + assert actual_process_info == expected_process_info, ( + f"Expected: {json.dumps(expected_process_info)}, but got: {json.dumps(actual_process_info)}" + ) + + mock_save_state.assert_called_once() + + # Check that _initialize_process_actor was called with the expected DaprProcessInfo + actor_context._initialize_process_actor.assert_called_once_with(dapr_process_info_instance, "parent_123") + + +@pytest.mark.asyncio +async def test_start_process(actor_context): + actor_context.initialize_task = True + + with patch.object(actor_context, "internal_execute", new=AsyncMock()) as mock_internal_execute: + await actor_context.start(keep_alive=False) + + assert actor_context.process_task is not None + mock_internal_execute.assert_called_once() + assert not actor_context.process_task.done() + + +def test_run_once(actor_context): + actor_context.initialize_task = True + process_event = '{"event": "test_event"}' + + with patch( + "semantic_kernel.processes.dapr_runtime.actors.process_actor.ActorProxy.create", return_value=AsyncMock() + ) as mock_proxy: + asyncio.run(actor_context.run_once(process_event)) + + external_event_queue = mock_proxy.return_value + external_event_queue.enqueue.assert_called_once_with(process_event) + + assert actor_context.process_task is not None + + +@pytest.mark.asyncio +async def test_stop(actor_context): + actor_context.initialize_task = True + actor_context.process_task = asyncio.create_task(asyncio.sleep(1)) + + await actor_context.stop() + + assert actor_context.process_task.done() + + +def test_get_process_info(actor_context): + with patch.object(actor_context, "to_dapr_process_info", return_value=MagicMock()) as mock_to_dapr_process_info: + process_info = asyncio.run(actor_context.get_process_info()) + mock_to_dapr_process_info.assert_called_once() + assert process_info is mock_to_dapr_process_info.return_value + + +def test_handle_message(actor_context): + message_mock = MagicMock() + message_mock.target_event_id = "test_event" + actor_context.output_edges = {"test_event": [MagicMock()]} + + with patch.object(actor_context, "run_once", new=AsyncMock()) as mock_run_once: + asyncio.run(actor_context.handle_message(message_mock)) + + mock_run_once.assert_called_once() diff --git a/python/tests/unit/processes/dapr_runtime/test_step_actor.py b/python/tests/unit/processes/dapr_runtime/test_step_actor.py new file mode 100644 index 000000000000..990f6efaeeaa --- /dev/null +++ b/python/tests/unit/processes/dapr_runtime/test_step_actor.py @@ -0,0 +1,102 @@ +# Copyright (c) Microsoft. All rights reserved. + +import json +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest +from dapr.actor import ActorId + +from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor +from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState +from semantic_kernel.processes.process_message import ProcessMessage + + +@pytest.fixture +def actor_context(): + ctx = MagicMock() + actor_id = ActorId("test_actor") + kernel = MagicMock() + return StepActor(ctx, actor_id, kernel) + + +@pytest.mark.asyncio +async def test_initialize_step(actor_context): + input_data = json.dumps({ + "step_info": { + "state": {"name": "TestStep", "id": "step_1"}, + "inner_step_python_type": "SomeStepType", + "edges": {}, + }, + "parent_process_id": "parent_1", + }) + + with ( + patch.object(actor_context._state_manager, "try_add_state", new=AsyncMock()) as mock_try_add_state, + patch.object(actor_context._state_manager, "save_state", new=AsyncMock()) as mock_save_state, + ): + await actor_context.initialize_step(input_data) + + assert actor_context.step_info is not None + mock_try_add_state.assert_any_call("DaprStepInfo", actor_context.step_info) + mock_save_state.assert_called_once() + + +@pytest.mark.asyncio +async def test_prepare_incoming_messages(actor_context): + message = ProcessMessage( + source_id="source_1", + destination_id="dest_1", + function_name="test_function", + values={"param1": "value1"}, + ) + mock_message_json = json.dumps(message.model_dump()) + + expected_state_key = "incomingMessagesState" + + with ( + patch("dapr.actor.ActorProxy.create", new=MagicMock()) as mock_actor_proxy, + patch.object(actor_context._state_manager, "try_add_state", new=AsyncMock()) as mock_try_add_state, + patch.object(actor_context._state_manager, "save_state", new=AsyncMock()) as mock_save_state, + ): + mock_queue = AsyncMock() + mock_queue.dequeue_all.return_value = [mock_message_json] + mock_actor_proxy.return_value = mock_queue + + incoming_message_count = await actor_context.prepare_incoming_messages() + + assert incoming_message_count == 1 + assert actor_context.incoming_messages.qsize() == 1 + mock_try_add_state.assert_called_with(expected_state_key, [mock_message_json]) + mock_save_state.assert_called_once() + + +@pytest.mark.asyncio +async def test_process_incoming_messages(actor_context): + actor_context.step_info = DaprStepInfo( + state=KernelProcessStepState(name="Test Step", id="step_123"), + inner_step_python_type="SomeStepType", + edges={}, + ) + + message = ProcessMessage( + source_id="source_1", + destination_id="dest_1", + function_name="test_function", + values={"param1": "value1"}, + ) + actor_context.incoming_messages.put(message) + + with ( + patch.object(actor_context, "handle_message", new=AsyncMock()) as mock_handle_message, + patch.object(actor_context._state_manager, "save_state", new=AsyncMock()) as mock_save_state, + patch.object( + actor_context._state_manager, "try_add_state", new=AsyncMock(return_value=True) + ) as mock_try_add_state, + ): + await actor_context.process_incoming_messages() + mock_handle_message.assert_called_once_with(message) + mock_save_state.assert_called_once() + expected_messages = [] + expected_messages = [json.dumps(msg.model_dump()) for msg in list(actor_context.incoming_messages.queue)] + mock_try_add_state.assert_any_call("incomingMessagesState", expected_messages) diff --git a/python/tests/unit/processes/kernel_process/test_kernel_process_event.py b/python/tests/unit/processes/kernel_process/test_kernel_process_event.py index 8b6fbeb43440..f5bbecd048af 100644 --- a/python/tests/unit/processes/kernel_process/test_kernel_process_event.py +++ b/python/tests/unit/processes/kernel_process/test_kernel_process_event.py @@ -34,7 +34,7 @@ def test_initialization_with_visibility(): # Assert assert event.id == event_id assert event.data == event_data - assert event.visibility == KernelProcessEventVisibility.Public + assert event.visibility == KernelProcessEventVisibility.Public.value def test_invalid_visibility(): diff --git a/python/tests/unit/processes/local_runtime/test_local_process.py b/python/tests/unit/processes/local_runtime/test_local_process.py index c7378b678648..de47189f9281 100644 --- a/python/tests/unit/processes/local_runtime/test_local_process.py +++ b/python/tests/unit/processes/local_runtime/test_local_process.py @@ -321,7 +321,7 @@ async def test_handle_message_with_valid_event_id(mock_process_with_output_edges assert isinstance(event, KernelProcessEvent) assert event.id == "valid_event_id" assert event.data == message.target_event_data - assert event.visibility == KernelProcessEventVisibility.Internal + assert event.visibility == KernelProcessEventVisibility.Internal.value END_PROCESS_ID = "END" diff --git a/python/tests/unit/processes/test_process_message_factory.py b/python/tests/unit/processes/test_process_message_factory.py new file mode 100644 index 000000000000..2870cb85cbff --- /dev/null +++ b/python/tests/unit/processes/test_process_message_factory.py @@ -0,0 +1,18 @@ +# Copyright (c) Microsoft. All rights reserved. + +from semantic_kernel.processes.kernel_process.kernel_process_edge import KernelProcessEdge +from semantic_kernel.processes.kernel_process.kernel_process_function_target import KernelProcessFunctionTarget +from semantic_kernel.processes.process_message_factory import ProcessMessageFactory + + +def test_create_from_edge(): + """Test initialization of KernelProcessEdge with valid input.""" + source_step_id = "step_1" + output_target = KernelProcessFunctionTarget( + step_id="step_2", function_name="process_data", parameter_name="input_data", target_event_id="event_1" + ) + edge = KernelProcessEdge(source_step_id=source_step_id, output_target=output_target) + + process_message = ProcessMessageFactory.create_from_edge(edge, "data") + + assert process_message.source_id == source_step_id diff --git a/python/tests/unit/processes/test_step_utils.py b/python/tests/unit/processes/test_step_utils.py new file mode 100644 index 000000000000..1a773fa5bc08 --- /dev/null +++ b/python/tests/unit/processes/test_step_utils.py @@ -0,0 +1,133 @@ +# Copyright (c) Microsoft. All rights reserved. + +from collections.abc import Callable +from typing import Any +from unittest.mock import MagicMock + +import pytest + +from semantic_kernel.functions.kernel_function import KernelFunction +from semantic_kernel.functions.kernel_function_decorator import kernel_function +from semantic_kernel.kernel import Kernel +from semantic_kernel.processes.kernel_process.kernel_process_message_channel import ( + KernelProcessMessageChannel, +) +from semantic_kernel.processes.kernel_process.kernel_process_step_context import ( + KernelProcessStepContext, +) +from semantic_kernel.processes.step_utils import find_input_channels, get_fully_qualified_name + + +@pytest.fixture +def mock_function() -> Callable[..., Any]: + @kernel_function + def mock_function(input: str, context: KernelProcessStepContext) -> None: + pass + + return mock_function + + +def test_find_input_channels_empty_functions(): + channel = MagicMock(spec=KernelProcessMessageChannel) + functions = {} + with pytest.raises(ValueError) as exc_info: + find_input_channels(channel, functions) + assert str(exc_info.value) == "The step has not been initialized." + + +def test_find_input_channels_with_required_params(mock_function): + channel = MagicMock(spec=KernelProcessMessageChannel) + + function = KernelFunction.from_method(method=mock_function, plugin_name="test") + + functions = {"TestFunction": function} + + inputs = find_input_channels(channel, functions) + + assert "TestFunction" in inputs + assert "input" in inputs["TestFunction"] + assert "context" in inputs["TestFunction"] + + +@kernel_function +def skipped_function(param1: "Kernel", param2: int = 0) -> None: + pass + + +def test_find_input_channels_with_only_skipped_params(): + channel = MagicMock(spec=KernelProcessMessageChannel) + + function = KernelFunction.from_method(method=skipped_function, plugin_name="test") + functions = {"SkippedFunction": function} + + inputs = find_input_channels(channel, functions) + + expected_inputs = {"SkippedFunction": {}} + + assert inputs == expected_inputs + + +@kernel_function +def function1(param1: str) -> None: + pass + + +@kernel_function +def function2(param2: KernelProcessStepContext, param3: float = 0.0) -> None: + pass + + +def test_find_input_channels_multiple_functions(): + channel = MagicMock(spec=KernelProcessMessageChannel) + + function1_instance = KernelFunction.from_method(method=function1, plugin_name="test") + function2_instance = KernelFunction.from_method(method=function2, plugin_name="test") + + functions = { + "Function1": function1_instance, + "Function2": function2_instance, + } + + inputs = find_input_channels(channel, functions) + + assert "Function1" in inputs + assert "param1" in inputs["Function1"] + assert inputs["Function1"]["param1"] is None + + assert "Function2" in inputs + assert "param2" in inputs["Function2"] + assert isinstance(inputs["Function2"]["param2"], KernelProcessStepContext) + assert "param3" not in inputs["Function2"] + + +def test_get_fully_qualified_name_standard_class(): + class TestClass: + pass + + result = get_fully_qualified_name(TestClass) + expected = f"{TestClass.__module__}.TestClass" + assert result == expected + + +def test_get_fully_qualified_name_builtin_type(): + result = get_fully_qualified_name(int) + expected = "builtins.int" + assert result == expected + + +def test_get_fully_qualified_name_third_party_class(): + from unittest.mock import MagicMock + + result = get_fully_qualified_name(MagicMock) + expected = "unittest.mock.MagicMock" + assert result == expected + + +def test_get_fully_qualified_name_nested_class(): + class OuterClass: + class InnerClass: + pass + + result = get_fully_qualified_name(OuterClass.InnerClass) + expected = f"{OuterClass.__module__}.InnerClass" + assert result == expected From 1fd880231eec5ce0e58ad60e264ff763fd129450 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Mon, 11 Nov 2024 10:05:10 -0500 Subject: [PATCH 08/16] unit test cleanup --- .../dapr_runtime/test_dapr_kernel_process.py | 16 ---------------- .../processes/dapr_runtime/test_process_actor.py | 2 -- 2 files changed, 18 deletions(-) diff --git a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py index 701a49b25f7d..08d43282efba 100644 --- a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py +++ b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py @@ -13,17 +13,14 @@ from semantic_kernel.processes.kernel_process.kernel_process_step_info import KernelProcessStepInfo -# Define a fake DaprKernelProcessContext with only the needed method class FakeDaprKernelProcessContext: def __init__(self, process): self.process = process self.start_with_event = AsyncMock() - print("FakeDaprKernelProcessContext initialized") # Diagnostic print to confirm usage @pytest.mark.asyncio async def test_start_with_valid_parameters(): - # Arrange state = MagicMock(spec=KernelProcessState) state.name = "valid_state" state.id = "state_1" @@ -38,10 +35,8 @@ async def test_start_with_valid_parameters(): "semantic_kernel.processes.dapr_runtime.dapr_kernel_process.DaprKernelProcessContext", new=FakeDaprKernelProcessContext, ): - # Act result = await start(process=process, kernel=kernel, initial_event=initial_event) - # Assert assert isinstance(result, FakeDaprKernelProcessContext) assert result.process == process result.start_with_event.assert_called_once_with(initial_event) @@ -49,46 +44,39 @@ async def test_start_with_valid_parameters(): @pytest.mark.asyncio async def test_start_with_invalid_process(): - # Arrange kernel = MagicMock(spec=Kernel) initial_event = KernelProcessEvent(id="event_1", data="data_1") - # Act & Assert with pytest.raises(ProcessInvalidConfigurationException, match="process cannot be None"): await start(process=None, kernel=kernel, initial_event=initial_event) @pytest.mark.asyncio async def test_start_with_invalid_kernel(): - # Arrange state = MagicMock(spec=KernelProcessState) type(state).name = PropertyMock(return_value="valid_state") mock_step = MagicMock(spec=KernelProcessStepInfo) process = KernelProcess(state=state, steps=[mock_step]) initial_event = KernelProcessEvent(id="event_1", data="data_1") - # Act & Assert with pytest.raises(ProcessInvalidConfigurationException, match="kernel cannot be None"): await start(process=process, kernel=None, initial_event=initial_event) @pytest.mark.asyncio async def test_start_with_invalid_initial_event(): - # Arrange state = MagicMock(spec=KernelProcessState) type(state).name = PropertyMock(return_value="valid_state") mock_step = MagicMock(spec=KernelProcessStepInfo) process = KernelProcess(state=state, steps=[mock_step]) kernel = MagicMock(spec=Kernel) - # Act & Assert with pytest.raises(ProcessInvalidConfigurationException, match="initial_event cannot be None"): await start(process=process, kernel=kernel, initial_event=None) @pytest.mark.asyncio async def test_start_with_initial_event_as_string(): - # Arrange state = MagicMock(spec=KernelProcessState) type(state).name = PropertyMock(return_value="valid_state") mock_step = MagicMock(spec=KernelProcessStepInfo) @@ -96,19 +84,15 @@ async def test_start_with_initial_event_as_string(): kernel = MagicMock(spec=Kernel) initial_event = "start_event" - # Mock DaprKernelProcessContext and its start_with_event method with patch( "semantic_kernel.processes.dapr_runtime.dapr_kernel_process.DaprKernelProcessContext", new=MagicMock() ) as mock_process_context_class: mock_process_context_instance = mock_process_context_class.return_value mock_process_context_instance.start_with_event = AsyncMock() - # Act result = await start(process=process, kernel=kernel, initial_event=initial_event, data="event_data") - # Assert assert result == mock_process_context_instance - # Verify that the initial event was correctly converted to a KernelProcessEvent mock_process_context_instance.start_with_event.assert_called_once() args, _ = mock_process_context_instance.start_with_event.call_args actual_event = args[0] diff --git a/python/tests/unit/processes/dapr_runtime/test_process_actor.py b/python/tests/unit/processes/dapr_runtime/test_process_actor.py index ff2e5a30b199..900052c5980f 100644 --- a/python/tests/unit/processes/dapr_runtime/test_process_actor.py +++ b/python/tests/unit/processes/dapr_runtime/test_process_actor.py @@ -66,7 +66,6 @@ async def test_initialize_process(actor_context): expected_process_info = clean_structure(input_data["process_info"]) - # Convert input data into the expected DaprProcessInfo instance dapr_process_info_instance = DaprProcessInfo( inner_step_python_type="SomeProcessType", state=KernelProcessStepState(name="Test Process", id="proc_123"), @@ -105,7 +104,6 @@ async def test_initialize_process(actor_context): mock_save_state.assert_called_once() - # Check that _initialize_process_actor was called with the expected DaprProcessInfo actor_context._initialize_process_actor.assert_called_once_with(dapr_process_info_instance, "parent_123") From 65d2bdc906fcd94486ddf12c28f951fe78d1bde2 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Mon, 11 Nov 2024 10:42:06 -0500 Subject: [PATCH 09/16] Revert sample changes. --- .../chat_gpt_api_function_calling.py | 75 ++++--------------- .../chat_completion/azure_chat_gpt_api.py | 2 +- .../json_structured_output.py | 26 ++++--- python/samples/demos/process_with_dapr/app.py | 4 + .../getting_started_with_agents/step3_chat.py | 4 - 5 files changed, 32 insertions(+), 79 deletions(-) diff --git a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py index a5f53fe32fbe..f0381c1048ac 100644 --- a/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py +++ b/python/samples/concepts/auto_function_calling/chat_gpt_api_function_calling.py @@ -2,9 +2,8 @@ import asyncio import os -from enum import Enum from functools import reduce -from typing import TYPE_CHECKING, Annotated +from typing import TYPE_CHECKING from semantic_kernel import Kernel from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior @@ -16,62 +15,27 @@ from semantic_kernel.core_plugins.math_plugin import MathPlugin from semantic_kernel.core_plugins.time_plugin import TimePlugin from semantic_kernel.functions import KernelArguments -from semantic_kernel.functions.kernel_function_decorator import kernel_function if TYPE_CHECKING: from semantic_kernel.functions import KernelFunction -class Coordinates: - lat: float - lon: float - - def __init__(self, lat: float, lon: float): - self.lat = lat - self.lon = lon - - -class Status(Enum): - HOTELS = "hotels" - ATTRACTIONS = "attractions" - RESTAURANTS = "restaurants" - GEOS = "geos" - - -class Location: - name: str - coordinates: Coordinates - status: list[Status] - - def __init__(self, name: str, coordinates: Coordinates, status: list[Status]): - self.name = name - self.coordinates = coordinates - self.status = status - - -class TravelPlugin: - @kernel_function(name="search", description="Provides the coordinates for locations using fuzzy search.") - def search( - self, - query: Annotated[str, "the name of the location to search for"], - coordinates: Annotated[Coordinates, "lat/lon coordinates to search around"], - radius: Annotated[int | None, "the radius to search within in meters"] = 1, - categories: Annotated[list[Status] | None, "categories to search for"] = None, - ) -> list[Location]: - return [ - Location( - name="Space Needle", coordinates=Coordinates(lat=47.6205, lon=-122.3493), status=[Status.ATTRACTIONS] - ), - ] - - system_message = """ -You are a chat bot who helps users find information about travel destinations. +You are a chat bot. Your name is Mosscap and +you have one goal: figure out what people need. +Your full name, should you need to know it, is +Splendid Speckled Mosscap. You communicate +effectively, but you tend to answer with long +flowery prose. You are also a math wizard, +especially for adding and subtracting. +You also excel at joke telling, where your tone is often sarcastic. +Once you have the answer I am looking for, +you will return a full answer to me as soon as possible. """ # This concept example shows how to handle both streaming and non-streaming responses # To toggle the behavior, set the following flag accordingly: -stream = False +stream = True kernel = Kernel() @@ -82,7 +46,6 @@ def search( # adding plugins to the kernel kernel.add_plugin(MathPlugin(), plugin_name="math") kernel.add_plugin(TimePlugin(), plugin_name="time") -kernel.add_plugin(TravelPlugin(), plugin_name="travel") chat_function = kernel.add_function( prompt="{{$chat_history}}{{$user_input}}", @@ -120,7 +83,7 @@ def search( max_tokens=2000, temperature=0.7, top_p=0.8, - function_choice_behavior=FunctionChoiceBehavior.Auto(filters={"included_plugins": ["travel", "math", "time"]}), + function_choice_behavior=FunctionChoiceBehavior.Auto(auto_invoke=True), ) history = ChatHistory() @@ -186,7 +149,6 @@ async def handle_streaming( print("\n") if result_content: - streaming_chat_message = reduce(lambda first, second: first + second, result_content) return "".join([str(content) for content in result_content]) return None @@ -212,17 +174,6 @@ async def chat() -> bool: else: result = await kernel.invoke(chat_function, arguments=arguments) - chat_history: ChatHistory = result.metadata["messages"] - - # for msg in chat_history: - # if hasattr(msg, "inner_content"): - # msg.inner_content = None - # for item in msg.items: - # if isinstance(item, (FunctionCallContent, FunctionResultContent)): - # item.inner_content = None - - print(chat_history.model_dump_json()) - # If tools are used, and auto invoke tool calls is False, the response will be of type # ChatMessageContent with information about the tool calls, which need to be sent # back to the model to get the final response. diff --git a/python/samples/concepts/chat_completion/azure_chat_gpt_api.py b/python/samples/concepts/chat_completion/azure_chat_gpt_api.py index 065940ea368e..d2f372ec762f 100644 --- a/python/samples/concepts/chat_completion/azure_chat_gpt_api.py +++ b/python/samples/concepts/chat_completion/azure_chat_gpt_api.py @@ -8,7 +8,7 @@ from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion from semantic_kernel.contents import ChatHistory -logging.basicConfig(level=logging.DEBUG) +logging.basicConfig(level=logging.WARNING) system_message = """ You are a chat bot. Your name is Mosscap and diff --git a/python/samples/concepts/structured_output/json_structured_output.py b/python/samples/concepts/structured_output/json_structured_output.py index a65f11ff6bde..f6ea600cd56f 100644 --- a/python/samples/concepts/structured_output/json_structured_output.py +++ b/python/samples/concepts/structured_output/json_structured_output.py @@ -40,15 +40,17 @@ # used to parse the structured output from the OpenAI service, # and ensure that the model correctly outputs the schema based # on the Pydantic model. +from semantic_kernel.kernel_pydantic import KernelBaseModel # noqa: E402 -# class Step(KernelBaseModel): -# explanation: str -# output: str +class Step(KernelBaseModel): + explanation: str + output: str -# class Reasoning(KernelBaseModel): -# steps: list[Step] -# final_answer: str + +class Reasoning(KernelBaseModel): + steps: list[Step] + final_answer: str ################################################################### @@ -59,14 +61,14 @@ # converted to the proper JSON Schema and sent to the LLM. # Uncomment the follow lines and comment out the Pydantic model # above to use this option. -class Step: - explanation: str - output: str +# class Step: +# explanation: str +# output: str -class Reasoning: - steps: list[Step] - final_answer: str +# class Reasoning: +# steps: list[Step] +# final_answer: str ################################################################### diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index f89a042a0c93..161efd910340 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -37,16 +37,19 @@ kernel = Kernel() +# Define a Process Actor Factory that allows a dependency to be injected during Process Actor creation def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: """Factory function to create ProcessActor instances with dependencies.""" return ProcessActor(ctx, actor_id, kernel) +# Define a Step Actor Factory that allows a dependency to be injected during Step Actor creation def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor: """Factory function to create StepActor instances with dependencies.""" return StepActor(ctx, actor_id, kernel=kernel) +# Define a lifespan method that registers the actors with the Dapr runtime @asynccontextmanager async def lifespan(app: FastAPI): print("## actor startup ##") @@ -58,6 +61,7 @@ async def lifespan(app: FastAPI): yield +# Define the FastAPI app along with the DaprApp and the DaprActor app = FastAPI(title="SKProcess", lifespan=lifespan) dapr_app = DaprApp(app) actor = DaprActor(app) diff --git a/python/samples/getting_started_with_agents/step3_chat.py b/python/samples/getting_started_with_agents/step3_chat.py index a2c536aca22a..e81c5d0c516c 100644 --- a/python/samples/getting_started_with_agents/step3_chat.py +++ b/python/samples/getting_started_with_agents/step3_chat.py @@ -75,14 +75,10 @@ async def main(): await chat.add_chat_message(ChatMessageContent(role=AuthorRole.USER, content=input)) print(f"# {AuthorRole.USER}: '{input}'") - chat_history: list[ChatMessageContent] = [] async for content in chat.invoke(): print(f"# {content.role} - {content.name or '*'}: '{content.content}'") - chat_history.append(content) print(f"# IS COMPLETE: {chat.is_complete}") - for msg in chat_history: - print(msg.model_dump_json()) if __name__ == "__main__": From e1fee76253b7656656bbfb994f456d4f5e9c37d4 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Mon, 11 Nov 2024 11:19:51 -0500 Subject: [PATCH 10/16] Fix typo --- python/samples/demos/process_with_dapr/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index 161efd910340..b83b1c5c1973 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -158,7 +158,7 @@ def get_process() -> "KernelProcess": myAStep = process.add_step(step_type=AStep) myBStep = process.add_step(step_type=BStep) - # Intialize the CStep with an initial state and the state's current cycle set to 1 + # Initialize the CStep with an initial state and the state's current cycle set to 1 myCStep = process.add_step(step_type=CStep, initial_state=CStepState(current_cycle=1)) # Define the input event and where to send it to From 2b99a87bfd56f5b6fb98c91be5e72b1839241269 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Mon, 11 Nov 2024 14:01:56 -0500 Subject: [PATCH 11/16] Fix return type --- python/semantic_kernel/processes/process_event.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/semantic_kernel/processes/process_event.py b/python/semantic_kernel/processes/process_event.py index 583fd1364ea8..626e9d594e79 100644 --- a/python/semantic_kernel/processes/process_event.py +++ b/python/semantic_kernel/processes/process_event.py @@ -1,6 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. -from typing import Optional +from typing import Any from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.processes.kernel_process.kernel_process_event import ( @@ -21,7 +21,7 @@ def id(self) -> str: return f"{self.namespace}.{self.inner_event.id}" @property - def data(self) -> Optional[object]: + def data(self) -> Any | None: """The data of the event.""" return self.inner_event.data From a152b6acf85496504f71e3f2fcb91c5a717a73e6 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 14 Nov 2024 13:46:56 -0500 Subject: [PATCH 12/16] Improve import depth. Fix running nested processes. --- python/samples/demos/process_with_dapr/app.py | 35 ++++++++------ python/semantic_kernel/processes/__init__.py | 9 ++++ .../processes/dapr_runtime/__init__.py | 17 +++++++ .../dapr_runtime/actors/process_actor.py | 48 +++++++++++++------ .../dapr_runtime/actors/step_actor.py | 10 ++-- .../dapr_kernel_process_context.py | 6 +-- .../dapr_runtime/dapr_process_info.py | 5 +- .../processes/dapr_runtime/dapr_step_info.py | 2 + .../processes/kernel_process/__init__.py | 19 ++++++++ .../processes/local_runtime/local_process.py | 2 +- .../processes/process_event.py | 5 -- .../test_dapr_kernel_process_context.py | 2 +- .../dapr_runtime/test_process_actor.py | 2 + 13 files changed, 117 insertions(+), 45 deletions(-) diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index b83b1c5c1973..347772e9a114 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -17,16 +17,20 @@ from semantic_kernel import Kernel from semantic_kernel.functions import kernel_function from semantic_kernel.kernel_pydantic import KernelBaseModel -from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor -from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor -from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor -from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor -from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor -from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start -from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep -from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext -from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState -from semantic_kernel.processes.process_builder import ProcessBuilder +from semantic_kernel.processes import ProcessBuilder +from semantic_kernel.processes.dapr_runtime import ( + EventBufferActor, + ExternalEventBufferActor, + MessageBufferActor, + ProcessActor, + StepActor, + start, +) +from semantic_kernel.processes.kernel_process import ( + KernelProcessStep, + KernelProcessStepContext, + KernelProcessStepState, +) if TYPE_CHECKING: from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess @@ -133,7 +137,7 @@ async def activate(self, state: KernelProcessStepState[CStepState]): """Activates the step and sets the state.""" step_state = CStepState.model_validate(state.state) print(f"##### CStep activated with Cycle = '{step_state.current_cycle}'.") - self.state = state.state + self.state = step_state @kernel_function() async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str): @@ -146,9 +150,6 @@ async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepda await context.emit_event(process_event=CommonEvents.CStepDone.value) -kernel = Kernel() - - def get_process() -> "KernelProcess": # Define the process builder process = ProcessBuilder(name="ProcessWithDapr") @@ -182,8 +183,12 @@ def get_process() -> "KernelProcess": async def start_process(process_id: str): try: process = get_process() + _ = await start( - process=process, kernel=kernel, initial_event=CommonEvents.StartProcess.value, process_id=process_id + process=process, + kernel=kernel, + initial_event=CommonEvents.StartProcess.value, + process_id=process_id, ) return JSONResponse(content={"processId": process_id}, status_code=200) except Exception as e: diff --git a/python/semantic_kernel/processes/__init__.py b/python/semantic_kernel/processes/__init__.py index e69de29bb2d1..1bd382e7b9c3 100644 --- a/python/semantic_kernel/processes/__init__.py +++ b/python/semantic_kernel/processes/__init__.py @@ -0,0 +1,9 @@ +# Copyright (c) Microsoft. All rights reserved. + +from semantic_kernel.processes.process_builder import ProcessBuilder +from semantic_kernel.processes.process_types import TState + +__all__ = [ + "ProcessBuilder", + "TState", +] diff --git a/python/semantic_kernel/processes/dapr_runtime/__init__.py b/python/semantic_kernel/processes/dapr_runtime/__init__.py index e69de29bb2d1..5c05437db5e8 100644 --- a/python/semantic_kernel/processes/dapr_runtime/__init__.py +++ b/python/semantic_kernel/processes/dapr_runtime/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) Microsoft. All rights reserved. + +from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor +from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor +from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor +from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor +from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start + +__all__ = [ + "EventBufferActor", + "ExternalEventBufferActor", + "MessageBufferActor", + "ProcessActor", + "StepActor", + "start", +] diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py index 11e80bfac09e..a57e44a4ba58 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/process_actor.py @@ -6,6 +6,7 @@ import logging import uuid from queue import Queue +from typing import Any from dapr.actor import ActorId, ActorProxy from dapr.actor.runtime.context import ActorRuntimeContext @@ -71,15 +72,27 @@ def name(self) -> str: raise KernelException(error_message) return self.process.state.name - async def initialize_process(self, input: dict) -> None: + async def initialize_process(self, input: dict | str) -> None: """Initializes the process.""" - process_info_dict = input.get("process_info") + if isinstance(input, str): + input = json.loads(input) - if process_info_dict is None: - raise ValueError("The process info is not defined.") + if not isinstance(input, dict): + raise TypeError("input must be a JSON string or a dictionary") + process_info_data = input.get("process_info") parent_process_id = input.get("parent_process_id") + if process_info_data is None: + raise ValueError("The process info is not defined.") + + if isinstance(process_info_data, str): + process_info_dict = json.loads(process_info_data) + elif isinstance(process_info_data, dict): + process_info_dict = process_info_data + else: + raise TypeError("process_info must be a JSON string or a dictionary") + # Reconstruct the DaprProcessInfo from the dictionary dapr_process_info = DaprProcessInfo.model_validate(process_info_dict) @@ -141,9 +154,8 @@ async def run_once(self, process_event: str) -> None: try: await self.process_task except asyncio.CancelledError: - print("Process task was cancelled") + logger.error("Process task was cancelled") except Exception as ex: - print(ex) logger.error(f"Error in run_once: {ex}") raise ex @@ -162,6 +174,11 @@ async def initialize_step(self): # The process does not need any further initialization pass + async def activate_step(self): + """Overrides the step's activate_step method.""" + # The process does not need any further initialization + pass + async def _on_activate(self) -> None: """Called when the actor is activated.""" try: @@ -251,8 +268,11 @@ async def _initialize_process_actor( actor_id=scoped_process_id, actor_interface=ProcessInterface, ) - payload = {"process_info": step.model_dump(), "parent_process_id": self.id.id} - await process_actor.initialize_process(payload) + process_payload: dict[str, Any] = { + "process_info": step.model_dump_json(), + "parent_process_id": self.id.id, + } + await process_actor.initialize_process(process_payload) step_actor = ActorProxy.create( # type: ignore actor_type=f"{ProcessActor.__name__}", actor_id=scoped_process_id, @@ -263,17 +283,18 @@ async def _initialize_process_actor( assert step.state and step.state.id is not None # nosec scoped_step_id = self._scoped_actor_id(ActorId(step.state.id)) - step_actor = ActorProxy.create( # type: ignore + step_actor: StepInterface = ActorProxy.create( # type: ignore actor_type=f"{StepActor.__name__}", actor_id=scoped_step_id, actor_interface=StepInterface, ) + assert step_actor is not None # nosec step_dict = step.model_dump() - payload = {"step_info": step_dict, "parent_process_id": self.id.id} + step_payload: dict[str, Any] = {"step_info": step_dict, "parent_process_id": self.id.id} try: - await step_actor.initialize_step(json.dumps(payload)) + await step_actor.initialize_step(json.dumps(step_payload)) except Exception as ex: - print(ex) + logger.error(f"Error initializing ProcessActor step: {ex}") raise ex # Add the local step to the list of steps @@ -316,8 +337,7 @@ async def internal_execute(self, max_supersteps: int = 100, keep_alive: bool = T await self.send_outgoing_public_events() except Exception as ex: - print(f"An error occurred while running the process: {ex}") - # Optionally handle the exception + logger.error(f"An error occurred while running the process: {ex}") raise def _scoped_event(self, dapr_event: ProcessEvent): diff --git a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py index 0d50b831b5ba..7b38c7633a31 100644 --- a/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py +++ b/python/semantic_kernel/processes/dapr_runtime/actors/step_actor.py @@ -85,6 +85,9 @@ async def initialize_step(self, input: str) -> None: if input is None: raise ValueError("step_info must not be None") + if self.initialize_task: + return + try: input_dict: dict[str, Any] = json.loads(input) except (json.JSONDecodeError, TypeError): @@ -92,9 +95,6 @@ async def initialize_step(self, input: str) -> None: step_info = DaprStepInfo.model_validate(input_dict.get("step_info")) - if self.initialize_task: - return - await self._int_initialize_step(step_info, input_dict.get("parent_process_id")) try: @@ -358,7 +358,7 @@ async def emit_event(self, process_event: KernelProcessEvent): if self.event_namespace is None: raise ValueError("The event namespace must be initialized before emitting an event.") - await self.emit_process_event(ProcessEvent.from_kernel_process_event(process_event, self.event_namespace)) + await self.emit_process_event(ProcessEvent(inner_event=process_event, namespace=self.event_namespace)) async def emit_process_event(self, dapr_event: ProcessEvent): """Emits an event from the step.""" @@ -408,7 +408,7 @@ async def _on_activate(self) -> None: try: has_value, existing_step_info = await self._state_manager.try_get_state(ActorStateKeys.StepInfoState.value) except Exception as ex: - print(f"Error in Step {self.name}: {ex!s}") + logger.error(f"Error in Step {self.name}: {ex!s}") raise ex if has_value: parent_process_id = await self._state_manager.get_state(ActorStateKeys.StepParentProcessId.value) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py index ef46d1c8026a..b6f5780daab2 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process_context.py @@ -16,7 +16,7 @@ class DaprKernelProcessContext: """A Dapr kernel process context.""" - dapr_process: ActorProxy + dapr_process: ProcessInterface process: KernelProcess def __init__(self, process: KernelProcess): @@ -28,7 +28,7 @@ def __init__(self, process: KernelProcess): self.process = process process_id = ActorId(process.state.id) - self.dapr_process = ActorProxy.create( + self.dapr_process = ActorProxy.create( # type: ignore actor_type=f"{ProcessActor.__name__}", actor_id=process_id, actor_interface=ProcessInterface, @@ -37,7 +37,7 @@ def __init__(self, process: KernelProcess): async def start_with_event(self, initial_event: KernelProcessEvent) -> None: """Starts the process with the provided initial event.""" dapr_process = DaprProcessInfo.from_kernel_process(self.process) - dapr_process_dict = dapr_process.model_dump() + dapr_process_dict = dapr_process.model_dump_json() payload = { "process_info": dapr_process_dict, diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py index 71cb2ea3a6b5..4a93ad10e66a 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_process_info.py @@ -1,6 +1,8 @@ # Copyright (c) Microsoft. All rights reserved. +from typing import Literal + from pydantic import Field from semantic_kernel.processes.dapr_runtime.dapr_step_info import DaprStepInfo @@ -14,7 +16,8 @@ class DaprProcessInfo(DaprStepInfo): """A Dapr process info.""" - steps: list[DaprStepInfo] = Field(default_factory=list) + type: Literal["DaprProcessInfo"] = Field("DaprProcessInfo") # type: ignore + steps: list["DaprStepInfo | DaprProcessInfo"] = Field(default_factory=list) def to_kernel_process(self) -> KernelProcess: """Converts the Dapr process info to a kernel process.""" diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py index 68e40229bd63..85f149709490 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_step_info.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. import importlib +from typing import Literal from pydantic import Field @@ -17,6 +18,7 @@ class DaprStepInfo(KernelBaseModel): """A Dapr step info.""" + type: Literal["DaprStepInfo"] = Field("DaprStepInfo") inner_step_python_type: str state: KernelProcessStepState edges: dict[str, list[KernelProcessEdge]] = Field(default_factory=dict) diff --git a/python/semantic_kernel/processes/kernel_process/__init__.py b/python/semantic_kernel/processes/kernel_process/__init__.py index e69de29bb2d1..85598533f3fc 100644 --- a/python/semantic_kernel/processes/kernel_process/__init__.py +++ b/python/semantic_kernel/processes/kernel_process/__init__.py @@ -0,0 +1,19 @@ +# Copyright (c) Microsoft. All rights reserved. + +from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess +from semantic_kernel.processes.kernel_process.kernel_process_event import ( + KernelProcessEvent, + KernelProcessEventVisibility, +) +from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep +from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext +from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState + +__all__ = [ + "KernelProcess", + "KernelProcessEvent", + "KernelProcessEventVisibility", + "KernelProcessStep", + "KernelProcessStepContext", + "KernelProcessStepState", +] diff --git a/python/semantic_kernel/processes/local_runtime/local_process.py b/python/semantic_kernel/processes/local_runtime/local_process.py index 3a25e05d38d9..eeb03b7888c2 100644 --- a/python/semantic_kernel/processes/local_runtime/local_process.py +++ b/python/semantic_kernel/processes/local_runtime/local_process.py @@ -186,7 +186,7 @@ async def internal_execute(self, max_supersteps: int = 100, keep_alive: bool = T await asyncio.gather(*message_tasks) except Exception as ex: - print("An error occurred while running the process: %s." % ex) + logger.error(f"An error occurred while running the process: {ex}.") raise async def to_kernel_process(self) -> "KernelProcess": diff --git a/python/semantic_kernel/processes/process_event.py b/python/semantic_kernel/processes/process_event.py index 626e9d594e79..14e6ca3d5ffd 100644 --- a/python/semantic_kernel/processes/process_event.py +++ b/python/semantic_kernel/processes/process_event.py @@ -29,8 +29,3 @@ def data(self) -> Any | None: def visibility(self) -> "KernelProcessEventVisibility": """The visibility of the event.""" return self.inner_event.visibility - - @classmethod - def from_kernel_process_event(cls, kernel_process_event: KernelProcessEvent, namespace: str) -> "ProcessEvent": - """Creates a new ProcessEvent from a KernelProcessEvent.""" - return cls(namespace=namespace, inner_event=kernel_process_event) diff --git a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py index 89469355375e..f262f74bbedc 100644 --- a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py +++ b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process_context.py @@ -53,7 +53,7 @@ async def test_start_with_event(process_context): dapr_process_info = DaprProcessInfo.from_kernel_process(context.process) expected_payload = { - "process_info": dapr_process_info.model_dump(), + "process_info": dapr_process_info.model_dump_json(), "parent_process_id": None, } mock_dapr_process.initialize_process.assert_awaited_once_with(expected_payload) diff --git a/python/tests/unit/processes/dapr_runtime/test_process_actor.py b/python/tests/unit/processes/dapr_runtime/test_process_actor.py index 900052c5980f..abec885b18ac 100644 --- a/python/tests/unit/processes/dapr_runtime/test_process_actor.py +++ b/python/tests/unit/processes/dapr_runtime/test_process_actor.py @@ -51,11 +51,13 @@ def clean_structure(data): async def test_initialize_process(actor_context): input_data = { "process_info": { + "type": "DaprProcessInfo", "state": {"name": "Test Process", "id": "proc_123"}, "steps": [ { "state": {"name": "Step1", "id": "step_123"}, "inner_step_python_type": "SomeStepType", + "type": "DaprStepInfo", } ], "inner_step_python_type": "SomeProcessType", From 13b60a2c853b2ca3447f70b39965e96e73d3e76c Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 14 Nov 2024 14:41:17 -0500 Subject: [PATCH 13/16] Clean up demo sample. --- python/samples/demos/process_with_dapr/app.py | 137 +++--------------- .../process_with_dapr/process/__init__.py | 6 + .../process_with_dapr/process/process.py | 38 +++++ .../demos/process_with_dapr/process/steps.py | 89 ++++++++++++ 4 files changed, 152 insertions(+), 118 deletions(-) create mode 100644 python/samples/demos/process_with_dapr/process/__init__.py create mode 100644 python/samples/demos/process_with_dapr/process/process.py create mode 100644 python/samples/demos/process_with_dapr/process/steps.py diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/app.py index 347772e9a114..829edc32d1d7 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/app.py @@ -1,10 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. -import asyncio import logging from contextlib import asynccontextmanager -from enum import Enum -from typing import TYPE_CHECKING, ClassVar import uvicorn from dapr.actor import ActorId @@ -12,12 +9,10 @@ from dapr.ext.fastapi import DaprActor, DaprApp from fastapi import FastAPI from fastapi.responses import JSONResponse -from pydantic import Field +from samples.demos.process_with_dapr.process.process import get_process +from samples.demos.process_with_dapr.process.steps import CommonEvents from semantic_kernel import Kernel -from semantic_kernel.functions import kernel_function -from semantic_kernel.kernel_pydantic import KernelBaseModel -from semantic_kernel.processes import ProcessBuilder from semantic_kernel.processes.dapr_runtime import ( EventBufferActor, ExternalEventBufferActor, @@ -26,20 +21,24 @@ StepActor, start, ) -from semantic_kernel.processes.kernel_process import ( - KernelProcessStep, - KernelProcessStepContext, - KernelProcessStepState, -) - -if TYPE_CHECKING: - from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess logging.basicConfig(level=logging.ERROR) kernel = Kernel() +######################################################################### +# The following Process and Dapr runtime sample uses a FastAPI app # +# to start a process and run steps. The process is defined in the # +# process/process.py file and the steps are defined in the steps.py # +# file. The process is started by calling the /processes/{process_id} # +# endpoint. The actors are registered with the Dapr runtime using # +# the DaprActor class. The ProcessActor and the StepActor require a # +# kernel dependency to be injected during creation. This is done by # +# defining a factory function that takes the kernel as a parameter # +# and returns the actor instance with the kernel injected. # +######################################################################### + # Define a Process Actor Factory that allows a dependency to be injected during Process Actor creation def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: @@ -57,10 +56,15 @@ def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor @asynccontextmanager async def lifespan(app: FastAPI): print("## actor startup ##") + # The process actor is used to manage the process: it starts, stops, and sends events to the process await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) + # The step actor is used to run the process steps await actor.register_actor(StepActor, actor_factory=step_actor_factory) + # The event buffer actor is used to handle incoming events and is used by a step to bubble up events await actor.register_actor(EventBufferActor) + # The message buffer actor is used to handle incoming messages from edges await actor.register_actor(MessageBufferActor) + # The external event buffer actor handles incoming events to kick off a process await actor.register_actor(ExternalEventBufferActor) yield @@ -76,109 +80,6 @@ async def healthcheck(): return "Healthy!" -class CommonEvents(Enum): - """Common events for the sample process.""" - - UserInputReceived = "UserInputReceived" - CompletionResponseGenerated = "CompletionResponseGenerated" - WelcomeDone = "WelcomeDone" - AStepDone = "AStepDone" - BStepDone = "BStepDone" - CStepDone = "CStepDone" - StartARequested = "StartARequested" - StartBRequested = "StartBRequested" - ExitRequested = "ExitRequested" - StartProcess = "StartProcess" - - -# Define a sample step that once the `on_input_event` is received, -# it will emit two events to start the A and B steps. -class KickOffStep(KernelProcessStep): - KICK_OFF_FUNCTION: ClassVar[str] = "kick_off" - - @kernel_function(name=KICK_OFF_FUNCTION) - async def print_welcome_message(self, context: KernelProcessStepContext): - print("##### Kickoff ran.") - await context.emit_event(process_event=CommonEvents.StartARequested.value, data="Get Going A") - await context.emit_event(process_event=CommonEvents.StartBRequested.value, data="Get Going B") - - -# Define a sample `AStep` step that will emit an event after 1 second. -# The event will be sent to the `CStep` step with the data `I did A`. -class AStep(KernelProcessStep): - @kernel_function() - async def do_it(self, context: KernelProcessStepContext): - print("##### AStep ran.") - await asyncio.sleep(1) - await context.emit_event(process_event=CommonEvents.AStepDone.value, data="I did A") - - -# Define a sample `BStep` step that will emit an event after 2 seconds. -# The event will be sent to the `CStep` step with the data `I did B`. -class BStep(KernelProcessStep): - @kernel_function() - async def do_it(self, context: KernelProcessStepContext): - print("##### BStep ran.") - await asyncio.sleep(2) - await context.emit_event(process_event=CommonEvents.BStepDone.value, data="I did B") - - -# Define a sample `CStepState` that will keep track of the current cycle. -class CStepState(KernelBaseModel): - current_cycle: int = 1 - - -# Define a sample `CStep` step that will emit an `ExitRequested` event after 3 cycles. -class CStep(KernelProcessStep[CStepState]): - state: CStepState = Field(default_factory=CStepState) - - # The activate method overrides the base class method to set the state in the step. - async def activate(self, state: KernelProcessStepState[CStepState]): - """Activates the step and sets the state.""" - step_state = CStepState.model_validate(state.state) - print(f"##### CStep activated with Cycle = '{step_state.current_cycle}'.") - self.state = step_state - - @kernel_function() - async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str): - self.state.current_cycle += 1 - if self.state.current_cycle >= 3: - print("##### CStep run cycle 3 - exiting.") - await context.emit_event(process_event=CommonEvents.ExitRequested.value) - return - print(f"##### CStep run cycle {self.state.current_cycle}") - await context.emit_event(process_event=CommonEvents.CStepDone.value) - - -def get_process() -> "KernelProcess": - # Define the process builder - process = ProcessBuilder(name="ProcessWithDapr") - - # Add the step types to the builder - kickoff_step = process.add_step(step_type=KickOffStep) - myAStep = process.add_step(step_type=AStep) - myBStep = process.add_step(step_type=BStep) - - # Initialize the CStep with an initial state and the state's current cycle set to 1 - myCStep = process.add_step(step_type=CStep, initial_state=CStepState(current_cycle=1)) - - # Define the input event and where to send it to - process.on_input_event(event_id=CommonEvents.StartProcess.value).send_event_to(target=kickoff_step) - - # Define the process flow - kickoff_step.on_event(event_id=CommonEvents.StartARequested.value).send_event_to(target=myAStep) - kickoff_step.on_event(event_id=CommonEvents.StartBRequested.value).send_event_to(target=myBStep) - myAStep.on_event(event_id=CommonEvents.AStepDone.value).send_event_to(target=myCStep, parameter_name="astepdata") - - # Define the fan in behavior once both AStep and BStep are done - myBStep.on_event(event_id=CommonEvents.BStepDone.value).send_event_to(target=myCStep, parameter_name="bstepdata") - myCStep.on_event(event_id=CommonEvents.CStepDone.value).send_event_to(target=kickoff_step) - myCStep.on_event(event_id=CommonEvents.ExitRequested.value).stop_process() - - # Build the process - return process.build() - - @app.get("/processes/{process_id}") async def start_process(process_id: str): try: diff --git a/python/samples/demos/process_with_dapr/process/__init__.py b/python/samples/demos/process_with_dapr/process/__init__.py new file mode 100644 index 000000000000..37dfc46cdb60 --- /dev/null +++ b/python/samples/demos/process_with_dapr/process/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft. All rights reserved. + +from samples.demos.process_with_dapr.process.process import get_process +from samples.demos.process_with_dapr.process.steps import AStep, BStep, CStep, KickOffStep + +__all__ = ["AStep", "BStep", "KickOffStep", "CStep", "get_process"] diff --git a/python/samples/demos/process_with_dapr/process/process.py b/python/samples/demos/process_with_dapr/process/process.py new file mode 100644 index 000000000000..a699b2a5d542 --- /dev/null +++ b/python/samples/demos/process_with_dapr/process/process.py @@ -0,0 +1,38 @@ +# Copyright (c) Microsoft. All rights reserved. + +from typing import TYPE_CHECKING + +from samples.demos.process_with_dapr.process.steps import AStep, BStep, CommonEvents, CStep, CStepState, KickOffStep +from semantic_kernel.processes import ProcessBuilder + +if TYPE_CHECKING: + from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess + + +def get_process() -> "KernelProcess": + # Define the process builder + process = ProcessBuilder(name="ProcessWithDapr") + + # Add the step types to the builder + kickoff_step = process.add_step(step_type=KickOffStep) + myAStep = process.add_step(step_type=AStep) + myBStep = process.add_step(step_type=BStep) + + # Initialize the CStep with an initial state and the state's current cycle set to 1 + myCStep = process.add_step(step_type=CStep, initial_state=CStepState(current_cycle=1)) + + # Define the input event and where to send it to + process.on_input_event(event_id=CommonEvents.StartProcess.value).send_event_to(target=kickoff_step) + + # Define the process flow + kickoff_step.on_event(event_id=CommonEvents.StartARequested.value).send_event_to(target=myAStep) + kickoff_step.on_event(event_id=CommonEvents.StartBRequested.value).send_event_to(target=myBStep) + myAStep.on_event(event_id=CommonEvents.AStepDone.value).send_event_to(target=myCStep, parameter_name="astepdata") + + # Define the fan in behavior once both AStep and BStep are done + myBStep.on_event(event_id=CommonEvents.BStepDone.value).send_event_to(target=myCStep, parameter_name="bstepdata") + myCStep.on_event(event_id=CommonEvents.CStepDone.value).send_event_to(target=kickoff_step) + myCStep.on_event(event_id=CommonEvents.ExitRequested.value).stop_process() + + # Build the process + return process.build() diff --git a/python/samples/demos/process_with_dapr/process/steps.py b/python/samples/demos/process_with_dapr/process/steps.py new file mode 100644 index 000000000000..e7635fe97cbb --- /dev/null +++ b/python/samples/demos/process_with_dapr/process/steps.py @@ -0,0 +1,89 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +from enum import Enum +from typing import ClassVar + +from pydantic import Field + +from semantic_kernel.functions import kernel_function +from semantic_kernel.kernel_pydantic import KernelBaseModel +from semantic_kernel.processes.kernel_process import ( + KernelProcessStep, + KernelProcessStepContext, + KernelProcessStepState, +) + + +class CommonEvents(Enum): + """Common events for the sample process.""" + + UserInputReceived = "UserInputReceived" + CompletionResponseGenerated = "CompletionResponseGenerated" + WelcomeDone = "WelcomeDone" + AStepDone = "AStepDone" + BStepDone = "BStepDone" + CStepDone = "CStepDone" + StartARequested = "StartARequested" + StartBRequested = "StartBRequested" + ExitRequested = "ExitRequested" + StartProcess = "StartProcess" + + +# Define a sample step that once the `on_input_event` is received, +# it will emit two events to start the A and B steps. +class KickOffStep(KernelProcessStep): + KICK_OFF_FUNCTION: ClassVar[str] = "kick_off" + + @kernel_function(name=KICK_OFF_FUNCTION) + async def print_welcome_message(self, context: KernelProcessStepContext): + print("##### Kickoff ran.") + await context.emit_event(process_event=CommonEvents.StartARequested.value, data="Get Going A") + await context.emit_event(process_event=CommonEvents.StartBRequested.value, data="Get Going B") + + +# Define a sample `AStep` step that will emit an event after 1 second. +# The event will be sent to the `CStep` step with the data `I did A`. +class AStep(KernelProcessStep): + @kernel_function() + async def do_it(self, context: KernelProcessStepContext): + print("##### AStep ran.") + await asyncio.sleep(1) + await context.emit_event(process_event=CommonEvents.AStepDone.value, data="I did A") + + +# Define a sample `BStep` step that will emit an event after 2 seconds. +# The event will be sent to the `CStep` step with the data `I did B`. +class BStep(KernelProcessStep): + @kernel_function() + async def do_it(self, context: KernelProcessStepContext): + print("##### BStep ran.") + await asyncio.sleep(2) + await context.emit_event(process_event=CommonEvents.BStepDone.value, data="I did B") + + +# Define a sample `CStepState` that will keep track of the current cycle. +class CStepState(KernelBaseModel): + current_cycle: int = 1 + + +# Define a sample `CStep` step that will emit an `ExitRequested` event after 3 cycles. +class CStep(KernelProcessStep[CStepState]): + state: CStepState = Field(default_factory=CStepState) + + # The activate method overrides the base class method to set the state in the step. + async def activate(self, state: KernelProcessStepState[CStepState]): + """Activates the step and sets the state.""" + step_state = CStepState.model_validate(state.state) + print(f"##### CStep activated with Cycle = '{step_state.current_cycle}'.") + self.state = step_state + + @kernel_function() + async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepdata: str): + self.state.current_cycle += 1 + if self.state.current_cycle >= 3: + print("##### CStep run cycle 3 - exiting.") + await context.emit_event(process_event=CommonEvents.ExitRequested.value) + return + print(f"##### CStep run cycle {self.state.current_cycle}") + await context.emit_event(process_event=CommonEvents.CStepDone.value) From 9ebb1cd85f8d08841bd025f1daf890f464974e78 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 14 Nov 2024 14:58:28 -0500 Subject: [PATCH 14/16] Simplify being able to pass in enum and convert string for user. --- .../concepts/processes/cycles_with_fan_in.py | 28 ++++++------ .../concepts/processes/nested_process.py | 12 ++--- .../process_with_dapr/process/process.py | 14 +++--- .../demos/process_with_dapr/process/steps.py | 12 ++--- .../step01/step01_processes.py | 18 ++++---- .../processes/fish_and_chips_process.py | 18 ++++---- .../step03/processes/fish_sandwich_process.py | 20 ++++----- .../step03/processes/fried_fish_process.py | 36 +++++++-------- .../step03/processes/potato_fries_process.py | 34 +++++++------- .../processes/single_food_item_process.py | 44 +++++++++---------- .../step03/steps/cut_food_step.py | 8 ++-- .../steps/cut_food_with_sharpening_step.py | 22 ++++------ .../step03/steps/fry_food_step.py | 6 +-- .../step03/steps/gather_ingredients_step.py | 10 ++--- .../dapr_runtime/dapr_kernel_process.py | 6 ++- .../kernel_process_step_context.py | 6 ++- .../local_runtime/local_kernel_process.py | 6 ++- .../processes/process_builder.py | 12 ++++- .../process_function_target_builder.py | 9 +++- .../processes/process_step_builder.py | 11 ++++- 20 files changed, 174 insertions(+), 158 deletions(-) diff --git a/python/samples/concepts/processes/cycles_with_fan_in.py b/python/samples/concepts/processes/cycles_with_fan_in.py index 005e2c1685da..d1b51e31cb5c 100644 --- a/python/samples/concepts/processes/cycles_with_fan_in.py +++ b/python/samples/concepts/processes/cycles_with_fan_in.py @@ -42,8 +42,8 @@ class KickOffStep(KernelProcessStep): @kernel_function(name=KICK_OFF_FUNCTION) async def print_welcome_message(self, context: KernelProcessStepContext): - await context.emit_event(process_event=CommonEvents.StartARequested.value, data="Get Going A") - await context.emit_event(process_event=CommonEvents.StartBRequested.value, data="Get Going B") + await context.emit_event(process_event=CommonEvents.StartARequested, data="Get Going A") + await context.emit_event(process_event=CommonEvents.StartBRequested, data="Get Going B") # Define a sample `AStep` step that will emit an event after 1 second. @@ -52,7 +52,7 @@ class AStep(KernelProcessStep): @kernel_function() async def do_it(self, context: KernelProcessStepContext): await asyncio.sleep(1) - await context.emit_event(process_event=CommonEvents.AStepDone.value, data="I did A") + await context.emit_event(process_event=CommonEvents.AStepDone, data="I did A") # Define a sample `BStep` step that will emit an event after 2 seconds. @@ -61,7 +61,7 @@ class BStep(KernelProcessStep): @kernel_function() async def do_it(self, context: KernelProcessStepContext): await asyncio.sleep(2) - await context.emit_event(process_event=CommonEvents.BStepDone.value, data="I did B") + await context.emit_event(process_event=CommonEvents.BStepDone, data="I did B") # Define a sample `CStepState` that will keep track of the current cycle. @@ -84,9 +84,9 @@ async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepda print(f"CStep Current Cycle: {self.state.current_cycle}") if self.state.current_cycle == 3: print("CStep Exit Requested") - await context.emit_event(process_event=CommonEvents.ExitRequested.value) + await context.emit_event(process_event=CommonEvents.ExitRequested) return - await context.emit_event(process_event=CommonEvents.CStepDone.value) + await context.emit_event(process_event=CommonEvents.CStepDone) kernel = Kernel() @@ -105,17 +105,17 @@ async def cycles_with_fan_in(): myCStep = process.add_step(step_type=CStep) # Define the input event and where to send it to - process.on_input_event(event_id=CommonEvents.StartProcess.value).send_event_to(target=kickoff_step) + process.on_input_event(event_id=CommonEvents.StartProcess).send_event_to(target=kickoff_step) # Define the process flow - kickoff_step.on_event(event_id=CommonEvents.StartARequested.value).send_event_to(target=myAStep) - kickoff_step.on_event(event_id=CommonEvents.StartBRequested.value).send_event_to(target=myBStep) - myAStep.on_event(event_id=CommonEvents.AStepDone.value).send_event_to(target=myCStep, parameter_name="astepdata") + kickoff_step.on_event(event_id=CommonEvents.StartARequested).send_event_to(target=myAStep) + kickoff_step.on_event(event_id=CommonEvents.StartBRequested).send_event_to(target=myBStep) + myAStep.on_event(event_id=CommonEvents.AStepDone).send_event_to(target=myCStep, parameter_name="astepdata") # Define the fan in behavior once both AStep and BStep are done - myBStep.on_event(event_id=CommonEvents.BStepDone.value).send_event_to(target=myCStep, parameter_name="bstepdata") - myCStep.on_event(event_id=CommonEvents.CStepDone.value).send_event_to(target=kickoff_step) - myCStep.on_event(event_id=CommonEvents.ExitRequested.value).stop_process() + myBStep.on_event(event_id=CommonEvents.BStepDone).send_event_to(target=myCStep, parameter_name="bstepdata") + myCStep.on_event(event_id=CommonEvents.CStepDone).send_event_to(target=kickoff_step) + myCStep.on_event(event_id=CommonEvents.ExitRequested).stop_process() # Build the process kernel_process = process.build() @@ -123,7 +123,7 @@ async def cycles_with_fan_in(): async with await start( process=kernel_process, kernel=kernel, - initial_event=KernelProcessEvent(id=CommonEvents.StartProcess.value, data="foo"), + initial_event=KernelProcessEvent(id=CommonEvents.StartProcess, data="foo"), ) as process_context: process_state = await process_context.get_state() c_step_state: KernelProcessStepState[CStepState] = next( diff --git a/python/samples/concepts/processes/nested_process.py b/python/samples/concepts/processes/nested_process.py index 501c26e0b9e7..2b210c776701 100644 --- a/python/samples/concepts/processes/nested_process.py +++ b/python/samples/concepts/processes/nested_process.py @@ -58,12 +58,12 @@ async def repeat(self, message: str, context: KernelProcessStepContext, count: i print(f"[REPEAT] {output}") await context.emit_event( - process_event=ProcessEvents.OutputReadyPublic.value, + process_event=ProcessEvents.OutputReadyPublic, data=output, visibility=KernelProcessEventVisibility.Public, ) await context.emit_event( - process_event=ProcessEvents.OutputReadyInternal.value, + process_event=ProcessEvents.OutputReadyInternal, data=output, visibility=KernelProcessEventVisibility.Internal, ) @@ -74,7 +74,7 @@ def create_linear_process(name: str): echo_step = process_builder.add_step(step_type=EchoStep) repeat_step = process_builder.add_step(step_type=RepeatStep) - process_builder.on_input_event(event_id=ProcessEvents.StartProcess.value).send_event_to(target=echo_step) + process_builder.on_input_event(event_id=ProcessEvents.StartProcess).send_event_to(target=echo_step) echo_step.on_function_result(function_name=EchoStep.ECHO).send_event_to( target=repeat_step, parameter_name="message" @@ -93,8 +93,8 @@ async def nested_process(): nested_process_step = process_builder.add_step_from_process(create_linear_process("Inner")) - process_builder.steps[1].on_event(ProcessEvents.OutputReadyInternal.value).send_event_to( - nested_process_step.where_input_event_is(ProcessEvents.StartProcess.value) + process_builder.steps[1].on_event(ProcessEvents.OutputReadyInternal).send_event_to( + nested_process_step.where_input_event_is(ProcessEvents.StartProcess) ) process = process_builder.build() @@ -102,7 +102,7 @@ async def nested_process(): test_input = "Test" process_handle = await start( - process=process, kernel=kernel, initial_event=ProcessEvents.StartProcess.value, data=test_input + process=process, kernel=kernel, initial_event=ProcessEvents.StartProcess, data=test_input ) process_info = await process_handle.get_state() diff --git a/python/samples/demos/process_with_dapr/process/process.py b/python/samples/demos/process_with_dapr/process/process.py index a699b2a5d542..e6741a85f116 100644 --- a/python/samples/demos/process_with_dapr/process/process.py +++ b/python/samples/demos/process_with_dapr/process/process.py @@ -22,17 +22,17 @@ def get_process() -> "KernelProcess": myCStep = process.add_step(step_type=CStep, initial_state=CStepState(current_cycle=1)) # Define the input event and where to send it to - process.on_input_event(event_id=CommonEvents.StartProcess.value).send_event_to(target=kickoff_step) + process.on_input_event(event_id=CommonEvents.StartProcess).send_event_to(target=kickoff_step) # Define the process flow - kickoff_step.on_event(event_id=CommonEvents.StartARequested.value).send_event_to(target=myAStep) - kickoff_step.on_event(event_id=CommonEvents.StartBRequested.value).send_event_to(target=myBStep) - myAStep.on_event(event_id=CommonEvents.AStepDone.value).send_event_to(target=myCStep, parameter_name="astepdata") + kickoff_step.on_event(event_id=CommonEvents.StartARequested).send_event_to(target=myAStep) + kickoff_step.on_event(event_id=CommonEvents.StartBRequested).send_event_to(target=myBStep) + myAStep.on_event(event_id=CommonEvents.AStepDone).send_event_to(target=myCStep, parameter_name="astepdata") # Define the fan in behavior once both AStep and BStep are done - myBStep.on_event(event_id=CommonEvents.BStepDone.value).send_event_to(target=myCStep, parameter_name="bstepdata") - myCStep.on_event(event_id=CommonEvents.CStepDone.value).send_event_to(target=kickoff_step) - myCStep.on_event(event_id=CommonEvents.ExitRequested.value).stop_process() + myBStep.on_event(event_id=CommonEvents.BStepDone).send_event_to(target=myCStep, parameter_name="bstepdata") + myCStep.on_event(event_id=CommonEvents.CStepDone).send_event_to(target=kickoff_step) + myCStep.on_event(event_id=CommonEvents.ExitRequested).stop_process() # Build the process return process.build() diff --git a/python/samples/demos/process_with_dapr/process/steps.py b/python/samples/demos/process_with_dapr/process/steps.py index e7635fe97cbb..083a2e78e9bb 100644 --- a/python/samples/demos/process_with_dapr/process/steps.py +++ b/python/samples/demos/process_with_dapr/process/steps.py @@ -38,8 +38,8 @@ class KickOffStep(KernelProcessStep): @kernel_function(name=KICK_OFF_FUNCTION) async def print_welcome_message(self, context: KernelProcessStepContext): print("##### Kickoff ran.") - await context.emit_event(process_event=CommonEvents.StartARequested.value, data="Get Going A") - await context.emit_event(process_event=CommonEvents.StartBRequested.value, data="Get Going B") + await context.emit_event(process_event=CommonEvents.StartARequested, data="Get Going A") + await context.emit_event(process_event=CommonEvents.StartBRequested, data="Get Going B") # Define a sample `AStep` step that will emit an event after 1 second. @@ -49,7 +49,7 @@ class AStep(KernelProcessStep): async def do_it(self, context: KernelProcessStepContext): print("##### AStep ran.") await asyncio.sleep(1) - await context.emit_event(process_event=CommonEvents.AStepDone.value, data="I did A") + await context.emit_event(process_event=CommonEvents.AStepDone, data="I did A") # Define a sample `BStep` step that will emit an event after 2 seconds. @@ -59,7 +59,7 @@ class BStep(KernelProcessStep): async def do_it(self, context: KernelProcessStepContext): print("##### BStep ran.") await asyncio.sleep(2) - await context.emit_event(process_event=CommonEvents.BStepDone.value, data="I did B") + await context.emit_event(process_event=CommonEvents.BStepDone, data="I did B") # Define a sample `CStepState` that will keep track of the current cycle. @@ -83,7 +83,7 @@ async def do_it(self, context: KernelProcessStepContext, astepdata: str, bstepda self.state.current_cycle += 1 if self.state.current_cycle >= 3: print("##### CStep run cycle 3 - exiting.") - await context.emit_event(process_event=CommonEvents.ExitRequested.value) + await context.emit_event(process_event=CommonEvents.ExitRequested) return print(f"##### CStep run cycle {self.state.current_cycle}") - await context.emit_event(process_event=CommonEvents.CStepDone.value) + await context.emit_event(process_event=CommonEvents.CStepDone) diff --git a/python/samples/getting_started_with_processes/step01/step01_processes.py b/python/samples/getting_started_with_processes/step01/step01_processes.py index 80dde1447776..738f41212b0d 100644 --- a/python/samples/getting_started_with_processes/step01/step01_processes.py +++ b/python/samples/getting_started_with_processes/step01/step01_processes.py @@ -70,13 +70,13 @@ async def get_user_input(self, context: KernelProcessStepContext): print(f"USER: {user_message}") if "exit" in user_message: - await context.emit_event(process_event=ChatBotEvents.Exit.value, data=None) + await context.emit_event(process_event=ChatBotEvents.Exit, data=None) return self.state.current_input_index += 1 # Emit the user input event - await context.emit_event(process_event=CommonEvents.UserInputReceived.value, data=user_message) + await context.emit_event(process_event=CommonEvents.UserInputReceived, data=user_message) class ChatUserInputStep(ScriptedUserInputStep): @@ -140,7 +140,7 @@ async def get_chat_response(self, context: "KernelProcessStepContext", user_mess self.state.chat_messages.append(answer) # Emit an event: assistantResponse - await context.emit_event(process_event=ChatBotEvents.AssistantResponseGenerated.value, data=answer) + await context.emit_event(process_event=ChatBotEvents.AssistantResponseGenerated, data=answer) kernel = Kernel() @@ -157,7 +157,7 @@ async def step01_processes(): response_step = process.add_step(ChatBotResponseStep) # Define the input event that starts the process and where to send it - process.on_input_event(event_id=ChatBotEvents.StartProcess.value).send_event_to(target=intro_step) + process.on_input_event(event_id=ChatBotEvents.StartProcess).send_event_to(target=intro_step) # Define the event that triggers the next step in the process intro_step.on_function_result(function_name=IntroStep.print_intro_message.__name__).send_event_to( @@ -165,16 +165,14 @@ async def step01_processes(): ) # Define the event that triggers the process to stop - user_input_step.on_event(event_id=ChatBotEvents.Exit.value).stop_process() + user_input_step.on_event(event_id=ChatBotEvents.Exit).stop_process() # For the user step, send the user input to the response step - user_input_step.on_event(event_id=CommonEvents.UserInputReceived.value).send_event_to( + user_input_step.on_event(event_id=CommonEvents.UserInputReceived).send_event_to( target=response_step, parameter_name="user_message" ) # For the response step, send the response back to the user input step - response_step.on_event(event_id=ChatBotEvents.AssistantResponseGenerated.value).send_event_to( - target=user_input_step - ) + response_step.on_event(event_id=ChatBotEvents.AssistantResponseGenerated).send_event_to(target=user_input_step) # Build the kernel process kernel_process = process.build() @@ -183,7 +181,7 @@ async def step01_processes(): await start( process=kernel_process, kernel=kernel, - initial_event=KernelProcessEvent(id=ChatBotEvents.StartProcess.value, data=None), + initial_event=KernelProcessEvent(id=ChatBotEvents.StartProcess, data=None), ) diff --git a/python/samples/getting_started_with_processes/step03/processes/fish_and_chips_process.py b/python/samples/getting_started_with_processes/step03/processes/fish_and_chips_process.py index 9fe17941ced0..0a449df4cedd 100644 --- a/python/samples/getting_started_with_processes/step03/processes/fish_and_chips_process.py +++ b/python/samples/getting_started_with_processes/step03/processes/fish_and_chips_process.py @@ -20,7 +20,7 @@ class Functions(Enum): class OutputEvents(Enum): CondimentsAdded = "CondimentsAdded" - @kernel_function(name=Functions.AddCondiments.value) + @kernel_function(name=Functions.AddCondiments) async def add_condiments( self, context: KernelProcessStepContext, fish_actions: list[str], potato_actions: list[str] ): @@ -30,7 +30,7 @@ async def add_condiments( fish_actions.extend(potato_actions) fish_actions.append("Condiments") await context.emit_event( - process_event=AddFishAndChipsCondimentsStep.OutputEvents.CondimentsAdded.value, data=fish_actions + process_event=AddFishAndChipsCondimentsStep.OutputEvents.CondimentsAdded, data=fish_actions ) @@ -41,7 +41,7 @@ class ProcessEvents(Enum): class ExternalFishAndChipsStep(ExternalStep): def __init__(self): - super().__init__(FishAndChipsProcess.ProcessEvents.FishAndChipsReady.value) + super().__init__(FishAndChipsProcess.ProcessEvents.FishAndChipsReady) @staticmethod def create_process(process_name: str = "FishAndChipsProcess"): @@ -51,21 +51,21 @@ def create_process(process_name: str = "FishAndChipsProcess"): add_condiments_step = process_builder.add_step(AddFishAndChipsCondimentsStep) external_step = process_builder.add_step(FishAndChipsProcess.ExternalFishAndChipsStep) - process_builder.on_input_event(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips.value).send_event_to( - make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish.value) + process_builder.on_input_event(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips).send_event_to( + make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish) ).send_event_to( - make_potato_fries_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries.value) + make_potato_fries_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries) ) - make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady.value).send_event_to( + make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to( ProcessFunctionTargetBuilder(add_condiments_step, parameter_name="fishActions") ) - make_potato_fries_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady.value).send_event_to( + make_potato_fries_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady).send_event_to( ProcessFunctionTargetBuilder(add_condiments_step, parameter_name="potatoActions") ) - add_condiments_step.on_event(AddFishAndChipsCondimentsStep.OutputEvents.CondimentsAdded.value).send_event_to( + add_condiments_step.on_event(AddFishAndChipsCondimentsStep.OutputEvents.CondimentsAdded).send_event_to( ProcessFunctionTargetBuilder(external_step, parameter_name="fishActions") ) diff --git a/python/samples/getting_started_with_processes/step03/processes/fish_sandwich_process.py b/python/samples/getting_started_with_processes/step03/processes/fish_sandwich_process.py index db476aa721dc..0f526bb4ec05 100644 --- a/python/samples/getting_started_with_processes/step03/processes/fish_sandwich_process.py +++ b/python/samples/getting_started_with_processes/step03/processes/fish_sandwich_process.py @@ -18,11 +18,11 @@ class Functions(Enum): class OutputEvents(Enum): BunsAdded = "BunsAdded" - @kernel_function(name=Functions.AddBuns.value) + @kernel_function(name=Functions.AddBuns) async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]): print(f"BUNS_ADDED_STEP: Buns added to ingredient {food_actions[0]}") food_actions.append("Buns") - await context.emit_event(process_event=self.OutputEvents.BunsAdded.value, data=food_actions) + await context.emit_event(process_event=self.OutputEvents.BunsAdded, data=food_actions) class AddSpecialSauceStep(KernelProcessStep): @@ -32,16 +32,16 @@ class Functions(Enum): class OutputEvents(Enum): SpecialSauceAdded = "SpecialSauceAdded" - @kernel_function(name=Functions.AddSpecialSauce.value) + @kernel_function(name=Functions.AddSpecialSauce) async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]): print(f"SPECIAL_SAUCE_ADDED: Special sauce added to ingredient {food_actions[0]}") food_actions.append("Sauce") - await context.emit_event(process_event=self.OutputEvents.SpecialSauceAdded.value, data=food_actions) + await context.emit_event(process_event=self.OutputEvents.SpecialSauceAdded, data=food_actions) class ExternalFriedFishStep(ExternalStep): def __init__(self): - super().__init__(FishSandwichProcess.ProcessEvents.FishSandwichReady.value) + super().__init__(FishSandwichProcess.ProcessEvents.FishSandwichReady) class FishSandwichProcess: @@ -57,19 +57,19 @@ def create_process(process_name: str = "FishSandwichProcess"): add_special_sauce_step = process_builder.add_step(AddSpecialSauceStep) external_step = process_builder.add_step(ExternalFriedFishStep) - process_builder.on_input_event(FishSandwichProcess.ProcessEvents.PrepareFishSandwich.value).send_event_to( - make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish.value) + process_builder.on_input_event(FishSandwichProcess.ProcessEvents.PrepareFishSandwich).send_event_to( + make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish) ) - make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady.value).send_event_to( + make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to( ProcessFunctionTargetBuilder(add_buns_step) ) - add_buns_step.on_event(AddBunStep.OutputEvents.BunsAdded.value).send_event_to( + add_buns_step.on_event(AddBunStep.OutputEvents.BunsAdded).send_event_to( ProcessFunctionTargetBuilder(add_special_sauce_step) ) - add_special_sauce_step.on_event(AddSpecialSauceStep.OutputEvents.SpecialSauceAdded.value).send_event_to( + add_special_sauce_step.on_event(AddSpecialSauceStep.OutputEvents.SpecialSauceAdded).send_event_to( ProcessFunctionTargetBuilder(external_step) ) diff --git a/python/samples/getting_started_with_processes/step03/processes/fried_fish_process.py b/python/samples/getting_started_with_processes/step03/processes/fried_fish_process.py index 9128cd102b89..ab0a9e063ba9 100644 --- a/python/samples/getting_started_with_processes/step03/processes/fried_fish_process.py +++ b/python/samples/getting_started_with_processes/step03/processes/fried_fish_process.py @@ -32,19 +32,17 @@ def create_process(process_name: str = "FriedFishProcess") -> ProcessBuilder: chopStep = process_builder.add_step(CutFoodStep, name="chopStep") fryStep = process_builder.add_step(FryFoodStep) - process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish.value).send_event_to( + process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish).send_event_to( gatherIngredientsStep ) - gatherIngredientsStep.on_event( - GatherFriedFishIngredientsStep.OutputEvents.IngredientsGathered.value - ).send_event_to(ProcessFunctionTargetBuilder(chopStep, function_name=CutFoodStep.Functions.ChopFood.value)) - - chopStep.on_event(CutFoodStep.OutputEvents.ChoppingReady.value).send_event_to( - ProcessFunctionTargetBuilder(fryStep) + gatherIngredientsStep.on_event(GatherFriedFishIngredientsStep.OutputEvents.IngredientsGathered).send_event_to( + ProcessFunctionTargetBuilder(chopStep, function_name=CutFoodStep.Functions.ChopFood) ) - fryStep.on_event(FryFoodStep.OutputEvents.FoodRuined.value).send_event_to( + chopStep.on_event(CutFoodStep.OutputEvents.ChoppingReady).send_event_to(ProcessFunctionTargetBuilder(fryStep)) + + fryStep.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to( ProcessFunctionTargetBuilder(gatherIngredientsStep) ) @@ -58,35 +56,33 @@ def create_process_with_stateful_steps(process_name: str = "FriedFishWithStatefu chop_step = process_builder.add_step(CutFoodWithSharpeningStep, name="chopStep") fry_step = process_builder.add_step(FryFoodStep) - process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish.value).send_event_to( + process_builder.on_input_event(FriedFishProcess.ProcessEvents.PrepareFriedFish).send_event_to( gather_ingredients_step ) gather_ingredients_step.on_event( - GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsGathered.value + GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsGathered ).send_event_to( - ProcessFunctionTargetBuilder(chop_step, function_name=CutFoodWithSharpeningStep.Functions.ChopFood.value) + ProcessFunctionTargetBuilder(chop_step, function_name=CutFoodWithSharpeningStep.Functions.ChopFood) ) gather_ingredients_step.on_event( - GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock.value + GatherFriedFishIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock ).stop_process() - chop_step.on_event(CutFoodWithSharpeningStep.OutputEvents.ChoppingReady.value).send_event_to( + chop_step.on_event(CutFoodWithSharpeningStep.OutputEvents.ChoppingReady).send_event_to( ProcessFunctionTargetBuilder(fry_step) ) - chop_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening.value).send_event_to( - ProcessFunctionTargetBuilder( - chop_step, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife.value - ) + chop_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening).send_event_to( + ProcessFunctionTargetBuilder(chop_step, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife) ) - chop_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened.value).send_event_to( - ProcessFunctionTargetBuilder(chop_step, function_name=CutFoodWithSharpeningStep.Functions.ChopFood.value) + chop_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened).send_event_to( + ProcessFunctionTargetBuilder(chop_step, function_name=CutFoodWithSharpeningStep.Functions.ChopFood) ) - fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined.value).send_event_to( + fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to( ProcessFunctionTargetBuilder(gather_ingredients_step) ) diff --git a/python/samples/getting_started_with_processes/step03/processes/potato_fries_process.py b/python/samples/getting_started_with_processes/step03/processes/potato_fries_process.py index f34bd275ac1c..e756fd9e15c8 100644 --- a/python/samples/getting_started_with_processes/step03/processes/potato_fries_process.py +++ b/python/samples/getting_started_with_processes/step03/processes/potato_fries_process.py @@ -36,19 +36,17 @@ def create_process(process_name: str = "PotatoFriesProcess"): slice_step = process_builder.add_step(CutFoodStep, name="sliceStep") fry_step = process_builder.add_step(FryFoodStep) - process_builder.on_input_event(PotatoFriesProcess.ProcessEvents.PreparePotatoFries.value).send_event_to( + process_builder.on_input_event(PotatoFriesProcess.ProcessEvents.PreparePotatoFries).send_event_to( gather_ingredients_step ) gather_ingredients_step.on_event( - GatherPotatoFriesIngredientsStep.OutputEvents.IngredientsGathered.value - ).send_event_to(ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodStep.Functions.SliceFood.value)) + GatherPotatoFriesIngredientsStep.OutputEvents.IngredientsGathered + ).send_event_to(ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodStep.Functions.SliceFood)) - slice_step.on_event(CutFoodStep.OutputEvents.SlicingReady.value).send_event_to( - ProcessFunctionTargetBuilder(fry_step) - ) + slice_step.on_event(CutFoodStep.OutputEvents.SlicingReady).send_event_to(ProcessFunctionTargetBuilder(fry_step)) - fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined.value).send_event_to( + fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to( ProcessFunctionTargetBuilder(gather_ingredients_step) ) @@ -61,35 +59,33 @@ def create_process_with_stateful_steps(process_name: str = "PotatoFriesWithState slice_step = process_builder.add_step(CutFoodWithSharpeningStep, name="sliceStep") fry_step = process_builder.add_step(FryFoodStep) - process_builder.on_input_event(PotatoFriesProcess.ProcessEvents.PreparePotatoFries.value).send_event_to( + process_builder.on_input_event(PotatoFriesProcess.ProcessEvents.PreparePotatoFries).send_event_to( gather_ingredients_step ) gather_ingredients_step.on_event( - GatherPotatoFriesIngredientsWithStockStep.OutputEvents.IngredientsGathered.value + GatherPotatoFriesIngredientsWithStockStep.OutputEvents.IngredientsGathered ).send_event_to( - ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodWithSharpeningStep.Functions.SliceFood.value) + ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodWithSharpeningStep.Functions.SliceFood) ) gather_ingredients_step.on_event( - GatherPotatoFriesIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock.value + GatherPotatoFriesIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock ).stop_process() - slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.SlicingReady.value).send_event_to( + slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.SlicingReady).send_event_to( ProcessFunctionTargetBuilder(fry_step) ) - slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening.value).send_event_to( - ProcessFunctionTargetBuilder( - slice_step, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife.value - ) + slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening).send_event_to( + ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodWithSharpeningStep.Functions.SharpenKnife) ) - slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened.value).send_event_to( - ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodWithSharpeningStep.Functions.SliceFood.value) + slice_step.on_event(CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened).send_event_to( + ProcessFunctionTargetBuilder(slice_step, function_name=CutFoodWithSharpeningStep.Functions.SliceFood) ) - fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined.value).send_event_to( + fry_step.on_event(FryFoodStep.OutputEvents.FoodRuined).send_event_to( ProcessFunctionTargetBuilder(gather_ingredients_step) ) diff --git a/python/samples/getting_started_with_processes/step03/processes/single_food_item_process.py b/python/samples/getting_started_with_processes/step03/processes/single_food_item_process.py index 686fd1a10a13..327ff80e70a2 100644 --- a/python/samples/getting_started_with_processes/step03/processes/single_food_item_process.py +++ b/python/samples/getting_started_with_processes/step03/processes/single_food_item_process.py @@ -22,15 +22,15 @@ class Functions(Enum): class OutputEvents(Enum): FoodPacked = "FoodPacked" - @kernel_function(name=Functions.PackFood.value) + @kernel_function(name=Functions.PackFood) async def pack_food(self, context: KernelProcessStepContext, food_actions: list[str]): print(f"PACKING_FOOD: Food {food_actions[0]} Packed! - {food_actions}") - await context.emit_event(process_event=PackOrderStep.OutputEvents.FoodPacked.value) + await context.emit_event(process_event=PackOrderStep.OutputEvents.FoodPacked) class ExternalSingleOrderStep(ExternalStep): def __init__(self): - super().__init__(SingleFoodItemProcess.ProcessEvents.SingleOrderReady.value) + super().__init__(SingleFoodItemProcess.ProcessEvents.SingleOrderReady) class DispatchSingleOrderStep(KernelProcessStep): @@ -43,30 +43,28 @@ class OutputEvents(Enum): PrepareFishSandwich = "PrepareFishSandwich" PrepareFishAndChips = "PrepareFishAndChips" - @kernel_function(name=Functions.PrepareSingleOrder.value) + @kernel_function(name=Functions.PrepareSingleOrder) async def dispatch_single_order(self, context: KernelProcessStepContext, food_item: FoodItem): food_name = food_item.to_friendly_string() print(f"DISPATCH_SINGLE_ORDER: Dispatching '{food_name}'!") food_actions = [] if food_item == FoodItem.POTATO_FRIES: - await context.emit_event( - process_event=DispatchSingleOrderStep.OutputEvents.PrepareFries.value, data=food_actions - ) + await context.emit_event(process_event=DispatchSingleOrderStep.OutputEvents.PrepareFries, data=food_actions) elif food_item == FoodItem.FRIED_FISH: await context.emit_event( - process_event=DispatchSingleOrderStep.OutputEvents.PrepareFriedFish.value, data=food_actions + process_event=DispatchSingleOrderStep.OutputEvents.PrepareFriedFish, data=food_actions ) elif food_item == FoodItem.FISH_SANDWICH: await context.emit_event( - process_event=DispatchSingleOrderStep.OutputEvents.PrepareFishSandwich.value, data=food_actions + process_event=DispatchSingleOrderStep.OutputEvents.PrepareFishSandwich, data=food_actions ) elif food_item == FoodItem.FISH_AND_CHIPS: await context.emit_event( - process_event=DispatchSingleOrderStep.OutputEvents.PrepareFishAndChips.value, data=food_actions + process_event=DispatchSingleOrderStep.OutputEvents.PrepareFishAndChips, data=food_actions ) @@ -91,39 +89,39 @@ def create_process(process_name: str = "SingleFoodItemProcess"): ProcessFunctionTargetBuilder(dispatch_order_step) ) - dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFriedFish.value).send_event_to( - make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish.value) + dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFriedFish).send_event_to( + make_fried_fish_step.where_input_event_is(FriedFishProcess.ProcessEvents.PrepareFriedFish) ) - dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFries.value).send_event_to( - make_potato_fries_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries.value) + dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFries).send_event_to( + make_potato_fries_step.where_input_event_is(PotatoFriesProcess.ProcessEvents.PreparePotatoFries) ) - dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFishSandwich.value).send_event_to( - make_fish_sandwich_step.where_input_event_is(FishSandwichProcess.ProcessEvents.PrepareFishSandwich.value) + dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFishSandwich).send_event_to( + make_fish_sandwich_step.where_input_event_is(FishSandwichProcess.ProcessEvents.PrepareFishSandwich) ) - dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFishAndChips.value).send_event_to( - make_fish_and_chips_step.where_input_event_is(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips.value) + dispatch_order_step.on_event(DispatchSingleOrderStep.OutputEvents.PrepareFishAndChips).send_event_to( + make_fish_and_chips_step.where_input_event_is(FishAndChipsProcess.ProcessEvents.PrepareFishAndChips) ) - make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady.value).send_event_to( + make_fried_fish_step.on_event(FriedFishProcess.ProcessEvents.FriedFishReady).send_event_to( ProcessFunctionTargetBuilder(pack_order_step) ) - make_potato_fries_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady.value).send_event_to( + make_potato_fries_step.on_event(PotatoFriesProcess.ProcessEvents.PotatoFriesReady).send_event_to( ProcessFunctionTargetBuilder(pack_order_step) ) - make_fish_sandwich_step.on_event(FishSandwichProcess.ProcessEvents.FishSandwichReady.value).send_event_to( + make_fish_sandwich_step.on_event(FishSandwichProcess.ProcessEvents.FishSandwichReady).send_event_to( ProcessFunctionTargetBuilder(pack_order_step) ) - make_fish_and_chips_step.on_event(FishAndChipsProcess.ProcessEvents.FishAndChipsReady.value).send_event_to( + make_fish_and_chips_step.on_event(FishAndChipsProcess.ProcessEvents.FishAndChipsReady).send_event_to( ProcessFunctionTargetBuilder(pack_order_step) ) - pack_order_step.on_event(PackOrderStep.OutputEvents.FoodPacked.value).send_event_to( + pack_order_step.on_event(PackOrderStep.OutputEvents.FoodPacked).send_event_to( ProcessFunctionTargetBuilder(external_step) ) diff --git a/python/samples/getting_started_with_processes/step03/steps/cut_food_step.py b/python/samples/getting_started_with_processes/step03/steps/cut_food_step.py index 054f26c5e49a..08c928c61cb7 100644 --- a/python/samples/getting_started_with_processes/step03/steps/cut_food_step.py +++ b/python/samples/getting_started_with_processes/step03/steps/cut_food_step.py @@ -19,16 +19,16 @@ class OutputEvents(Enum): def get_action_string(self, food: str, action: str) -> str: return f"{food}_{action}" - @kernel_function(name=Functions.ChopFood.value) + @kernel_function(name=Functions.ChopFood) async def chop_food(self, context: KernelProcessStepContext, food_actions: list[str]): food_to_be_cut = food_actions[0] food_actions.append(self.get_action_string(food_to_be_cut, "chopped")) print(f"CUTTING_STEP: Ingredient {food_to_be_cut} has been chopped!") - await context.emit_event(process_event=CutFoodStep.OutputEvents.ChoppingReady.value, data=food_actions) + await context.emit_event(process_event=CutFoodStep.OutputEvents.ChoppingReady, data=food_actions) - @kernel_function(name=Functions.SliceFood.value) + @kernel_function(name=Functions.SliceFood) async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]): food_to_be_cut = food_actions[0] food_actions.append(self.get_action_string(food_to_be_cut, "sliced")) print(f"CUTTING_STEP: Ingredient {food_to_be_cut} has been sliced!") - await context.emit_event(process_event=CutFoodStep.OutputEvents.SlicingReady.value, data=food_actions) + await context.emit_event(process_event=CutFoodStep.OutputEvents.SlicingReady, data=food_actions) diff --git a/python/samples/getting_started_with_processes/step03/steps/cut_food_with_sharpening_step.py b/python/samples/getting_started_with_processes/step03/steps/cut_food_with_sharpening_step.py index f7ffd3367ccf..e2d8c8da4938 100644 --- a/python/samples/getting_started_with_processes/step03/steps/cut_food_with_sharpening_step.py +++ b/python/samples/getting_started_with_processes/step03/steps/cut_food_with_sharpening_step.py @@ -38,13 +38,13 @@ def knife_needs_sharpening(self) -> bool: def get_action_string(self, food: str, action: str) -> str: return f"{food}_{action}" - @kernel_function(name=Functions.ChopFood.value) + @kernel_function(name=Functions.ChopFood) async def chop_food(self, context: KernelProcessStepContext, food_actions: list[str]): food_to_be_cut = food_actions[0] if self.knife_needs_sharpening(): print(f"CUTTING_STEP: Dull knife, cannot chop {food_to_be_cut} - needs sharpening.") await context.emit_event( - process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening.value, data=food_actions + process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening, data=food_actions ) return @@ -55,17 +55,15 @@ async def chop_food(self, context: KernelProcessStepContext, food_actions: list[ print( f"CUTTING_STEP: Ingredient {food_to_be_cut} has been chopped! - knife sharpness: {self.state.knife_sharpness}" # noqa: E501 ) - await context.emit_event( - process_event=CutFoodWithSharpeningStep.OutputEvents.ChoppingReady.value, data=food_actions - ) + await context.emit_event(process_event=CutFoodWithSharpeningStep.OutputEvents.ChoppingReady, data=food_actions) - @kernel_function(name=Functions.SliceFood.value) + @kernel_function(name=Functions.SliceFood) async def slice_food(self, context: KernelProcessStepContext, food_actions: list[str]): food_to_be_cut = food_actions[0] if self.knife_needs_sharpening(): print(f"CUTTING_STEP: Dull knife, cannot slice {food_to_be_cut} - needs sharpening.") await context.emit_event( - process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening.value, data=food_actions + process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeNeedsSharpening, data=food_actions ) return @@ -76,14 +74,10 @@ async def slice_food(self, context: KernelProcessStepContext, food_actions: list print( f"CUTTING_STEP: Ingredient {food_to_be_cut} has been sliced! - knife sharpness: {self.state.knife_sharpness}" # noqa: E501 ) - await context.emit_event( - process_event=CutFoodWithSharpeningStep.OutputEvents.SlicingReady.value, data=food_actions - ) + await context.emit_event(process_event=CutFoodWithSharpeningStep.OutputEvents.SlicingReady, data=food_actions) - @kernel_function(name=Functions.SharpenKnife.value) + @kernel_function(name=Functions.SharpenKnife) async def sharpen_knife(self, context: KernelProcessStepContext, food_actions: list[str]): self.state.knife_sharpness += self.state.sharpening_boost print(f"KNIFE SHARPENED: Knife sharpness is now {self.state.knife_sharpness}!") - await context.emit_event( - process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened.value, data=food_actions - ) + await context.emit_event(process_event=CutFoodWithSharpeningStep.OutputEvents.KnifeSharpened, data=food_actions) diff --git a/python/samples/getting_started_with_processes/step03/steps/fry_food_step.py b/python/samples/getting_started_with_processes/step03/steps/fry_food_step.py index 9752c4ee163f..c32212a6cac9 100644 --- a/python/samples/getting_started_with_processes/step03/steps/fry_food_step.py +++ b/python/samples/getting_started_with_processes/step03/steps/fry_food_step.py @@ -23,7 +23,7 @@ class OutputEvents(Enum): random_seed: int = Field(default_factory=Random) - @kernel_function(name=Functions.FryFood.value) + @kernel_function(name=Functions.FryFood) async def fry_food(self, context: KernelProcessStepContext, food_actions: list[str]): food_to_fry = food_actions[0] fryer_malfunction = self.random_seed.randint(0, 10) @@ -32,13 +32,13 @@ async def fry_food(self, context: KernelProcessStepContext, food_actions: list[s if fryer_malfunction < 5: food_actions.append(f"{food_to_fry}_frying_failed") print(f"FRYING_STEP: Ingredient {food_to_fry} got burnt while frying :(") - await context.emit_event(process_event=FryFoodStep.OutputEvents.FoodRuined.value, data=food_actions) + await context.emit_event(process_event=FryFoodStep.OutputEvents.FoodRuined, data=food_actions) return food_actions.append(f"{food_to_fry}_frying_succeeded") print(f"FRYING_STEP: Ingredient {food_to_fry} is ready!") await context.emit_event( - process_event=FryFoodStep.OutputEvents.FriedFoodReady.value, + process_event=FryFoodStep.OutputEvents.FriedFoodReady, data=food_actions, visibility=KernelProcessEventVisibility.Public, ) diff --git a/python/samples/getting_started_with_processes/step03/steps/gather_ingredients_step.py b/python/samples/getting_started_with_processes/step03/steps/gather_ingredients_step.py index 7b2f5807b0bd..262c0ca8e401 100644 --- a/python/samples/getting_started_with_processes/step03/steps/gather_ingredients_step.py +++ b/python/samples/getting_started_with_processes/step03/steps/gather_ingredients_step.py @@ -23,7 +23,7 @@ class OutputEvents(Enum): def __init__(self, ingredient: FoodIngredients): super().__init__(ingredient=ingredient) - @kernel_function(name=Functions.GatherIngredients.value) + @kernel_function(name=Functions.GatherIngredients) async def gather_ingredients(self, context: KernelProcessStepContext, food_actions: list[str]): ingredient = self.ingredient.to_friendly_string() updated_food_actions = [] @@ -34,7 +34,7 @@ async def gather_ingredients(self, context: KernelProcessStepContext, food_actio print(f"GATHER_INGREDIENT: Gathered ingredient {ingredient}") await context.emit_event( - process_event=GatherIngredientsStep.OutputEvents.IngredientsGathered.value, data=updated_food_actions + process_event=GatherIngredientsStep.OutputEvents.IngredientsGathered, data=updated_food_actions ) @@ -59,7 +59,7 @@ def __init__(self, ingredient: FoodIngredients): async def activate(self, state: KernelProcessStepState[GatherIngredientsState]) -> None: self.state = state.state - @kernel_function(name=Functions.GatherIngredients.value) + @kernel_function(name=Functions.GatherIngredients) async def gather_ingredients(self, context: KernelProcessStepContext, food_actions: list[str]): ingredient = self.ingredient.to_friendly_string() updated_food_actions = [] @@ -68,7 +68,7 @@ async def gather_ingredients(self, context: KernelProcessStepContext, food_actio if self.state.ingredients_stock == 0: print(f"GATHER_INGREDIENT: Could not gather {ingredient} - OUT OF STOCK!") await context.emit_event( - process_event=GatherIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock.value, + process_event=GatherIngredientsWithStockStep.OutputEvents.IngredientsOutOfStock, data=updated_food_actions, ) return @@ -80,6 +80,6 @@ async def gather_ingredients(self, context: KernelProcessStepContext, food_actio self.state.ingredients_stock -= 1 print(f"GATHER_INGREDIENT: Gathered ingredient {ingredient} - remaining: {self.state.ingredients_stock}") await context.emit_event( - process_event=GatherIngredientsWithStockStep.OutputEvents.IngredientsGathered.value, + process_event=GatherIngredientsWithStockStep.OutputEvents.IngredientsGathered, data=updated_food_actions, ) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py index 99373933fbea..a54458e5e7a9 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py @@ -1,5 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. +from enum import Enum from typing import TYPE_CHECKING from semantic_kernel.exceptions.process_exceptions import ProcessInvalidConfigurationException @@ -16,7 +17,7 @@ async def start( process: "KernelProcess", kernel: "Kernel", - initial_event: KernelProcessEvent | str, + initial_event: KernelProcessEvent | str | Enum, process_id: str | None = None, **kwargs, ) -> DaprKernelProcessContext: @@ -30,6 +31,9 @@ async def start( if initial_event is None: raise ProcessInvalidConfigurationException("initial_event cannot be None") + if isinstance(initial_event, Enum): + initial_event = initial_event.value + if isinstance(initial_event, str): initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data")) diff --git a/python/semantic_kernel/processes/kernel_process/kernel_process_step_context.py b/python/semantic_kernel/processes/kernel_process/kernel_process_step_context.py index 4a9bb4c4208d..8b90b204a5cc 100644 --- a/python/semantic_kernel/processes/kernel_process/kernel_process_step_context.py +++ b/python/semantic_kernel/processes/kernel_process/kernel_process_step_context.py @@ -1,5 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. +from enum import Enum from semantic_kernel.exceptions.process_exceptions import ProcessEventUndefinedException from semantic_kernel.kernel_pydantic import KernelBaseModel @@ -18,7 +19,7 @@ def __init__(self, channel: KernelProcessMessageChannel): """Initialize the step context.""" super().__init__(step_message_channel=channel) - async def emit_event(self, process_event: "KernelProcessEvent | str", **kwargs) -> None: + async def emit_event(self, process_event: "KernelProcessEvent | str | Enum", **kwargs) -> None: """Emit an event from the current step. It is possible to either specify a `KernelProcessEvent` object or the ID of the event @@ -33,6 +34,9 @@ async def emit_event(self, process_event: "KernelProcessEvent | str", **kwargs) if process_event is None: raise ProcessEventUndefinedException("Process event cannot be None") + if isinstance(process_event, Enum): + process_event = process_event.value + if not isinstance(process_event, KernelProcessEvent): process_event = KernelProcessEvent(id=process_event, **kwargs) diff --git a/python/semantic_kernel/processes/local_runtime/local_kernel_process.py b/python/semantic_kernel/processes/local_runtime/local_kernel_process.py index fa4a72fcbddc..19d61a20cc27 100644 --- a/python/semantic_kernel/processes/local_runtime/local_kernel_process.py +++ b/python/semantic_kernel/processes/local_runtime/local_kernel_process.py @@ -1,5 +1,6 @@ # Copyright (c) Microsoft. All rights reserved. +from enum import Enum from typing import TYPE_CHECKING from semantic_kernel.exceptions.process_exceptions import ProcessInvalidConfigurationException @@ -14,7 +15,7 @@ @experimental_function async def start( - process: "KernelProcess", kernel: "Kernel", initial_event: KernelProcessEvent | str, **kwargs + process: "KernelProcess", kernel: "Kernel", initial_event: KernelProcessEvent | str | Enum, **kwargs ) -> LocalKernelProcessContext: """Start the kernel process.""" if process is None: @@ -26,6 +27,9 @@ async def start( if initial_event is None: raise ProcessInvalidConfigurationException("initial_event cannot be None") + if isinstance(initial_event, Enum): + initial_event = initial_event.value + if isinstance(initial_event, str): initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data")) diff --git a/python/semantic_kernel/processes/process_builder.py b/python/semantic_kernel/processes/process_builder.py index ace5dd32bfa3..7628185a91c9 100644 --- a/python/semantic_kernel/processes/process_builder.py +++ b/python/semantic_kernel/processes/process_builder.py @@ -3,6 +3,7 @@ import contextlib import inspect from copy import copy +from enum import Enum from typing import TYPE_CHECKING from pydantic import Field @@ -73,8 +74,11 @@ def resolve_function_target( return targets[0] - def where_input_event_is(self, event_id: str) -> "ProcessFunctionTargetBuilder": + def where_input_event_is(self, event_id: str | Enum) -> "ProcessFunctionTargetBuilder": """Filters the input event.""" + if isinstance(event_id, Enum): + event_id = event_id.value + if event_id not in self.external_event_target_map: raise ValueError(f"The process named '{self.name}' does not expose an event with Id '{event_id}'") @@ -84,11 +88,15 @@ def where_input_event_is(self, event_id: str) -> "ProcessFunctionTargetBuilder": target.target_event_id = event_id return target - def on_input_event(self, event_id: str) -> "ProcessEdgeBuilder": # type: ignore + def on_input_event(self, event_id: str | Enum) -> "ProcessEdgeBuilder": # type: ignore """Creates a new ProcessEdgeBuilder for the input event.""" from semantic_kernel.processes.process_builder import ProcessBuilder # noqa: F401 ProcessEdgeBuilder.model_rebuild() + + if isinstance(event_id, Enum): + event_id = event_id.value + return ProcessEdgeBuilder(source=self, event_id=event_id) def link_to(self, event_id: str, edge_builder: ProcessStepEdgeBuilder) -> None: diff --git a/python/semantic_kernel/processes/process_function_target_builder.py b/python/semantic_kernel/processes/process_function_target_builder.py index 05f7764005fa..7d2339990fc4 100644 --- a/python/semantic_kernel/processes/process_function_target_builder.py +++ b/python/semantic_kernel/processes/process_function_target_builder.py @@ -1,5 +1,7 @@ # Copyright (c) Microsoft. All rights reserved. +from enum import Enum + from semantic_kernel.kernel_pydantic import KernelBaseModel from semantic_kernel.processes.kernel_process.kernel_process_function_target import KernelProcessFunctionTarget from semantic_kernel.processes.process_end_step import EndStep @@ -16,12 +18,17 @@ class ProcessFunctionTargetBuilder(KernelBaseModel): parameter_name: str | None = None target_event_id: str | None = None - def __init__(self, step: ProcessStepBuilder, function_name: str | None = None, parameter_name: str | None = None): + def __init__( + self, step: ProcessStepBuilder, function_name: str | Enum | None = None, parameter_name: str | None = None + ): """Initializes a new instance of ProcessFunctionTargetBuilder.""" from semantic_kernel.functions.kernel_function_metadata import KernelFunctionMetadata # noqa: F401 ProcessFunctionTargetBuilder.model_rebuild() + if isinstance(function_name, Enum): + function_name = function_name.value + if isinstance(step, EndStep): function_name = "END" parameter_name = None diff --git a/python/semantic_kernel/processes/process_step_builder.py b/python/semantic_kernel/processes/process_step_builder.py index 9b7d971115c8..99e1a7283fb6 100644 --- a/python/semantic_kernel/processes/process_step_builder.py +++ b/python/semantic_kernel/processes/process_step_builder.py @@ -2,6 +2,7 @@ import logging import uuid +from enum import Enum from typing import TYPE_CHECKING, Any, Generic from pydantic import Field @@ -65,16 +66,22 @@ def __init__(self, name: str, type: type[TStep] | None = None, initial_state: TS **kwargs, ) - def on_input_event(self, event_id: str) -> "ProcessStepEdgeBuilder": + def on_input_event(self, event_id: str | Enum) -> "ProcessStepEdgeBuilder": """Creates a new ProcessStepEdgeBuilder for the input event.""" from semantic_kernel.processes.process_step_edge_builder import ProcessStepEdgeBuilder + if isinstance(event_id, Enum): + event_id = event_id.value + return ProcessStepEdgeBuilder(source=self, event_id=event_id) - def on_event(self, event_id: str) -> "ProcessStepEdgeBuilder": + def on_event(self, event_id: str | Enum) -> "ProcessStepEdgeBuilder": """Creates a new ProcessStepEdgeBuilder for the event.""" from semantic_kernel.processes.process_step_edge_builder import ProcessStepEdgeBuilder + if isinstance(event_id, Enum): + event_id = event_id.value + scoped_event_id = self.get_scoped_event_id(event_id) return ProcessStepEdgeBuilder(source=self, event_id=scoped_event_id) From ba87c489fe77485ce53e1836d5c898991e372861 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 14 Nov 2024 15:15:17 -0500 Subject: [PATCH 15/16] Fix mypy errors --- .../dapr_runtime/dapr_kernel_process.py | 11 ++++++----- .../local_runtime/local_kernel_process.py | 11 ++++++----- .../semantic_kernel/processes/process_builder.py | 16 +++++++--------- .../processes/process_function_target_builder.py | 11 +++++------ .../processes/process_step_builder.py | 10 ++++------ 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py index a54458e5e7a9..cd43c67956e9 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py @@ -31,15 +31,16 @@ async def start( if initial_event is None: raise ProcessInvalidConfigurationException("initial_event cannot be None") - if isinstance(initial_event, Enum): - initial_event = initial_event.value + initial_event_str: str | KernelProcessEvent = ( + initial_event.value if isinstance(initial_event, Enum) else initial_event + ) - if isinstance(initial_event, str): - initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data")) + if isinstance(initial_event_str, str): + initial_event_str = KernelProcessEvent(id=initial_event_str, data=kwargs.get("data")) if process_id is not None: process.state.id = process_id process_context = DaprKernelProcessContext(process=process) - await process_context.start_with_event(initial_event) + await process_context.start_with_event(initial_event_str) return process_context diff --git a/python/semantic_kernel/processes/local_runtime/local_kernel_process.py b/python/semantic_kernel/processes/local_runtime/local_kernel_process.py index 19d61a20cc27..6a7408b5b29b 100644 --- a/python/semantic_kernel/processes/local_runtime/local_kernel_process.py +++ b/python/semantic_kernel/processes/local_runtime/local_kernel_process.py @@ -27,12 +27,13 @@ async def start( if initial_event is None: raise ProcessInvalidConfigurationException("initial_event cannot be None") - if isinstance(initial_event, Enum): - initial_event = initial_event.value + initial_event_str: str | KernelProcessEvent = ( + initial_event.value if isinstance(initial_event, Enum) else initial_event + ) - if isinstance(initial_event, str): - initial_event = KernelProcessEvent(id=initial_event, data=kwargs.get("data")) + if isinstance(initial_event_str, str): + initial_event_str = KernelProcessEvent(id=initial_event_str, data=kwargs.get("data")) process_context = LocalKernelProcessContext(process, kernel) - await process_context.start_with_event(initial_event) + await process_context.start_with_event(initial_event_str) return process_context diff --git a/python/semantic_kernel/processes/process_builder.py b/python/semantic_kernel/processes/process_builder.py index 7628185a91c9..c4e024298af3 100644 --- a/python/semantic_kernel/processes/process_builder.py +++ b/python/semantic_kernel/processes/process_builder.py @@ -76,16 +76,15 @@ def resolve_function_target( def where_input_event_is(self, event_id: str | Enum) -> "ProcessFunctionTargetBuilder": """Filters the input event.""" - if isinstance(event_id, Enum): - event_id = event_id.value + event_id_str: str = event_id.value if isinstance(event_id, Enum) else event_id - if event_id not in self.external_event_target_map: - raise ValueError(f"The process named '{self.name}' does not expose an event with Id '{event_id}'") + if event_id_str not in self.external_event_target_map: + raise ValueError(f"The process named '{self.name}' does not expose an event with Id '{event_id_str}'") - target = self.external_event_target_map[event_id] + target = self.external_event_target_map[event_id_str] target = copy(target) target.step = self - target.target_event_id = event_id + target.target_event_id = event_id_str return target def on_input_event(self, event_id: str | Enum) -> "ProcessEdgeBuilder": # type: ignore @@ -94,10 +93,9 @@ def on_input_event(self, event_id: str | Enum) -> "ProcessEdgeBuilder": # type: ProcessEdgeBuilder.model_rebuild() - if isinstance(event_id, Enum): - event_id = event_id.value + event_id_str: str = event_id.value if isinstance(event_id, Enum) else event_id - return ProcessEdgeBuilder(source=self, event_id=event_id) + return ProcessEdgeBuilder(source=self, event_id=event_id_str) def link_to(self, event_id: str, edge_builder: ProcessStepEdgeBuilder) -> None: """Links to the given event ID.""" diff --git a/python/semantic_kernel/processes/process_function_target_builder.py b/python/semantic_kernel/processes/process_function_target_builder.py index 7d2339990fc4..30a695273721 100644 --- a/python/semantic_kernel/processes/process_function_target_builder.py +++ b/python/semantic_kernel/processes/process_function_target_builder.py @@ -26,18 +26,17 @@ def __init__( ProcessFunctionTargetBuilder.model_rebuild() - if isinstance(function_name, Enum): - function_name = function_name.value + function_name_str: str | None = function_name.value if isinstance(function_name, Enum) else function_name if isinstance(step, EndStep): - function_name = "END" + function_name_str = "END" parameter_name = None else: - target = step.resolve_function_target(function_name, parameter_name) - function_name = target.function_name + target = step.resolve_function_target(function_name_str, parameter_name) + function_name_str = target.function_name parameter_name = target.parameter_name - super().__init__(step=step, function_name=function_name, parameter_name=parameter_name) + super().__init__(step=step, function_name=function_name_str, parameter_name=parameter_name) def build(self) -> KernelProcessFunctionTarget: """Builds the KernelProcessFunctionTarget.""" diff --git a/python/semantic_kernel/processes/process_step_builder.py b/python/semantic_kernel/processes/process_step_builder.py index 99e1a7283fb6..ee09eb5f92dd 100644 --- a/python/semantic_kernel/processes/process_step_builder.py +++ b/python/semantic_kernel/processes/process_step_builder.py @@ -70,19 +70,17 @@ def on_input_event(self, event_id: str | Enum) -> "ProcessStepEdgeBuilder": """Creates a new ProcessStepEdgeBuilder for the input event.""" from semantic_kernel.processes.process_step_edge_builder import ProcessStepEdgeBuilder - if isinstance(event_id, Enum): - event_id = event_id.value + event_id_str: str = event_id.value if isinstance(event_id, Enum) else event_id - return ProcessStepEdgeBuilder(source=self, event_id=event_id) + return ProcessStepEdgeBuilder(source=self, event_id=event_id_str) def on_event(self, event_id: str | Enum) -> "ProcessStepEdgeBuilder": """Creates a new ProcessStepEdgeBuilder for the event.""" from semantic_kernel.processes.process_step_edge_builder import ProcessStepEdgeBuilder - if isinstance(event_id, Enum): - event_id = event_id.value + event_id_str: str = event_id.value if isinstance(event_id, Enum) else event_id - scoped_event_id = self.get_scoped_event_id(event_id) + scoped_event_id = self.get_scoped_event_id(event_id_str) return ProcessStepEdgeBuilder(source=self, event_id=scoped_event_id) def resolve_function_target( From 6196927895607cfeff679531124d9b2d128e4e2d Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 14 Nov 2024 16:32:02 -0500 Subject: [PATCH 16/16] Refactor support for Dapr FastAPI and Flask samples. --- python/.vscode/launch.json | 16 +++- python/pyproject.toml | 3 +- .../samples/demos/process_with_dapr/README.md | 95 +++++++++++-------- .../{app.py => fastapi_app.py} | 39 ++------ .../demos/process_with_dapr/flask_app.py | 65 +++++++++++++ .../processes/dapr_runtime/__init__.py | 6 ++ .../dapr_runtime/dapr_actor_registration.py | 53 +++++++++++ .../dapr_runtime/dapr_kernel_process.py | 4 - .../dapr_runtime/test_dapr_kernel_process.py | 12 --- python/uv.lock | 76 +++++++++++---- 10 files changed, 260 insertions(+), 109 deletions(-) rename python/samples/demos/process_with_dapr/{app.py => fastapi_app.py} (55%) create mode 100644 python/samples/demos/process_with_dapr/flask_app.py create mode 100644 python/semantic_kernel/processes/dapr_runtime/dapr_actor_registration.py diff --git a/python/.vscode/launch.json b/python/.vscode/launch.json index 1a31a5cf1529..831aaf5149bc 100644 --- a/python/.vscode/launch.json +++ b/python/.vscode/launch.json @@ -13,14 +13,24 @@ "justMyCode": true }, { - "name": "Pythonapp with Dapr", + "name": "Python FastAPI app with Dapr", "type": "python", "request": "launch", - "program": "${workspaceFolder}/samples/demos/process_with_dapr/app.py", + "program": "${workspaceFolder}/samples/demos/process_with_dapr/fastapi_app.py", "console": "integratedTerminal", "preLaunchTask": "daprd-debug-python", "postDebugTask": "daprd-down-python", "justMyCode": false - } + }, + { + "name": "Python Flask API app with Dapr", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/samples/demos/process_with_dapr/flask_app.py", + "console": "integratedTerminal", + "preLaunchTask": "daprd-debug-python", + "postDebugTask": "daprd-down-python", + "justMyCode": false + } ] } \ No newline at end of file diff --git a/python/pyproject.toml b/python/pyproject.toml index 47d4a4ead371..5cb6477f4b14 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -118,7 +118,8 @@ aws = [ ] dapr = [ "dapr>=1.14.0", - "dapr.ext.fastapi>=1.14.0", + "dapr-ext-fastapi>=1.14.0", + "flask-dapr>=1.14.0" ] [tool.uv] diff --git a/python/samples/demos/process_with_dapr/README.md b/python/samples/demos/process_with_dapr/README.md index 6a10f6d533d2..9799977b3c59 100644 --- a/python/samples/demos/process_with_dapr/README.md +++ b/python/samples/demos/process_with_dapr/README.md @@ -8,6 +8,7 @@ For more information about Semantic Kernel Processes and Dapr, see the following - [Overview of the Process Framework (docs)](https://learn.microsoft.com/semantic-kernel/frameworks/process/process-framework) - [Getting Started with Processes (samples)](../../getting_started_with_processes/) +- [Semantic Kernel Dapr Runtime](../../../semantic_kernel/processes/dapr_runtime/) #### Dapr @@ -15,6 +16,15 @@ For more information about Semantic Kernel Processes and Dapr, see the following - [Dapr Actor documentation](https://v1-10.docs.dapr.io/developing-applications/building-blocks/actors/) - [Dapr local development](https://docs.dapr.io/getting-started/install-dapr-selfhost/) +### Supported Dapr Extensions: + +| Extension | Supported | +|--------------------|:----:| +| FastAPI | ✅ | +| Flask | ✅ | +| gRPC | ❌ | +| Dapr Workflow | ❌ | + ## Running the Demo Before running this Demo, make sure to configure Dapr for local development following the links above. The Dapr containers must be running for this demo application to run. @@ -36,7 +46,7 @@ flowchart LR ``` 1. Build and run the sample. Running the Dapr service locally can be done using the Dapr Cli or with the Dapr VS Code extension. The VS Code extension is the recommended approach if you want to debug the code as it runs. - - If using VSCode to debug, select the `Pythonapp with Dapr` option from the Run and Debug dropdown list. + - If using VSCode to debug, select either the `Python FastAPI App with Dapr` or the `Python Flask API App with Dapr` option from the Run and Debug dropdown list. 1. When the service is up and running, it will expose a single API in localhost port 5001. #### Invoking the process: @@ -92,72 +102,79 @@ Below are the key aspects of the code that show how Dapr and Semantic Kernel Pro **_General Imports and Dapr Packages_** -```python -# Copyright (c) Microsoft. All rights reserved. +**_FastAPI App_** -import asyncio +```python import logging from contextlib import asynccontextmanager -from enum import Enum -from typing import TYPE_CHECKING, ClassVar import uvicorn -from dapr.actor import ActorId -from dapr.actor.runtime.context import ActorRuntimeContext -from dapr.ext.fastapi import DaprActor, DaprApp +from dapr.ext.fastapi import DaprActor from fastapi import FastAPI from fastapi.responses import JSONResponse -from pydantic import Field +``` + +**_Flask API App_** + +```python +import asyncio +import logging + +from flask import Flask, jsonify +from flask_dapr.actor import DaprActor ``` **_Semantic Kernel Process Imports_** ```python +from samples.demos.process_with_dapr.process.process import get_process +from samples.demos.process_with_dapr.process.steps import CommonEvents from semantic_kernel import Kernel -from semantic_kernel.functions import kernel_function -from semantic_kernel.kernel_pydantic import KernelBaseModel -from semantic_kernel.processes.dapr_runtime.actors.event_buffer_actor import EventBufferActor -from semantic_kernel.processes.dapr_runtime.actors.external_event_buffer_actor import ExternalEventBufferActor -from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor -from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor -from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor -from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start -from semantic_kernel.processes.kernel_process.kernel_process_step import KernelProcessStep -from semantic_kernel.processes.kernel_process.kernel_process_step_context import KernelProcessStepContext -from semantic_kernel.processes.kernel_process.kernel_process_step_state import KernelProcessStepState -from semantic_kernel.processes.process_builder import ProcessBuilder +from semantic_kernel.processes.dapr_runtime import ( + register_fastapi_dapr_actors, + start, +) ``` **_Define the FastAPI app, Dapr App, and the DaprActor_** ```python +# Define the kernel that is used throughout the process kernel = Kernel() -def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: - """Factory function to create ProcessActor instances with dependencies.""" - return ProcessActor(ctx, actor_id, kernel) - - -def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor: - """Factory function to create StepActor instances with dependencies.""" - return StepActor(ctx, actor_id, kernel=kernel) - - +# Define a lifespan method that registers the actors with the Dapr runtime @asynccontextmanager async def lifespan(app: FastAPI): print("## actor startup ##") - await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) - await actor.register_actor(StepActor, actor_factory=step_actor_factory) - await actor.register_actor(EventBufferActor) - await actor.register_actor(MessageBufferActor) - await actor.register_actor(ExternalEventBufferActor) + await register_fastapi_dapr_actors(actor, kernel) yield +# Define the FastAPI app along with the DaprActor app = FastAPI(title="SKProcess", lifespan=lifespan) -dapr_app = DaprApp(app) actor = DaprActor(app) ``` -- Build and run a Process as you normally would. For this Demo we run a simple example process from with a FastAPI method in response to a GET request. [See the FastAPI app here](./app.py). +If using Flask, you will define: + +```python +kernel = Kernel() + +app = Flask("SKProcess") + +# Enable DaprActor Flask extension +actor = DaprActor(app) + +# Synchronously register actors +print("## actor startup ##") +register_flask_dapr_actors(actor, kernel) + +# Create the global event loop +loop = asyncio.new_event_loop() +asyncio.set_event_loop(loop) +``` + +- Build and run a Process as you normally would. For this Demo we run a simple example process from with either a FastAPI or a Flask API method in response to a GET request. +- [See the FastAPI app here](./fastapi_app.py). +- [See the Flask API app here](./flask_app.py) diff --git a/python/samples/demos/process_with_dapr/app.py b/python/samples/demos/process_with_dapr/fastapi_app.py similarity index 55% rename from python/samples/demos/process_with_dapr/app.py rename to python/samples/demos/process_with_dapr/fastapi_app.py index 829edc32d1d7..d34f96503acb 100644 --- a/python/samples/demos/process_with_dapr/app.py +++ b/python/samples/demos/process_with_dapr/fastapi_app.py @@ -4,9 +4,7 @@ from contextlib import asynccontextmanager import uvicorn -from dapr.actor import ActorId -from dapr.actor.runtime.context import ActorRuntimeContext -from dapr.ext.fastapi import DaprActor, DaprApp +from dapr.ext.fastapi import DaprActor from fastapi import FastAPI from fastapi.responses import JSONResponse @@ -14,17 +12,14 @@ from samples.demos.process_with_dapr.process.steps import CommonEvents from semantic_kernel import Kernel from semantic_kernel.processes.dapr_runtime import ( - EventBufferActor, - ExternalEventBufferActor, - MessageBufferActor, - ProcessActor, - StepActor, + register_fastapi_dapr_actors, start, ) logging.basicConfig(level=logging.ERROR) +# Define the kernel that is used throughout the process kernel = Kernel() ######################################################################### @@ -40,38 +35,16 @@ ######################################################################### -# Define a Process Actor Factory that allows a dependency to be injected during Process Actor creation -def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: - """Factory function to create ProcessActor instances with dependencies.""" - return ProcessActor(ctx, actor_id, kernel) - - -# Define a Step Actor Factory that allows a dependency to be injected during Step Actor creation -def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor: - """Factory function to create StepActor instances with dependencies.""" - return StepActor(ctx, actor_id, kernel=kernel) - - # Define a lifespan method that registers the actors with the Dapr runtime @asynccontextmanager async def lifespan(app: FastAPI): print("## actor startup ##") - # The process actor is used to manage the process: it starts, stops, and sends events to the process - await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) - # The step actor is used to run the process steps - await actor.register_actor(StepActor, actor_factory=step_actor_factory) - # The event buffer actor is used to handle incoming events and is used by a step to bubble up events - await actor.register_actor(EventBufferActor) - # The message buffer actor is used to handle incoming messages from edges - await actor.register_actor(MessageBufferActor) - # The external event buffer actor handles incoming events to kick off a process - await actor.register_actor(ExternalEventBufferActor) + await register_fastapi_dapr_actors(actor, kernel) yield -# Define the FastAPI app along with the DaprApp and the DaprActor +# Define the FastAPI app along with the DaprActor app = FastAPI(title="SKProcess", lifespan=lifespan) -dapr_app = DaprApp(app) actor = DaprActor(app) @@ -88,7 +61,7 @@ async def start_process(process_id: str): _ = await start( process=process, kernel=kernel, - initial_event=CommonEvents.StartProcess.value, + initial_event=CommonEvents.StartProcess, process_id=process_id, ) return JSONResponse(content={"processId": process_id}, status_code=200) diff --git a/python/samples/demos/process_with_dapr/flask_app.py b/python/samples/demos/process_with_dapr/flask_app.py new file mode 100644 index 000000000000..bd7483e1854f --- /dev/null +++ b/python/samples/demos/process_with_dapr/flask_app.py @@ -0,0 +1,65 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import logging + +from flask import Flask, jsonify +from flask_dapr.actor import DaprActor + +from samples.demos.process_with_dapr.process.process import get_process +from samples.demos.process_with_dapr.process.steps import CommonEvents +from semantic_kernel import Kernel +from semantic_kernel.processes.dapr_runtime import ( + register_flask_dapr_actors, + start, +) + +logging.basicConfig(level=logging.ERROR) + +# Define the kernel that is used throughout the process +kernel = Kernel() + +app = Flask("SKProcess") + +# Enable DaprActor Flask extension +actor = DaprActor(app) + +# Synchronously register actors +print("## actor startup ##") +register_flask_dapr_actors(actor, kernel) + +# Create the global event loop +loop = asyncio.new_event_loop() +asyncio.set_event_loop(loop) + + +@app.route("/healthz", methods=["GET"]) +def healthcheck(): + return "Healthy!", 200 + + +@app.route("/processes/", methods=["GET"]) +def start_process(process_id): + try: + process = get_process() + + # Run the start coroutine in a synchronous manner + asyncio.set_event_loop(loop) + _ = asyncio.run( + start( + process=process, + kernel=kernel, + initial_event=CommonEvents.StartProcess, + process_id=process_id, + ) + ) + + return jsonify({"processId": process_id}), 200 + except Exception as e: + logging.exception("Error starting process") + return jsonify({"error": str(e)}), 500 + + +# Run application +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5001) # nosec diff --git a/python/semantic_kernel/processes/dapr_runtime/__init__.py b/python/semantic_kernel/processes/dapr_runtime/__init__.py index 5c05437db5e8..5ec7b7c4583f 100644 --- a/python/semantic_kernel/processes/dapr_runtime/__init__.py +++ b/python/semantic_kernel/processes/dapr_runtime/__init__.py @@ -5,6 +5,10 @@ from semantic_kernel.processes.dapr_runtime.actors.message_buffer_actor import MessageBufferActor from semantic_kernel.processes.dapr_runtime.actors.process_actor import ProcessActor from semantic_kernel.processes.dapr_runtime.actors.step_actor import StepActor +from semantic_kernel.processes.dapr_runtime.dapr_actor_registration import ( + register_fastapi_dapr_actors, + register_flask_dapr_actors, +) from semantic_kernel.processes.dapr_runtime.dapr_kernel_process import start __all__ = [ @@ -13,5 +17,7 @@ "MessageBufferActor", "ProcessActor", "StepActor", + "register_fastapi_dapr_actors", + "register_flask_dapr_actors", "start", ] diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_actor_registration.py b/python/semantic_kernel/processes/dapr_runtime/dapr_actor_registration.py new file mode 100644 index 000000000000..88a0378f5395 --- /dev/null +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_actor_registration.py @@ -0,0 +1,53 @@ +# Copyright (c) Microsoft. All rights reserved. + +from typing import TYPE_CHECKING + +from dapr.actor import ActorId +from dapr.actor.runtime.context import ActorRuntimeContext +from dapr.ext.fastapi import DaprActor as FastAPIDaprActor +from flask_dapr.actor import DaprActor as FlaskDaprActor + +from semantic_kernel.processes.dapr_runtime import ( + EventBufferActor, + ExternalEventBufferActor, + MessageBufferActor, + ProcessActor, + StepActor, +) + +if TYPE_CHECKING: + from semantic_kernel.kernel import Kernel + + +def create_actor_factories(kernel: "Kernel") -> tuple: + """Creates actor factories for ProcessActor and StepActor.""" + + def process_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> ProcessActor: + return ProcessActor(ctx, actor_id, kernel) + + def step_actor_factory(ctx: ActorRuntimeContext, actor_id: ActorId) -> StepActor: + return StepActor(ctx, actor_id, kernel=kernel) + + return process_actor_factory, step_actor_factory + + +# Asynchronous registration for FastAPI +async def register_fastapi_dapr_actors(actor: FastAPIDaprActor, kernel: "Kernel") -> None: + """Registers the actors with the Dapr runtime for use with a FastAPI app.""" + process_actor_factory, step_actor_factory = create_actor_factories(kernel) + await actor.register_actor(ProcessActor, actor_factory=process_actor_factory) + await actor.register_actor(StepActor, actor_factory=step_actor_factory) + await actor.register_actor(EventBufferActor) + await actor.register_actor(MessageBufferActor) + await actor.register_actor(ExternalEventBufferActor) + + +# Synchronous registration for Flask +def register_flask_dapr_actors(actor: FlaskDaprActor, kernel: "Kernel") -> None: + """Registers the actors with the Dapr runtime for use with a Flask app.""" + process_actor_factory, step_actor_factory = create_actor_factories(kernel) + actor.register_actor(ProcessActor, actor_factory=process_actor_factory) + actor.register_actor(StepActor, actor_factory=step_actor_factory) + actor.register_actor(EventBufferActor) + actor.register_actor(MessageBufferActor) + actor.register_actor(ExternalEventBufferActor) diff --git a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py index cd43c67956e9..cf8a3dabb09a 100644 --- a/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py +++ b/python/semantic_kernel/processes/dapr_runtime/dapr_kernel_process.py @@ -9,14 +9,12 @@ from semantic_kernel.utils.experimental_decorator import experimental_function if TYPE_CHECKING: - from semantic_kernel.kernel import Kernel from semantic_kernel.processes.kernel_process.kernel_process import KernelProcess @experimental_function async def start( process: "KernelProcess", - kernel: "Kernel", initial_event: KernelProcessEvent | str | Enum, process_id: str | None = None, **kwargs, @@ -26,8 +24,6 @@ async def start( raise ProcessInvalidConfigurationException("process cannot be None") if process.state is None: raise ProcessInvalidConfigurationException("process state cannot be empty") - if kernel is None: - raise ProcessInvalidConfigurationException("kernel cannot be None") if initial_event is None: raise ProcessInvalidConfigurationException("initial_event cannot be None") diff --git a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py index 08d43282efba..22081358bf1a 100644 --- a/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py +++ b/python/tests/unit/processes/dapr_runtime/test_dapr_kernel_process.py @@ -51,18 +51,6 @@ async def test_start_with_invalid_process(): await start(process=None, kernel=kernel, initial_event=initial_event) -@pytest.mark.asyncio -async def test_start_with_invalid_kernel(): - state = MagicMock(spec=KernelProcessState) - type(state).name = PropertyMock(return_value="valid_state") - mock_step = MagicMock(spec=KernelProcessStepInfo) - process = KernelProcess(state=state, steps=[mock_step]) - initial_event = KernelProcessEvent(id="event_1", data="data_1") - - with pytest.raises(ProcessInvalidConfigurationException, match="kernel cannot be None"): - await start(process=process, kernel=None, initial_event=initial_event) - - @pytest.mark.asyncio async def test_start_with_invalid_initial_event(): state = MagicMock(spec=KernelProcessState) diff --git a/python/uv.lock b/python/uv.lock index c5a574a8fea0..22d4b70d5b5e 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -5,19 +5,25 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform == 'darwin'", "python_full_version < '3.11' and sys_platform == 'darwin'", "python_full_version == '3.11.*' and sys_platform == 'darwin'", - "python_full_version < '3.13' and sys_platform == 'darwin'", + "python_full_version < '3.11' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and sys_platform == 'darwin'", + "python_full_version == '3.12.*' and sys_platform == 'darwin'", "python_full_version >= '3.13' and sys_platform == 'darwin'", "python_full_version < '3.11' and sys_platform == 'linux'", "python_full_version == '3.11.*' and sys_platform == 'linux'", "python_full_version < '3.11' and sys_platform == 'linux'", "python_full_version == '3.11.*' and sys_platform == 'linux'", - "python_full_version < '3.13' and sys_platform == 'linux'", + "python_full_version < '3.11' and sys_platform == 'linux'", + "python_full_version == '3.11.*' and sys_platform == 'linux'", + "python_full_version == '3.12.*' and sys_platform == 'linux'", "python_full_version >= '3.13' and sys_platform == 'linux'", "python_full_version < '3.11' and sys_platform == 'win32'", "python_full_version == '3.11.*' and sys_platform == 'win32'", "python_full_version < '3.11' and sys_platform == 'win32'", "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version < '3.11' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", "python_full_version >= '3.13' and sys_platform == 'win32'", ] supported-markers = [ @@ -394,6 +400,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406 }, ] +[[package]] +name = "blinker" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, +] + [[package]] name = "boto3" version = "1.35.53" @@ -1051,6 +1066,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, ] +[[package]] +name = "flask" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blinker", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "click", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "itsdangerous", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "jinja2", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "werkzeug", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/50/dff6380f1c7f84135484e176e0cac8690af72fa90e932ad2a0a60e28c69b/flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac", size = 680824 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/47/93213ee66ef8fae3b93b3e29206f6b251e65c97bd91d8e1c5596ef15af0a/flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136", size = 102979 }, +] + +[[package]] +name = "flask-dapr" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dapr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "flask", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/23/40884197b8b853a8c301235a88648f4ae319698ade2bf73f86393870806b/flask-dapr-1.14.0.tar.gz", hash = "sha256:e9e3209b716d9a41d53d9b644454a03e9f3408509c13ed67414f0c8b01ab6688", size = 8661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/e4/63739afdaf6b8bfbf3f77fafc0d772d723d7826cdce2889b8f849bf9bb7b/flask_dapr-1.14.0-py3-none-any.whl", hash = "sha256:61d47f79e4f6c5742ddb22ef04917599c3e42b550da817801400edaca6a5d979", size = 10192 }, +] + [[package]] name = "flatbuffers" version = "24.3.25" @@ -1825,6 +1869,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 }, ] +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, +] + [[package]] name = "jedi" version = "0.19.1" @@ -2621,7 +2674,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/7f/7fbae15a3982dc9595e49ce0f19332423b260045d0a6afe93cdbe2f1f624/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3", size = 363333771 }, { url = "https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b", size = 363438805 }, - { url = "https://files.pythonhosted.org/packages/e2/2a/4f27ca96232e8b5269074a72e03b4e0d43aa68c9b965058b1684d07c6ff8/nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc", size = 396895858 }, ] [[package]] @@ -2631,7 +2683,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/93/b5/9fb3d00386d3361b03874246190dfec7b206fd74e6e287b26a8fcb359d95/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:79279b35cf6f91da114182a5ce1864997fd52294a87a16179ce275773799458a", size = 12354556 }, { url = "https://files.pythonhosted.org/packages/67/42/f4f60238e8194a3106d06a058d494b18e006c10bb2b915655bd9f6ea4cb1/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb", size = 13813957 }, - { url = "https://files.pythonhosted.org/packages/f3/79/8cf313ec17c58ccebc965568e5bcb265cdab0a1df99c4e674bb7a3b99bfe/nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922", size = 9938035 }, ] [[package]] @@ -2641,7 +2692,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/77/aa/083b01c427e963ad0b314040565ea396f914349914c298556484f799e61b/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0eedf14185e04b76aa05b1fea04133e59f465b6f960c0cbf4e37c3cb6b0ea198", size = 24133372 }, { url = "https://files.pythonhosted.org/packages/2c/14/91ae57cd4db3f9ef7aa99f4019cfa8d54cb4caa7e00975df6467e9725a9f/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338", size = 24640306 }, - { url = "https://files.pythonhosted.org/packages/7c/30/8c844bfb770f045bcd8b2c83455c5afb45983e1a8abf0c4e5297b481b6a5/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec", size = 19751955 }, ] [[package]] @@ -2651,7 +2701,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/a1/aa/b656d755f474e2084971e9a297def515938d56b466ab39624012070cb773/nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:961fe0e2e716a2a1d967aab7caee97512f71767f852f67432d572e36cb3a11f3", size = 894177 }, { url = "https://files.pythonhosted.org/packages/ea/27/1795d86fe88ef397885f2e580ac37628ed058a92ed2c39dc8eac3adf0619/nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5", size = 883737 }, - { url = "https://files.pythonhosted.org/packages/a8/8b/450e93fab75d85a69b50ea2d5fdd4ff44541e0138db16f9cd90123ef4de4/nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e", size = 878808 }, ] [[package]] @@ -2663,7 +2712,6 @@ dependencies = [ ] wheels = [ { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 }, - { url = "https://files.pythonhosted.org/packages/3f/d0/f90ee6956a628f9f04bf467932c0a25e5a7e706a684b896593c06c82f460/nvidia_cudnn_cu12-9.1.0.70-py3-none-win_amd64.whl", hash = "sha256:6278562929433d68365a07a4a1546c237ba2849852c0d4b2262a486e805b977a", size = 679925892 }, ] [[package]] @@ -2676,7 +2724,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/7a/8a/0e728f749baca3fbeffad762738276e5df60851958be7783af121a7221e7/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399", size = 211422548 }, { url = "https://files.pythonhosted.org/packages/27/94/3266821f65b92b3138631e9c8e7fe1fb513804ac934485a8d05776e1dd43/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9", size = 211459117 }, - { url = "https://files.pythonhosted.org/packages/f6/ee/3f3f8e9874f0be5bbba8fb4b62b3de050156d159f8b6edc42d6f1074113b/nvidia_cufft_cu12-11.2.1.3-py3-none-win_amd64.whl", hash = "sha256:d802f4954291101186078ccbe22fc285a902136f974d369540fd4a5333d1440b", size = 210576476 }, ] [[package]] @@ -2686,7 +2733,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/80/9c/a79180e4d70995fdf030c6946991d0171555c6edf95c265c6b2bf7011112/nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1f173f09e3e3c76ab084aba0de819c49e56614feae5c12f69883f4ae9bb5fad9", size = 56314811 }, { url = "https://files.pythonhosted.org/packages/8a/6d/44ad094874c6f1b9c654f8ed939590bdc408349f137f9b98a3a23ccec411/nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b", size = 56305206 }, - { url = "https://files.pythonhosted.org/packages/1c/22/2573503d0d4e45673c263a313f79410e110eb562636b0617856fdb2ff5f6/nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771", size = 55799918 }, ] [[package]] @@ -2701,7 +2747,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/46/6b/a5c33cf16af09166845345275c34ad2190944bcc6026797a39f8e0a282e0/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e", size = 127634111 }, { url = "https://files.pythonhosted.org/packages/3a/e1/5b9089a4b2a4790dfdea8b3a006052cfecff58139d5a4e34cb1a51df8d6f/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260", size = 127936057 }, - { url = "https://files.pythonhosted.org/packages/f2/be/d435b7b020e854d5d5a682eb5de4328fd62f6182507406f2818280e206e2/nvidia_cusolver_cu12-11.6.1.9-py3-none-win_amd64.whl", hash = "sha256:e77314c9d7b694fcebc84f58989f3aa4fb4cb442f12ca1a9bde50f5e8f6d1b9c", size = 125224015 }, ] [[package]] @@ -2714,7 +2759,6 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/96/a9/c0d2f83a53d40a4a41be14cea6a0bf9e668ffcf8b004bd65633f433050c0/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3", size = 207381987 }, { url = "https://files.pythonhosted.org/packages/db/f7/97a9ea26ed4bbbfc2d470994b8b4f338ef663be97b8f677519ac195e113d/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1", size = 207454763 }, - { url = "https://files.pythonhosted.org/packages/a2/e0/3155ca539760a8118ec94cc279b34293309bcd14011fc724f87f31988843/nvidia_cusparse_cu12-12.3.1.170-py3-none-win_amd64.whl", hash = "sha256:9bc90fb087bc7b4c15641521f31c0371e9a612fc2ba12c338d3ae032e6b6797f", size = 204684315 }, ] [[package]] @@ -2732,7 +2776,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/02/45/239d52c05074898a80a900f49b1615d81c07fceadd5ad6c4f86a987c0bc4/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4abe7fef64914ccfa909bc2ba39739670ecc9e820c83ccc7a6ed414122599b83", size = 20552510 }, { url = "https://files.pythonhosted.org/packages/ff/ff/847841bacfbefc97a00036e0fce5a0f086b640756dc38caea5e1bb002655/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57", size = 21066810 }, - { url = "https://files.pythonhosted.org/packages/81/19/0babc919031bee42620257b9a911c528f05fb2688520dcd9ca59159ffea8/nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1", size = 95336325 }, ] [[package]] @@ -2742,7 +2785,6 @@ source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/06/39/471f581edbb7804b39e8063d92fc8305bdc7a80ae5c07dbe6ea5c50d14a5/nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7959ad635db13edf4fc65c06a6e9f9e55fc2f92596db928d169c0bb031e88ef3", size = 100417 }, { url = "https://files.pythonhosted.org/packages/87/20/199b8713428322a2f22b722c62b8cc278cc53dffa9705d744484b5035ee9/nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a", size = 99144 }, - { url = "https://files.pythonhosted.org/packages/54/1b/f77674fbb73af98843be25803bbd3b9a4f0a96c75b8d33a2854a5c7d2d77/nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485", size = 66307 }, ] [[package]] @@ -3465,8 +3507,6 @@ version = "6.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/2b/f4dea5d993d9cd22ad958eea828a41d5d225556123d372f02547c29c4f97/psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e", size = 246648 }, - { url = "https://files.pythonhosted.org/packages/9f/14/4aa97a7f2e0ac33a050d990ab31686d651ae4ef8c86661fef067f00437b9/psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85", size = 249905 }, { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, @@ -4610,6 +4650,7 @@ chroma = [ dapr = [ { name = "dapr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "dapr-ext-fastapi", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "flask-dapr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] google = [ { name = "google-cloud-aiplatform", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -4694,6 +4735,7 @@ requires-dist = [ { name = "dapr", marker = "extra == 'dapr'", specifier = ">=1.14.0" }, { name = "dapr-ext-fastapi", marker = "extra == 'dapr'", specifier = ">=1.14.0" }, { name = "defusedxml", specifier = "~=0.7" }, + { name = "flask-dapr", marker = "extra == 'dapr'", specifier = ">=1.14.0" }, { name = "google-cloud-aiplatform", marker = "extra == 'google'", specifier = "~=1.60" }, { name = "google-generativeai", marker = "extra == 'google'", specifier = "~=0.7" }, { name = "ipykernel", marker = "extra == 'notebooks'", specifier = "~=6.29" }, @@ -5069,7 +5111,7 @@ dependencies = [ { name = "nvidia-nccl-cu12", marker = "(platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'linux') or (platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'win32')" }, { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'linux') or (platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'win32')" }, { name = "nvidia-nvtx-cu12", marker = "(platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'linux') or (platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'win32')" }, - { name = "setuptools", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "setuptools", marker = "(python_full_version >= '3.12' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform == 'win32')" }, { name = "sympy", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "triton", marker = "(python_full_version < '3.13' and platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'darwin') or (python_full_version < '3.13' and platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'linux') or (python_full_version < '3.13' and platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform == 'win32')" }, { name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },