Python: [BREAKING] Python: Rename workflow to workflows (#1007)

* Rename workflow to workflows

* Update occurence of workflow to new name
This commit is contained in:
Evan Mattson
2025-09-30 20:21:34 +09:00
committed by GitHub
Unverified
parent 189434dd4b
commit b42bb700fb
82 changed files with 87 additions and 90 deletions
@@ -20,4 +20,4 @@ from ._telemetry import * # noqa: F403
from ._threads import * # noqa: F403
from ._tools import * # noqa: F403
from ._types import * # noqa: F403
from ._workflow import * # noqa: F403
from ._workflows import * # noqa: F403
@@ -1,6 +1,6 @@
# Get Started with Microsoft Agent Framework Workflow
# Get Started with Microsoft Agent Framework Workflows
Workflow capabilities now ship with the core `agent-framework` package.
Workflow capabilities ship with the core `agent-framework` package.
```bash
pip install agent-framework
@@ -1,11 +1,14 @@
# Copyright (c) Microsoft. All rights reserved.
from dataclasses import dataclass
from dataclasses import dataclass # noqa: I001
from typing import Any, cast
from agent_framework._workflow._executor import RequestInfoMessage, RequestResponse
from agent_framework._workflow._runner_context import _decode_checkpoint_value, _encode_checkpoint_value # type: ignore
from agent_framework._workflow._typing_utils import is_instance_of
from agent_framework._workflows._executor import RequestInfoMessage, RequestResponse
from agent_framework._workflows._runner_context import ( # type: ignore
_decode_checkpoint_value, # type: ignore
_encode_checkpoint_value, # type: ignore
)
from agent_framework._workflows._typing_utils import is_instance_of
@dataclass(kw_only=True)
@@ -4,8 +4,8 @@ import pytest
from typing_extensions import Never
from agent_framework import WorkflowBuilder, WorkflowContext, WorkflowRunState, WorkflowStatusEvent, handler
from agent_framework._workflow._checkpoint import InMemoryCheckpointStorage
from agent_framework._workflow._executor import Executor
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework._workflows._executor import Executor
class StartExecutor(Executor):
@@ -18,7 +18,7 @@ from agent_framework import (
WorkflowStatusEvent,
handler,
)
from agent_framework._workflow._checkpoint import InMemoryCheckpointStorage
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
class _FakeAgentExec(Executor):
@@ -14,7 +14,7 @@ from agent_framework import (
WorkflowContext,
handler,
)
from agent_framework._workflow._edge import (
from agent_framework._workflows._edge import (
Edge,
FanInEdgeGroup,
FanOutEdgeGroup,
@@ -23,7 +23,7 @@ from agent_framework._workflow._edge import (
SwitchCaseEdgeGroupCase,
SwitchCaseEdgeGroupDefault,
)
from agent_framework._workflow._edge_runner import create_edge_runner
from agent_framework._workflows._edge_runner import create_edge_runner
from agent_framework.observability import EdgeGroupDeliveryStatus
# Add for test
@@ -627,7 +627,7 @@ async def test_source_edge_group_with_selection_func_send_message() -> None:
data = MockMessage(data="test")
message = Message(data=data, source_id=source.id)
with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send:
with patch("agent_framework._workflows._edge_runner.EdgeRunner._execute_on_target") as mock_send:
success = await edge_runner.send_message(message, shared_state, ctx)
assert success is True
@@ -680,7 +680,7 @@ async def test_source_edge_group_with_selection_func_send_message_with_target()
data = MockMessage(data="test")
message = Message(data=data, source_id=source.id, target_id=target1.id)
with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send:
with patch("agent_framework._workflows._edge_runner.EdgeRunner._execute_on_target") as mock_send:
success = await edge_runner.send_message(message, shared_state, ctx)
assert success is True
@@ -913,7 +913,7 @@ async def test_target_edge_group_send_message_buffer() -> None:
data = MockMessage(data="test")
with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send:
with patch("agent_framework._workflows._edge_runner.EdgeRunner._execute_on_target") as mock_send:
success = await edge_runner.send_message(
Message(data=data, source_id=source1.id),
shared_state,
@@ -1262,7 +1262,7 @@ async def test_switch_case_edge_group_send_message() -> None:
data = MockMessage(data=-1)
message = Message(data=data, source_id=source.id)
with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send:
with patch("agent_framework._workflows._edge_runner.EdgeRunner._execute_on_target") as mock_send:
success = await edge_runner.send_message(message, shared_state, ctx)
assert success is True
@@ -1271,7 +1271,7 @@ async def test_switch_case_edge_group_send_message() -> None:
# Default condition should
data = MockMessage(data=1)
message = Message(data=data, source_id=source.id)
with patch("agent_framework._workflow._edge_runner.EdgeRunner._execute_on_target") as mock_send:
with patch("agent_framework._workflows._edge_runner.EdgeRunner._execute_on_target") as mock_send:
success = await edge_runner.send_message(message, shared_state, ctx)
assert success is True
@@ -22,8 +22,8 @@ from agent_framework import (
WorkflowStatusEvent,
handler,
)
from agent_framework._workflow._executor import AgentExecutorResponse, Executor
from agent_framework._workflow._workflow_context import WorkflowContext
from agent_framework._workflows._executor import AgentExecutorResponse, Executor
from agent_framework._workflows._workflow_context import WorkflowContext
class _SimpleAgent(BaseAgent):
@@ -33,8 +33,8 @@ from agent_framework import (
WorkflowStatusEvent,
handler,
)
from agent_framework._workflow._checkpoint import InMemoryCheckpointStorage
from agent_framework._workflow._magentic import (
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
from agent_framework._workflows._magentic import (
MagenticAgentExecutor,
MagenticContext,
MagenticOrchestratorExecutor,
@@ -533,7 +533,7 @@ async def _collect_agent_responses_setup(participant_obj: object):
captured: list[ChatMessage] = []
async def sink(event) -> None: # type: ignore[no-untyped-def]
from agent_framework._workflow._magentic import MagenticAgentMessageEvent
from agent_framework._workflows._magentic import MagenticAgentMessageEvent
if isinstance(event, MagenticAgentMessageEvent) and event.message is not None:
captured.append(event.message)
@@ -7,17 +7,21 @@ from typing import Any
import pytest
from agent_framework._workflow._checkpoint import CheckpointStorage, WorkflowCheckpoint
from agent_framework._workflow._events import RequestInfoEvent, WorkflowEvent
from agent_framework._workflow._executor import (
from agent_framework._workflows._checkpoint import CheckpointStorage, WorkflowCheckpoint
from agent_framework._workflows._events import RequestInfoEvent, WorkflowEvent
from agent_framework._workflows._executor import (
PendingRequestDetails,
RequestInfoExecutor,
RequestInfoMessage,
RequestResponse,
)
from agent_framework._workflow._runner_context import CheckpointState, Message, _encode_checkpoint_value # type: ignore
from agent_framework._workflow._shared_state import SharedState
from agent_framework._workflow._workflow_context import WorkflowContext
from agent_framework._workflows._runner_context import ( # type: ignore
CheckpointState,
Message,
_encode_checkpoint_value,
)
from agent_framework._workflows._shared_state import SharedState
from agent_framework._workflows._workflow_context import WorkflowContext
PENDING_STATE_KEY = RequestInfoExecutor._PENDING_SHARED_STATE_KEY # pyright: ignore[reportPrivateUsage]
@@ -16,10 +16,10 @@ from agent_framework import (
WorkflowStatusEvent,
handler,
)
from agent_framework._workflow._edge import SingleEdgeGroup
from agent_framework._workflow._runner import Runner
from agent_framework._workflow._runner_context import InProcRunnerContext, Message, RunnerContext
from agent_framework._workflow._shared_state import SharedState
from agent_framework._workflows._edge import SingleEdgeGroup
from agent_framework._workflows._runner import Runner
from agent_framework._workflows._runner_context import InProcRunnerContext, Message, RunnerContext
from agent_framework._workflows._shared_state import SharedState
@dataclass
@@ -21,7 +21,7 @@ from agent_framework import (
WorkflowStatusEvent,
handler,
)
from agent_framework._workflow._checkpoint import InMemoryCheckpointStorage
from agent_framework._workflows._checkpoint import InMemoryCheckpointStorage
class _EchoAgent(BaseAgent):
@@ -6,7 +6,7 @@ from typing import Any
import pytest
from agent_framework import Executor, WorkflowBuilder, WorkflowContext, handler
from agent_framework._workflow._edge import (
from agent_framework._workflows._edge import (
Case,
Default,
Edge,
@@ -17,7 +17,7 @@ from agent_framework._workflow._edge import (
SwitchCaseEdgeGroupCase,
SwitchCaseEdgeGroupDefault,
)
from agent_framework._workflow._workflow_executor import (
from agent_framework._workflows._workflow_executor import (
WorkflowExecutor,
)
@@ -3,8 +3,8 @@
from dataclasses import dataclass
from typing import Any, Generic, TypeVar, Union
from agent_framework._workflow import RequestInfoMessage, RequestResponse
from agent_framework._workflow._typing_utils import is_instance_of
from agent_framework._workflows import RequestInfoMessage, RequestResponse
from agent_framework._workflows._typing_utils import is_instance_of
def test_basic_types() -> None:
@@ -18,7 +18,7 @@ from agent_framework import (
handler,
validate_workflow_graph,
)
from agent_framework._workflow._edge import SingleEdgeGroup
from agent_framework._workflows._edge import SingleEdgeGroup
class StringExecutor(Executor):
@@ -21,15 +21,15 @@ from agent_framework import (
if TYPE_CHECKING:
from _pytest.logging import LogCaptureFixture
from agent_framework._workflow._runner_context import InProcRunnerContext
from agent_framework._workflows._runner_context import InProcRunnerContext
@asynccontextmanager
async def make_context(
executor_id: str = "exec",
) -> AsyncIterator[tuple[WorkflowContext[object], "InProcRunnerContext"]]:
from agent_framework._workflow._runner_context import InProcRunnerContext
from agent_framework._workflow._shared_state import SharedState
from agent_framework._workflows._runner_context import InProcRunnerContext
from agent_framework._workflows._shared_state import SharedState
runner_ctx = InProcRunnerContext()
shared_state = SharedState()
@@ -7,11 +7,11 @@ from opentelemetry import trace
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
from agent_framework import WorkflowBuilder
from agent_framework._workflow._executor import Executor, handler
from agent_framework._workflow._runner_context import InProcRunnerContext, Message
from agent_framework._workflow._shared_state import SharedState
from agent_framework._workflow._workflow import Workflow
from agent_framework._workflow._workflow_context import WorkflowContext
from agent_framework._workflows._executor import Executor, handler
from agent_framework._workflows._runner_context import InProcRunnerContext, Message
from agent_framework._workflows._shared_state import SharedState
from agent_framework._workflows._workflow import Workflow
from agent_framework._workflows._workflow_context import WorkflowContext
from agent_framework.observability import (
OtelAttr,
create_processing_span,
@@ -5,7 +5,7 @@ from typing import cast
from agent_framework._agents import ChatAgent
from agent_framework._types import AgentRunResponse, ChatMessage, Role
from agent_framework._workflow import (
from agent_framework._workflows import (
AgentExecutor,
AgentExecutorRequest,
AgentExecutorResponse,
+1 -1
View File
@@ -7,7 +7,7 @@ This directory contains samples demonstrating the capabilities of Microsoft Agen
For step-by-step tutorials and examples, see the [getting_started](./getting_started/) directory:
- **[Agents](./getting_started/agents/)** - Learn how to create and use agents with various providers (Azure OpenAI, OpenAI, Azure AI, etc.)
- **[Workflow](./getting_started/workflow/)** - Explore workflow patterns for orchestrating multiple agents
- **[Workflows](./getting_started/workflows/)** - Explore workflow patterns for orchestrating multiple agents
- **[Chat Client](./getting_started/chat_client/)** - Examples of using chat clients directly
- **[Threads](./getting_started/threads/)** - Manage conversation threads and chat message stores
- **[Context Providers](./getting_started/context_providers/)** - Integrate with context providers like Mem0 and Redis
@@ -1,8 +1,8 @@
# Workflow Getting Started Samples
# Workflows Getting Started Samples
## Installation
Workflow support ships with the core `agent-framework` package, so no extra installation step is required.
Microsoft Agent Framework Workflows support ships with the core `agent-framework` or `agent-framework-core` package, so no extra installation step is required.
To install with visualization support:
@@ -14,7 +14,7 @@ from agent_framework import (
WorkflowStatusEvent,
handler,
)
from agent_framework._workflow._events import WorkflowOutputEvent
from agent_framework._workflows._events import WorkflowOutputEvent
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from typing_extensions import Never
@@ -52,13 +52,13 @@ class Writer(Executor):
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "writer"):
# Create a domain specific agent using your configured AzureOpenAIChatClient.
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You are an excellent content writer. You create new content and edit contents based on the feedback."
),
)
# Associate this agent with the executor node. The base Executor stores it on self.agent.
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def handle(self, message: ChatMessage, ctx: WorkflowContext[list[ChatMessage]]) -> None:
@@ -89,12 +89,12 @@ class Reviewer(Executor):
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "reviewer"):
# Create a domain specific agent that evaluates and refines content.
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You are an excellent content reviewer. You review the content and provide feedback to the writer."
),
)
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def handle(self, messages: list[ChatMessage], ctx: WorkflowContext[Never, str]) -> None:
@@ -43,13 +43,13 @@ class Writer(Executor):
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "writer"):
# Create a domain specific agent using your configured AzureOpenAIChatClient.
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You are an excellent content writer. You create new content and edit contents based on the feedback."
),
)
# Associate the agent with this executor node. The base Executor stores it on self.agent.
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def handle(self, message: ChatMessage, ctx: WorkflowContext[list[ChatMessage], str]) -> None:
@@ -85,12 +85,12 @@ class Reviewer(Executor):
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "reviewer"):
# Create a domain specific agent that evaluates and refines content.
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You are an excellent content reviewer. You review the content and provide feedback to the writer."
),
)
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def handle(self, messages: list[ChatMessage], ctx: WorkflowContext[list[ChatMessage], str]) -> None:
@@ -27,7 +27,7 @@ from agent_framework import ( # noqa: E402
handler,
)
from agent_framework.openai import OpenAIChatClient # noqa: E402
from getting_started.workflow.agents.workflow_as_agent_reflection_pattern import ( # noqa: E402
from getting_started.workflows.agents.workflow_as_agent_reflection_pattern import ( # noqa: E402
ReviewRequest,
ReviewResponse,
Worker,
@@ -35,7 +35,7 @@ from azure.identity import AzureCliCredential
if TYPE_CHECKING:
from agent_framework import Workflow
from agent_framework._workflow._checkpoint import WorkflowCheckpoint
from agent_framework._workflows._checkpoint import WorkflowCheckpoint
"""
Sample: Checkpoint + human-in-the-loop quickstart.
@@ -23,7 +23,7 @@ from azure.identity import AzureCliCredential
if TYPE_CHECKING:
from agent_framework import Workflow
from agent_framework._workflow._checkpoint import WorkflowCheckpoint
from agent_framework._workflows._checkpoint import WorkflowCheckpoint
"""
Sample: Checkpointing and Resuming a Workflow (with an Agent stage)
@@ -212,7 +212,7 @@ def _render_checkpoint_summary(checkpoints: list["WorkflowCheckpoint"]) -> None:
async def main():
# Clear existing checkpoints in this sample directory for a clean run.
checkpoint_dir = Path(TEMP_DIR)
for file in checkpoint_dir.glob("*.json"):
for file in checkpoint_dir.glob("*.json"): # noqa: ASYNC240
file.unlink()
# Backing store for checkpoints written by with_checkpointing.
@@ -4,8 +4,6 @@ import asyncio
import os
from typing import Any
from typing_extensions import Never
from agent_framework import ( # Core chat primitives used to build requests
AgentExecutor, # Wraps an LLM agent that can be invoked inside a workflow
AgentExecutorRequest, # Input message bundle for an AgentExecutor
@@ -19,6 +17,7 @@ from agent_framework import ( # Core chat primitives used to build requests
from agent_framework.azure import AzureOpenAIChatClient # Thin client wrapper for Azure OpenAI chat models
from azure.identity import AzureCliCredential # Uses your az CLI login for credentials
from pydantic import BaseModel # Structured outputs for safer parsing
from typing_extensions import Never
"""
Sample: Conditional routing with structured outputs
@@ -8,8 +8,6 @@ from dataclasses import dataclass
from typing import Literal
from uuid import uuid4
from typing_extensions import Never
from agent_framework import (
AgentExecutor,
AgentExecutorRequest,
@@ -25,6 +23,7 @@ from agent_framework import (
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from typing_extensions import Never
"""
Sample: Multi-Selection Edge Group for email triage and response.
@@ -3,8 +3,6 @@
import asyncio
from typing import cast
from typing_extensions import Never
from agent_framework import (
Executor,
WorkflowBuilder,
@@ -12,6 +10,7 @@ from agent_framework import (
WorkflowOutputEvent,
handler,
)
from typing_extensions import Never
"""
Sample: Sequential workflow with streaming.
@@ -2,9 +2,8 @@
import asyncio
from typing_extensions import Never
from agent_framework import WorkflowBuilder, WorkflowContext, WorkflowOutputEvent, executor
from typing_extensions import Never
"""
Sample: Foundational sequential workflow with streaming using function-style executors.
@@ -6,8 +6,6 @@ from dataclasses import dataclass
from typing import Any, Literal
from uuid import uuid4
from typing_extensions import Never
from agent_framework import ( # Core chat primitives used to form LLM requests
AgentExecutor, # Wraps an agent so it can run inside a workflow
AgentExecutorRequest, # Message bundle sent to an AgentExecutor
@@ -23,6 +21,7 @@ from agent_framework import ( # Core chat primitives used to form LLM requests
from agent_framework.azure import AzureOpenAIChatClient # Thin client for Azure OpenAI chat models
from azure.identity import AzureCliCredential # Uses your az CLI login for credentials
from pydantic import BaseModel # Structured outputs with validation
from typing_extensions import Never
"""
Sample: Switch-Case Edge Group with an explicit Uncertain branch.
@@ -40,14 +40,14 @@ class ResearcherExec(Executor):
agent: ChatAgent
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "researcher"):
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You're an expert market and product researcher. Given a prompt, provide concise, factual insights,"
" opportunities, and risks."
),
name=id,
)
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExecutorResponse]) -> None:
@@ -60,14 +60,14 @@ class MarketerExec(Executor):
agent: ChatAgent
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "marketer"):
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You're a creative marketing strategist. Craft compelling value propositions and target messaging"
" aligned to the prompt."
),
name=id,
)
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExecutorResponse]) -> None:
@@ -80,14 +80,14 @@ class LegalExec(Executor):
agent: ChatAgent
def __init__(self, chat_client: AzureOpenAIChatClient, id: str = "legal"):
agent = chat_client.create_agent(
self.agent = chat_client.create_agent(
instructions=(
"You're a cautious legal/compliance reviewer. Highlight constraints, disclaimers, and policy concerns"
" based on the prompt."
),
name=id,
)
super().__init__(agent=agent, id=id)
super().__init__(id=id)
@handler
async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExecutorResponse]) -> None:
@@ -3,8 +3,6 @@
import asyncio
from typing import Any
from typing_extensions import Never
from agent_framework import (
ChatMessage,
Executor,
@@ -15,6 +13,7 @@ from agent_framework import (
)
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from typing_extensions import Never
"""
Sample: Sequential workflow mixing agents and a custom summarizer executor
@@ -3,8 +3,6 @@
import asyncio
from dataclasses import dataclass
from typing_extensions import Never
from agent_framework import ( # Core chat primitives to build LLM requests
AgentExecutor, # Wraps an LLM agent for use inside a workflow
AgentExecutorRequest, # The message bundle sent to an AgentExecutor
@@ -20,6 +18,7 @@ from agent_framework import ( # Core chat primitives to build LLM requests
)
from agent_framework.azure import AzureOpenAIChatClient # Client wrapper for Azure OpenAI chat models
from azure.identity import AzureCliCredential # Uses your az CLI login for credentials
from typing_extensions import Never
"""
Sample: Concurrent fan out and fan in with three domain agents
@@ -7,8 +7,6 @@ from collections import defaultdict
from dataclasses import dataclass
import aiofiles
from typing_extensions import Never
from agent_framework import (
Executor, # Base class for custom workflow steps
WorkflowBuilder, # Fluent builder for executors and edges
@@ -17,6 +15,7 @@ from agent_framework import (
WorkflowViz, # Utility to visualize a workflow graph
handler, # Decorator to expose an Executor method as a step
)
from typing_extensions import Never
"""
Sample: Map reduce word count with fan out and fan in over file backed intermediate results
@@ -6,8 +6,6 @@ from dataclasses import dataclass
from typing import Any
from uuid import uuid4
from typing_extensions import Never
from agent_framework import (
AgentExecutorRequest,
AgentExecutorResponse,
@@ -20,6 +18,7 @@ from agent_framework import (
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from pydantic import BaseModel
from typing_extensions import Never
"""
Sample: Shared state with agents and conditional routing.
@@ -3,8 +3,6 @@
import asyncio
from dataclasses import dataclass
from typing_extensions import Never
from agent_framework import (
AgentExecutor,
AgentExecutorRequest,
@@ -21,6 +19,7 @@ from agent_framework import (
)
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from typing_extensions import Never
"""
Sample: Concurrent (Fan-out/Fan-in) with Agents + Visualization
+1 -1
View File
@@ -1365,7 +1365,7 @@ name = "exceptiongroup"
version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
{ name = "typing-extensions", 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')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
wheels = [