diff --git a/.claude/settings.json b/.claude/settings.json index 8eb165fe0..c65924b97 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -41,5 +41,8 @@ ] } ] + }, + "enabledPlugins": { + "temporal@temporal-marketplace": true } -} \ No newline at end of file +} diff --git a/.claude/skills/workflows/SKILL.md b/.claude/skills/workflows/SKILL.md new file mode 100644 index 000000000..2bafb0147 --- /dev/null +++ b/.claude/skills/workflows/SKILL.md @@ -0,0 +1,105 @@ +--- +name: workflows +description: Framework for building durable workflows with orchestrated activities, used for background jobs, multi-step pipelines, scheduled tasks, LLM agents, or any process requiring fault tolerance, retries, and long-running execution. This skill provides comprehensive documentation and guidance for working with the Mistral Workflows framework. +--- + +# Workflows Documentation + +This skill provides comprehensive documentation and guidance for the Mistral Workflows framework, which is designed for building durable, fault-tolerant workflows with orchestrated activities. + +## About Workflows + +Mistral Workflows is an orchestration control plane that accelerates the development and reliable execution of complex, AI-driven workflows. Built on Temporal for fault-tolerant workflow execution, it combines a user-friendly API with a rich Python framework optimized for Mistral's AI services. + +## Documentation Structure + +The documentation is organized into several categories: + +### Getting Started + +- **[Introduction](references/getting-started/introduction.mdx)**: Overview of Mistral Workflows and its core architecture +- **[Value Proposition](references/getting-started/value-proposition.mdx)**: Why Mistral Workflows vs. raw Temporal — AI-specific features and DX improvements +- **[Installation](references/getting-started/installation.mdx)**: Guide to installing and setting up the Workflows framework (CLI scaffolding, optional deps) +- **[Core Concepts](references/getting-started/core-concepts.mdx)**: Workflows, activities, workers, executions vs runs +- **[Python SDK](references/getting-started/python-sdk.mdx)**: Documentation for the Python SDK and WorkflowsClient +- **[Your First Workflow](references/getting-started/your-first-workflow.mdx)**: Step-by-step guide to creating your first workflow + +### Guides + +- **[Workflows](references/guides/workflows.mdx)**: Creating workflows, determinism enforcement (sandbox), input types, timeouts, signals/queries/updates, child workflows, continue-as-new +- **[Activities](references/guides/activities.mdx)**: Timeouts, retries, heartbeats, local activities, sticky sessions, nested activities +- **[Workflows Exception Handling](references/guides/workflows-exception.mdx)**: WorkflowsException, ErrorCode enum, factory methods +- **[Error Codes](references/guides/error-codes.mdx)**: API error codes WF_1000-WF_1600 with HTTP status, description, and resolution +- **[Signals, Queries, and Updates](references/guides/signals-queries-updates.mdx)**: Workflow communication patterns with input validation +- **[Scheduling](references/guides/scheduling.mdx)**: Cron expressions, ScheduleDefinition, SchedulePolicy, overlap handling +- **[Dependency Injection](references/guides/dependency-injection.mdx)**: FastAPI-style Depends() pattern +- **[Streaming](references/guides/streaming.mdx)**: Task API, token streaming, progress updates +- **[Streaming Consumption](references/guides/streaming-consumption.mdx)**: WorkflowsClient.stream_events(), NATS subjects, SSE API +- **[Concurrency](references/guides/concurrency.mdx)**: execute_activities_in_parallel() with List/Chain/Offset executors +- **[Rate Limiting](references/guides/rate-limiting.mdx)**: Distributed rate limiting across workers +- **[Handling Large Data](references/guides/handling-large-data.mdx)**: OffloadableField, blob storage (S3/Azure/GCS) +- **[Payload Encoding](references/guides/payload-encoding.mdx)**: Payload offloading, AES-GCM encryption, key rotation +- **[Observability](references/guides/observability.mdx)**: OpenTelemetry traces, trace sampling +- **[Durable Agents](references/guides/durable-agents.mdx)**: Agent, Runner, RemoteSession/LocalSession, MCP, multi-agent handoffs +- **[Conversational Workflows](references/guides/assist-workflows.mdx)**: InteractiveWorkflow, HITL, ChatInput/FormInput, Canvas editing, Rich UI components, Tool UI states +- **[Local Execution](references/guides/local-execution.mdx)**: No-infra dev mode with Pydantic model params +- **[Limitations](references/guides/limitations.mdx)**: System constraints and limits +- **[Workflows Plugins](references/guides/workflows-plugins.mdx)**: Mistral AI plugin, Webhook plugin, Nuage plugin, custom plugins +- **[Deployment Patterns](references/guides/_deployment-patterns.mdx)**: Best practices for deploying workflows +- **[Migration v2 to v3](references/guides/migration-v2-to-v3.mdx)**: Breaking changes and upgrade steps from SDK v2 to v3 + +### Testing + +- **[Testing Workflows](references/guides/testing.md)**: Integration testing with `create_test_worker`, hang prevention, sandbox pitfalls + +**Quick-test script** — run any workflow in a local Temporal test environment with zero setup: +```bash +python .claude/skills/workflows/scripts/test_workflow.py --input '{"key": "value"}' [--timeout 30] +``` + +**Timeout policy for testing:** Use aggressive (short) timeouts to keep the feedback loop tight. A hanging test wastes more time than a false timeout. Defaults: + +| Context | Recommended timeout | When to increase | +|---|---|---| +| `--timeout` (quick-test script) | `15` seconds | Workflow makes multiple LLM calls or heavy I/O | +| `execution_timeout` (pytest) | `timedelta(seconds=10)` | Known long-running workflow | +| `asyncio.wait_for` (pytest) | `15` seconds | Should always be slightly above `execution_timeout` | + +If a workflow is known to be long-running (e.g. multi-step agent, large data processing), increase timeouts proportionally — but start short and only raise them when you see legitimate timeout failures, not preemptively. + +### Internal References + +These are additional patterns and utilities not covered in the official docs: + +- **[Execution IDs](references/execution_ids.md)**: Generate deterministic execution IDs for child workflows +- **[Pipeline Pattern](references/pipeline_pattern.md)**: Build multi-step workflows with declarative StepSpec definitions +- **[Workflow Testing](references/workflow_testing.md)**: Ensure workflow classes are properly registered in workers + +## When to Use This Skill + +Use this skill when you need to: + +1. **Build durable workflows**: Create long-running, fault-tolerant processes +2. **Orchestrate activities**: Coordinate multiple tasks and operations +3. **Handle background jobs**: Manage asynchronous processing and task queues +4. **Create multi-step pipelines**: Build complex workflows with multiple stages +5. **Schedule tasks**: Set up recurring or delayed execution of workflows +6. **Develop LLM agents**: Build durable AI agents with MCP tool support +7. **Build conversational workflows**: Create interactive workflows with HITL, forms, canvas, and rich UI +8. **Ensure fault tolerance**: Implement systems that can recover from failures automatically +9. **Stream events**: Real-time token streaming and progress updates via NATS + +## Key Features + +- **Fault tolerance**: Automatic recovery from failures and retries +- **Durable execution**: Workflows can run for extended periods (seconds to years) +- **Determinism enforcement**: Sandbox-based determinism with configurable enforcement +- **Rich Python framework**: Easy-to-use decorators and APIs (`mistralai.workflows`) +- **Built-in observability**: Deep integration with OpenTelemetry for monitoring +- **Streaming**: NATS-backed real-time token and progress streaming +- **Rate limiting**: Distributed rate limiting shared across workers +- **Dependency injection**: FastAPI-style Depends() pattern +- **Large payload handling**: OffloadableField with S3/Azure/GCS blob storage +- **Conversational workflows**: Interactive workflows with Le Chat integration, forms, canvas, and rich UI components +- **Durable agents**: AI agents with MCP support, multi-agent handoffs, and persistent state +- **Scalability**: Designed to handle complex, distributed applications diff --git a/.claude/skills/workflows/references/execution_ids.md b/.claude/skills/workflows/references/execution_ids.md new file mode 100644 index 000000000..ddcab81a7 --- /dev/null +++ b/.claude/skills/workflows/references/execution_ids.md @@ -0,0 +1,202 @@ +# Deterministic Child Workflow Execution IDs + +Generate reproducible execution IDs for child workflows to enable idempotency and prevent duplicate executions. + +## Overview + +When executing child workflows, providing a deterministic execution ID ensures: +- **Idempotency**: Re-running the parent workflow won't create duplicate child executions +- **Traceability**: Easy to correlate parent and child workflows +- **Replay safety**: Workflow replays use the same execution IDs + +## SDK Context + +The SDK's `execute_workflow` accepts an optional `execution_id` parameter. When omitted: +- **Inside a workflow**: a random child workflow ID is generated +- **Outside a workflow (client calls)**: The SDK auto-generates a 64-char hex ID via `generate_two_part_id()` using uuid5 + +For child workflows where idempotency matters, always provide a deterministic `execution_id`. + +## Implementation + +```python +def get_child_workflow_execution_id(task_name: str, case_id: str) -> str: + """Generate a deterministic execution ID for a child workflow. + + Args: + task_name: Name/type of the task being executed + case_id: Unique identifier for the case/entity being processed + + Returns: + A deterministic, unique execution ID + + Example: + >>> get_child_workflow_execution_id("validate-input", "case-123") + "case-123-validate-input" + """ + return f"{case_id}-{task_name}" +``` + +## Usage + +### Basic Usage + +```python +import mistralai.workflows as workflows +from .utils import get_child_workflow_execution_id + +@workflows.workflow.define(name="parent-workflow") +class ParentWorkflow: + + @workflows.workflow.entrypoint + async def run(self, params: ParentParams) -> Result: + case_id = params.case_id + + # Execute child workflow with deterministic ID + validation_result = await workflows.workflow.execute_workflow( + ValidateInputWorkflow, + ValidateParams(data=params.data), + execution_id=get_child_workflow_execution_id( + task_name="validate-input", + case_id=case_id + ), + ) + + # Another child workflow with fire-and-forget + handle = await workflows.workflow.execute_workflow( + ProcessDataWorkflow, + ProcessParams(data=validation_result.data), + execution_id=get_child_workflow_execution_id( + task_name="process-data", + case_id=case_id + ), + wait=False, # returns ChildWorkflowHandle immediately + ) + + # Can await the handle later + process_result = await handle + + return Result(output=process_result.output) +``` + +### In Pipeline Pattern + +```python +async def run_task_queue( + self, + input_object: T, + ctx: Context, + steps: list[StepSpec], + case_id: str +) -> T: + for step in steps: + step_label = step.task.task_type.name.lower() + + # Generate deterministic execution ID + execution_id = get_child_workflow_execution_id( + task_name=step_label, + case_id=case_id + ) + + params = step.task.make_params(input_object, ctx, execution_id, self.process_type) + + input_object = await workflows.workflow.execute_workflow( + step.task.workflow_cls, + params, + execution_id=execution_id + ) + + return input_object +``` + +## Extended Patterns + +### Including Additional Context + +For workflows that process items within a case: + +```python +def get_child_workflow_execution_id( + task_name: str, + case_id: str, + item_id: str | None = None +) -> str: + """Generate execution ID with optional item-level granularity.""" + if item_id: + return f"{case_id}-{task_name}-{item_id}" + return f"{case_id}-{task_name}" +``` + +Usage: + +```python +# Processing multiple items within a case +for item in items: + await workflows.workflow.execute_workflow( + ProcessItemWorkflow, + ProcessItemParams(item=item), + execution_id=get_child_workflow_execution_id( + task_name="process-item", + case_id=case_id, + item_id=item.id, + ), + ) +``` + +## `execute_workflow` Full Signature + +For reference, the SDK's `execute_workflow` accepts: + +```python +await workflows.workflow.execute_workflow( + workflow=MyWorkflow, # workflow class (decorated with @workflow.define) + params=MyParams(...), # Pydantic BaseModel + execution_timeout=timedelta(hours=1), # max runtime (default: 1h) + execution_id="my-deterministic-id", # optional; auto-generated if None + wait=True, # True → await result; False → return ChildWorkflowHandle + parent_close_policy=None, # TERMINATE (wait=True) or ABANDON (wait=False) by default +) +``` + +## Why Deterministic IDs Matter + +### Without Deterministic IDs + +```python +# BAD: Random/missing execution IDs +await workflows.workflow.execute_workflow( + ChildWorkflow, + params, + # No execution_id - system generates random one +) +``` + +Problems: +- Each replay creates new child workflow executions +- No way to correlate parent-child relationships +- Duplicate work if parent workflow is retried + +### With Deterministic IDs + +```python +# GOOD: Deterministic execution ID +await workflows.workflow.execute_workflow( + ChildWorkflow, + params, + execution_id=get_child_workflow_execution_id("child-task", case_id), +) +``` + +Benefits: +- Replays reuse existing child executions +- Clear parent-child correlation in traces +- Safe retries without duplicate work + +## Best Practices + +1. **Always provide execution IDs** for child workflows +2. **Use consistent naming**: lowercase, hyphenated task names +3. **Include enough context**: case ID at minimum, item ID if processing collections +4. **Keep IDs readable**: they appear in logs and traces +5. **Don't include timestamps** unless you specifically want daily re-execution +6. **Use the same ID generation** across all child workflow calls in a parent diff --git a/.claude/skills/workflows/references/getting-started/core-concepts.mdx b/.claude/skills/workflows/references/getting-started/core-concepts.mdx new file mode 100644 index 000000000..757e464d4 --- /dev/null +++ b/.claude/skills/workflows/references/getting-started/core-concepts.mdx @@ -0,0 +1,192 @@ +--- +id: core-concepts +title: Core Concepts +sidebar_position: 4 +--- + +# Core Concepts: Workflows, Activities & Workers + +Workflows provides a robust framework for building distributed applications through three key components that work together seamlessly. + +## 1. Workflows: The Brains of Your Application + +Workflows define the high-level business logic and coordination of your application. + +```python +@workflows.workflow.define(name="data_pipeline") +class DataProcessingWorkflow: + @workflows.workflow.entrypoint + async def run(self, raw_data: str) -> dict: + # Clean the data before parallel processing + cleaned_data_result = await clean_data(raw_data) + + # Run activities in parallel + analysis_result, transformed_data = await asyncio.gather( + analyze_data(cleaned_data_result), + transform_data(cleaned_data_result), + ) + + # For large-scale parallel processing, use the concurrency framework + # [Learn more about concurrency patterns](../guides/concurrency) + + return await generate_report(analysis_result, transformed_data) +``` + +Key characteristics: + +- Deterministic execution (same inputs → same outputs) +- Long-running (can execute for years with checkpointing) +- Stateful coordination +- Input/output limited to 2MB +- **A workflow will timeout if the delay between activities is more than 2 seconds** + +Workflows should contain only orchestration logic - they decide what needs to happen and in what order, but never perform actual work directly. + +## 2. Activities: The Workhorses + +Activities perform the actual work in your application. + +```python +@workflows.activity() +async def clean_data(raw_data: str) -> dict: + """Remove noise and normalize data format""" + # Implementation details... +``` + +Key characteristics: + +- Isolated execution in separate processes +- Automatic retries on failure +- Input/output limited to 2MB +- Idempotent by design (safe to retry) +- Focused on single responsibilities + +## 3. Workers: The Execution Engines + +Workers execute workflows and activities. They form the scalable execution layer. + +```python +async def main(): + await workflows.run_worker([ + DataProcessingWorkflow, + clean_data, + analyze_data, + transform_data, + generate_report + ]) +``` + +### Scaling with Multiple Workers + +When you need more throughput or want to test different code simultaneously, you can run multiple workers. Here are the common patterns: + +> **What is a task queue?** A task queue is a lightweight routing mechanism that determines which workers can execute which workflows and activities. Workers poll specific task queues for work, and workflows/activities are assigned to task queues when executed. [Learn more about task queues](https://docs.temporal.io/task-queue). + +```mermaid +graph TD + Queue[Task Queue] -->|Task 1| Worker1[Worker 1] + Queue -->|Task 2| Worker2[Worker 2] + Queue -->|Task 3| Worker3[Worker 3] +``` + +**Pattern 1: Horizontal Scaling (Same code, more capacity)** + +- Multiple workers running identical code +- Same namespace (same API key) +- Same task queue +- Tasks distributed automatically +- Use case: Production workloads needing more throughput + +```bash +## Worker 1, 2, 3... all identical +MISTRAL_API_KEY=prod_key uv run python my_workflow.py +``` + +**Pattern 2: Environment Separation (Dev/Staging/Prod)** + +- Different workspaces for different environments +- Each environment gets its own namespace +- Complete isolation between environments + +```bash +## Dev workspace +MISTRAL_API_KEY=dev_workspace_key uv run python my_workflow.py + +## Prod workspace +MISTRAL_API_KEY=prod_workspace_key uv run python my_workflow.py +``` + +**Pattern 3: Testing Different Code (Same workspace)** + +- Same workspace (same namespace) +- Different task queues for isolation +- Use case: Testing changes without affecting running workers + +```bash +## Stable version +MISTRAL_API_KEY=workspace_key uv run python my_workflow.py + +## Testing changes +TEMPORAL_TASK_QUEUE=testing MISTRAL_API_KEY=workspace_key uv run python my_workflow_v2.py +``` + +:::danger Critical: Avoid Worker Conflicts + +**Namespaces are automatically derived from your API key: `customer_id:workspace_id`** + +Workers using the same API key share the same namespace + +**What could happen:** + +- Version conflicts: Different code versions handling the same workflows +- Unpredictable behavior: Any worker can pick up any task +- Hard to debug: Can't trace which worker executed what + +**How to avoid conflicts:** + +- For different environments → Use separate workspaces (different namespaces) +- For testing changes → Use different task queues on the same workspace +- For scaling → Use same workspace, same task queue, same code + +::: + +## Complete Execution Flow + +1. Workflow triggered (API/schedule/manual) +2. Task added to queue +3. Available worker pulls task and executes workflow +4. When workflow hits activity: + - Activity task added to queue + - Any available worker pulls and executes it +5. Results flow back through the system + +## Key Differences + +| Component | Responsibility | Execution Location | Lifetime | Scaling Impact | +| --------- | -------------- | -------------------- | ------------ | ---------------------------------------- | +| Workflow | Orchestration | Worker process | Long-running | More workers = more concurrent workflows | +| Activity | Actual work | Any available worker | Short-lived | More workers = more parallel execution | +| Worker | Execution | Your infrastructure | Long-running | Horizontal scaling unit | + +## Executions vs Runs + +Understanding the distinction between **Executions** and **Runs** helps clarify the API behavior. + +### Execution + +An **Execution** represents a workflow invocation with a unique `execution_id`. When you call action endpoints like `GET /executions/{id}`, `POST /executions/{id}/terminate`, or `POST /executions/{id}/signals`, you interact with the **latest run** of that execution. + +### Run + +A **Run** is a single attempt within an execution. When a workflow is reset or retried, a new run is created for the same execution. Key points: + +- **1 Execution = 1+ Runs**: An execution can have multiple runs over its lifetime +- **Only 1 active run at a time**: For any execution, only one run can be active (RUNNING) at any moment +- **Action endpoints target latest run**: This is Temporal's default behavior and ensures you always interact with the current state + +### API Endpoints + +- `GET /v1/workflows/runs` - List all workflow runs (preferred) +- `GET /v1/workflows/executions` - **Deprecated** - Legacy alias for `/runs` +- `GET /v1/workflows/executions/{id}` - Get execution details (targets latest run) +- Action endpoints (`/terminate`, `/signals`, `/queries`, etc.) - Target latest run diff --git a/.claude/skills/workflows/references/getting-started/installation.mdx b/.claude/skills/workflows/references/getting-started/installation.mdx new file mode 100644 index 000000000..7f664a384 --- /dev/null +++ b/.claude/skills/workflows/references/getting-started/installation.mdx @@ -0,0 +1,93 @@ +--- +id: installation +title: Installation Guide +sidebar_position: 2 +--- + +# Installation + +This guide will walk you through setting up Workflows and verifying your installation. + +## Prerequisites + +Before installing the Workflows SDK, ensure you have: + +1. Python 3.12 or later installed +2. [uv](https://docs.astral.sh/uv/getting-started/installation/) package manager installed + +## Install Workflows + +Install the Workflows package from PyPI using uv: + +```bash +uv add mistralai-workflows +``` + +This will create a virtual environment (if one doesn't exist) and install Workflows along with its core dependencies. + +## Scaffold a Project with the CLI + +If you want to start from a ready-to-run Python project instead of wiring the SDK manually, use `mistralai-workflows-cli`: + +```bash +uvx mistralai-workflows-cli setup +``` + +This scaffolds a ready-to-run Python project with the Workflows SDK already configured, a minimal example workflow, and helper commands to register and execute workflows. + +The generated project also includes an embedded Workflows skill at `.agents/skills/workflows/SKILL.md`, so coding agents already have the project-specific guidance needed to work with the SDK. + +### Installing with Optional Dependencies + +The Workflows SDK provides optional extras for specific features. Install only what you need: + +#### Cloud Storage Providers + +For handling large payloads with [payload offloading](../../appendices/payload_encoding#payload-offloading): + +```bash +## AWS S3 support +uv add "mistralai-workflows[s3]" + +## Azure Blob Storage support +uv add "mistralai-workflows[azure]" + +## Google Cloud Storage support +uv add "mistralai-workflows[gcs]" + +## All storage providers +uv add "mistralai-workflows[storage]" +``` + +#### Mistral AI Integration + +For using Mistral AI models in your workflows: + +```bash +uv add "mistralai-workflows[mistralai]" +``` + +#### All Optional Features + +To install all optional dependencies: + +```bash +uv add "mistralai-workflows[all]" +``` + +## Verify Installation + +To verify your installation was successful, run the following command: + +```bash +uv run python -c "import mistralai.workflows; print('Workflows is installed successfully!')" +``` + +If you encounter any errors during this step, please check that your Python environment is properly configured. + +## Next Steps + +Now that you have Workflows installed, you can proceed to: + +- [Your First Workflow](your-first-workflow) - Create and run your first workflow +- [Core Concepts](core-concepts) - Understand the fundamental concepts diff --git a/.claude/skills/workflows/references/getting-started/introduction.mdx b/.claude/skills/workflows/references/getting-started/introduction.mdx new file mode 100644 index 000000000..259def5cc --- /dev/null +++ b/.claude/skills/workflows/references/getting-started/introduction.mdx @@ -0,0 +1,30 @@ +--- +id: introduction +title: Welcome to the Workflows documentation +sidebar_position: 1.1 +--- + +Mistral Workflows is an orchestration control plane designed to accelerate the development and reliable execution of complex, AI-driven workflows. Built on Temporal for fault-tolerant workflow execution, Workflows combines a user-friendly API with a rich Python framework optimized for Mistral's AI services. + +# What is Workflows? + +Workflows addresses the complexity of building, managing, and scaling multi-step AI processes reliably. It provides a structured environment for defining, executing, and monitoring workflows—from simple sequences to complex, stateful processes—ensuring completion even with transient failures. + +### Core Architecture + +- **Worker Framework** (`workflows/worker`): Python decorators for building and running Temporal workflows with minimal boilerplate +- **Python SDK** (`mistralai.Mistral`): Convenient client library for programmatic interaction with the Workflows API via `client.workflows.*` +- **Built-in Observability**: Deep OpenTelemetry integration linking Temporal executions with distributed traces + +### Key Features + +- **Rapid Development**: Python-first framework with intuitive decorators and pre-built components +- **Reliable Execution**: Leverages Temporal's battle-tested fault tolerance, automatic retries, and state management +- **Mistral-Native**: Optimized for orchestrating workflows utilizing Mistral's AI models and services +- **Scalable & Flexible**: Handles complex, long-running processes with multiple deployment patterns + +## Why Choose Workflows? + +Modern AI applications involve multi-step processes that are complex to build reliably. Integrating services, handling retries, ensuring observability, and managing long-running tasks quickly becomes an engineering challenge. Workflows provides the infrastructure to focus on your AI workflow logic rather than orchestration complexity. + +📖 **For a detailed comparison with raw Temporal and a full feature list, see [Value Proposition](./value-proposition).** diff --git a/.claude/skills/workflows/references/getting-started/python-sdk.mdx b/.claude/skills/workflows/references/getting-started/python-sdk.mdx new file mode 100644 index 000000000..5550b8f31 --- /dev/null +++ b/.claude/skills/workflows/references/getting-started/python-sdk.mdx @@ -0,0 +1,257 @@ +--- +id: python-sdk +title: Python SDK +sidebar_position: 5 +--- + +# Python SDK Guide + +The Workflows Python SDK provides a convenient way to interact with the Workflows platform programmatically, allowing you to execute workflows, monitor their progress, and manage workflow definitions. + +## Prerequisites + +Before using the SDK, ensure you have: + +1. Followed the [installation instructions](./installation) to set up Workflows +2. Completed the [your first workflow](./your-first-workflow) guide to run a worker with your first workflow + +## Getting Started + +### Basic Setup + +Initialize the client with your API credentials and namespace: + +```python +from mistralai.workflows.client import get_mistral_client + +## Initialize client +client = get_mistral_client( + server_url="https://api.mistral.ai", + api_key="your-api-key", # Should match your worker's `MISTRAL_API_KEY` +) +``` + +## Core Workflow Operations + +### 1. Executing Workflows + +Start a workflow execution with optional input data and custom execution ID: + +```python +from pydantic import BaseModel + +class InputData(BaseModel): + name: str + +execution_id = "custom-id-123" +execution = await client.workflows.execute_workflow_async( + workflow_identifier="simple_example_workflow", + input=InputData(name="MyName").model_dump(mode="json"), + execution_id=execution_id # Optional +) +``` + +### 2. Execute and Wait for Results + +For workflows where you need immediate results, use the synchronous execution method: + +```python +from pydantic import BaseModel + +class InputData(BaseModel): + name: str + +result = await client.workflows.execute_workflow_async( + workflow_identifier="simple_example_workflow", + input=InputData(name="MyName").model_dump(mode="json"), +) +``` + +### 3. Checking Execution Status + +Monitor the progress of your workflow executions: + +```python +status = await client.workflows.executions.get_workflow_execution_async(execution_id=execution_id) +print(f"Current status: {status.status}") +``` + +## Advanced Workflow Interactions + +### Signaling Workflows + +Send signals to running workflows to trigger specific behaviors: + +```python +from pydantic import BaseModel + +class SignalData(BaseModel): + new_value: int + +await client.workflows.executions.signal_workflow_execution_async( + execution_id="your-execution-id", # Execution id of the running workflow with signal method + name="update_config", # Name of the signal method + input=SignalData(new_value=42).model_dump(mode="json") +) +``` + +### Querying Workflow State + +Retrieve information from running workflows without modifying their state: + +```python +response = await client.workflows.executions.query_workflow_execution_async( + execution_id="your-execution-id", # Execution id of the running workflow with query method + name="get_status" # Name of the query method +) +print(response.result) +``` + +### Updating Running Workflows + +Modify workflow behavior during execution: + +```python +from pydantic import BaseModel + +class UpdateData(BaseModel): + timeout: int + +response = await client.workflows.executions.update_workflow_execution_async( + execution_id="your-execution-id", + name="change_settings", + input=UpdateData(timeout=300).model_dump(mode="json") +) +``` + +### Terminating Running Workflows + +Terminate a workflow during execution: + +```python +await client.workflows.executions.terminate_workflow_execution_async(execution_id=execution_id) +``` + +## Workflow Management + +### Listing Available Workflows + +Discover all registered workflows in your namespace: + +```python +response = await client.workflows.get_workflows_async() +print(f"These are all the available workflows: {response.workflows}") +``` + +### Retrieving Workflow Definitions + +Get detailed information about a specific workflow: + +```python +response = await client.workflows.get_workflow_async(workflow_identifier="simple_example_workflow") +print(f"The definition of this workflow is: {response.workflow}.") +``` + +## Execution Monitoring + +### Viewing Execution Traces + +Get detailed OpenTelemetry traces for debugging and analysis: + +```python +trace = await client.workflows.executions.get_workflow_execution_trace_otel_async(execution_id) +``` + +### Getting Trace Summaries + +Retrieve condensed information about workflow executions: + +```python +summary = await client.workflows.executions.get_workflow_execution_trace_summary_async(execution_id) +``` + +### Accessing Trace Events + +Examine individual events in a workflow execution: + +```python +events = await client.workflows.executions.get_workflow_execution_trace_events_async( + execution_id, + merge_same_id_events=True # Combines events with the same ID +) +``` + +## Scheduling Workflows + +### Creating Recurring Executions + +Set up workflows to run on a schedule: + +```python +from mistralai.workflows.models import ScheduleDefinition +schedule_id = "daily-name-schedule" +schedule = await client.workflows.schedules.schedule_workflow_async( + workflow_identifier="simple_example_workflow", + schedule=ScheduleDefinition( + input={"name": "MyName"}, + cron_expressions=["0 0 * * *"] # Runs daily at midnight + ), + schedule_id=schedule_id, +) +``` + +### Managing Schedules + +View and manage all your scheduled workflows: + +```python +## List all schedules +response = await client.workflows.schedules.get_schedules_async() +print(f"Here are all the defined schedules: {response.schedules}") +## Remove a schedule +await client.workflows.schedules.unschedule_workflow_async(schedule_id=schedule_id) +``` + +## Complete Example + +Here's a complete example showing workflow execution and result retrieval: + +```python +from dotenv import load_dotenv + +load_dotenv() + +async def main() -> None: + from mistralai.workflows.client import get_mistral_client + from pydantic import BaseModel + + class InputData(BaseModel): + report_type: str + + client = get_mistral_client( + server_url="https://api.mistral.ai", + api_key=os.environ["MISTRAL_API_KEY"], + ) + + # Execute workflow + result = await client.workflows.execute_workflow_async( + workflow_identifier="report_generator", + input=InputData(report_type="weekly").model_dump(mode="json"), + ) + + print(f"Workflow completed with result: {result}") + +if __name__ == "__main__": + + import asyncio + asyncio.run(main()) +``` + +## Next Steps + +Explore these related topics to deepen your understanding: + +- [Workflows Guide](../guides/workflows) - Learn about workflow fundamentals and design patterns +- [Activities Guide](../guides/activities) - Learn about activity functions and their usage +- [Scheduling](../guides/scheduling) - Advanced scheduling techniques and cron expressions +- [Signals, Queries & Updates](../guides/signals-queries-updates) - Advanced workflow interaction patterns diff --git a/.claude/skills/workflows/references/getting-started/value-proposition.mdx b/.claude/skills/workflows/references/getting-started/value-proposition.mdx new file mode 100644 index 000000000..73673a5c2 --- /dev/null +++ b/.claude/skills/workflows/references/getting-started/value-proposition.mdx @@ -0,0 +1,333 @@ +--- +id: value-proposition +title: "Value Proposition: Why Mistral Workflows?" +sidebar_position: 2 +--- + +# Mistral Workflows: Value Proposition + +Mistral Workflows (SDK + control plane) is our orchestration platform for building production grade AI workflows. It combines the reliability of Temporal with a developer-friendly Python SDK and native Mistral AI integrations. + +--- + +## Why We Built This (vs. Using Raw Temporal) + +Temporal is excellent infrastructure. We extend it with AI-specific features: + +| What Temporal Provides | What We Add | +|------------------------|-------------| +| Verbose SDK patterns | **Simpler DX**: direct activity calls, config on decorators, auto-schemas | +| No LLM-specific features | Native Mistral AI plugin (Agents, Tools, Sessions) | +| **No streaming** | **NATS-backed real-time event/token streaming** | +| Temporal UI (cluster-level view) | Native integration with AI Studio + Le Chat | +| No chat/interaction primitives | Primitives for building interactive chat experiences | +| No builtin interactivity | **HITL (Human-in-the-Loop)** interactive workflows with `wait_for_input()` | +| Basic tracing support | Pre-configured OpenTelemetry + Tempo + Grafana | +| Manual worker registration | Auto-registration with Workflows control plane | +| Temporal gRPC API | **Higher-level REST API** for workflows, executions, events, schedules | +| Manual namespace management | **Automatic namespace isolation** per org+workspace (`{org_id}:{workspace_id}`) | + +--- + +## Core Temporal Features We Leverage + +Temporal provides battle-tested distributed systems primitives: + +- **Fault Tolerance**: Workflows survive process crashes, network failures, infrastructure outages +- **Exactly-Once Execution**: Activities execute exactly once despite retries +- **Durability**: Full execution history persisted; workflows can run for months +- **Deterministic Replay**: Workflow state reconstructed from event history +- **Automatic Retries**: Configurable retry policies with exponential backoff +- **Signals & Queries**: External interaction with running workflows +- **Child Workflows**: Compose complex workflows from smaller units +- **Schedules**: Cron-like scheduled executions + +--- + +## Simpler Developer Experience + +Our SDK reduces boilerplate while adding capabilities. Here's why it's simpler: + +### 1. Direct Activity Calls + +**Raw Temporal:** Every activity call requires `execute_activity()` with explicit timeout/retry: +```python +result = await workflow.execute_activity( + my_activity, name, + start_to_close_timeout=timedelta(minutes=5), + retry_policy=RetryPolicy(maximum_attempts=3), +) +``` + +**Our SDK:** Call activities directly — config lives on the decorator: +```python +@workflows.activity(start_to_close_timeout=timedelta(minutes=5), retry_policy_max_attempts=3) +async def my_activity(name: str) -> str: ... + +## In workflow: +result = await my_activity(name) # Just call it +``` + +### 2. Configuration on Decorators + +| Raw Temporal | Our SDK | +|--------------|---------| +| `@activity.defn` (no config) | `@activity(timeout=..., retry=..., rate_limit=..., display_name=...)` | +| `@workflow.defn` (no config) | `@workflow.define(name=..., display_name=..., description=...)` | +| Config at every call site | Config once on the decorator | + +### 3. Auto-Generated Schemas + +| Raw Temporal | Our SDK | +|--------------|---------| +| No schema export | **Auto-generates JSON schemas** from signatures | +| Manual UI integration | Schemas registered → AI Studio input forms | + +### 4. Built-in Dependency Injection + +```python +@workflows.activity() +async def my_activity( + db: Database = Depends(get_database), # Injected + client: MistralClient = Depends(get_client) # Injected +) -> Result: ... +``` + +📖 **Full comparison:** See code examples in [Workflows Guide](../guides/workflows) and [Activities Guide](../guides/activities) + +--- + +## Complete Feature List (What We Add on Top of Temporal) + +### 1. Real-Time Streaming + +Temporal workflows return results only when complete—no way to stream intermediate outputs. + +- Token-by-token LLM output in AI Studio and Le Chat +- Progress updates via observable tasks +- 15-minute message persistence with replay +- NATS JetStream → Abraxas SSE → Client + +📖 **Docs:** [Streaming Guide](../guides/streaming) | [Streaming Architecture](../appendices/streaming) + +### 2. Dependency Injection + +FastAPI-style `Depends()` pattern for activities: +- Sync/async functions, context managers, generators +- Single instance per worker (shared across executions) +- Automatic lifecycle management + +📖 **Docs:** [Dependency Injection Guide](../guides/dependency-injection) + +### 3. Distributed Rate Limiting + +- Rate limits shared across **all workers** in the workspace +- Per-activity or shared via `key` parameter +- Prevents API quota exhaustion + +📖 **Docs:** [Rate Limiting Guide](../guides/rate-limiting) + +### 4. Concurrency Framework + +`execute_activities_in_parallel()` with 3 patterns: +- **List Executor**: Known collection of items +- **Chain Executor**: Token-based pagination (S3, DynamoDB) +- **Offset Pagination**: Index-based pagination + +Includes automatic continue-as-new for large datasets. + +📖 **Docs:** [Concurrency Guide](../guides/concurrency) + +### 5. Large Payload Handling + +Temporal has a 2MB limit and supports custom codecs for encryption. We add: +- **Built-in Payload Offloading**: Auto-offload to S3/GCS/Azure (Temporal requires third-party solutions) +- **Offloadable Fields**: Per-field offloading in activities +- **Pre-configured Encryption**: AES-GCM + key rotation out of the box + +📖 **Docs:** [Handling Large Data](../guides/handling-large-data) | [Payload Encoding](../appendices/payload-encoding) + +### 6. Observability / Task System + +- Observable `task()` context manager with state updates +- Automatic lifecycle events (started, completed, failed) +- OpenTelemetry tracing across workflows and activities +- Tempo integration for distributed trace queries +- Prometheus metrics + Grafana dashboards + +📖 **Docs:** [Observability Guide](../guides/observability) | [Streaming Guide](../guides/streaming) + +### 7. UI Metadata & Discovery + +- `workflow_display_name`, `workflow_description` for AI Studio +- Auto-generated JSON schemas → UI input forms +- `available_in_chat_assistant` flag for Le Chat + +📖 **Docs:** [Workflows Guide](../guides/workflows) + +### 8. Durable Agents (Mistral Plugin) + +LLM agents with Temporal's durability guarantees: +- Activities as agent tools +- Multi-agent handoffs +- MCP support (stdio/SSE) +- Built-in tools: WebSearch, CodeInterpreter, ImageGeneration, DocumentLibrary + +📖 **Docs:** [Durable Agents Guide](../guides/durable-agents) + +### 9. HITL (Human-in-the-Loop) Interactive Workflows + +Temporal workflows run autonomously with no built-in support for human interaction. We add **interactive workflow primitives** for pausing workflows and collecting human input: + +**Core Capability:** +- **`InteractiveWorkflow` base class**: Workflows that can pause and resume based on human input +- **`wait_for_input()`**: Pause workflow execution until user provides input +- **Durability guarantee**: Workflows survive crashes while waiting for input (full Temporal durability) + +📖 **Docs:** [Conversational Workflows Guide](../guides/assist-workflows) + +### 10. Local Execution Mode + +Temporal has a test environment, but requires spinning up a test server. We add: +- Run workflows/activities as plain Python functions (no server) +- Automatic retries via tenacity +- Dependency injection works locally +- **Limitations**: No durability, streaming, or human-in-the-loop + +📖 **Docs:** [Local Execution Guide](../guides/local-execution) + +### 11. Simplified Worker Versioning (Experimental) + +Temporal has worker versioning with PINNED behavior. We simplify it: +- Auto-registration as current version on startup +- No manual version management required +- Temporal Worker Controller integration for Kubernetes + +📖 **Docs:** [Worker Versioning](../appendices/worker-versioning) + +### 12. Simplified Sticky Sessions + +Temporal has Sessions for activity affinity. We simplify the API: +- Single decorator flag: `sticky_to_worker=True` +- No manual session management +- Works with dependency injection for state reuse + +📖 **Docs:** [Activities Guide](../guides/activities#sticky-worker-sessions) + +### 13. Simplified Worker Setup + +- Single `run_worker()` call +- Auto-discovery of decorated activities +- Auto-registration with control plane + +📖 **Docs:** [Your First Workflow](./your-first-workflow) + +### 14. Higher-Level REST API + +| Endpoint | Purpose | +|----------|---------| +| `/v1/workflows` | Lifecycle management, registry | +| `/v1/executions` | Monitoring, control, history | +| `/v1/events` | Event querying, SSE streaming | +| `/v1/schedules` | Cron and one-time schedules | +| `/v1/workers` | Worker capability discovery | + +### 15. Namespace Isolation + +Multi-tenant isolation built on Temporal namespaces: + +- **Namespace Format**: `{customer_id}:{workspace_id}` — Each org+workspace combination gets a dedicated Temporal namespace +- **Complete isolation**: Workflows, activities, schedules, and workers are isolated per namespace +- **Automatic resolution**: SDK and API automatically resolve namespace from authenticated context +- **Access control**: Namespace-level authentication and authorization via Kong/Albe +- **Independent scaling**: Each namespace can scale workers independently +- **Shared workflows**: Special handling for workflows owned by reserved namespaces that can be called across workspaces +- **Easy management**: Create and manage organizations and workspaces directly from AI Studio + +This enables: +- **SaaS multi-tenancy**: Complete isolation between organizations and their workspaces +- **Team/project isolation**: Different workspaces within the same organization are isolated +- **Cross-workspace sharing**: Opt-in shared workflows for common utilities + +### 16. AI Studio Integration + +- Timeline visualization with zoom/pan +- Input forms from Pydantic schemas +- Live execution status, signal sending + +### 17. Conversational Workflows and Le Chat integration + +Native integration with Le Chat (Mistral's chat interface): + +**Workflow Invocation:** +- Workflows appear as callable assistants in Le Chat +- LLM can invoke workflows as tools during conversations +- Automatic parameter validation from workflow schemas + +**Available Inputs:** +- **`ChatInput`**: Free-form conversational input for approvals, decisions, or feedback +- **`FormInput`**: Structured forms with typed fields and validation + - `TextField` (with regex validation), `NumberField` (min/max constraints) + - `DateTimeField`, `SingleChoice` (dropdown/select) + - Custom UI rendering in Le Chat + +**Rich Outputs:** +- **`TodoList`**: Real-time progress tracking with step-by-step status updates + - Three states: `todo`, `in_progress`, `done` + - Context manager support for automatic status transitions +- **Canvas outputs**: Rich content rendering + - Markdown, code with syntax highlighting, mermaid diagrams + - SVG, HTML, React components, presentation slides +- **Streaming agent responses**: Token-by-token LLM output streamed in real-time via tRPC + +📖 **Docs:** [Conversational Workflows Guide](../guides/assist-workflows) + +--- + +## Coming Soon + +Check the Milestones page for our roadmap: +https://www.notion.so/mistralai/Workflows-Milestones-2996ba59a7fe80719b9dd731ecbd380e?source=copy_link + +--- + +## Architecture at a Glance + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Clients │ +│ MistralClient (SDK) │ AI Studio │ Le Chat │ HTTP │ +└──────────────────────────┬──────────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────────┐ +│ API Gateway (Kong) │ +│ + Auth (Albe/JWT) │ +└──────────────────────────┬──────────────────────────────────────┘ + │ +┌──────────────────────────▼──────────────────────────────────────┐ +│ Workflows Control Plane (FastAPI) │ +│ /workflows /executions /events /schedules /workers │ +└───────┬─────────────────────────────────────────────────────────┘ + │ + ├──────────────────┬──────────────────┬───────────────────┐ + ▼ ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌────────────┐ +│ Temporal │ │ PostgreSQL │ │ NATS │ │ Tempo │ +│ Server │ │ (state) │ │ (streaming) │ │ (traces) │ +└───────────────┘ └───────────────┘ └───────────────┘ └────────────┘ + ▲ + │ +┌───────┴─────────────────────────────────────────────────────────┐ +│ Workflow Workers │ +│ @workflow.define │ @activity │ Mistral Plugin │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Next Steps + +- [Core Concepts](./core-concepts) — Understand workflows, activities, and workers +- [Your First Workflow](./your-first-workflow) — Build and run a workflow +- [Workflows Guide](../guides/workflows) — Deep dive into workflow patterns +- [Activities Guide](../guides/activities) — Learn about activity best practices diff --git a/.claude/skills/workflows/references/getting-started/your-first-workflow.mdx b/.claude/skills/workflows/references/getting-started/your-first-workflow.mdx new file mode 100644 index 000000000..d40130012 --- /dev/null +++ b/.claude/skills/workflows/references/getting-started/your-first-workflow.mdx @@ -0,0 +1,93 @@ +--- +id: your-first-workflow +title: Your First Workflow +sidebar_position: 3 +--- + +# Your First Workflow + +We'll walk through creating a simple workflow that executes a single activity. + +## Prerequisites + +First, follow the [installation instructions](./installation) to set up Workflows. +Before running your workflow, you'll need to: + +1. Connect to the console with your Mistral account +2. **Create a dedicated workspace** in the [Mistral Console](https://console.mistral.ai/) (requires admin permissions - if you're not an admin, ask your admin to create one for you) - this gives you an isolated namespace where you can safely run workers without conflicts +3. Create a new API key in that workspace (the namespace is automatically derived as `customer_id:workspace_id` from your API key) +4. Create a `.env` file with the following content: + +```bash +MISTRAL_API_KEY= +DEPLOYMENT_NAME= +``` + +## Step 1: Define Your Workflow and Worker + +Create a file `my_workflow.py` + +```python +import mistralai.workflows as workflows + +## Activities are async functions that can take any JSON-serializable types +@workflows.activity() +async def hello_world(name: str) -> dict: + """Activities are the building blocks of workflows. + 1. It's the place where you do the actual work + (e.g. call an API, process data, CPU intensive tasks, etc.) + 2. It must be async + 3. Parameters can be any JSON-serializable type (str, int, dict, list, etc.) + """ + return {"message": f"Hello, {name}!"} + +## Workflows orchestrate activities +@workflows.workflow.define(name="simple_example_workflow") +class SimpleExampleWorkflow: + @workflows.workflow.entrypoint + async def run(self, name: str) -> dict: + """Workflow entry point. + 1. It coordinate multiple activities + 2. It may need to wait for external events + """ + return await hello_world(name) + +## The Worker runs your workflows and activities +async def main() -> None: + await workflows.run_worker([SimpleExampleWorkflow]) + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) +``` + +## Step 2: Run Your Worker with the `simple_example_workflow` Workflow + +```bash +uv run python my_workflow.py +``` + +The worker will start, connect to the Mistral API, and register your workflow and wait for any task to do. +At that point you should already see your workflow registered in [AI studio](https://console.mistral.ai/build/workflows). + +Next step is now execute your workflow. + +## Step 3: Trigger execution of Your Workflow + +1. Visit [https://console.mistral.ai/](https://console.mistral.ai/) (make sure you are located in the same workspace than the one you created your API key in) +1. Click `Workflows` in the left sidebar +1. Select `simple_example_workflow` +1. Launch the workflow using the `Start Workflow` button and the input `{"name": }` +1. Find your execution in the `Executions` list +1. Make sure the workflow ran until the end by checking if the output is correct, like in this example: ![expected_workflow_output](expected_workflow_output.png) + +## Multi-Worker Setup + +For scaling patterns and running multiple workers, see [Core Concepts - Scaling with Multiple Workers](./core-concepts#scaling-with-multiple-workers). + +## Next Steps + +- [Core Concepts](core-concepts) - Understand the fundamentals +- [Workflows](../guides/workflows) - Deep dive in workflows +- [Activities](../guides/activities) - Deep dive in activities diff --git a/.claude/skills/workflows/references/guides/_deployment-patterns.mdx b/.claude/skills/workflows/references/guides/_deployment-patterns.mdx new file mode 100644 index 000000000..4b788aac9 --- /dev/null +++ b/.claude/skills/workflows/references/guides/_deployment-patterns.mdx @@ -0,0 +1,78 @@ +--- +id: deployment-patterns +title: Deployment Patterns +sidebar_position: 4 +--- + +*Four deployment strategies for different environments and use cases* + +# Overview +- Four distinct deployment patterns +- Kubernetes-native with Helm charts +- Local development options +- Hybrid cloud strategies + +## 1. Remote Fully (Production) +- **Components**: Temporal + Workflows API + Workers all on Kubernetes +- **Helm charts**: mistral-temporal, mistralai-workflows, mistralai-workflows-worker +- **Use case**: Production deployments, full observability, auto-scaling +- **Benefits**: High availability, resource isolation, operational visibility + +## 2. Hybrid (Development/Testing) +- **Components**: Temporal + Workflows API on Kubernetes, Workers local/elsewhere +- **Use case**: Development against production data, distributed teams +- **Benefits**: Local debugging, production-like environment, flexible scaling + +## 3. Local Passthru (Development) +- **Components**: Direct activity execution without Temporal orchestration +- **Implementation**: Activities detect `not temporalio.workflow.in_workflow()` and execute directly +- **Use case**: Fast iteration, debugging, unit testing +- **Benefits**: No infrastructure overhead, immediate execution, debugging-friendly + +## 4. Local with Temporal (Development) +- **Components**: `temporal server start-dev` + local API + local workers +- **Use case**: Full-stack local development, integration testing +- **Benefits**: Complete workflow testing, offline development, learning + +## Kubernetes Deployment + +### Helm Chart Structure +- mistral-ai-suite umbrella chart +- `global.mistral.apps.workflows.enabled` flag +- Component dependencies and ordering +- Configuration management + +### Configuration Management +- Environment-specific values +- Secret management strategies +- Resource limits and requests +- Scaling policies + +### Monitoring and Observability +- OpenTelemetry integration +- Grafana dashboards +- Alerting strategies +- Log aggregation + +## Local Development Setup + +### Prerequisites and Installation +- uv and Python environment setup +- Temporal server installation +- Development configuration + +### Switching Between Patterns +- Configuration changes for different patterns +- Environment variable management +- Testing strategies per pattern + +## Production Considerations +- Security and authentication +- Scaling worker pools +- Resource management +- Disaster recovery +- Multi-region deployments + +## Next Steps +- [Observability](observability) - Monitor your deployments +- [Configuration Reference](../appendices/configuration-reference) - All config options \ No newline at end of file diff --git a/.claude/skills/workflows/references/guides/activities.mdx b/.claude/skills/workflows/references/guides/activities.mdx new file mode 100644 index 000000000..bb2996331 --- /dev/null +++ b/.claude/skills/workflows/references/guides/activities.mdx @@ -0,0 +1,373 @@ +--- +id: activities +title: Activities +sidebar_position: 2 +--- + +# Activities: The Workhorses of Your Application + +Activities perform the actual work in your application while workflows coordinate them. + +## What is an Activity? + +An activity is a unit of work that performs actual computations, API calls, or other operations. Key characteristics: + +- Must be idempotent (safe to retry) +- Execute in isolated processes +- Have automatic retry mechanisms +- Accept any JSON-serializable types as inputs/outputs (str, int, dict, list, etc.) +- Input/output limited to 2MB + +> **Security Warning:** Do not pass sensitive data (API keys, passwords, PII, tokens) as activity inputs or outputs. +> All activity parameters and return values are persisted in the event history in plaintext unless +> [payload encryption](payload-encoding) is explicitly configured. Treat all inputs/outputs as visible +> to anyone with access to the namespace. + +## Defining an Activity + +Basic activity structure: + +```python +import mistralai.workflows as workflows + +@workflows.activity() +async def my_activity(input_data: str, count: int = 1) -> dict: + """Activity implementation""" + # Perform work here + return {"result": input_data, "processed_count": count} +``` + +:::warning +**All activity parameters and return types must have type annotations.** An activity missing any type hint on its arguments or return value will fail validation at registration time. Always provide explicit types for every parameter and the return type. + +```python +## ❌ Invalid - missing type annotations +@workflows.activity() +async def bad_activity(data, count=1): + return {"result": data} + +## ✅ Valid - all parameters and return type are annotated +@workflows.activity() +async def good_activity(data: str, count: int = 1) -> dict: + return {"result": data} +``` +::: + +## Core Activity Features + +### 1. Activity Naming + +Customize activity identification with: + +```python +@workflows.activity( + name="custom_activity_name", # Used for registration and execution + display_name="User-Friendly Name" # Used in logs and observability tools +) +``` + +[Learn more about observability and naming](#) + +### 2. Timeouts + +Configure execution time limits to prevent runaway activities: + +```python +from datetime import datetime + +@workflows.activity( + start_to_close_timeout=datetime.timedelta(minutes=10) +) +``` + +[Learn more about timeouts](#) + +### 3. Retry Policies + +Automatic retries with configurable policies to handle transient failures: + +```python +@workflows.activity( + retry_policy_max_attempts=5, + retry_policy_backoff_coefficient=2.0 +) +``` + +[Learn more about retry policies](#) + +### 4. Worker Stickiness + +Execute activities on the same worker for performance optimization: + +```python +@workflows.activity( + sticky_to_worker=True +) +``` + +See [Sticky Worker Sessions](#sticky-worker-sessions) for detailed documentation + +### 5. Heartbeat Timeout + +Detect stuck activities quickly by requiring periodic heartbeat signals: + +```python +from datetime import timedelta +from temporalio import activity as temporal_activity + +@workflows.activity( + start_to_close_timeout=timedelta(minutes=30), + heartbeat_timeout=timedelta(seconds=30) +) +async def long_running_task(items: list[str]) -> dict: + results = [] + for i, item in enumerate(items): + result = await process_item(item) + results.append(result) + # Report progress to prevent timeout + temporal_activity.heartbeat({"processed": i + 1, "total": len(items)}) + return {"results": results} +``` + +When `heartbeat_timeout` is set, activities must call `temporal_activity.heartbeat()` periodically. If no heartbeat is received within the timeout, Temporal considers the activity failed and triggers a retry. This enables fast detection of stuck activities without waiting for the full `start_to_close_timeout`. + +**Note:** Not supported for local activities. + +## Activity vs Workflow + +| Feature | Activity | Workflow | +| ----------- | ------------------ | -------------------- | +| Duration | Seconds to minutes | Seconds to years | +| State | Stateless | Stateful | +| Retries | Automatic | Manual recovery | +| Parallelism | Single operation | Complex coordination | + +## Granularity and Failure Handling + +Activities should be designed to be as granular as possible. This means breaking down complex tasks into smaller, manageable activities. However, each activity should encapsulate all the logic that is susceptible to failure. This granular approach has several benefits: + +- **Isolation of Failures**: Smaller activities make it easier to isolate and handle failures. If a failure occurs, only the affected activity needs to be retried. +- **Easier Debugging**: Granular activities make it easier to identify the exact point of failure and debug issues. +- **Better Retry Mechanisms**: Since each activity is idempotent and can be retried independently, granular activities ensure that only the failed part of the process is retried, saving time and resources. + +For example, if you have a process that involves fetching data from an API, processing that data, and then storing it in a database, you might define three separate activities: + +1. Fetch data from API +2. Process the data +3. Store the data in the database + +## Nested Activities + +When designing activities, it's important to understand how state management works, especially when activities are nested within each other. If an activity is encapsulated within another activity, only the parent activity will be considered for retries and state management. This means that the state will be saved before the nested activity, and only the parent activity will be retried in case of failure. + +```python +import mistralai.workflows as workflows + +@workflows.activity() +async def parent_activity(input_data: str) -> dict: + """Parent activity that encapsulates a nested activity.""" + # Some logic here + nested_result = await nested_activity(input_data) + return {"result_data": nested_result["result_data"]} + +@workflows.activity() +async def nested_activity(input_data: str) -> dict: + """Nested activity.""" + # Logic for the nested activity + return {"result_data": "processed_data"} +``` + +In this example, if nested_activity fails, the entire parent_activity will be retried, not just the nested activity. The state will be saved before the nested activity is called. + +## Local Activities + +For performance optimization, activities can run directly in the workflow worker process instead of being scheduled through Temporal's task queue. This is useful for fast operations (< 1 second) where scheduling overhead is significant. + +### When to Use + +**Good for:** + +- Quick computations, validations, data transformations +- High-volume scenarios where latency matters +- Operations completing in under 1 second + +**Avoid for:** + +- Long-running operations (> a few seconds) +- External API calls or I/O-heavy tasks +- Operations needing separate retry isolation or scaling + +### Basic Usage + +```python +from mistralai.workflows import run_activities_locally + +@workflows.activity() +async def validate_email(email: str) -> bool: + return "@" in email + +@workflows.workflow.define(name="user-workflow") +class UserWorkflow: + @workflows.workflow.entrypoint + async def execute(self, email: str) -> bool: + with run_activities_locally(): + result = await validate_email(email) + return result +``` + +### Mixed Execution + +Combine local and remote activities: + +```python +@workflows.workflow.define(name="mixed-workflow") +class MixedWorkflow: + @workflows.workflow.entrypoint + async def execute(self, email: str) -> dict: + # Fast lookup runs locally + with run_activities_locally(): + domain = await quick_lookup(email) + + # Slow operation runs as regular activity + verified = await external_api_call(email) + + return {"domain": domain, "verified": verified} +``` + +### Performance Impact + +| Execution Mode | Typical Latency | Best For | +| ---------------- | --------------- | --------------------------- | +| Local Activity | < 10ms | Quick computations, lookups | +| Regular Activity | 50-200ms | API calls, complex logic | + +### Limitations + +### Limitations + +**Bypasses Temporal Scheduling:** + +- No task queue isolation - activities share resources with workflows +- Worker process blocking - slow local activities block the workflow worker +- No independent scaling - cannot scale local activities separately +- Limited failure isolation - worker crashes affect both workflows and local activities + +**⚠️ Warning:** Local activities can cause worker crashes if they fail unexpectedly. Unlike regular activities, local activity failures can bring down the entire worker process, potentially causing data loss and requiring manual intervention to restart the workflow. +**Activity settings (partial support):** +Timeouts, retry policies, and dependency injection work the same for local activities. However, rate limiting is NOT supported for local activities. + +**Note:** The `sticky_to_worker`, `rate_limit`, and `heartbeat_timeout` parameters do not apply to local activities since they already run in the workflow worker process. + +```python +@workflows.activity( + start_to_close_timeout=timedelta(seconds=5), + retry_policy_max_attempts=3 +) +async def timed_local_activity(data: str) -> str: + # Timeouts and retry policies apply even when running locally + # Rate limiting is NOT supported for local activities + return data.upper() +``` + +## Sticky Worker Sessions + +Sticky worker sessions route multiple activities to the same worker instance, enabling resource reuse and stateful operations across activity calls. + +### When to Use + +**Good for:** + +- Sharing expensive resources (ML models, database connections, cached data) +- Stateful data processing across multiple activity calls +- Reducing initialization overhead for related operations + +**Avoid for:** + +- Activities that must be highly available (session breaks if worker crashes) +- Long-running workflows (ties up specific worker resources) +- When worker-level state isn't needed + +### Basic Usage + +```python +from mistralai.workflows import run_sticky_worker_session + +## Worker-level state +_loaded_model = None + +@workflows.activity(sticky_to_worker=True) +async def load_model() -> None: + global _loaded_model + if _loaded_model is None: + _loaded_model = load_expensive_model() + +@workflows.activity(sticky_to_worker=True) +async def predict(data: dict) -> dict: + return _loaded_model.predict(data) + +@workflows.workflow.define(name="ml-inference") +class MLInferenceWorkflow: + @workflows.workflow.entrypoint + async def execute(self, batch: list[dict]) -> list[dict]: + # All activities run on same worker + async with run_sticky_worker_session(): + await load_model() # Load once + results = [await predict(item) for item in batch] + return results +``` + +### Session Reuse + +Capture a session explicitly to reuse across multiple scopes: + +```python +@workflows.workflow.define(name="multi-batch") +class MultiBatchWorkflow: + @workflows.workflow.entrypoint + async def execute(self, batches: list[list[dict]]) -> list[list[dict]]: + # Capture worker once + session = await get_sticky_worker_session() + + all_results = [] + for batch in batches: + async with run_sticky_worker_session(session): + results = [await process_item(item) for item in batch] + all_results.append(results) + return all_results +``` + +### Limitations + +**Session breaks on worker failure:** + +- If the worker crashes or scales down, the session ends +- Subsequent activities route to a different worker +- Design activities to handle cold starts gracefully + +**In-memory state only:** + +- Worker-level state is lost on worker restart or redeployment +- Use databases or external storage for persistent state +- Not a replacement for distributed state management + +**Worker resource contention:** + +- Long-running sessions tie up specific worker capacity +- Can create hot spots if many workflows target the same worker +- Monitor worker utilization to avoid resource starvation + +**Note:** The `sticky_to_worker` parameter does not apply to local activities since they already run in the workflow worker process. + +### Performance Comparison + +| Feature | Regular Activity | Sticky Session | Local Activity | +| ---------------- | ---------------- | -------------- | -------------- | +| Routing Overhead | Standard | Standard | None | +| Worker Isolation | Yes | Yes | No | +| Resource Sharing | No | Yes | N/A | +| Best For | Independent ops | Resource reuse | Fast lookups | + +## Next Steps + +- [Workflows Guide](workflows) - Learn how to orchestrate activities +- [Observability Guide](observability) - Monitor and trace your activities diff --git a/.claude/skills/workflows/references/guides/assist-workflows.mdx b/.claude/skills/workflows/references/guides/assist-workflows.mdx new file mode 100644 index 000000000..f8fd95e91 --- /dev/null +++ b/.claude/skills/workflows/references/guides/assist-workflows.mdx @@ -0,0 +1,1045 @@ +--- +id: conversational-workflows +title: Conversational Workflows +sidebar_position: 9 +--- + +# Conversational Workflows + +Conversational workflows are meant to be integrated in conversations interface, allowing a user to trigger a workflow, +interact with it by providing inputs during its execution, and follow its progress. + +## Getting started + +To use Conversational workflow features, install the Mistral plugin: + +```bash +uv add 'mistralai-workflows[mistralai]' +``` + +The simplest conversational workflow sends an assistant message to the user, then waits for their response. +Extend `InteractiveWorkflow` and use `send_assistant_message()` followed by `wait_for_input()` with `ChatInput`: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="greeting-workflow", + workflow_display_name="Greeting", + workflow_description="A simple conversational workflow", +) +class GreetingWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self) -> workflows_mistralai.ChatAssistantWorkflowOutput: + # Send a message to the user + await workflows_mistralai.send_assistant_message( + "Hello! I'm here to help you get started. What's your name?" + ) + + # Wait for the user's response + user_input = await self.wait_for_input( + workflows_mistralai.ChatInput() + ) + + name = user_input.message[0].text if user_input.message else "friend" + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=f"Nice to meet you, {name}!")] + ) +``` + +`send_assistant_message()` displays a message to the user in the chat interface. It also accepts an optional `canvas` keyword argument to include a `CanvasResource` alongside the text (see [Canvas Editing](#canvas-editing-human-in-the-loop)). `ChatInput()` pauses the workflow and waits for the user to respond. You can optionally pass a `prompt` to `ChatInput()` to provide additional context (in placeholder) and `suggestions` to offer pre-filled options that users can select directly. + +### Timeout + +`wait_for_input()` accepts an optional `timeout` parameter. If the user does not respond within the specified duration, an `asyncio.TimeoutError` is raised. The timeout can be a `timedelta` or a number of seconds (`float`). By default, the workflow waits indefinitely. + +```python +from datetime import timedelta + +## Wait for user response, but time out after 5 minutes +user_input = await self.wait_for_input( + workflows_mistralai.ChatInput(), + timeout=timedelta(minutes=5), +) +``` + +:::tip +Wrap the call in a `try`/`except asyncio.TimeoutError` block to handle the timeout gracefully instead of failing the workflow. +::: + +## Structured Form Inputs + +For workflows that need structured form input with typed fields, validation, and custom UI rendering, use `FormInput` instead of `ChatInput`: + +```python +from datetime import date, datetime + +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai +from mistralai.workflows.conversational import ( + FormInput, + TextField, + NumberField, + DateField, + DateTimeField, + SingleChoice, +) + +class ExpenseForm(FormInput): + """Structured form for expense submission.""" + + description: str = TextField(description="Expense description") + amount: float = NumberField( + description="Amount in USD", + minimum=0, + maximum=10000, + ) + category: str = SingleChoice( + options=[ + ("travel", "Travel"), + ("equipment", "Equipment"), + ("software", "Software"), + ], + description="Expense category", + ) + expense_date: date = DateField(description="Date of expense") + due_date: datetime = DateTimeField(description="Reimbursement due date") + receipt_id: str = TextField( + description="Receipt ID", + pattern=r"^RCP-\d{6}$", + ) + +@workflows.workflow.define( + name="expense-submission-workflow", + workflow_display_name="Expense Submission", + workflow_description="Submit an expense with structured form", +) +class ExpenseSubmissionWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self) -> workflows_mistralai.ChatAssistantWorkflowOutput: + expense = await self.wait_for_input( + ExpenseForm, + label="Submit Expense", + ) + + result = f"""Expense submitted: +- Description: {expense.description} +- Amount: ${expense.amount:.2f} +- Category: {expense.category} +- Date: {expense.expense_date.isoformat()} +- Due date: {expense.due_date.isoformat()} +- Receipt: {expense.receipt_id}""" + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=result)] + ) +``` + +### Field Types + +| Field Type | Description | Properties | +| --------------- | ---------------- | ----------------------------------------------------------------------------- | +| `TextField` | Text input | `description`, `pattern` (optional regex) | +| `NumberField` | Numeric input | `description`, `minimum`, `maximum`, `exclusive_minimum`, `exclusive_maximum` | +| `DateTimeField` | Date/time picker | `description` | +| `DateField` | Date picker | `description` | +| `SingleChoice` | Dropdown/select | `options` (list of tuples or strings), `description` | +| `MultiChoice` | Multi-select | `options` (list of tuples or strings), `description` | +| `FileField` | File upload | `description`, `multiple` (default `False`) | + +### TextField + +```python +name: str = TextField(description="Your name") +email: str = TextField( + description="Email address", + pattern=r"^[\w.-]+@[\w.-]+\.\w+$", # Optional regex validation +) +``` + +### NumberField + +```python +amount: float = NumberField( + description="Amount", + minimum=0, # Inclusive minimum + maximum=10000, # Inclusive maximum +) +price: float = NumberField( + description="Price", + exclusive_minimum=0, # Must be greater than 0 + exclusive_maximum=100, # Must be less than 100 +) +``` + +### DateTimeField + +```python +from datetime import datetime + +scheduled_at: datetime = DateTimeField(description="Schedule date and time") +``` + +### DateField + +```python +from datetime import date + +scheduled_at: date = DateField(description="Schedule date") +``` + +### SingleChoice + +```python +## With labels (value, display_label) +priority: str = SingleChoice( + options=[ + ("low", "Low Priority"), + ("medium", "Medium Priority"), + ("high", "High Priority"), + ], + description="Select priority", +) + +## Simple string options (value = label) +status: str = SingleChoice( + options=["pending", "approved", "rejected"], + description="Status", +) +``` + +### MultiChoice + +```python +## With labels (value, display_label) +tags: list[str] = MultiChoice( + options=[ + ("frontend", "Frontend"), + ("backend", "Backend"), + ("infra", "Infrastructure"), + ], + description="Select applicable tags", +) + +## Simple string options (value = label) +colors: list[str] = MultiChoice( + options=["red", "green", "blue"], + description="Pick colors", +) +``` + +### FileField + +```python +from mistralai.workflows.conversational import FileField + +## Single file upload +document: str = FileField(description="Upload a document") + +## Multiple file uploads +attachments: list[str] = FileField(description="Upload files", multiple=True) +``` + +The workflow receives URLs (strings) pointing to files uploaded by the user. To process a file, download it from the provided URL within your workflow. These URLs may expire, so if your workflow needs long-term access to the files, it is responsible for storing them elsewhere. + +## Confirmation Inputs + +For workflows that need a simple single-choice confirmation with direct submit, use `ConfirmationInput` or `AcceptDeclineConfirmation`. These helpers create a single-field form where selecting an option immediately submits the form. + +### ConfirmationInput + +`ConfirmationInput` provides a list of options that should be rendered as buttons. Selection of an option should immediately submit the form: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="type-selection-workflow", + workflow_display_name="Type Selection", + workflow_description="Select your favorite type", +) +class TypeSelectionWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self) -> workflows_mistralai.ChatAssistantWorkflowOutput: + await workflows_mistralai.send_assistant_message("Let's find out your type preference!") + + selection = await self.wait_for_input( + workflows_mistralai.ConfirmationInput( + options=[ + ("fire", "Fire"), + ("water", "Water"), + ("grass", "Grass"), + ("electric", "Electric"), + ], + description="What is your favorite type?", + ) + ) + + selected_type = selection.choice # Returns the value, e.g., "fire" + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=f"You selected {selected_type}!")] + ) +``` + +| Property | Type | Description | +| ------------- | -------------------------------------- | ------------------------------------------------------------ | +| `options` | `list[tuple[str, str]]` or `list[str]` | List of options as `(value, label)` tuples or simple strings | +| `description` | `str` | Description shown above the options | + +The returned object has a `choice` property containing the selected option value. + +### AcceptDeclineConfirmation + +`AcceptDeclineConfirmation` is a specialized confirmation with two options: accept and decline. Clients can render this as a standard validation UI with keyboard shortcuts for quick responses: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="approval-workflow", + workflow_display_name="Approval", + workflow_description="Confirm an action", +) +class ApprovalWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self) -> workflows_mistralai.ChatAssistantWorkflowOutput: + confirmation = await self.wait_for_input( + workflows_mistralai.AcceptDeclineConfirmation( + description="Do you want to proceed with this action?", + accept_label="Yes, proceed", + decline_label="Cancel", + ) + ) + + if workflows_mistralai.is_accepted(confirmation): + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text="Action confirmed!")] + ) + else: + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text="Action cancelled.")] + ) +``` + +| Property | Type | Description | +| --------------- | ----- | ----------------------------------- | +| `description` | `str` | Description shown above the buttons | +| `accept_label` | `str` | Label for the accept button | +| `decline_label` | `str` | Label for the decline button | + +Use the `is_accepted()` helper function to check whether the user accepted or declined: + +```python +if workflows_mistralai.is_accepted(confirmation): + # User accepted + pass +else: + # User declined + pass +``` + +## Todo List Progress Tracking + +Display a checklist of steps with real-time status updates using `TodoList`: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="expense-processing-workflow", + workflow_display_name="Expense Processing", + workflow_description="Process expense with step-by-step progress", +) +class ExpenseProcessingWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self, expense_id: str) -> workflows_mistralai.ChatAssistantWorkflowOutput: + # Define the steps + validate_item = workflows_mistralai.TodoListItem( + title="Validate expense", + description="Check expense details and receipts" + ) + approve_item = workflows_mistralai.TodoListItem( + title="Get approval", + description="Route to manager for approval" + ) + process_item = workflows_mistralai.TodoListItem( + title="Process payment", + description="Submit for reimbursement" + ) + + async with workflows_mistralai.TodoList( + items=[validate_item, approve_item, process_item] + ) as todo_list: + # Step 1: Validate (using context manager for automatic status) + async with validate_item: + pass # ... validation logic ... + + # Step 2: Approve (using context manager for automatic status) + async with approve_item: + pass # ... approval logic ... + + # Step 3: Process (using context manager for automatic status) + async with process_item: + pass # ... processing logic ... + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=f"Expense {expense_id} processed successfully")] + ) +``` + +### Updating Item Status + +There are two ways to update the status of a `TodoListItem`: + +**Context Manager:** + +```python +async with item: + # Status automatically set to "in_progress" on enter + # ... do work ... + # Status automatically set to "done" on successful exit +``` + +**Manual Control (for fine-grained status updates):** + +```python +await item.set_status("in_progress") +## ... do work ... +await item.set_status("done") +``` + +Use manual control when you need to update status at specific points, handle conditional flows, or implement custom exception handling. + +### TodoListItem Properties + +| Property | Type | Description | +| ------------- | ----------------------------------- | ------------------------------------- | +| `id` | `str` | Auto-generated UUID | +| `title` | `str` | Display title for the step | +| `description` | `str` | Detailed description | +| `status` | `"todo" \| "in_progress" \| "done"` | Current status (defaults to `"todo"`) | + +## Streaming Agent Responses + +When using agents with `RemoteSession(stream=True)`, responses are automatically streamed to the UI as custom events. No additional code is needed: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="expense-analysis-workflow", + workflow_display_name="Expense Analysis", + workflow_description="AI-powered expense analysis", +) +class ExpenseAnalysisWorkflow: + @workflows.workflow.entrypoint + async def run(self, expense_data: str) -> workflows_mistralai.ChatAssistantWorkflowOutput: + # Create a streaming session - responses will automatically + # stream to the UI as they are generated + session = workflows_mistralai.RemoteSession(stream=True) + + analyst_agent = workflows_mistralai.Agent( + model="mistral-medium-2508", + name="expense-analyst", + description="Analyzes expense reports for policy compliance", + instructions="""You are an expense report analyst. Review the expense data +and provide insights on: +1. Policy compliance +2. Unusual patterns +3. Optimization suggestions + +Be concise and professional.""", + ) + + # The agent's response streams automatically custom events with JSON patches to update the UI. + await workflows_mistralai.Runner.run( + agent=analyst_agent, + inputs=f"Analyze this expense report:\n\n{expense_data}", + session=session, + ) + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text="Analysis complete.")] + ) +``` + +:::tip +When `stream=True`, the agent's text output is streamed token-by-token to the UI. This provides a responsive experience for longer responses. +::: + +## Rich Outputs (Canvas) + +Return rich content like markdown, code, or diagrams using `ResourceOutput`: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="expense-report-workflow", + workflow_display_name="Expense Report", + workflow_description="Generate expense report with charts", +) +class ExpenseReportWorkflow: + @workflows.workflow.entrypoint + async def run(self, department: str) -> workflows_mistralai.ChatAssistantWorkflowOutput: + # Generate a mermaid chart + chart_content = """ +pie title Expenses by Category + "Travel" : 45 + "Equipment" : 25 + "Software" : 20 + "Other" : 10 +""" + + canvas = workflows_mistralai.CanvasPayload( + type="mermaid", + title="Expense Breakdown", + content=chart_content, + ) + + resource = workflows_mistralai.CanvasResource( + canvas=canvas, + ) + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[ + workflows_mistralai.TextOutput(text=f"Expense report for {department}:"), + workflows_mistralai.ResourceOutput(resource=resource), + ] + ) +``` + +### Canvas Types + +| Type | Description | +| --------------- | ----------------------------- | +| `text/markdown` | Markdown content | +| `text/html` | HTML content | +| `image/svg+xml` | SVG images | +| `slides` | Presentation slides | +| `react` | React components | +| `code` | Code with syntax highlighting | +| `mermaid` | Mermaid diagrams | + +## Canvas Editing (Human-in-the-Loop) + +You can send a canvas mid-workflow using `send_assistant_message()` and then let the user edit it. +The `canvas_uri` passed to `CanvasInput` must match the `uri` of a `CanvasResource` output from a previous step. + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai +from mistralai.workflows.conversational import CanvasInput + +@workflows.workflow.define( + name="report-review-workflow", + workflow_display_name="Report Review", + workflow_description="Generate a report and let the user edit it", +) +class ReportReviewWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self) -> workflows_mistralai.ChatAssistantWorkflowOutput: + # Send a canvas to the user as an assistant message + canvas_resource = workflows_mistralai.CanvasResource( + canvas=workflows_mistralai.CanvasPayload( + type="text/markdown", + title="Weekly Report", + content="# Weekly Report\n\n## Summary\n\nTODO: fill in", + ), + ) + await workflows_mistralai.send_assistant_message( + "Here is your report draft. You can review and edit it below.", + canvas=canvas_resource, + ) + + # Wait for the user to edit the canvas + edited = await self.wait_for_input( + CanvasInput(canvas_uri=canvas_resource.uri, prompt="Any feedback?"), + label="Review & Edit Report", + ) + + # Use the edited content + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[ + workflows_mistralai.TextOutput(text="Report finalized!"), + workflows_mistralai.ResourceOutput( + resource=workflows_mistralai.CanvasResource( + canvas=workflows_mistralai.CanvasPayload( + type="text/markdown", + title=edited.canvas.title, + content=edited.canvas.content, + ), + ) + ), + ] + ) +``` + +`CanvasInput` returns a model with: + +- `canvas.title` — the title of the edited canvas +- `canvas.content` — the edited content +- `chatInput` — optional chat message (only present when `prompt` is provided and the user sends a message) + +## Rich UI Components + +Workflows can render rich, interactive UI components in the chat interface using the design system component library. Components are defined as Python objects and sent as `UIComponentResource` resources. + +### Basic Usage + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai +from mistralai.workflows.conversational_ui_components import ( + Badge, + Card, + Column, + Markdown, + Row, +) + +@workflows.workflow.define( + name="report-workflow", + workflow_display_name="Report", + workflow_description="Generate a rich UI report", +) +class ReportWorkflow: + @workflows.workflow.entrypoint + async def run(self) -> workflows_mistralai.ChatAssistantWorkflowOutput: + report = Card( + title="Summary", + children=[ + Row( + children=[ + Markdown(content="**Score:** 0.82"), + Badge(variant="success", children="Pass"), + ], + ), + ], + ) + + await workflows_mistralai.send_assistant_message( + [ + workflows_mistralai.TextOutput(text="Here is your report:"), + workflows_mistralai.ResourceOutput( + resource=workflows_mistralai.UIComponentResource(component=report), + ), + ] + ) + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[ + workflows_mistralai.ResourceOutput( + resource=workflows_mistralai.UIComponentResource(component=report), + ), + ], + ) +``` + +### Available Components + +All components are imported from `mistralai.workflows.conversational_ui_components`. + +| Component | Description | Key Props | +| ------------ | --------------------------------------------- | --------------------------------------------------------------------- | +| `Alert` | Important messages with severity levels | `title`, `variant` (info/warning/error/success), `children` | +| `Avatar` | User avatar image | `src`, `alt`, `text`, `size` | +| `Badge` | Small label for status indicators | `variant` (default/primary/success/warning/error), `size`, `children` | +| `ButtonLink` | Link styled as a button | `href`, `variant`, `size`, `external`, `children` | +| `Card` | Container with optional title and description | `title`, `description`, `padding`, `children` | +| `Chart` | Line or bar chart | `variant` (line/bar), `data`, `xAxis`, `yAxis`, `title` | +| `Column` | Vertical layout container | `alignment`, `distribution`, `gap`, `children` | +| `Image` | Image display | `src`, `alt`, `size` | +| `Markdown` | Markdown-formatted text | `content` | +| `PieChart` | Pie chart with labeled segments | `data`, `title` | +| `Row` | Horizontal layout container | `alignment`, `distribution`, `gap`, `wrap`, `children` | +| `Tooltip` | Additional information on hover | `trigger`, `children` | + +### Nesting Components + +Components that accept `children` can contain other components, allowing you to build complex layouts: + +```python +from mistralai.workflows.conversational_ui_components import ( + Card, + Chart, + Column, + Row, +) + +layout = Row( + children=[ + Card( + title="Revenue", + children=[ + Chart( + variant="line", + xAxis="month", + yAxis=["actual", "target"], + data=[ + {"month": "Jan", "actual": 100, "target": 120}, + {"month": "Feb", "actual": 140, "target": 130}, + {"month": "Mar", "actual": 160, "target": 140}, + ], + ), + ], + ), + Card( + title="Distribution", + children=[ + Chart( + variant="bar", + xAxis="category", + yAxis="count", + data=[ + {"category": "A", "count": 42}, + {"category": "B", "count": 28}, + {"category": "C", "count": 15}, + ], + ), + ], + ), + ], +) +``` + +## Tool UI States + +Tool UI States provide optional visual representations of tool execution in the chat interface. When attached to `ChatAssistantWorkingTask`, they enable specialized UI feedback for different types of tool operations, allowing workflows to display the status and results of tool calls in a structured, user-friendly way. + +### Tool UI State Types + +There are three types of tool UI states: + +#### File Tool UI State + +Represents file operations such as creating, replacing, or deleting files: + +```python +from mistralai.workflows.conversational import ( + FileToolUIState, + CreateFileOperation, + ReplaceFileOperation, + DeleteFileOperation, +) + +## Create a file +create_state = FileToolUIState( + toolCallId="tc-1", + operations=[ + CreateFileOperation( + uri="file:///workspace/new.py", + content="print('Hello World')" + ) + ], +) + +## Replace file content +replace_state = FileToolUIState( + toolCallId="tc-2", + operations=[ + ReplaceFileOperation( + uri="file:///workspace/main.py", + fileContentBefore="old content", + blocks=[SearchReplaceBlock(search="old", replace="new")], + ) + ], +) + +## Delete a file +delete_state = FileToolUIState( + toolCallId="tc-3", + operations=[ + DeleteFileOperation(uri="file:///workspace/old.py") + ], +) +``` + +#### Generic Tool UI State + +Represents generic tool execution with various status states: + +```python +from mistralai.workflows.conversational import ( + GenericToolUIState, + ToolResultRunning, + ToolResultSuccess, + ToolResultFailed, +) + +## Tool is running +running_state = GenericToolUIState( + toolCallId="tc-1", + name="bash", + arguments={"command": "ls -la"}, + result=ToolResultRunning(), +) + +## Tool completed successfully +success_state = GenericToolUIState( + toolCallId="tc-2", + name="grep", + arguments={"pattern": "TODO"}, + result=ToolResultSuccess(value={"matches": ["line1", "line2"]}), +) + +## Tool failed +failed_state = GenericToolUIState( + toolCallId="tc-3", + name="bash", + arguments={"command": "false"}, + result=ToolResultFailed(error="exit code 1"), +) +``` + +#### Command Tool UI State + +Represents command execution with running/success/failed states: + +```python +from mistralai.workflows.conversational import ( + CommandToolUIState, + CommandResultRunning, + CommandResultSuccess, + CommandResultFailed, +) + +## Command is running +running_state = CommandToolUIState( + toolCallId="tc-1", + command="npm install", + result=CommandResultRunning(), +) + +## Command completed successfully +success_state = CommandToolUIState( + toolCallId="tc-2", + command="pytest", + result=CommandResultSuccess(output="All tests passed"), +) + +## Command failed +failed_state = CommandToolUIState( + toolCallId="tc-3", + command="invalid-command", + result=CommandResultFailed(error="Command not found"), +) +``` + +### Using Tool UI States in Working Tasks + +Tool UI States can be attached to `ChatAssistantWorkingTask` to provide visual feedback during tool execution: + +```python +from mistralai.workflows.conversational import ChatAssistantWorkingTask + +## Show a working task with file operations +task = ChatAssistantWorkingTask( + title="Creating file", + content="Generating new.py", + toolUIState=FileToolUIState( + toolCallId="tc-1", + operations=[CreateFileOperation(uri="file:///workspace/new.py", content="print('hi')")], + ), +) + +## Show a working task with command execution +command_task = ChatAssistantWorkingTask( + title="Running tests", + content="Executing pytest", + toolUIState=CommandToolUIState( + toolCallId="tc-2", + command="pytest", + result=CommandResultRunning(), + ), +) +``` + +## Publish in Le Chat + +To publish a conversational workflow as an assistant in Le Chat (Mistral's chat interface), your workflow must return a `ChatAssistantWorkflowOutput`. +The output will not be displayed in Le Chat, but we enforce a common interface for inter-operability. + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="expense-summary-workflow", + workflow_display_name="Expense Summary", + workflow_description="Generates a summary of expenses", +) +class ExpenseSummaryWorkflow: + @workflows.workflow.entrypoint + async def run(self, department: str) -> workflows_mistralai.ChatAssistantWorkflowOutput: + summary = f"Expense summary for {department}: Total $12,500" + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=summary)] + ) +``` + +### Tagging Input Variants + +When a workflow accepts a union of input types, clients may need a way to know which variant to use. The `@input_tag` decorator adds an `x-input-tag` field to a model's JSON schema so clients can identify and select the right one. + +```python +from pydantic import BaseModel + +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai +from mistralai.workflows.plugins.mistralai import input_tag + +class FullParams(BaseModel): + config: str + options: dict[str, str] + +@input_tag("simplified") +class SimpleParams(BaseModel): + prompt: str + +@workflows.workflow.define( + name="multi-client-workflow", + workflow_display_name="Multi-Client", +) +class MultiClientWorkflow: + @workflows.workflow.entrypoint + async def run(self, params: FullParams | SimpleParams) -> workflows_mistralai.ChatAssistantWorkflowOutput: + if isinstance(params, SimpleParams): + resolved = params.prompt + else: + resolved = params.config + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=f"Received: {resolved}")] + ) +``` + +`SimpleParams.model_json_schema()` now contains `"x-input-tag": "simplified"`. Clients inspect the union members in the workflow's `input_schema` and select the variant whose tag they recognise. + +### Error Handling + +To signal that a workflow has failed, set `isError=True` on the output. +The text content is used as the error message displayed to the user, and the workflow is marked as failed in the conversation: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="expense-validation-workflow", + workflow_display_name="Expense Validation", + workflow_description="Validates expense data", +) +class ExpenseValidationWorkflow: + @workflows.workflow.entrypoint + async def run(self, expense_id: str) -> workflows_mistralai.ChatAssistantWorkflowOutput: + expense = lookup_expense(expense_id) + if expense is None: + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=f"Expense {expense_id} not found.")], + isError=True, + ) + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=f"Expense {expense_id} is valid.")] + ) +``` + +### Structured Content + +`ChatAssistantWorkflowOutput` accepts an optional `structuredContent` field (`dict[str, Any]`) +for attaching arbitrary structured data to the workflow output. + +```python +return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text="Done.")], + structuredContent={"tool": "web_search", "results": [{"url": "https://example.com"}]}, +) +``` + +## Complete Example + +Here's a full expense approval workflow combining todo list, user input, and streaming agent analysis: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.workflow.define( + name="full-expense-workflow", + workflow_display_name="Full Expense Processing", + workflow_description="Complete expense workflow with AI analysis and approval", +) +class FullExpenseWorkflow(workflows.InteractiveWorkflow): + @workflows.workflow.entrypoint + async def run(self, expense_data: str) -> workflows_mistralai.ChatAssistantWorkflowOutput: + # Define workflow steps + analyze_item = workflows_mistralai.TodoListItem( + title="AI Analysis", + description="Analyze expense for compliance" + ) + review_item = workflows_mistralai.TodoListItem( + title="Manager Review", + description="Get manager approval" + ) + process_item = workflows_mistralai.TodoListItem( + title="Process", + description="Complete processing" + ) + + async with workflows_mistralai.TodoList( + items=[analyze_item, review_item, process_item] + ) as todo_list: + # Step 1: AI Analysis with streaming (using context manager) + async with analyze_item: + session = workflows_mistralai.RemoteSession(stream=True) + analyst = workflows_mistralai.Agent( + model="mistral-medium-2508", + name="expense-analyst", + description="Expense policy analyst", + instructions="Analyze the expense for policy compliance. Be brief.", + ) + + await workflows_mistralai.Runner.run( + agent=analyst, + inputs=expense_data, + session=session, + ) + + # Step 2: Manager Review (using context manager) + async with review_item: + decision = await self.wait_for_input( + workflows_mistralai.ChatInput( + "Do you approve or reject this expense? Please explain.", + suggestions=[ + [workflows_mistralai.TextChunk(text="Yes, approve this expense")], + [workflows_mistralai.TextChunk(text="Reject")], + ], + ) + ) + + # Step 3: Process (using manual status control for conditional logic) + await process_item.set_status("in_progress") + decision_text = decision.message[0].text if decision.message else "" + if "approve" in decision_text.lower(): + result = f"Expense approved. {decision_text}" + else: + result = f"Expense rejected. {decision_text}" + await process_item.set_status("done") + + return workflows_mistralai.ChatAssistantWorkflowOutput( + content=[workflows_mistralai.TextOutput(text=result)] + ) + +if __name__ == "__main__": + import asyncio + asyncio.run(workflows.run_worker([FullExpenseWorkflow])) +``` diff --git a/.claude/skills/workflows/references/guides/concurrency.mdx b/.claude/skills/workflows/references/guides/concurrency.mdx new file mode 100644 index 000000000..af0cc1bad --- /dev/null +++ b/.claude/skills/workflows/references/guides/concurrency.mdx @@ -0,0 +1,487 @@ +--- +id: concurrency +title: Concurrency Patterns +sidebar_position: 9 +--- + +# Concurrency Patterns: Scale Your Workflows + +_Process thousands of items efficiently with Mistral Workflows' parallel execution patterns_ + +## Overview + +Mistral Workflows provides a powerful concurrency framework that enables you to execute activities in parallel across three distinct patterns: + +- **List Executor**: Process a known collection of items +- **Chain Executor**: Process items sequentially from a stream/queue (token-based pagination) +- **Offset Pagination Executor**: Process items by fetching pages/chunks by index + +All patterns are built on Temporal's workflow continuation patterns, providing automatic fault tolerance, progress tracking, and scalability for large datasets. + +### Key Benefits + +- **Massive Parallelism**: Execute thousands of activities concurrently +- **Automatic Continue-As-New**: Handle large datasets without hitting Temporal's execution history limits +- **Type Safety**: Comprehensive type validation for all inputs and outputs +- **Fault Tolerance**: Built-in error handling and retry mechanisms +- **Progress Tracking**: Monitor execution progress through built-in observability features + +## List Executor Pattern + +### Use Case + +Process a known collection of items where you have all items upfront. + +### When to Use + +- Database query results +- File contents or uploaded documents +- API responses that return all items at once +- Batch processing of users, files, or records + +### Code Pattern + +```python +import mistralai.workflows as workflows + +@workflows.activity() +async def process_item(item_id: int, value: str) -> dict: + # Process individual item + return {"processed_value": f"processed_{value}"} + +## ... (inside a workflow) +## Execute in parallel +items = [{"item_id": i, "value": f"item_{i}"} for i in range(1000)] +results = await workflows.execute_activities_in_parallel( + activity=process_item, + items=items, + max_concurrent_scheduled_tasks=100 # Optional: limit concurrency +) +## ... +``` + +### Configuration Options + +| Parameter | Description | Default | +| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `max_concurrent_scheduled_tasks` | Maximum number of concurrent activity executions that can be scheduled simultaneously. This limits how many activities are waiting to be executed at once. | 100 | +| `extra_params` | Additional parameters to pass to the activity | None | + +**Note**: The List Executor does not use `max_concurrent_executions_per_worker` parameter. This parameter is only relevant for the Offset Pagination Executor. + +## Chain Executor Pattern + +### Use Case + +Process items sequentially from a stream/queue using token-based pagination. + +### When to Use + +- AWS S3 ListObjects (uses ContinuationToken) +- DynamoDB Scan/Query (uses LastEvaluatedKey) +- Azure Blob Storage (uses marker) +- Any API that uses continuation tokens instead of page numbers + +### Code Pattern + +```python +import mistralai.workflows as workflows + +@workflows.activity() +async def process_item(item_id: int, value: str) -> dict: + # Process individual item + return {"processed_value": f"processed_{value}"} + +@workflows.activity() +async def get_next_item(prev_item: dict | None) -> dict | None: + # Get next item from previous item + if prev_item is None: + # First item + return {"item_id": 0, "value": "item_0"} + + next_id = prev_item["item_id"] + 1 + if next_id >= 1000: # Stop condition + return None + + return {"item_id": next_id, "value": f"item_{next_id}"} + +## ... (inside a workflow) +## Execute chain +results = await workflows.execute_activities_in_parallel( + activity=process_item, + get_item_from_prev_item_activity=get_next_item +) +## ... +``` + +**Note**: The Chain Executor does not use `max_concurrent_scheduled_tasks` or `max_concurrent_executions_per_worker` parameters. + +### How It Works + +The Chain Executor separates **item discovery** (sequential) from **item processing** (parallel): + +1. **Item fetching is chained**: The executor calls `get_item_from_prev_item_activity` sequentially—first with `None` to get the first item, then with each result to get the next item, until the function returns `None` +2. **Processing is parallelized**: As soon as an item is fetched, it's immediately dispatched for processing via the `activity` function. Items don't wait for each other to finish processing + +This means fetching item N+1 depends on item N's result, but _processing_ item N+1 runs concurrently with processing items 1 through N. + +## Offset Pagination Executor Pattern + +### Use Case + +Process items by fetching pages/chunks using index-based pagination. + +### When to Use + +- Traditional REST APIs with page numbers +- SQL database chunking with OFFSET/LIMIT +- File processing by byte offset +- Any index-based data fetching + +### Code Pattern + +```python +import mistralai.workflows as workflows + +@workflows.activity() +async def process_item(item_id: int, value: str) -> dict: + # Process individual item + return {"processed_value": f"processed_{value}"} + +@workflows.activity() +async def get_item_by_index(params: workflows.GetItemFromIndexParams) -> dict: + # Get item by index + return { + "item_id": params.idx, + "value": f"item_{params.idx}", + "extra_data": params.extra_params + } + +## Execute with offset pagination +results = await workflows.execute_activities_in_parallel( + activity=process_item, + get_item_from_index_activity=get_item_by_index, + n_items=1000, # Total number of items + max_concurrent_executions_per_worker=50, # Optional: controls how many items are processed together + max_concurrent_scheduled_tasks=100, # Optional: limit concurrent activity executions + extra_params={"batch_id": "daily_processing"} # Optional: extra parameters +) +``` + +### Configuration Options + +| Parameter | Description | Default | +| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| `n_items` | Total number of items to process | Required | +| `max_concurrent_scheduled_tasks` | Maximum number of concurrent activity executions that can be scheduled simultaneously. This limits how many activities are waiting to be executed at once. | 100 | +| `max_concurrent_executions_per_worker` | Controls how many items are processed together in a single activity execution. Only used by Offset Pagination Executor. | 100 | +| `extra_params` | Additional parameters to pass to the activity | None | + +**Note**: Items processed together are wrapped in a single activity. If any item fails, the entire group is retried together. + +## Offset Pagination Executor Best Practices + +### Understanding Parameter Interactions + +The Offset Pagination Executor uses two key parameters: + +1. **`max_concurrent_executions_per_worker`**: Controls how many items are processed together in a single activity execution. +2. **`max_concurrent_scheduled_tasks`**: Controls how many of these activity executions can run concurrently. + +**Example**: If you have 1000 items with `max_concurrent_executions_per_worker=10` and `max_concurrent_scheduled_tasks=5`, the system will: + +- Process items in groups of 10 +- Execute up to 5 groups concurrently +- Process all items efficiently while maintaining manageable group sizes + +### Retry Behavior Considerations + +**Important**: All items processed together are wrapped in a single activity. This means: + +- **Pros**: Efficient processing, reduced overhead +- **Cons**: If any single item in a group fails, the entire group is retried + +**Best Practices**: + +- Choose `max_concurrent_executions_per_worker` values that balance efficiency with retry granularity +- Smaller values: More fine-grained retries, but higher overhead +- Larger values: More efficient, but larger retry scope +- Consider item failure rates when choosing values + +### Performance Optimization Strategies + +1. **For I/O-bound tasks** (API calls, database queries): + + - Use larger groups (50-100 items) + - Higher `max_concurrent_scheduled_tasks` (100-200) + - Example: `max_concurrent_executions_per_worker=50, max_concurrent_scheduled_tasks=150` + +2. **For CPU-bound tasks**: + + - Use smaller groups (5-20 items) + - Lower `max_concurrent_scheduled_tasks` (20-50) + - Example: `max_concurrent_executions_per_worker=10, max_concurrent_scheduled_tasks=30` + +3. **For mixed workloads**: + - Medium groups (20-50 items) + - Balanced concurrency (50-100) + - Example: `max_concurrent_executions_per_worker=25, max_concurrent_scheduled_tasks=75` + +### Memory and Resource Considerations + +- **Group size impacts memory usage**: Larger groups consume more memory per activity +- **Concurrency impacts resource contention**: Higher concurrency may lead to resource exhaustion +- **Temporal limits**: Remember Temporal's 2MB input/output limit per activity + +## Advanced Features + +### Error Handling + +The concurrency framework automatically handles: + +- Activity failures with retry mechanisms +- Type validation errors +- Temporal workflow continuation for large datasets +- Progress tracking and state management + +### Performance Optimization + +#### Concurrency Limits + +Adjust concurrency based on your workload: + +```python +## For I/O-bound tasks (API calls, database queries) +results = await workflows.execute_activities_in_parallel( + activity=api_call_activity, + items=items, + max_concurrent_scheduled_tasks=200 # Higher concurrency for I/O-bound +) + +## For CPU-bound tasks +results = await workflows.execute_activities_in_parallel( + activity=cpu_intensive_activity, + items=items, + max_concurrent_scheduled_tasks=50 # Lower concurrency for CPU-bound +) +``` + +#### Batch Processing + +For very large datasets, the framework automatically handles continue-as-new: + +```python +## Process 100,000 items with List Executor - automatically continues as new workflow +results = await workflows.execute_activities_in_parallel( + activity=process_item, + items=large_item_list, # 100,000 items + max_concurrent_scheduled_tasks=100 +) + +## Process 100,000 items with Offset Pagination Executor +results = await workflows.execute_activities_in_parallel( + activity=process_item, + get_item_from_index_activity=get_item_by_index, + n_items=100000, + max_concurrent_executions_per_worker=100, # Process 100 items together per activity + max_concurrent_scheduled_tasks=50 # Execute 50 activities concurrently +) +``` + +## Real-World Examples + +### Document Processing Pipeline + +```python +@workflows.activity() +async def extract_text(document_id: str, content: str, metadata: dict) -> dict: + # Use OCR or text extraction + extracted_text = await ocr_service.extract(content) + return { + "document_id": document_id, + "extracted_text": extracted_text, + "analysis_results": {} + } + +## Process all documents in parallel +documents = await fetch_documents_from_storage() +results = await workflows.execute_activities_in_parallel( + activity=extract_text, + items=documents +) +``` + +### Batch Data Transformation + +```python +@workflows.activity() +async def enrich_user_data(user_id: str, name: str, email: str) -> dict: + # Fetch additional data from external services + profile_score = await analytics_service.calculate_score(user_id) + recommendations = await recommendation_service.get_recommendations(user_id) + + return { + "user_id": user_id, + "name": name, + "email": email, + "profile_score": profile_score, + "recommendations": recommendations + } + +## Enrich all users in parallel +users = await database.get_all_users() +enriched_users = await workflows.execute_activities_in_parallel( + activity=enrich_user_data, + items=users, + max_concurrent_scheduled_tasks=50 +) +``` + +### Multi-Service Orchestration + +```python +@workflows.activity() +async def process_order(order_id: str, customer_id: str, items: list[str]) -> dict: + # Call multiple services in parallel + payment_result = await payment_service.process(order_id) + inventory_result = await inventory_service.reserve(items) + shipping_result = await shipping_service.schedule(order_id) + + return { + "order_id": order_id, + "status": "processed", + "fulfillment_details": { + "payment": payment_result, + "inventory": inventory_result, + "shipping": shipping_result + } + } + +## Process all orders in parallel +orders = await fetch_pending_orders() +results = await workflows.execute_activities_in_parallel( + activity=process_order, + items=orders +) +``` + +## Performance Considerations + +### Memory Usage + +- Large datasets are processed efficiently to avoid memory issues +- Temporal's continue-as-new mechanism ensures workflow state remains manageable +- Each activity execution is isolated with its own memory footprint + +### Network I/O Optimization + +- Activities can be executed on workers close to data sources +- Use `sticky_to_worker=True` for activities that benefit from locality +- Configure appropriate concurrency limits based on network bandwidth + +### Error Recovery + +- Failed activities are automatically retried according to their retry policy +- The framework maintains progress state, so only failed items need reprocessing + +### Monitoring and Alerting + +- Implement custom event recording with `workflows.record_event()` +- Set up alerts for long-running or failed executions + +## Troubleshooting + +### Common Issues + +**Issue**: `ValueError: 'activity' must be an activity, please decorate it with @workflows.activity` + +**Solution**: Ensure your activity function is decorated with `@workflows.activity()` + +**Issue**: `ValueError: Must specify one execution pattern` + +**Solution**: Provide exactly one of: `items`, `get_item_from_prev_item_activity`, or `get_item_from_index_activity` + +**Issue**: Excessive retries with Offset Pagination Executor + +**Solution**: If you're experiencing excessive retries with the Offset Pagination Executor, consider: + +- Reducing `max_concurrent_executions_per_worker` to create smaller groups of items +- Investigating individual item failures that might be causing entire groups to retry +- Adding better error handling within your activity to prevent failures + +**Issue**: Memory issues with large groups + +**Solution**: If you encounter memory issues: + +- Reduce `max_concurrent_executions_per_worker` to process fewer items together +- Ensure individual items are not too large (remember Temporal's 2MB limit) +- Monitor memory usage and adjust group sizes accordingly + +### Debugging Tips + +1. **Check Activity Signatures**: Ensure all activities have proper type annotations +2. **Validate Concurrency Limits**: Start with lower concurrency and increase gradually +3. **Use Logging**: Add detailed logging in your activities for debugging +4. **Offset Pagination Debugging**: For Offset Pagination Executor issues: + - Start with small values (e.g., `max_concurrent_executions_per_worker=1`) + - Check for individual item failures that might affect entire groups + +## Next Steps + +- [Workflows Guide](workflows) - Learn how to orchestrate activities +- [Activities Guide](activities) - Understand activity implementation details +- [Observability Guide](observability) - Monitor and trace your concurrent executions +- [Limitations Guide](limitations) - Understand Temporal's execution constraints + +## API Reference + +### `execute_activities_in_parallel()` Function + +```python +async def execute_activities_in_parallel( + activity: Callable[[T], Awaitable[U]], + *, + # List Executor + items: List[T] | None = None, + max_concurrent_scheduled_tasks: int = DEFAULT_MAX_CONCURRENT_SCHEDULED_TASKS, + + # Chain Executor + get_item_from_prev_item_activity: Callable[[T | None], Awaitable[T | None]] | None = None, + + # Offset Pagination Executor + get_item_from_index_activity: Callable[[GetItemFromIndexParams], Awaitable[T]] | None = None, + n_items: int | None = None, + max_concurrent_executions_per_worker: int = DEFAULT_MAX_CONCURRENT_EXECUTIONS_PER_WORKER, + + # Common + extra_params: Dict[str, Any] | None = None, +) -> None | List[U] +``` + +**Parameters**: + +- `activity`: The activity function to execute on each item +- `items`: List of items to process (List Executor) +- `get_item_from_prev_item_activity`: Function to get next item from previous (Chain Executor) +- `get_item_from_index_activity`: Function to get item by index (Offset Pagination Executor) +- `n_items`: Total number of items (Offset Pagination Executor) +- `max_concurrent_scheduled_tasks`: Maximum number of concurrent activity executions that can be scheduled simultaneously. Applies to List Executor and Offset Pagination Executor only. +- `max_concurrent_executions_per_worker`: **Only for Offset Pagination Executor** - Controls how many items are processed together in a single activity execution. +- `extra_params`: Extra parameters to pass to activities + +**Parameter Usage by Executor**: + +| Executor | `max_concurrent_scheduled_tasks` | `max_concurrent_executions_per_worker` | +| -------------------------- | -------------------------------- | -------------------------------------- | +| List Executor | ✅ Yes | ❌ No | +| Chain Executor | ❌ No | ❌ No | +| Offset Pagination Executor | ✅ Yes | ✅ Yes | + +**Returns**: + +- `None` if activity returns None +- `List[U]` list of activity results + +**Raises**: + +- `ValueError`: If activity is not properly decorated or parameters are invalid diff --git a/.claude/skills/workflows/references/guides/dependency-injection.mdx b/.claude/skills/workflows/references/guides/dependency-injection.mdx new file mode 100644 index 000000000..8020ea7d5 --- /dev/null +++ b/.claude/skills/workflows/references/guides/dependency-injection.mdx @@ -0,0 +1,185 @@ +--- +id: dependency-injection +title: Dependency Injection +sidebar_position: 6 +--- + +# Dependency Injection in Workflows + +Dependency injection provides a clean way to access shared resources in your workflows and activities. It automatically handles the creation and management of resources like database connections, API clients, or configuration objects, so you don't have to manually create and pass these around in your code. + +## How It Works + +The system supports multiple ways to provide dependencies, allowing you to choose the approach that best fits your resource's requirements: + +1. **Synchronous functions** - Ideal for simple configuration values or in-memory objects +2. **Asynchronous functions** - Perfect for I/O-bound dependencies like database connections +3. **Context managers** - Best for resources that require cleanup operations +4. **Generators** - Useful for streaming data or complex resource management + +When you declare a dependency in your activity or workflow, the system automatically provides that resource when needed, handling all the lifecycle management for you. + +### Dependency Lifecycle and Resource Sharing + +**Important**: All dependencies defined with `Depends()` are initialized once when the worker starts up and then shared across all activity executions. This means: + +- **Single Instance**: The same instance is reused for every activity call +- **Resource Efficiency**: Reduces connection overhead and resource consumption +- **Connection Pooling**: Database connections, API clients, and other resources are maintained and reused + +This approach is particularly beneficial for: + +- **Database connections**: Avoids creating new connections for each query +- **API clients**: Maintains persistent connections and authentication +- **Configuration objects**: Loads configuration once and shares it across all activities + +## Defining Dependencies + +### Synchronous Function Provider + +For simple configuration values or objects that don't require async initialization: + +```python +def get_config() -> dict: + """Provides application configuration""" + return { + "timeout": 30, + "retries": 3, + "api_url": "https://api.example.com" + } +``` + +### Asynchronous Function Provider + +For dependencies that require async initialization, like database connections: + +```python +async def get_db_connection() -> DatabaseConnection: + """Creates and returns a database connection""" + conn = await DatabaseConnection.create("postgres://user:pass@localhost/db") + return conn +``` + +### Context Manager Provider + +For resources that need proper cleanup, like sessions that require logout: + +```python +from contextlib import contextmanager + +@contextmanager +def get_logged_in_session(): + """Provides a session with automatic login/logout""" + session = Session() + session.login() + try: + yield session + finally: + session.logout() +``` + +### Async Context Manager Provider + +For async resources that need cleanup, like database connections: + +```python +from contextlib import asynccontextmanager + +@asynccontextmanager +async def get_db_connection_with_cleanup(): + """Provides a database connection with proper cleanup""" + conn = await DatabaseConnection.create("postgres://...") + try: + yield conn + finally: + await conn.close() +``` + +### Generator Provider + +For streaming data or complex resource management: + +```python +def get_data_stream(): + """Provides a stream of data""" + with open("data.txt") as f: + for line in f: + yield line.strip() +``` + +### Async Generator Provider + +For async streaming data sources: + +```python +async def get_async_data_stream(): + """Provides an async stream of data""" + async with aiofiles.open("data.txt") as f: + async for line in f: + yield line.strip() +``` + +## Using Dependencies in Activities + +Activities can declare their dependencies using the `Depends()` marker. The system will automatically provide these dependencies when the activity executes: + +```python +import mistralai.workflows as workflows +from mistralai.workflows import Depends + +@workflows.activity() +async def create_user( + name: str, + db: DatabaseConnection = Depends(get_db_connection), + config: dict = Depends(get_config), + session: Session = Depends(get_logged_in_session) +): + """Creates a new user with all required dependencies""" + timeout = config["timeout"] + db.query( + "INSERT INTO users (name) VALUES ($1)", + name + ) + session.track_event("user_created", {"user_id": name}) + return {"status": "success", "timeout_used": timeout} +``` + +## Common Use Cases + +### Database Connections + +A more complete database connection example with proper session management: + +```python +async def get_db_connection(): + """Provides a database connection with proper cleanup""" + engine = await create_db_engine("postgres://...") + SessionLocal = async_sessionmaker(bind=engine, expire_on_commit=False) + + @asynccontextmanager + async def get_session() -> AsyncIterator[AsyncSession]: + async with SessionLocal() as session: + try: + yield session + finally: + await session.close() + + return get_session +``` + +### API Clients + +Example of a payment service client with initialization: + +```python +async def get_payment_client() -> PaymentServiceClient: + """Creates and initializes a payment service client""" + client = PaymentServiceClient(api_key="your_key") + await client.initialize() + return client +``` + +## Next Steps + +- [Workflow Guide](workflows) - Learn more about workflow fundamentals +- [Activity Guide](activities) - Understand how activities complement workflows diff --git a/.claude/skills/workflows/references/guides/durable-agents.mdx b/.claude/skills/workflows/references/guides/durable-agents.mdx new file mode 100644 index 000000000..f1ef472c4 --- /dev/null +++ b/.claude/skills/workflows/references/guides/durable-agents.mdx @@ -0,0 +1,403 @@ +--- +id: durable-agents +title: Durable Agents +sidebar_position: 8 +--- + +# Durable Agents: LLM Agents on Mistral Workflows + +Durable Agents allow you to run LLM agents within your Mistral workflows. + +## Installation + +To use Durable Agents, install the Mistral plugin: + +```bash +uv add 'mistralai-workflows[mistralai]' +``` + +## What is a Durable Agent? + +A Durable Agent is an LLM agent that executes within a workflow, benefiting from: + +- **Durability**: Agent state is preserved across failures and restarts +- **Tool Integration**: Use activities as agent tools +- **Multi-Agent Handoffs**: Agents can delegate tasks to specialized agents +- **MCP Support**: Connect to external tools via Model Context Protocol (stdio / SSE) + +## Architecture Overview + +```mermaid +flowchart TB + subgraph Runner["Runner"] + direction TB + R[Runner.run] + end + + subgraph Session["Session"] + S[RemoteSession / LocalSession] + end + + subgraph Coordinator["Coordinator Agent"] + CA[deal-coordinator] + end + + subgraph Specialists["Specialist Agents"] + RA[risk-agent] + CompA[compliance-agent] + end + + subgraph Activities["Activities"] + A1[parse_deal_document] + A2[calculate_risk_score] + A3[check_compliance] + end + + subgraph BuiltIn["Built-in Tools"] + T1[WebSearchTool] + end + + subgraph External["External"] + MCP[MCP Server] + end + + R -->|manages| S + S -->|runs| CA + CA -->|handoff| RA + CA -->|handoff| CompA + CA -->|uses| A1 + RA -->|uses| A2 + RA -->|connects| MCP + CompA -->|uses| A3 + CompA -->|uses| T1 +``` + +The Runner orchestrates agent execution through a Session. Agents can hand off tasks to specialized agents and each agent can use activities, built-in Mistral tools or MCP servers as tools. + +## Core Components + +### Agent + +The `Agent` class defines an LLM agent with its model, instructions, tools and handoffs: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="my-agent", + description="Agent that performs specific tasks", + instructions="Use tools to complete the user's request.", + tools=[my_activity], # Workflows activities as tools + handoffs=[other_agent], # Agents to delegate to +) +``` + +### Runner + +The `Runner` executes an agent with user inputs and manages the conversation loop: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +outputs = await workflows_mistralai.Runner.run( + agent=agent, + inputs="What is the interest rate for 2024?", + session=session, + max_turns=10, +) +``` + +### Sessions + +Sessions manage agent state and API communication. Two session types are available: + +| Session | Use Case | Backend | +| --------------- | -------------------------- | --------------------- | +| `RemoteSession` | Production (recommended) | Mistral Agents SDK | +| `LocalSession` | Experimental / On-premises | Direct completion API | + +## Basic Example + +Here's a simple agent workflow that uses an activity as a tool: + +```python +import mistralai +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +@workflows.activity() +async def get_interest_rate(year: int) -> dict: + """Get the interest rate for a given year. + + Args: + year: The year to get the interest rate for + """ + # Your implementation here + return {"interest_rate": 1.62} + +@workflows.workflow.define(name="finance_agent_workflow") +class FinanceAgentWorkflow: + @workflows.workflow.entrypoint + async def entrypoint(self, question: str) -> dict: + session = workflows_mistralai.RemoteSession() + + agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="finance-agent", + description="Agent for financial queries", + instructions="Use tools to answer financial questions.", + tools=[get_interest_rate], + ) + + outputs = await workflows_mistralai.Runner.run( + agent=agent, + inputs=question, + session=session, + ) + + answer = "\n".join([ + output.text for output in outputs + if isinstance(output, mistralai.TextChunk) + ]) + + return {"answer": answer} +``` + +## Multi-Agent Handoffs + +Agents can delegate tasks to specialized agents using handoffs. The system automatically manages the handoff conversation: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +## Create a specialized agent for interest rate queries +interest_rate_agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="ecb-interest-rate-agent", + description="Agent for European Central Bank interest rate research", + instructions="Use tools to get the interest rate for a given year.", + tools=[get_interest_rate], +) + +## Main agent that can hand off to the specialist +finance_agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="finance-agent", + description="Agent for financial queries", + handoffs=[interest_rate_agent], # Can delegate to interest_rate_agent +) + +outputs = await workflows_mistralai.Runner.run( + agent=finance_agent, + inputs="What was the ECB interest rate in 2023?", + session=workflows_mistralai.RemoteSession(), +) +``` + +When the finance agent receives a query about ECB interest rates, it can automatically hand off to the specialized `interest_rate_agent`. + +## MCP Integration + +Connect to external tool servers using the Model Context Protocol. Two transport types are supported: + +### Stdio MCP Server + +For local command-line MCP servers: + +```python +from mistralai.workflows.plugins.mistralai import MCPStdioConfig + +mcp_config = MCPStdioConfig( + command="npx", + args=["-y", "@modelcontextprotocol/server-everything"], + name="server-everything", +) + +agent = Agent( + model="mistral-medium-latest", + name="mcp-agent", + description="Agent with access to MCP tools", + mcp_clients=[mcp_config], +) +``` + +### SSE MCP Server + +For remote MCP servers over Server-Sent Events: + +```python +from mistralai.workflows.plugins.mistralai import MCPSSEConfig + +mcp_config = MCPSSEConfig( + url="https://your-mcp-server.com/sse", + timeout=60, + name="remote-tools", + headers={"Authorization": "Bearer your-token"}, # Optional +) + +agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="sse-mcp-agent", + description="Agent with access to remote MCP tools", + mcp_clients=[mcp_config], +) +``` + +## Built-in Tools + +Use Mistral's built-in tools alongside activities: + +```python +import mistralai +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="web-search-agent", + description="Agent with web search capability", + instructions="Use web search to answer user questions", + tools=[mistralai.WebSearchTool()], +) +``` + +Available built-in tools: + +- `mistralai.WebSearchTool()` - Web search capability +- `mistralai.CodeInterpreterTool()` - Code execution +- `mistralai.ImageGenerationTool()` - Image generation +- `mistralai.DocumentLibraryTool()` - Document analysis + +## Session Types + +### RemoteSession (Recommended) + +Uses the Mistral Agents SDK for production workloads: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +session = workflows_mistralai.RemoteSession() + +outputs = await workflows_mistralai.Runner.run( + agent=agent, + inputs="Your question here", + session=session, +) +``` + +Features: + +- Full Agents SDK integration +- Automatic agent creation and updates +- Managed conversation state +- Production-ready + +### LocalSession (Experimental) + +Runs agents locally using the completion endpoint: + +```python +import mistralai.workflows as workflows +import mistralai.workflows.plugins.mistralai as workflows_mistralai + +session = workflows_mistralai.LocalSession() + +outputs = await workflows_mistralai.Runner.run( + agent=agent, + inputs="Your question here", + session=session, +) +``` + +Use cases: + +- On-premises deployments that does not have access to Agents (Bora) +- Development and testing +- Full context control + +:::warning +`LocalSession` is experimental and may be removed in future versions. Use `RemoteSession` for production workloads. +::: + +## Complete Workflow Example + +A full example combining activities, handoffs and workflow orchestration: + +```python +import asyncio +import mistralai +import mistralai.workflows as workflows + +@workflows.activity() +async def calculate_risk_score(deal_type: str, amount: float) -> dict: + """Calculate financial risk score for a deal. + + Args: + deal_type: The type of deal being analyzed + amount: The monetary amount of the deal + """ + risk_score = min(100.0, amount / 10000.0) + risk_factors = [] + if amount > 100000: + risk_factors.append("High value transaction") + return {"risk_score": risk_score, "risk_factors": risk_factors} + +@workflows.workflow.define(name="deal_analysis_workflow") +class DealAnalysisWorkflow: + @workflows.workflow.entrypoint + async def entrypoint(self, deal_request: str) -> dict: + """Analyze a deal request. + + Args: + deal_request: The deal request to analyze + """ + session = workflows_mistralai.RemoteSession() + + # Risk assessment agent + risk_agent = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="risk-agent", + description="Analyzes financial risk of deals", + instructions="Use the risk calculation tool to assess deal risk.", + tools=[calculate_risk_score], + ) + + # Main coordinator agent + coordinator = workflows_mistralai.Agent( + model="mistral-medium-latest", + name="deal-coordinator", + description="Coordinates deal analysis", + instructions="Analyze the deal request and hand off to specialists.", + handoffs=[risk_agent], + ) + + outputs = await workflows_mistralai.Runner.run( + agent=coordinator, + inputs=deal_request, + session=session, + ) + + analysis = "\n".join([ + output.text for output in outputs + if isinstance(output, mistralai.TextChunk) + ]) + + return {"analysis": analysis} + +if __name__ == "__main__": + asyncio.run(workflows.run_worker([DealAnalysisWorkflow])) +``` + +## Best Practices + +1. **Use RemoteSession for production** - It provides better reliability and Agents SDK integration +2. **Keep activities granular** - Small, focused activities work better as agent tools +3. **Provide clear instructions** - Agent performance depends on clear instructions +4. **Use handoffs for specialization** - Create specialized agents for specific domains and improve context management by delegating tasks +5. **Handle tool errors gracefully** - Activities used as tools should return meaningful error messages diff --git a/.claude/skills/workflows/references/guides/error-codes.mdx b/.claude/skills/workflows/references/guides/error-codes.mdx new file mode 100644 index 000000000..7484dffb1 --- /dev/null +++ b/.claude/skills/workflows/references/guides/error-codes.mdx @@ -0,0 +1,219 @@ +--- +id: error-codes +title: API Error Codes +sidebar_position: 3 +--- + +# API Error Codes + +When a request to the Workflows API fails, the response includes a structured error code in `WF_XXXX` format: + +```json +{ + "detail": "Workflow execution not found", + "code": "WF_1100" +} +``` + +For **4xx** errors, `detail` contains a specific message describing what went wrong. For **5xx** errors, `detail` is always `"An error occurred"` — the actual cause is logged server-side. + +## Quick Lookup + +| Code | Name | HTTP Status | Category | +|------|------|-------------|----------| +| [WF_1000](#wf_1000) | Unknown Error | 500 | General | +| [WF_1001](#wf_1001) | Invalid Request | 422 | General | +| [WF_1100](#wf_1100) | Workflow Not Found | 404 | Workflow | +| [WF_1101](#wf_1101) | Workflow Already Started | 409 | Workflow | +| [WF_1102](#wf_1102) | Workflow Not Running | 409 | Workflow | +| [WF_1103](#wf_1103) | Temporal Request Failed | 500 / 504 | Workflow | +| [WF_1104](#wf_1104) | Workflow Registration Failed | 500 | Workflow | +| [WF_1105](#wf_1105) | Execution Not Found | 500 | Workflow | +| [WF_1200](#wf_1200) | Schedule Failed | 422 / 500 / 503 | Schedule | +| [WF_1201](#wf_1201) | Schedule Not Found | 404 | Schedule | +| [WF_1300](#wf_1300) | Temporal Client Creation Failed | 500 | Temporal | +| [WF_1301](#wf_1301) | Temporal Initialization Failed | 500 | Temporal | +| [WF_1302](#wf_1302) | Temporal Payload Encoding Required | 500 | Temporal | +| [WF_1400](#wf_1400) | NATS Error | 500 | Streaming | +| [WF_1500](#wf_1500) | Trace Error | 500 | Tracing | +| [WF_1600](#wf_1600) | Event Store Error | 500 | Event Store | + +--- + +## General Errors (1000–1099) + +### WF_1000 + +**Unknown Error** · `500 Internal Server Error` + +A catch-all for errors that don't map to a specific code. If you see this, check server logs or contact the platform team. + +### WF_1001 + +**Invalid Request** · `422 Unprocessable Entity` + +The request was well-formed but contained invalid data. Currently returned when providing an invalid event ID during a workflow reset — the response includes a `valid_reset_events` field listing valid alternatives. + +```json +{ + "detail": "Invalid event ID for reset", + "code": "WF_1001", + "valid_reset_events": [3, 7, 12] +} +``` + +--- + +## Workflow Errors (1100–1199) + +### WF_1100 + +**Workflow Not Found** · `404 Not Found` + +The workflow execution does not exist in Temporal. This usually means the execution ID is wrong or the workflow has been purged. + +**Resolution:** Verify the execution ID. Check the [Workflows Dashboard](https://workflows.mistral.ai) for the correct ID. + +### WF_1101 + +**Workflow Already Started** · `409 Conflict` + +A workflow execution with the same ID is already running. Workflow IDs must be unique within a namespace. + +**Resolution:** Use a different execution ID, or wait for the existing execution to complete. If you need to restart it, terminate the running execution first. + +### WF_1102 + +**Workflow Not Running** · `409 Conflict` + +You attempted an action (signal, query, update, or terminate) on a workflow that is no longer running. The response includes the current workflow status. + +```json +{ + "detail": "Workflow not running", + "code": "WF_1102", + "status": "COMPLETED" +} +``` + +**Resolution:** Check the workflow's current status. If it completed or failed, start a new execution instead. + +### WF_1103 + +**Temporal Request Failed** · `500 Internal Server Error` or `504 Gateway Timeout` + +The underlying Temporal RPC call failed. This covers connection issues, timeouts, and unexpected Temporal errors. A `504` specifically indicates a deadline exceeded (the operation took too long). + +**Resolution:** Retry the request. If the issue persists, check Temporal cluster health. + +### WF_1104 + +**Workflow Registration Failed** · `500 Internal Server Error` + +Worker registration failed — the system could not register workflow definitions. This typically indicates a mismatch between workflow specs and version identifiers during worker startup. + +**Resolution:** Check worker logs for registration errors. Verify that workflow definitions are valid and that the worker can reach the API. + +### WF_1105 + +**Execution Not Found** · `500 Internal Server Error` + +An execution that was expected to exist could not be found. Unlike `WF_1100` (which is a 404 for user-facing lookups), this indicates an internal inconsistency — the execution should have existed at this point in the flow. + +**Resolution:** This is an internal error. If it persists, report it to the platform team. + +--- + +## Schedule Errors (1200–1299) + +### WF_1200 + +**Schedule Failed** · `422` / `500` / `503` + +Schedule creation or management failed. The HTTP status varies by cause: + +| Status | Cause | +|--------|-------| +| **422** | Invalid schedule specification (bad cron expression, invalid arguments) or attempting to schedule a workflow with offloaded payloads | +| **503** | Search attributes not yet available for the namespace — a transient error during namespace setup | +| **500** | Other internal failures during schedule creation or deletion | + +**Resolution:** For `422`, check your cron expression and input payload size. For `503`, retry after a few seconds. For `500`, check server logs. + +### WF_1201 + +**Schedule Not Found** · `404 Not Found` + +The schedule ID does not exist. It may have already been deleted or never created. + +**Resolution:** List existing schedules to find the correct ID. + +--- + +## Temporal Errors (1300–1399) + +### WF_1300 + +**Temporal Client Creation Failed** · `500 Internal Server Error` + +The system failed to construct a Temporal client, usually due to configuration issues (bad address, invalid credentials). + +**Resolution:** Check Temporal connection configuration (host, port, TLS settings, namespace). + +### WF_1301 + +**Temporal Initialization Failed** · `500 Internal Server Error` + +Namespace creation or search attribute registration failed during Temporal initialization. This happens during system startup. + +**Resolution:** Verify Temporal cluster health and that the namespace configuration is valid. + +### WF_1302 + +**Temporal Payload Encoding Required** · `500 Internal Server Error` + +Payload encoding is enforced but the input data was not encoded. This occurs in deployments where `temporal.enforce_payload_encoding` is enabled (typically hybrid deployments where data must stay encrypted). + +**Resolution:** Ensure your client is using the payload codec. See [Payload Encoding](../appendices/payload-encoding) for details. + +--- + +## Streaming Errors (1400–1499) + +### WF_1400 + +**NATS Error** · `500 Internal Server Error` + +A NATS operation failed — connection, publishing, or reading from a stream. + +**Resolution:** Check NATS connectivity and that `NATS_ENABLED=true` and `NATS_HOST` are set correctly. See [Streaming](streaming) for configuration details. + +--- + +## Tracing Errors (1500–1599) + +### WF_1500 + +**Trace Error** · `500 Internal Server Error` + +Failed to retrieve or parse traces from the Tempo backend. This can mean missing spans, malformed trace data, or connectivity issues with the trace provider. + +**Resolution:** Check Tempo/tracing backend health. If traces are missing, the workflow may not have emitted spans yet — wait and retry. + +--- + +## Event Store Errors (1600–1699) + +### WF_1600 + +**Event Store Error** · `500 Internal Server Error` + +A database consistency error in the event store, typically when an expected event cannot be found after a conflict. + +**Resolution:** This is an internal error. Retry the operation. If it persists, report it to the platform team. + +--- + +## SDK Error Codes + +The Python SDK (`mistralai-workflows`) has its own set of error codes for worker-side errors (invalid workflow definitions, activity configuration issues, etc.). These are different from the API error codes above and are documented in the [Workflows Exception](workflows-exception) guide. diff --git a/.claude/skills/workflows/references/guides/handling-large-data.mdx b/.claude/skills/workflows/references/guides/handling-large-data.mdx new file mode 100644 index 000000000..f1f4cbecd --- /dev/null +++ b/.claude/skills/workflows/references/guides/handling-large-data.mdx @@ -0,0 +1,140 @@ +--- +id: ha +title: How to handle large data +sidebar_position: 9 +--- + +# Handling Large Payloads with Offloaded Attributes in Workflows + +This guide explains how to use the **offloaded attribute** feature in Workflows to handle large payloads efficiently between activities, especially when dealing with Temporal's 2MB payload limit. + +## **Why Use Offloaded Attributes?** + +Temporal enforces a **2MB payload limit** for workflows and activities. To work around this, Workflows allows you to **offload large payloads** to blob storage. This ensures that your activities can handle large data without hitting Temporal's size restrictions. + +Offloaded attributes is the preferred way to handle large payloads in your activities. +Note that this differs from payload offloading which makes the payload available within the workflow itself, but is far less efficient. + +**Key Points:** + +- Offloaded values are **not accessible** in the workflow context (e.g., during workflow runs, signals, updates, or queries). +- Upload and download of offloaded data happen **within the activity context**, so timeouts are governed by the activity's own timeout settings. +- Each `OffloadableField` is stored as a separate blob. For performance, **group related fields** in a single Pydantic class if they are always used together. + +## Prerequisites + +To use offloaded attributes, you need to install the Workflows SDK with the appropriate cloud storage provider: + +```bash +## For AWS S3 +uv add "mistralai-workflows[s3]" + +## For Azure Blob Storage +uv add "mistralai-workflows[azure]" + +## For Google Cloud Storage +uv add "mistralai-workflows[gcs]" + +## Or install all storage providers +uv add "mistralai-workflows[storage]" +``` + +See the [installation guide](../getting-started/installation#cloud-storage-providers) for more details. + +## Config + +:::info +Blob storage bucket/container must have an **expiry policy** as Workflows does not automatically delete payloads. + +Align the expiry with your Temporal workflow retention period (default: 30 days). + +Blobs are prefixed by `temporal-activity-payload/`, allowing per-namespace policies. +::: + +If you use the **starter-app**, use these environment variables to configure blob storage: + +``` +## Azure: +ACTIVITY_ATTRIBUTES_OFFLOADING__ENABLED=true +ACTIVITY_ATTRIBUTES_OFFLOADING__MIN_SIZE_BYTES=1048576 # 1MB +ACTIVITY_ATTRIBUTES_OFFLOADING__STORAGE_CONFIG__STORAGE_PROVIDER=azure +ACTIVITY_ATTRIBUTES_OFFLOADING__STORAGE_CONFIG__CONTAINER_NAME=XXX +ACTIVITY_ATTRIBUTES_OFFLOADING__STORAGE_CONFIG__AZURE_CONNECTION_STRING=XXX +``` + +## **How to Define Offloadable Fields** + +To define a field as offloadable, use the `OffloadableField` type in your Pydantic model: + +```python +from mistralai.workflows.core.encoding.fields_offloader import OffloadableModel, OffloadableField + +class MyPayload(OffloadableModel): + random_field: str # Regular field (not offloaded) + large_field: OffloadableField[str] = OffloadableField(value="Hello World") # Offloadable +``` + +## **Using Offloadable Fields in Activities** + +In your activity, access the offloaded value using the `get_value()` method. +The system handles offloading and restoration automatically: + +```python +@workflows.activity(display_name="Append string to file") +async def my_activity(params: MyPayload) -> MyPayload: + # Access the offloaded value using get_value() + logger.info("Large field value", value=params.large_field.get_value()) + + # Return a new payload with the updated value + return MyPayload( + random_field="activity_return", + large_field=OffloadableField(value=params.large_field.get_value() + "_updated") + ) +``` + +## **Using Offloadable Fields in Workflows** + +In the workflow context, **do not** access the `get_value()` method of offloaded fields. Instead, pass the `OffloadableField` object directly to the next activity: + +```python +@workflows.workflow.define(name="sub-workflow") +def my_workflow(...): + # Call an activity with an offloadable field + activity_result = await my_activity( + MyPayload( + random_field="activity_param", + large_field=OffloadableField(value="initial_small_value") + ) + ) + + # Pass the offloaded field to the next activity + next_activity_params = MyPayload( + random_field="second_activity_param", + # OK: Pass the OffloadableField object directly + large_field=activity_result.large_field + ) + + # DO NOT: Try to access the value in the workflow context as it could be offloaded + # large_field=OffloadableField(value=activity_result.large_field.get_value()) + + await my_activity(next_activity_params) +``` + +## **Performance Optimization: Grouping Offloadable Fields** + +Each `OffloadableField` is stored as a **separate blob** in blob storage. To optimize performance, especially when multiple fields are always used together, **group them into a single Pydantic class**. This reduces the number of blob storage operations and improves efficiency. + +**Example:** + +```python +from mistralai.workflows.core.encoding.fields_offloader import OffloadableModel, OffloadableField +from pydantic import BaseModel + +class LargeDataGroup(BaseModel): + field1: str + field2: bytes + field3: dict[str, str] + +class MyPayload(OffloadableModel): + large_data: OffloadableField[LargeDataGroup] # Single offloaded group +``` diff --git a/.claude/skills/workflows/references/guides/limitations.mdx b/.claude/skills/workflows/references/guides/limitations.mdx new file mode 100644 index 000000000..4876c7079 --- /dev/null +++ b/.claude/skills/workflows/references/guides/limitations.mdx @@ -0,0 +1,255 @@ +--- +id: limitations +title: System Limitations +sidebar_position: 3 +--- + +# Limitations + +This document outlines the key constraints and requirements when working with workflows and activities in the system. Understanding these limitations helps you design robust and efficient applications. + +## Workflow Limitations + +Workflows should focus on orchestration logic, keeping operations deterministic and fast (under 2 seconds between activities), while delegating all I/O, non-deterministic operations, and heavy computations to activities. + +### Timeout of 2 seconds between activities + +Workflows must complete CPU-intensive operations within 2 seconds between activity invocations. This means: + +- Workflow code itself must execute quickly +- Heavy computations should be moved to activities (with appropriate `start_to_close_timeout`, [see more](#set-appropriate-timeouts)) +- The 2-second limit applies to the workflow's processing time between activity calls + +_Why?_ Workflows are designed for orchestration rather than heavy computation. The 2-second limit ensures quick recovery/resume from the last checkpoint, as the system creates checkpoints at each activity call. + +**Operations that should be moved to activities** (not done in workflows): + +- Large data validation + +```python +## ❌ Wrong - Should be in an activity +Dataset.model_validate(large_amount_of_data) +``` + +- Complex computations + +```python +## ❌ Wrong - Should be in an activity +sum([x for x in range(1000000)]) +``` + +- Cryptographic operations + +```python +## ❌ Wrong - Should be in an activity +hashlib.sha256(large_data).hexdigest() +``` + +- Heavy data transformations + +```python +## ❌ Wrong - Should be in an activity +map(lambda x: x * 2, large_list) +``` + +- Any operation that might exceed 2 seconds of CPU time + +### No I/O operations + +**All I/O operations must be performed in activities.** This includes: + +- Network calls (HTTP, gRPC, database queries) + +```python +## ❌ Wrong - Should be in an activity +await conn.execute("SELECT * FROM users") +``` + +- File system operations + +```python +## ❌ Wrong - Should be in an activity +async with aiofiles.open("file.txt", mode="r") as f: + contents = await f.read() +``` + +- Any external system interactions + +```python +## ❌ Wrong - Should be in an activity +await client.send_message("Hello") +``` + +_Why?_ Workflow code may be replayed during recovery, and I/O operations would violate determinism requirements. + +### Allowed long-running operations + +Workflows can safely perform these operations that don't block execution: + +- Activity execution (which can run much longer, [see Activity Limitations](#activity-limitations)) + ```python + # ✅ Correct - Activity can run for hours + result = await my_activity(...) + ``` +- Waiting for conditions + ```python + # ✅ Correct - Can wait for years + await workflows.workflow.wait_condition(lambda: self.processing_complete) + ``` +- Timed delays + ```python + # ✅ Correct - Can sleep for years + await asyncio.sleep(60 * 60 * 24 * 365) + ``` +- Child workflows + ```python + # ✅ Correct - Can run for at most 1 year (see `execution_timeout`) + child_result = await workflows.workflow.execute_workflow( + workflow=MyWorkflow, + params=MyWorkflowParams(...), + execution_timeout=timedelta(days=365) + ) + ``` + +### Code must be deterministic + +Workflow code must be deterministic - given the same activity history and inputs, it must produce the same outputs. This means that any non-deterministic operations like: + +- Generating random numbers + +```python +## ❌ Wrong - Non-deterministic +if random.random() > 0.5: + ... +else: + ... +``` + +- Getting current time + +```python +## ❌ Wrong - Non-deterministic +import time + +await my_activity(time.time()) +``` + +- Reading environment variables + +```python +## ❌ Wrong - Non-deterministic +if os.getenv("ENV") == "prod": + ... +``` + +must be performed in activities. While activities themselves can produce different outputs for the same inputs (as they might contain non-deterministic operations), the workflow code must behave deterministically based on the activity results it receives. + +### Maximum Execution History + +The execution history for each workflow is capped at 51,200 events or 50MB per workflow execution. This limit is again due to temporal's current constraints. In order to avoid hitting this limit, we recommend using `workflows.execute_activities_in_parallel`, that allows you to execute large amounts of activities in parallel, while having the lowest footprint on the execution history. [Learn more about concurrency patterns](concurrency). + +## Activity Limitations + +Activities are where you should perform all non-deterministic, I/O-bound, or CPU-intensive operations. Here's how to properly structure activity code: + +### Perform all I/O operations + +Activities are the proper place for all I/O operations, including: + +- Database queries + +```python +@workflows.activity() +async def query_database( + params: QueryParams, + conn: asyncpg.Connection = Depends(get_db_connection), +) -> QueryResult: + # ✅ Correct - I/O in activity + return await conn.fetch(params.query) +``` + +- API calls + +```python +@workflows.activity() +async def call_external_api(params: ApiParams) -> ApiResponse: + # ✅ Correct - network I/O in activity + async with httpx.AsyncClient() as client: + response = await client.post(params.url, json=params.data) + return ApiResponse(data=response.json()) +``` + +- File operations + +```python +@workflows.activity() +async def process_file(params: FileParams) -> FileResult: + # ✅ Correct - file I/O in activity + async with aiofiles.open(params.path, mode='r') as f: + contents = await f.read() + return FileResult(content=contents) +``` + +### Handle CPU-intensive operations + +Move all heavy computations to activities: + +```python +@workflows.activity() +def process_large_dataset(params: DatasetParams) -> ProcessedResult: + # ✅ Correct - heavy computation in activity + large_dataset = await load_large_dataset(params.dataset_id) + processed = [transform(x) for x in large_dataset] + return ProcessedResult(data=processed) +``` + +### Use non-deterministic operations + +Activities can safely use non-deterministic operations: + +```python +@workflows.activity() +def get_current_time_with_id(params: TimeParams) -> TimeResult: + # ✅ Correct - non-deterministic operations in activity + current_time = datetime.now().isoformat() + random_id = str(uuid.uuid4()) + return TimeResult(id=random_id, timestamp=current_time, timezone=params.timezone) +``` + +### Set appropriate timeouts + +Configure timeouts based on operation characteristics: + +```python +@workflows.activity(start_to_close_timeout=timedelta(hours=1)) +async def long_running_process(params: ProcessParams) -> ProcessResult: + # ✅ Correct - long operation with appropriate timeout + result = await perform_complex_operation(params) + return ProcessResult(data=result) +``` + +### Asynchronous Requirement + +**All your code must be asynchronous or extremely CPU-bound.** This means: + +1. **For I/O operations (network calls, file operations, etc.), always use async libraries:** + + ✅ **Do use:** + + - `httpx.AsyncClient` or `aiohttp` instead of synchronous `requests` + - `aiofiles` instead of `open()` for file operations + - Async database drivers (e.g., `sqlalchemy.ext.asyncio`) + + ❌ **Don’t use:** + + - Synchronous `requests` for HTTP calls + - Blocking `open()` for file operations + - Synchronous database drivers (e.g., `sqlalchemy`) + +2. For CPU-bound operations that cannot be made async, ensure they're implemented in activities with appropriate timeouts. + +## Additional Considerations + +Most limitations stem from Temporal's underlying architecture. For comprehensive details, refer to the [official Temporal documentation](https://docs.temporal.io/workflow-execution/limits). + +When designing workflows, remember that workflow code is replayed during recovery, so keep logic simple and deterministic, while moving complex operations and all I/O to activities. diff --git a/.claude/skills/workflows/references/guides/local-execution.mdx b/.claude/skills/workflows/references/guides/local-execution.mdx new file mode 100644 index 000000000..8755c921a --- /dev/null +++ b/.claude/skills/workflows/references/guides/local-execution.mdx @@ -0,0 +1,172 @@ +--- +id: local-execution +title: Local Execution +sidebar_position: 10 +--- + +# Local Execution + +Run workflows and activities directly without infrastructure. Useful for quick iteration during development. + +## Why Use Local Execution + +Local execution enables running workflow code without deploying infrastructure: + +- **Rapid prototyping** - Iterate on activity/workflow logic before infrastructure is ready +- **Pure logic validation** - Verify business logic in isolation +- **CI checks** - Run lightweight tests that don't need durability guarantees + +:::warning +Local execution is limited to prototyping. It cannot replicate distributed capabilities like durability, streaming, or human-in-the-loop patterns. Move to full deployment as soon as possible. +::: + +## Executing Workflows Locally + +Use `workflows.execute_workflow()` to run workflows locally: + +```python +import mistralai.workflows as workflows +from pydantic import BaseModel + +@workflows.activity() +async def validate_data(data_id: str) -> bool: + return True + +@workflows.activity() +async def process_data(data_id: str) -> dict: + return {"processed_id": data_id, "status": "done"} + +class DataProcessingParams(BaseModel): + data_id: str + validate_first: bool = True + +@workflows.workflow.define(name="data-processing") +class DataProcessingWorkflow: + @workflows.workflow.entrypoint + async def run(self, data_id: str, validate_first: bool = True) -> dict: + if validate_first and not await validate_data(data_id): + raise ValueError("Validation failed") + return await process_data(data_id) + +## Local execution — params must be a Pydantic model, not a dict +result = await workflows.execute_workflow( + DataProcessingWorkflow, + params=DataProcessingParams(data_id="item-123", validate_first=True) +) +``` + +### Nested Workflows + +Child workflows via `workflows.execute_workflow()` execute directly in local mode: + +```python +import mistralai.workflows as workflows +from pydantic import BaseModel + +class ChildParams(BaseModel): + value: str + +class ParentParams(BaseModel): + data: str + +@workflows.workflow.define(name="child") +class ChildWorkflow: + @workflows.workflow.entrypoint + async def run(self, value: str) -> str: + return f"Child: {value}" + +@workflows.workflow.define(name="parent") +class ParentWorkflow: + @workflows.workflow.entrypoint + async def run(self, data: str) -> str: + child_result = await workflows.execute_workflow( + ChildWorkflow, params=ChildParams(value=data) + ) + return f"Parent got: {child_result}" + +## Full chain executes locally +result = await workflows.execute_workflow(ParentWorkflow, params=ParentParams(data="test")) +``` + +## Executing Activities Locally + +Activities called outside workflows execute directly with: + +- **Automatic retries** via tenacity (respects `retry_policy_max_attempts`, `retry_policy_backoff_coefficient`) +- **Dependency injection** - `Depends()` resolved automatically +- **Type validation** - Input/output types are validated +- **Nested calls** - Only outermost activity applies retry logic + +```python +import mistralai.workflows as workflows +from mistralai.workflows import Depends + +class HttpClient: + def __init__(self, timeout: int): + self.timeout = timeout + + async def get(self, path: str) -> dict: + return {"id": "123", "name": "Test User"} + +async def get_client() -> HttpClient: + return HttpClient(timeout=30) + +@workflows.activity(retry_policy_max_attempts=3) +async def fetch_user( + user_id: str, + client: HttpClient = Depends(get_client) +) -> dict: + return await client.get(f"/users/{user_id}") + +## Retries and DI work locally +user = await fetch_user("123") +``` + +## Tradeoffs: What You Lose + +Local execution cannot replicate distributed capabilities: + +| Feature | Local | Full Deployment | Impact | +| ---------------------------- | ---------------- | ------------------- | -------------------------------------- | +| **Durability** | ❌ None | ✅ Full history | Crash = lost state, no replay | +| **Streaming** | ❌ No events | ✅ Real-time events | No `Task` events, no progress tracking | +| **HITL (Human-in-the-Loop)** | ❌ Not supported | ✅ Signals/Updates | Cannot pause for human input | +| **Signals** | ❌ | ✅ | No external event injection | +| **Queries** | ❌ | ✅ | Cannot inspect running state | +| **Updates** | ❌ | ✅ | No synchronous state mutations | +| **Scheduling** | ❌ | ✅ | No cron/interval triggers | +| **`wait_condition`** | ❌ Throws | ✅ Works | Workflow primitives fail locally | +| **Failure Recovery** | ❌ | ✅ | No automatic checkpoint resume | +| **Event History** | ❌ | ✅ | No UI debugging | +| **Rate Limiting** | ⚠️ Local only | ✅ Distributed | No cross-worker coordination | +| **Worker Stickiness** | ⚠️ No-op | ✅ Works | Always same "worker" | + +### Critical Limitations + +**No Streaming/Observability**: The `Task` system emits events to the Workflows API. Locally, `should_publish_event()` returns false—no events are published. Progress tracking, custom task states, and real-time updates don't work. + +**No Human-in-the-Loop**: Patterns relying on signals (`workflow.signal`), updates (`workflow.update`), or external triggers cannot run locally. The workflow runs to completion without pause points. + +**No Timeout Enforcement**: `start_to_close_timeout` is respected but not enforced at system level. Runaway activities won't be killed. + +## How It Works + +The SDK detects execution context via `temporalio.workflow.in_workflow()`. Outside a workflow context, activities and workflows execute as regular Python async functions with retry wrappers. + +```python +import mistralai.workflows as workflows + +@workflows.activity() +async def send_email(to: str, subject: str, body: str) -> dict: + return {"message_id": "msg-123"} + +## Direct call - executes locally with retry logic +result = await send_email("user@example.com", "Hello", "Test message") +``` + +## Next Steps + +- [Activities](./activities) - Activity patterns and configuration +- [Workflows](./workflows) - Workflow fundamentals +- [Signals & Queries](./signals-queries-updates) - External interaction (requires deployment) +- [Streaming](./streaming) - Real-time event streaming (requires deployment) diff --git a/.claude/skills/workflows/references/guides/migration-v2-to-v3.mdx b/.claude/skills/workflows/references/guides/migration-v2-to-v3.mdx new file mode 100644 index 000000000..49bdc89eb --- /dev/null +++ b/.claude/skills/workflows/references/guides/migration-v2-to-v3.mdx @@ -0,0 +1,213 @@ +# Migrating from v2.0 to v3.0 + +## Package Namespace Migration + +The SDK package namespace has changed from `mistralai_workflows` to `mistralai.workflows`. Update all imports: + +```python +# ❌ OLD +from mistralai_workflows import workflow, activity, run_worker +from mistralai_workflows.task import task + +# ✅ NEW +from mistralai.workflows import workflow, activity, run_worker +from mistralai.workflows.task import task +``` + +This applies to all submodules (plugins, models, core, etc.). + +## Removed Deprecated APIs + +The following deprecated APIs have been removed. Code using them will fail at import or runtime. + +| Removed | Replacement | +|---------|-------------| +| `@activity(activity_name="...")` | `@activity(name="...")` | +| `@activity(display_name="...")` | Remove (no replacement) | +| `@activity(_extends=...)` | Remove (singledispatch extension mechanism removed) | +| `@workflow.define(workflow_name="...")` | `@workflow.define(name="...")` (`name` is now a required positional argument) | +| `record_event()` | Use the `task` context manager from `mistralai.workflows.task` | +| `record_event_progress()` | Use the `task` context manager | +| `record_event_progress_function()` | Use the `task` context manager | + +### `@workflow.define` — `name` is now required + +```python +# ❌ OLD +@workflow.define(workflow_name="my-workflow") + +# ❌ ALSO BROKEN (name was optional before) +@workflow.define() + +# ✅ NEW +@workflow.define("my-workflow") +# or +@workflow.define(name="my-workflow") +``` + +## Default Execution Timeout + +Workflow executions now have a **default timeout of 1 hour**. Previously there was no default, which could cause infinite retries when no workers were active. + +If your workflows run longer than 1 hour, set an explicit timeout: + +```python +@workflow.define("my-long-workflow", execution_timeout=timedelta(hours=4)) +``` + +This also applies to child workflows: + +```python +await execute_workflow(MyChildWorkflow, params, execution_timeout=timedelta(hours=2)) +``` + +## Determinism Enforcement Enabled by Default + +The Temporal sandbox is now enabled by default to catch non-deterministic workflow code (e.g., using `datetime.now()`, `random`, or unrestricted imports in workflow methods). + +If your workflows are not yet determinism-safe, you can disable enforcement: + +**Per-workflow:** +```python +@workflow.define("my-workflow", enforce_determinism=False) +``` + +**Globally (environment variable):** +```bash +DEFAULT_ENFORCE_DETERMINISM=0 +``` + +For workflows that need to opt out of the sandbox for specific imports, use the re-exported Temporal utilities on `workflow.unsafe`: +```python +from mistralai.workflows import workflow + +with workflow.unsafe.imports_passed_through(): + import some_non_deterministic_module +``` + +## Child Workflow `execution_timeout` Fix + +The `execution_timeout` parameter on `execute_workflow()` was previously incorrectly passed as `task_timeout` to Temporal, meaning it limited a single task rather than the full execution. This is now fixed — `execution_timeout` controls the total execution time including retries and continue-as-new. + +**Action required:** If you were relying on the old (incorrect) behavior where `execution_timeout` acted as a per-task timeout, adjust your timeout values accordingly. + +## `WorkflowVersion` Renamed to `WorkflowRegistration` + +The `WorkflowVersion` model has been renamed to `WorkflowRegistration` across the SDK. The server accepts both old and new field names during a transition period, but SDK code should be updated: + +| v2 | v3 | +|----|-----| +| `WorkflowVersion` | `WorkflowRegistration` | +| `workflow_version_id` | `workflow_registration_id` | +| `workflow_version_ids` | `workflow_registration_ids` | + +## Deployment-Based Task Queue Routing + +Workers now use `DEPLOYMENT_NAME` as the Temporal task queue name. The old `TEMPORAL_TASK_QUEUE` environment variable is kept for backwards compatibility but raises an error if it conflicts with `DEPLOYMENT_NAME`. + +**Versioned workers** (with `deployment_name` and `build_id`) are forbidden from using the `default` task queue to prevent Temporal versioning conflicts. + +--- + + +## `WorkflowsClient` Removed + +`WorkflowsClient` has been removed entirely. All workflow operations now go through the Mistral SDK client (`mistral_client`). + +### Creating a client + +```python +# ❌ OLD +from mistralai.workflows import WorkflowsClient + +client = WorkflowsClient( + base_url="https://api.mistral.ai", + api_version="v1", + api_key="your-key", +) + +# ✅ NEW +from mistralai.workflows.client import get_mistral_client + +mistral_client = get_mistral_client() +``` + +### Executing a workflow + +```python +# ❌ OLD +async with WorkflowsClient(base_url=..., api_key=...) as client: + await client.execute_workflow( + workflow_identifier="my-workflow", + input_data=params, + execution_id=exec_id, + task_queue=task_queue, + ) + +# ✅ NEW +mistral_client = get_mistral_client() +await mistral_client.workflows.execute_workflow_async( + workflow_identifier="my-workflow", + input=params.model_dump(mode="json"), + execution_id=exec_id, + task_queue=task_queue, +) +``` + +### Waiting for workflow completion + +```python +# ❌ OLD +result = await client.execute_workflow_and_wait( + workflow_identifier="my-workflow", + input_data=params, +) + +# ✅ NEW +result = await mistral_client.workflows.execute_workflow_and_wait_async( + workflow_identifier="my-workflow", + input=params.model_dump(mode="json"), +) +``` + +### Scheduling a workflow + +```python +# ❌ OLD +await client.schedule_workflow( + schedule=schedule_def, + workflow_identifier="my-workflow", +) + +# ✅ NEW +await mistral_client.workflows.schedule_workflow_async( + schedule=schedule_def.model_dump(mode="json"), + workflow_identifier="my-workflow", +) +``` + +### Streaming workflow events + +```python +# ❌ OLD +async for event in client.stream_events(execution_id=exec_id): + ... + +# ✅ NEW +from mistralai.workflows.client import stream_workflow_events + +async for event in stream_workflow_events(mistral_client, execution_id=exec_id): + ... +``` + +### Import changes + +| v2 | v3 | +|----|-----| +| `from mistralai.workflows import WorkflowsClient` | `from mistralai.workflows.client import get_mistral_client` | +| `WorkflowsClient(base_url=..., api_key=...)` | `get_mistral_client(server_url=..., api_key=...)` | +| `client.execute_workflow(...)` | `mistral_client.workflows.execute_workflow_async(...)` | +| `client.execute_workflow_and_wait(...)` | `mistral_client.workflows.execute_workflow_and_wait_async(...)` | +| `client.schedule_workflow(...)` | `mistral_client.workflows.schedule_workflow_async(...)` | +| `client.stream_events(...)` | `stream_workflow_events(mistral_client, ...)` | + diff --git a/.claude/skills/workflows/references/guides/observability.mdx b/.claude/skills/workflows/references/guides/observability.mdx new file mode 100644 index 000000000..e3cf0fcf8 --- /dev/null +++ b/.claude/skills/workflows/references/guides/observability.mdx @@ -0,0 +1,45 @@ +--- +id: observabilities +title: Workflow Observability +sidebar_position: 6 +--- + +# Workflow Observability + +This guide focuses on OpenTelemetry traces for execution-level diagnostics. If you need custom lifecycle and progress events emitted into workflow history for external consumers, see the [Task Events](../task-events) guide. + +## Traces (OpenTelemetry) + +Traces capture execution details (spans, timings, errors) and are optimized for debugging and performance analysis. They are independent from custom task events. + +### Activity Observability + +Activities automatically generate spans. Use the `name` parameter to make them more readable: + +```python +@workflows.activity(name="Processing customer emails") +async def process_emails(params: ActivityParams) -> ActivityResult: + # Your activity code +``` + +### Trace Sampling + +Trace collection is sampled. By default the worker uses a parent-based sampler with a configurable sample rate, so upstream decisions can be honored. + +**TL;DR:** For the finest control of sampling, pass a `traceparent` header at your workflow entry point (or API edge). This lets you force sampling on or off and propagate the parent trace consistently. + +### Fetching Workflow Traces + +```python +## Get trace data +trace = await client.workflows.executions.get_workflow_execution_trace_otel_async(execution_id) + +## Get trace summary +summary = await client.workflows.executions.get_workflow_execution_trace_summary_async(execution_id) + +## Get detailed events +events = await client.workflows.executions.get_workflow_execution_trace_events_async( + execution_id, + include_internal_events=False # Hide system events +) +``` diff --git a/.claude/skills/workflows/references/guides/payload-encoding.mdx b/.claude/skills/workflows/references/guides/payload-encoding.mdx new file mode 100644 index 000000000..b1c59955b --- /dev/null +++ b/.claude/skills/workflows/references/guides/payload-encoding.mdx @@ -0,0 +1,251 @@ +--- +id: payload-encoding +title: Payload encoding +sidebar_position: 4 +--- + +# Payload Encoding + +## Overview + +The **payload encoding process** enables seamless processing of payloads before they are sent to the Temporal server and after they are received. This process leverages **Temporal payload converters, codecs, and interceptors** to provide a transparent experience for developers. + +### Key Features + +- **Payload Offloading**: Temporal imposes a 2MB limit on payload size. The encoding process automatically offloads large payloads to a blob storage service and retrieves them during decoding. +- **Encryption/Decryption**: Payloads can be encrypted before being sent to the Orchestration Layer and decrypted by the worker allowing data to stay in the user’s infrastructure even in hybrid deployments. + +### Architecture Context + +Mistral workflows are designed to operate in a **hybrid mode**: + +- The **orchestration layer (Workflows API)** runs on Mistral infrastructure. +- The **code (workers/clients)** runs in the user’s infrastructure. + +To ensure data remains within the user’s infrastructure, the encoding/decoding process is implemented in the **Workflows SDK** and not in the Workflows API. + +## Architecture + +### PayloadEncoder + +The **PayloadEncoder** (`mistralai/workflows/worker`) is the core component for payload encoding/decoding. +It manages offloading, encryption, and other payload transformations, and is used by both the and **Temporal Worker**. + +### Temporal Components + +To allow a seemless integration, Mistral Workflows rely on three Temporal key components: **Payload Converter**, **Codec**, and **Interceptor**. + + + +| Component | Description | Constraints | +| --------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------- | +| **Payload Converter** | Converts between application-specific payloads and Temporal’s internal format. | No access to workflow context. Must use deterministic code. | +| **Codec** | Encodes/decodes payloads (serialization, compression, encryption). | No access to workflow context. | +| **Interceptor** | Intercepts payloads before/after Temporal server communication. | Can access workflow context. Must use deterministic code. | + +### Workflow + +The diagram below illustrates the end-to-end flow of payload encoding, from the client SDK to the Temporal server and back to the worker. It highlights the key steps: encoding/offloading, API orchestration, and decoding/context propagation. + +![Payload encoding design diagram](/img/payload-encoding-scheme.svg) + +--- + +#### 1. API Client (User Side / Application Layer) + +The user start a workflow using the execute_workflow method of the API Client. + +#### `execute_workflow` Process: + +1. **Encode the payload** using `PayloadEncoder`: + - Offloads large payloads to blob storage. + - _(Future: Encrypts the payload.)_ +2. **Transform the payload** into a `NetworkEncodedInput` (base64-encoded string with encoding options). +3. **Call the Workflows API** with the `NetworkEncodedInput` to start the workflow. + +#### `NetworkEncodedInput` Structure: + +```json +{ + "b64payload": "", + "encoding_options": ["BLOB_STORAGE", "..."], + "empty": false +} +``` + +--- + +#### 2. Workflows API (Server Side / Orchestration Layer) + +**Receive** the `NetworkEncodedInput` from the client and forwards it to temporal. + +#### Temporal Payload structure: + +```json +{ + "metadata": { + "encoding": "json/wf_v1", + "namespace": "XXX", + "execution_id": "XXX", + "offloaded": true + }, + "data": "" +} +``` + +--- + +#### 3. Workflows Worker (User Side / Application Layer) + +1. **Receive** the Temporal `Payload` from the Temporal server. +2. **Decode the payload**: + + - **Codec (`MistralWorkflowsPayloadCodec`)**: + - Uses `PayloadEncoder` to decode the payload. + - Fetches offloaded payloads from blob storage if needed. + - _(Future: Decrypts the payload.)_ + - **Payload Converter (`MistralWorkflowsPayloadConverter`)**: + - Transforms the Temporal `Payload` into a `PayloadWithContext`. + - `PayloadWithContext` contains the decoded payload and context (e.g., `execution_id`, `namespace`). + - **Interceptor (`WorkflowContextWorkflowInboundInterceptor`)**: + - Sets the context in `contextvar` for later use when calling activities/sub-workflows. + - Unwraps the payload from `PayloadWithContext` to send only the payload content as param to the workflow code. + - Execute the workflow code with the decoded payload. + +3. **Calling Activities/Sub-Workflows**: + - The process is reversed: + - **Interceptor**: Wraps the payload in `PayloadWithContext` to forward the context. + - **Payload Converter**: Transforms `PayloadWithContext` into a Temporal `Payload`. + - **Codec**: Uses `PayloadEncoder` to encode the payload (offloads/encrypts as needed). + - **Sends** the Temporal `Payload` to the Temporal server. + - The Temporal server forwards the `Payload` to the activity/sub-workflow worker and repeat the step 3. + +## Configuration + +### Base Encoding + +Payload encoding is **always enabled** by default. This ensures proper context propagation across workflows, activities, and workers. No configuration is needed for base encoding. + +The encoding system provides: + +- Workflow context propagation (namespace, execution ID, parent workflow tracking) +- Support for streaming events with correct lineage +- Foundation for optional offloading and encryption features + +--- + +### Payload Offloading + +Payload offloading allows seamless transmission of payloads larger than 2MB by configuring a blob storage (e.g., Azure Blob Storage, S3, or GCP Cloud Storage) accessible to both client and worker code. + +**Prerequisites** + +To use payload offloading, you need to install the Workflows SDK with the appropriate cloud storage provider: + +```bash +## For AWS S3 +uv add "mistralai-workflows[s3]" + +## For Azure Blob Storage +uv add "mistralai-workflows[azure]" + +## For Google Cloud Storage +uv add "mistralai-workflows[gcs]" + +## Or install all storage providers +uv add "mistralai-workflows[storage]" +``` + +See the [installation guide](../getting-started/installation#cloud-storage-providers) for more details. + +**Limitations :warning:** + +- **Workflow Replay Overhead**: When replaying a workflow, all payloads are downloaded again. This can lead to: + - **Timeout issues** during task execution. + - **Worker stalls** while rebuilding history. +- **Not for Generic Data Exchange**: This system is **not designed** for general-purpose data exchange due to the above limitations. + +**Use Case** +This feature is intended only for edge cases where large payloads are uncommon but may occasionally occur in very rare situations. + +For a more robust approach to handling large data exchange, prefer using the [activity field offloader](../guides/handling-large-data). + +:::info +Blob storage bucket/container must have an **expiry policy** as payloads are not automatically deleted. + +Align the expiry with your Temporal workflow retention period (default: 30 days). + +Blobs are prefixed by `temporal-payload/`, allowing per-namespace policies. +::: + +If you use the **starter-app**, use these environment variables to configure blob storage: + +``` +TEMPORAL_PAYLOAD_OFFLOADING__ENABLED=true + +## Azure: +TEMPORAL_PAYLOAD_OFFLOADING__STORAGE_CONFIG__STORAGE_PROVIDER=azure +TEMPORAL_PAYLOAD_OFFLOADING__STORAGE_CONFIG__CONTAINER_NAME=abraxas-temporal-payloads +TEMPORAL_PAYLOAD_OFFLOADING__STORAGE_CONFIG__AZURE_CONNECTION_STRING="XXX" +``` + +--- + +### Encryption + +Encryption allows you to encrypt the data sent to the Mistral API and through the Temporal server. +Encrypted data will show up as **encrypted** in traces as well. + +To enable it, you must generate a cryptographic key and configure the API Client and workers to use it. +Use the following Python code to generate a 256-bit AES-GCM key: + +```python +from cryptography.hazmat.primitives.ciphers.aead import AESGCM + +## Generate a 256-bit (32-byte) key +key = AESGCM.generate_key(bit_length=256) +print(f"Generated key: {key.hex()}") +``` + +There are two modes: +`full`: Encrypts every payload. +`partial`: Encrypt only `EncryptedStrField` fields (see: `mistralai.workflows.models`) + +Set the following environment variables in your .env: + +``` +TEMPORAL_PAYLOAD_ENCRYPTION__MODE=full # or partial +TEMPORAL_PAYLOAD_ENCRYPTION__MAIN_KEY= +``` + +#### Key Rotation + +To handle key rotation, follow these steps: + +#### 1. Create a New Key + +Create a new key using the same method as above. + +#### 2. Update Your Settings + +Add the new key as the `MAIN_KEY` and keep the old key as the `SECONDARY_KEY`. This lets the system decrypt older data while using the new key for encryption. + +``` +TEMPORAL_PAYLOAD_ENCRYPTION__MODE=full +TEMPORAL_PAYLOAD_ENCRYPTION__MAIN_KEY= +TEMPORAL_PAYLOAD_ENCRYPTION__SECONDARY_KEY= +``` + +#### 3. Wait for old workflows to Finish + +Allow sufficient time (days or weeks, depending on your workflows) for all data encrypted with the old key to be fully processed. + +#### 4. Remove the old Key + +Once you're sure no old data needs decrypting, delete the `SECONDARY_KEY` from your settings: + +``` +TEMPORAL_PAYLOAD_ENCRYPTION__MODE=full +TEMPORAL_PAYLOAD_ENCRYPTION__MAIN_KEY= +## TEMPORAL_PAYLOAD_ENCRYPTION__SECONDARY_KEY= +``` diff --git a/.claude/skills/workflows/references/guides/rate-limiting.mdx b/.claude/skills/workflows/references/guides/rate-limiting.mdx new file mode 100644 index 000000000..c4e04bc0e --- /dev/null +++ b/.claude/skills/workflows/references/guides/rate-limiting.mdx @@ -0,0 +1,58 @@ +--- +id: rate-limiting +title: Rate Limiting +sidebar_position: 7 +--- + +# Rate Limiting in Workflows + +Rate limiting is a crucial aspect of workflow management that helps control resource consumption and prevent any single workflow or activity from monopolizing shared resources. + +## How Rate Limiting Works + +Rate limits are always shared across all workers and workflows in the same task workspace (or `TEMPORAL_TASK_QUEUE` if configured). The `key` parameter controls how activities share these limits: + +### Case 1: Rate Limit Per Activity (No Key Provided) + +When **no key is provided**, the rate limit applies to the activity itself and is shared across all workers and workflows that use it. + +**Use this when:** You want to protect a shared resource (like an API client) that should have a global rate limit regardless of which workflow is using it. + +### Case 2: Rate Limit Across Activities (Key Provided) + +When **a key is provided**, multiple different activities that use the same key share a single rate limit pool across all workers and workflows. + +**Use this when:** You need to coordinate rate limits across multiple different activities (e.g., limiting total API calls across read, write, and delete operations using the same external service). + +### Example: Shared Rate-Limited API Client (No Key) + +```python +import mistralai.workflows as workflows +from mistralai import Mistral, Messages, Depends +from pydantic import BaseModel + +def get_mistral_client() -> Mistral: + """Creates a shared chat completion client with rate limiting""" + client = Mistral( + api_key="your_api_key", + ) + return client + +class CompletionParams(BaseModel): + model: str + messages: Messages + +@workflows.activity(rate_limit=workflows.RateLimit(time_window_in_sec=1, max_calls=100)) +async def generate_chat_response( + params: CompletionParams, + client: Mistral = Depends(get_mistral_client) +): + """Generates a chat response using a shared client""" + # This activity can be called from multiple workflows + # but will share the same rate limit across all of them + return await client.chat.complete_async(model=params.model, messages=params.messages) +``` + +**Behavior**: All workflows calling `generate_chat_response` share the same 100 calls/sec limit. If Workflow A makes 60 calls and Workflow B makes 50 calls in the same second, they compete for the same pool. + +**With a key**: Add `key="mistral_api"` to share this limit across multiple activities (e.g., `generate_chat_response`, `generate_embeddings`, `moderate_content`). diff --git a/.claude/skills/workflows/references/guides/scheduling.mdx b/.claude/skills/workflows/references/guides/scheduling.mdx new file mode 100644 index 000000000..ee75bceb1 --- /dev/null +++ b/.claude/skills/workflows/references/guides/scheduling.mdx @@ -0,0 +1,115 @@ +--- +id: scheduling +title: Workflow Scheduling +sidebar_position: 7 +--- + +# Workflow Scheduling + +Automatically run workflows at specified times without manual triggering. + +## How It Works + +Workers automatically register workflow schedules with Workflows during startup. The system handles: + +1. Schedule registration with Workflows +2. Periodic refresh of schedule definitions (every 10 seconds) +3. Execution of workflows according to the schedule + +## Defining Schedules + +Add schedules to workflows using cron expressions: + +```python +from mistralai.workflows.models import ScheduleDefinition + +schedule = ScheduleDefinition( + input={"report_type": "daily"}, + cron_expressions=["0 0 * * *"] # Daily at midnight UTC +) + +@workflows.workflow.define(schedules=[schedule]) +class ReportWorkflow: + async def run(self, report_type: str = "daily"): + # Generate report + pass +``` + +## Defining Schedule Policies + +Customize schedule behavior with policies: + +```python +from mistralai.workflows.models import SchedulePolicy, ScheduleOverlapPolicy + +## Override default schedule policy +schedule_policy = SchedulePolicy( + catchup_window=timedelta(days=1), # Allow 1 day of catchup + overlap_policy=ScheduleOverlapPolicy.SKIP, # Skip overlapping executions +) + +schedule = ScheduleDefinition( + input={"report_type": "daily"}, + cron_expressions=["0 0 * * *"], # Daily at midnight UTC + policy=schedule_policy +) + +@workflows.workflow.define(schedules=[schedule]) +class ReportWorkflow: + async def run(self, report_type: str = "daily"): + # Generate report + pass +``` + +For more details on schedule policies, see the [Temporal SchedulePolicy Documentation](https://docs.temporal.io/schedule#policies). + +## Key Considerations + +1. **Worker Configuration**: + + - Ensure all workers have identical schedule configurations + - Mismatched configurations can cause conflicts and unexpected behavior + +2. **Schedule Definition**: + - Uses standard cron syntax + - Includes input parameters for scheduled executions + - Supports multiple cron expressions per workflow + +## Complete Example + +```python +from datetime import timedelta +import mistralai.workflows as workflows +from mistralai.workflows.models import ScheduleDefinition, SchedulePolicy, ScheduleOverlapPolicy + +## Run every Saturday at 3 AM UTC +backup_schedule = ScheduleDefinition( + input={"retention_days": 30}, + cron_expressions=["0 3 * * 6"], + policy=SchedulePolicy( + catchup_window=timedelta(days=7), + overlap_policy=ScheduleOverlapPolicy.SKIP, + ) +) + +@workflows.workflow.define(schedules=[backup_schedule]) +class DatabaseBackupWorkflow: + async def run(self, retention_days: int = 30): + print(f"Starting backup with {retention_days} day retention") + # Backup implementation here + +## Start worker with: +## asyncio.run(workflows.run_worker([DatabaseBackupWorkflow])) +``` + +## Important Notes + +- Schedules use UTC time zone by default +- Each schedule can specify different input parameters +- Workers automatically maintain schedule registrations +- Ensure consistent schedule definitions across all workers + +## Next Steps + +- [Workflow Guide](workflows) - Learn workflow fundamentals +- [Signals, Queries & Updates](signals-queries-updates) - Other workflow interaction methods diff --git a/.claude/skills/workflows/references/guides/signals-queries-updates.mdx b/.claude/skills/workflows/references/guides/signals-queries-updates.mdx new file mode 100644 index 000000000..82d841d18 --- /dev/null +++ b/.claude/skills/workflows/references/guides/signals-queries-updates.mdx @@ -0,0 +1,202 @@ +--- +id: signals-queries-updates +title: Signals, Queries & Updates +sidebar_position: 4 +--- + +# Signals, Queries & Updates: Workflow Communication Mechanisms + +These features enable interaction with running workflows from external systems. + +## Signals + +Signals allow external systems to send messages to running workflows. + +### Key Characteristics: + +- Asynchronous communication +- Can be sent at any time during workflow execution +- Workflows must explicitly handle signals +- Can carry payload data + +### Basic Example + +```python +import mistralai.workflows as workflows + +@workflows.workflow.define() +class NotificationWorkflow: + def __init__(self): + self.notifications = [] + + @workflows.workflow.signal(name="add_notification") + async def add_notification(self, message: str, priority: int = 1): + self.notifications.append(message) + print(f"Received notification: {message} (Priority: {priority})") + + @workflows.workflow.entrypoint + async def run(self): + print("Workflow started, waiting for notifications...") + while True: + await workflows.workflow.wait_condition(lambda: len(self.notifications) > 0) + print(f"Processing {len(self.notifications)} notifications") + self.notifications.clear() +``` + +## Queries + +Queries allow external systems to get the current state of a workflow. + +### Key Characteristics: + +- Synchronous communication +- Read-only operations (should not modify workflow state) +- Can be called at any time during workflow execution +- Must return quickly (not for long-running operations) + +### Basic Example + +```python +import mistralai.workflows as workflows + +@workflows.workflow.define() +class ProcessingWorkflow: + def __init__(self): + self.progress = 0.0 + self.completed = False + + @workflows.workflow.query(name="get_status") + def get_status(self) -> dict: + return { + "progress": self.progress, + "completed": self.completed + } + + @workflows.workflow.entrypoint + async def run(self): + # Simulate work + for i in range(1, 11): + self.progress = i * 10 + await asyncio.sleep(1) + self.completed = True +``` + +## Updates + +Updates allow external systems to modify workflow state and get a response. Unlike signals, updates can return values and can also execute activities. + +### Key Characteristics: + +- Synchronous communication (with response) +- Can modify workflow state +- Can return values to the caller +- Can execute activities +- More structured than signals + +### Basic Example with Activity Execution + +```python +import mistralai.workflows as workflows +import asyncio + +## Activity definition +@workflows.activity() +async def process_update_data(data: str) -> str: + # Simulate processing + await asyncio.sleep(0.5) + return f"Processed: {data.upper()}" + +@workflows.workflow.define() +class DataProcessingWorkflow: + def __init__(self): + self.current_value = "default" + + @workflows.workflow.update(name="update_data") + async def update_data(self, new_value: str) -> dict: + # Execute an activity as part of the update + processed = await process_update_data(new_value) + + # Update workflow state + old_value = self.current_value + self.current_value = processed + + return { + "success": True, + "processed_value": processed, + "message": f"Updated from '{old_value}' to '{processed}'" + } + + @workflows.workflow.entrypoint + async def run(self): + print(f"Workflow started with value: {self.current_value}") + # Workflow continues running... +``` + +## Comparison Table + +| Feature | Communication Type | Modifies State | Returns Value | Can Execute Activities | +| ------- | ------------------ | -------------- | ------------- | ---------------------- | +| Signal | Asynchronous | Yes | No | No | +| Query | Synchronous | No | Yes | No | +| Update | Synchronous | Yes | Yes | Yes | + +## Input Validation + +Signals, queries, and updates validate incoming payloads against their declared parameters. This ensures type safety and prevents unexpected data from reaching your handlers. + +### Automatic Schema Enforcement + +When you declare parameters with type annotations, the system automatically: + +- Validates incoming payloads match the expected types +- **Rejects extra fields** not declared in the handler signature +- Returns HTTP 422 (Unprocessable Entity) with descriptive error messages on validation failure + +```python +@workflows.workflow.signal(name="add_notification") +async def add_notification(self, message: str, priority: int = 1): + # Only 'message' and 'priority' fields are accepted + # Extra fields like {"message": "hi", "extra": "bad"} will be rejected + ... +``` + +### Using Pydantic Models for Complex Inputs + +For handlers with complex or nested input structures, define a Pydantic model: + +```python +import pydantic + +class Address(pydantic.BaseModel): + street: str + city: str + +class UserProfile(pydantic.BaseModel): + name: str + address: Address + +@workflows.workflow.signal(name="update_profile") +async def update_profile(self, profile: UserProfile) -> None: + self._profile = profile +``` + +When using Pydantic models, their configuration is preserved: + +- If you set `model_config = pydantic.ConfigDict(extra="allow")`, extra fields will be accepted +- If you set `model_config = pydantic.ConfigDict(extra="forbid")`, extra fields are rejected (this is the default behavior for auto-generated schemas) + +### Validation Error Responses + +When validation fails, the API returns HTTP 422 with details about what went wrong: + +```json +{ + "detail": "Invalid input: Additional properties are not allowed ('unexpected_field' was unexpected)" +} +``` + +## Next Steps + +- [Workflow Guide](workflows) - Learn more about workflow fundamentals +- [Activity Guide](activities) - Understand how activities complement workflows +- [Observability Guide](observability) - Monitor your workflow interactions diff --git a/.claude/skills/workflows/references/guides/streaming-consumption.mdx b/.claude/skills/workflows/references/guides/streaming-consumption.mdx new file mode 100644 index 000000000..822294641 --- /dev/null +++ b/.claude/skills/workflows/references/guides/streaming-consumption.mdx @@ -0,0 +1,401 @@ +--- +id: streaming-consumption +title: Consuming Streaming Events +sidebar_position: 8 +--- + +# Consuming Streaming Events + +Subscribe to real-time events from workflows and activities using the Workflows API client or direct NATS subscriptions. + +## Using the Workflows API Client + +### Basic Consumption + +```python +from mistralai.workflows.client import get_mistral_client + +async with get_mistral_client( + server_url="https://api.mistral.ai", + api_key=os.environ["MISTRAL_API_KEY"], +) as client: + # Start a workflow + execution = await client.workflows.execute_workflow_async( + workflow_identifier="my-workflow", + input=params, + ) + + # Stream all events for this execution + event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=execution.execution_id, + ) + async with event_stream: + async for sse_event in event_stream: + payload = sse_event.data + if payload is None: + continue # skip heartbeat/comment SSE lines + event_data = payload.data # typed event response + event_type = event_data.event_type + print(f"[{payload.stream}] type={event_type} data={event_data}") +``` + +### Filtering by Stream Name + +Only receive events from a specific stream: + +```python +event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=execution_id, + stream="token", # Only token events +) +async with event_stream: + async for sse_event in event_stream: + payload = sse_event.data + if payload is None: + continue + print(payload.data) +``` + +### Detecting Completion + +Use `event_type` on the typed event data to detect workflow lifecycle events: + +```python +event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=execution_id, +) +async with event_stream: + async for sse_event in event_stream: + payload = sse_event.data + if payload is None or payload.data is None: + continue + + event = payload.data + event_type = event.event_type + + if event_type == "WORKFLOW_EXECUTION_COMPLETED": + print("Done!") + break + elif event_type in ("WORKFLOW_EXECUTION_FAILED", "WORKFLOW_EXECUTION_CANCELED"): + print(f"Ended: {event_type}") + break + else: + # Handle your custom events + record_event(event) +``` + +### Resume from Sequence + +If your connection drops, resume from where you left off using `start_seq`: + +```python +last_seq = 0 +while True: + try: + event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=execution_id, + start_seq=last_seq, + ) + async with event_stream: + async for sse_event in event_stream: + payload = sse_event.data + if payload is None: + continue + last_seq = payload.broker_sequence + 1 + process(payload) + break # Completed normally + except ConnectionError: + await asyncio.sleep(1) + # Loop will resume from last_seq +``` + +## NATS Subject Structure + +Understanding the subject hierarchy helps you filter events precisely. + +### Subject Format + +``` +{stream_name}.{workflow_name}.{root_exec_id}.{parent_exec_id}.{exec_id}.{topic}.{scope} +``` + +| Segment | Description | Example | +| ---------------- | -------------------------------------------------------- | ---------------------------------- | +| `stream_name` | Stream prefix + namespace (e.g., `workflows_stream_*`) | `workflows_stream_customer:ws` | +| `workflow_name` | Workflow name | `my-workflow` | +| `root_exec_id` | Root workflow exec ID (top-level ancestor) | `root123` | +| `parent_exec_id` | Parent workflow exec ID (direct parent) | `parent456` | +| `exec_id` | Current workflow exec ID | `exec789` | +| `topic` | Stream name (your choice) | `token` | +| `scope` | `workflow` or `activity.*` | `workflow` | + +### Scope Values + +**Workflow events** end with `.workflow`: + +``` +...token.workflow +``` + +**Activity events** end with `.activity.{name}.{id}.{attempt}`: + +``` +...token.activity.chat_activity.1.1 +``` + +## NATS Wildcards + +NATS supports two wildcards for flexible subscriptions: + +| Wildcard | Matches | Example | +| -------- | ------------------------------------ | ------------------------- | +| `*` | Single token (segment) | `*.my-workflow.*.*.*.*.*` | +| `>` | One or more tokens (rest of subject) | `*.*.*.*.*.token.>` | + +### Wildcard Examples + +``` +## All events for a specific workflow name (any execution) +*.my-workflow.*.*.*.*.> + +## All token events across all workflows +*.*.*.*.*.token.> + +## All workflow-level events (not activities) +*.*.*.*.*.*.workflow + +## All activity events +*.*.*.*.*.*.activity.> + +## Events for a specific execution +*.*.*.*.exec123.*.> + +## Events in a workflow tree (by root exec ID) +*.*.root123.*.*.*.> + +## Specific activity type across all workflows +*.*.*.*.*.*.activity.chat_activity.*.* +``` + +## API Routes + +### Stream Events Endpoint + +``` +GET /v1/workflows/executions/{execution_id}/stream +``` + +Query parameters for filtering: + +| Parameter | Description | Example | +| ------------------------ | ----------------------------------------- | --------------------------------- | +| `stream` | Filter by stream name | `?stream=token` | +| `workflow_name` | Filter by workflow name | `?workflow_name=my-workflow` | +| `workflow_exec_id` | Filter by execution ID | `?workflow_exec_id=exec789` | +| `root_workflow_exec_id` | Filter by root workflow exec ID | `?root_workflow_exec_id=root123` | +| `parent_workflow_exec_id`| Filter by parent workflow exec ID | `?parent_workflow_exec_id=parent456` | +| `activity_name` | Filter by activity name | `?activity_name=chat_activity` | +| `activity_id` | Filter by activity execution ID | `?activity_id=activity123` | +| `scope` | `workflow`, `activity`, or `*` | `?scope=activity` | +| `start_seq` | Resume from sequence | `?start_seq=42` | +| `metadata_filters` | Filter by metadata (JSON object) | `?metadata_filters={"key":"v"}` | +| `workflow_event_types` | Filter by workflow event types | `?workflow_event_types=WORKFLOW_COMPLETED` | + +### Example: Token Streaming + +```bash +curl -N "http://localhost:8000/v1/workflows/executions/${EXEC_ID}/stream?stream=token" +``` + +Response (Server-Sent Events): + +``` +data: {"stream":"token","data":{"event_type":"CUSTOM_TASK_IN_PROGRESS",...},"broker_sequence":1,"workflow_context":{...}} + +data: {"stream":"token","data":{"event_type":"CUSTOM_TASK_IN_PROGRESS",...},"broker_sequence":2,"workflow_context":{...}} + +data: {"stream":"token","data":{"event_type":"WORKFLOW_EXECUTION_COMPLETED",...},"broker_sequence":3,"workflow_context":{...}} +``` + +### Example: All Events with Wildcard + +```bash +## All events for an execution +curl -N "http://localhost:8000/v1/workflows/executions/${EXEC_ID}/stream" + +## Only activity events +curl -N "http://localhost:8000/v1/workflows/executions/${EXEC_ID}/stream?scope=activity" + +## Only workflow-level events +curl -N "http://localhost:8000/v1/workflows/executions/${EXEC_ID}/stream?scope=workflow" +``` + +## Sub-Workflow Events + +When a workflow spawns child workflows, events maintain parent-child relationships: + +```python +## Parent workflow +@workflows.workflow.define(name="parent-workflow") +class ParentWorkflow: + @workflows.workflow.entrypoint + async def run(self, params): + # Child workflow events will have parent_workflow_exec_id set + result = await workflows.workflow.execute_workflow( + ChildWorkflow, + params + ) + return result +``` + +### Consuming Events from Workflow Trees + +```python +## Get events from parent AND all children +event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=parent_execution_id, +) +async with event_stream: + async for sse_event in event_stream: + payload = sse_event.data + if payload is None: + continue + if payload.workflow_context.parent_workflow_exec_id: + print(f"[child] {payload.data}") + else: + print(f"[parent] {payload.data}") +``` + +### Filtering by Root ID + +Using NATS wildcards to get all events in a workflow tree: + +``` +## All events in a workflow tree by root exec ID +*.*.{root_exec_id}.*.*.*.> +``` + +## Event Types + +The SDK uses typed event responses discriminated by `event_type`. The full list of event types: + +| Event Type | Description | +| ------------------------------------ | ------------------------------ | +| `WORKFLOW_EXECUTION_STARTED` | Workflow started | +| `WORKFLOW_EXECUTION_COMPLETED` | Workflow finished successfully | +| `WORKFLOW_EXECUTION_FAILED` | Workflow failed | +| `WORKFLOW_EXECUTION_CANCELED` | Workflow was canceled | +| `WORKFLOW_EXECUTION_CONTINUED_AS_NEW`| Workflow continued as new | +| `WORKFLOW_TASK_TIMED_OUT` | Workflow task timed out | +| `WORKFLOW_TASK_FAILED` | Workflow task failed | +| `CUSTOM_TASK_STARTED` | Custom task started | +| `CUSTOM_TASK_IN_PROGRESS` | Custom task progress update | +| `CUSTOM_TASK_COMPLETED` | Custom task completed | +| `CUSTOM_TASK_FAILED` | Custom task failed | +| `CUSTOM_TASK_TIMED_OUT` | Custom task timed out | +| `CUSTOM_TASK_CANCELED` | Custom task canceled | +| `ACTIVITY_TASK_STARTED` | Activity started | +| `ACTIVITY_TASK_COMPLETED` | Activity finished | +| `ACTIVITY_TASK_RETRYING` | Activity is retrying | +| `ACTIVITY_TASK_FAILED` | Activity failed | + +Each event type maps to a specific Pydantic model (e.g. `WorkflowExecutionCompletedResponse`, +`CustomTaskInProgressResponse`) with fields like `event_id`, `event_timestamp`, `workflow_exec_id`, +`workflow_name`, and type-specific `attributes`. + +### Example Event + +```json +{ + "stream": "token", + "broker_sequence": 1, + "timestamp": "2025-01-15T10:30:00Z", + "data": { + "event_type": "WORKFLOW_EXECUTION_STARTED", + "event_id": "evt_abc123", + "event_timestamp": 1736938200000000000, + "workflow_name": "my-workflow", + "workflow_exec_id": "abc123", + "root_workflow_exec_id": "abc123", + "parent_workflow_exec_id": null, + "workflow_run_id": "run_456", + "attributes": {} + }, + "workflow_context": { + "workflow_name": "my-workflow", + "workflow_exec_id": "abc123", + "parent_workflow_exec_id": null + } +} +``` + +## Best Practices + +### 1. Always Handle Disconnection + +```python +async def resilient_consume(client, exec_id): + max_retries = 10 + + for attempt in range(max_retries): + try: + event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=exec_id, + ) + async with event_stream: + async for sse_event in event_stream: + payload = sse_event.data + if payload is None: + continue + yield payload + + if is_terminal_event(payload.data): + return + except ConnectionError: + await asyncio.sleep(min(2 ** attempt, 30)) +``` + +### 2. Filter Early + +Filter at the subscription level, not in your code: + +```python +## Good: Filter at source +event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=exec_id, + stream="token", +) +async with event_stream: + async for sse_event in event_stream: + if sse_event.data is not None: + process(sse_event.data) + +## Bad: Filter in code (wastes bandwidth) +event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=exec_id, +) +async with event_stream: + async for sse_event in event_stream: + if sse_event.data and sse_event.data.stream == "token": + process(sse_event.data) +``` + +### 3. Use Appropriate Scope + +If you only care about activity events: + +```python +event_stream = await client.workflows.events.get_stream_events_async( + workflow_exec_id=exec_id, scope="activity" +) +async with event_stream: + async for sse_event in event_stream: + if sse_event.data is not None: + # Only activity events, no workflow-level events + process(sse_event.data) +``` + +## Next Steps + +- [Publishing Events](streaming) - How to publish from workflows/activities +- [Streaming Architecture](../appendices/streaming) - Technical implementation details diff --git a/.claude/skills/workflows/references/guides/streaming.mdx b/.claude/skills/workflows/references/guides/streaming.mdx new file mode 100644 index 000000000..cd30339f2 --- /dev/null +++ b/.claude/skills/workflows/references/guides/streaming.mdx @@ -0,0 +1,148 @@ +--- +id: streaming +title: Streaming Events +sidebar_position: 7 +--- + +# Streaming: Real-Time Events from Workflows + +Stream events in real-time from your workflows and activities to power live UIs, progress indicators, and token-by-token LLM responses. + +## Quick Start + +### 1. Enable NATS + +```bash +NATS_ENABLED=true +NATS_HOST="nats://localhost:4222" +``` + +### 2. Publish from an Activity + +```python +import mistralai.workflows as workflows +from mistralai.workflows.core.task import Task + +@workflows.activity() +async def chat_activity(messages: list) -> dict: + initial_state = {"tokens": []} + + async with Task(type="token-stream", state=initial_state) as task: + + async for chunk in llm.stream(messages): + token = chunk.choices[0].delta.content + if token: + await task.update_state({"tokens": task.state["tokens"] + [token]}) + + return {"response": "".join(task.state["tokens"])} +``` + +### 3. Consume Events + +See [Consuming Streaming Events](streaming-consumption) for details on subscribing to events. + +## Publishing Patterns + +### Token Streaming (LLM) + +The most common pattern - stream tokens as they're generated: + +```python +@workflows.activity() +async def chat_activity(messages: list) -> dict: + initial_state = {"tokens": []} + + async with Task(type="token-stream", state=initial_state) as task: + + async for chunk in llm.stream(messages): + token = chunk.choices[0].delta.content + if token: + await task.update_state({"tokens": task.state["tokens"] + [token]}) + + return {"response": "".join(task.state["tokens"])} +``` + +### Progress Updates + +Report progress during long operations: + +```python +@workflows.activity(display_name="Processing text with explicit control") +async def streaming_tokens_with_progress_activity(text: str) -> dict: + """ + Example of explicit progress tracking with Task API. + + This pattern gives you full control over state updates and progress tracking. + """ + words = text.split() + initial_state = {"processed_words": [], "progress_idx": 0, "progress_total": len(words)} + + async with Task(type="progress-stream", state=initial_state) as task: + state = task.state + for i, word in enumerate(words): + await task.update_state({ + "processed_words": state["processed_words"] + [word], + "progress_idx": i + 1, + }) + state = task.state + await asyncio.sleep(0.1) + + final_state = task.state + return {"processed_text": " ".join(final_state["processed_words"]), "token_count": len(words)} +``` + +## Task Type Names + +The `type` parameter is a topic name you define. Best practices: + +| Good | Bad | +| --------------- | ---------- | +| `token` | `data` | +| `progress` | `Stream1` | +| `search_result` | `myStream` | + +- Use lowercase with underscores +- Keep names short and descriptive +- Use consistent naming across your app + +## Payload Limits + +NATS has a **1MB message limit**. For large data: + +```python +## Bad: Don't stream large payloads +## await task.update_state(large_document) + +## Good: Store large data externally, stream a reference +url = await storage.upload(large_document) +await task.update_state({"url": url, "size": len(large_document)}) +``` + +## Event Schema + +Each published event is wrapped with context: + +```python +{ + "stream": "token", # Your stream name + "sequence": 42, # Monotonic sequence number + "timestamp_unix_nano": ..., + "data": "Hello", # Your payload + "workflow_context": { + "namespace": "...", + "workflow_name": "my-workflow", + "workflow_exec_id": "abc123", + "parent_workflow_exec_id": null + }, + "activity_context": { # Only for activity events + "activity_name": "chat_activity", + "activity_exec_id": "1", + "activity_attempt_number": 1 + } +} +``` + +## Next Steps + +- [Consuming Streaming Events](streaming-consumption) - Subscribe and filter events +- [Streaming Architecture](../appendices/streaming) - Technical implementation details diff --git a/.claude/skills/workflows/references/guides/testing.md b/.claude/skills/workflows/references/guides/testing.md new file mode 100644 index 000000000..364fc5a92 --- /dev/null +++ b/.claude/skills/workflows/references/guides/testing.md @@ -0,0 +1,144 @@ +# Testing Workflows + +## Quick-test script + +The fastest way to verify a workflow works end-to-end. No test files, no conftest, no pytest: + +```bash +python .agents/skills/workflows/scripts/test_workflow.py src/workflows/my_workflow.py \ + --input '{"key": "value"}' \ + --timeout 30 +``` + +For interactive workflows that use `wait_for_input()`, provide `--interactions`: + +```bash +python .agents/skills/workflows/scripts/test_workflow.py src/workflows/my_workflow.py \ + --input '{}' \ + --interactions '[{"choice": "WFL"}]' \ + --timeout 60 +``` + +The script: +1. Discovers the workflow class in the given file +2. Starts a real worker in-process via `run_worker(detach=True)` — worker logs stream to stderr +3. Waits for the workflow to be registered on the Workflows API +4. Executes the workflow via `WorkflowsClient` +5. For interactive workflows: polls `__get_pending_inputs` and submits each `--interactions` entry in order +6. Waits for completion, prints PASSED + result JSON, or FAILED + traceback +7. On timeout: terminates the execution via the API and shuts down the worker +8. Exit code 0/1 for CI integration + +Options: +- `--input` (required): JSON input for the workflow +- `--timeout` (default 30): max seconds before the workflow is killed +- `--workflow-name`: select a specific workflow if the file contains multiple +- `--interactions`: JSON array of responses for interactive workflows + +Because the script uses a real worker, you get full worker logs (activity errors, retries, HTTP failures) in real time on stderr. No time-skipping — activities execute with real network calls. + +## Writing pytest tests + +For more control (multiple assertions, signal/query testing, spot-checks against external APIs), write pytest tests using `create_test_worker`. + +### Setup + +**conftest.py:** +```python +from mistralai.workflows.testing.fixtures import ( + clear_dependency_cache, # noqa: F401 + event_loop, # noqa: F401 + mock_upsert_search_attributes, # noqa: F401 + setup_test_config, # noqa: F401 + temporal_env, # noqa: F401 +) +``` + +**pyproject.toml:** +```toml +[tool.pytest.ini_options] +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" + +[dependency-groups] +dev = ["pytest-asyncio>=0.25.3"] +``` + +### Basic test pattern + +```python +from datetime import timedelta +import asyncio +from mistralai.workflows.testing import create_test_worker + +# Keep timeouts aggressive for a tight feedback loop. +# Increase only when the workflow is known to be long-running. +WORKFLOW_EXECUTION_TIMEOUT = timedelta(seconds=10) + +async def test_my_workflow(self, temporal_env) -> None: + async with create_test_worker( + temporal_env, + workflows=[MyWorkflow], + activities=[my_activity], + ): + handle = await temporal_env.client.start_workflow( + "my-workflow", + {"key": "value"}, + id="test-my-workflow", + task_queue="test-task-queue", + execution_timeout=WORKFLOW_EXECUTION_TIMEOUT, + ) + result = await asyncio.wait_for(handle.result(), timeout=15) + assert result["key"] == "expected" +``` + +## Preventing hangs + +Temporal retries failed workflow tasks indefinitely by default. If your workflow has a bug that crashes during task processing (not activity execution), the test will hang forever. + +Two guards prevent this: + +1. **`execution_timeout`** on `start_workflow()` — Temporal kills the workflow after this duration. The time-skipping test server fast-forwards retry delays, so the timeout triggers in ~1 real second. + +2. **`asyncio.wait_for(handle.result(), timeout=N)`** — client-side fallback in case the execution timeout doesn't propagate cleanly. + +Always use both. + +## Common pitfalls + +### `start_to_close_timeout` must be a `timedelta` + +```python +# WRONG — causes infinite retry loop +@activity(start_to_close_timeout=60) + +# RIGHT +@activity(start_to_close_timeout=timedelta(seconds=60)) +``` + +### Sandbox blocks third-party imports (v3+) + +Determinism enforcement is enabled by default in v3. If your workflow file imports a library like `httpx` at the top level, the sandbox will block it. + +Fix: wrap non-deterministic imports with `workflow.unsafe.imports_passed_through()`: + +```python +from mistralai.workflows import workflow + +with workflow.unsafe.imports_passed_through(): + import httpx +``` + +Or disable enforcement per-workflow: `@workflow.define("name", enforce_determinism=False)` + +### Search attribute errors in test env + +The in-memory test environment doesn't have custom search attributes (e.g. `OtelTraceId`). The `mock_upsert_search_attributes` fixture from `mistralai.workflows.testing.fixtures` handles this. Make sure your conftest imports it. + +### Results are dicts, not Pydantic models + +Temporal returns raw dicts. Access fields directly: `result["message"]`, not `result.message`. + +### Don't add `_emit_*` activities manually + +`create_test_worker` already registers all workflow-lifecycle event activities. Adding them again causes duplicate-activity registration errors. diff --git a/.claude/skills/workflows/references/guides/workflows-exception.mdx b/.claude/skills/workflows/references/guides/workflows-exception.mdx new file mode 100644 index 000000000..7c51e69a2 --- /dev/null +++ b/.claude/skills/workflows/references/guides/workflows-exception.mdx @@ -0,0 +1,176 @@ +--- +id: workflows-exception +title: Workflows Exception +sidebar_position: 2 +--- + +# WorkflowsException: Structured Error Handling + +Workflows provides a structured exception system through `WorkflowsException` for consistent error handling across workflows and activities. + +## Overview + +`WorkflowsException` is the standard exception class for handling errors in workflows. It provides: + +- Structured error codes via `ErrorCode` enum +- HTTP status code mapping +- Serialization to JSON responses +- Factory methods for common error scenarios + +## Basic Usage + +```python +from mistralai.workflows.exceptions import WorkflowsException, ErrorCode +from http import HTTPStatus + +## Raise a custom exception +raise WorkflowsException( + code=ErrorCode.WORKFLOW_DEFINITION_ERROR, + message=f"{workflow} class must be decorated with @workflows.workflow.define", + status=http.HTTPStatus.INTERNAL_SERVER_ERROR +) +``` + +## Constructor Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `message` | `str` | required | Human-readable error message | +| `status` | `HTTPStatus` | `INTERNAL_SERVER_ERROR` | HTTP status code | +| `code` | `ErrorCode` | `TEMPORAL_SERVICE_ERROR` | Structured error code | +| `type` | `str` | `"invalid_request_error"` | Error type string | +## Error Codes + +The `ErrorCode` enum provides structured error codes organized by category: + +### General Errors (40**) + +| Code | Description | +|------|-------------| +| `execution_error` | General execution error | +| `temporal_error` | Temporal-related error | +| `temporal_service_error` | Temporal service error | +| `temporal_connection_error` | Connection to Temporal failed | +| `temporal_client_creation_error` | Failed to create Temporal client | +| `search_attributes_creation_error` | Failed to create search attributes | + +### Activity Errors (41**) + +| Code | Description | +|------|-------------| +| `activity_definition_error` | Activity incorrectly defined | +| `activity_not_found_error` | Activity not found | +| `invalid_arguments_error` | Invalid arguments provided | +| `activity_not_module_level` | Activity must be at module level | +| `tool_argument_error` | Tool argument error | +| `rate_limit_error` | Rate limit exceeded | + +### Workflow Errors (42**) + +| Code | Description | +|------|-------------| +| `workflow_definition_error` | Workflow incorrectly defined | +| `workflow_description_error` | Workflow description error | +| `workflow_already_started` | Workflow already running | +| `workflow_not_found` | Workflow not found | +| `invalid_params_error` | Invalid parameters | +| `workflow_timeout_error` | Workflow timed out | +| `workflow_signal_definition_error` | Signal incorrectly defined | +| `workflow_update_definition_error` | Update incorrectly defined | +| `workflow_query_error` | Fail to query a workflow | + +### Worker Errors (43**) + +| Code | Description | +|------|-------------| +| `worker_registration_error` | Worker registration failed | +| `worker_runtime_config_error` | Worker runtime configuration error | + +### Durable Agent Errors (44**) + +| Code | Description | +|------|-------------| +| `agent_execution_error` | Agent Execution Error | + +### Infrastructure Errors (45**) + +| Code | Description | +|------|-------------| +| `namespace_already_used` | Namespace already in use | +| `in_memory_cache_error` | In-memory cache error | +| `rejected_query_error` | Query was rejected | +| `unserializable_payload_error` | Payload cannot be serialized | +| `blob_storage_config_error` | Blob storage configuration error | + +### API Endpoint Errors (46**) + +The following error codes are used to identify specific errors that can occur when interacting with the workflow API. These codes follow the `{HTTP_METHOD}_{ENDPOINT}_ERROR` naming convention and are returned in the `code` field of error responses. + +| Code | Description | +|------|--------------------------------------------------| +| `get_workflows_error` | Error when retrieving workflows | +| `get_workflows_versions_error` | Error when retrieving workflow versions | +| `get_workers_whoami_error` | Error when retrieving worker identity | +| `post_workflows_register_error` | Error when registering a workflow | +| `post_workflows_execute_error` | Error when executing a workflow | +| `post_executions_terminate_error` | Error when terminating an execution | +| `get_executions_error` | Error when retrieving executions | +| `get_executions_trace_otel_error` | Error when retrieving execution OTEL trace | +| `get_executions_trace_summary_error` | Error when retrieving execution trace summary | +| `get_executions_trace_events_error` | Error when retrieving execution trace events | +| `post_executions_signals_error` | Error when sending a signal to an execution | +| `post_executions_queries_error` | Error when querying an execution | +| `post_executions_updates_error` | Error when updating an execution | +| `post_schedules_error` | Error when creating a schedule | +| `delete_schedules_error` | Error when deleting a schedule | +| `get_schedules_error` | Error when retrieving schedules | +| `post_executions_stream_error` | Error when streaming execution results | +| `get_events_stream_error` | Error when streaming events | +| `post_events_error` | Error when posting events | + +## Exception Properties and Methods + +### `from_temporal_error()` + +Create an exception from Temporal errors: + +```python +from temporalio.exceptions import TemporalError + +try: + await client.workflows.execute_workflow_async(...) +except TemporalError as e: + raise WorkflowsException.from_temporal_error( + temporal_error=e, + message_override="Failed to execute workflow", + status_override=HTTPStatus.SERVICE_UNAVAILABLE + ) +``` + +Handles specific Temporal error types: +- `RPCError` → Maps to appropriate error code based on RPC status +- `WorkflowQueryRejectedError` → `REJECTED_QUERY_ERROR` +- `WorkflowAlreadyStartedError` → `WORKFLOW_ALREADY_STARTED` + +### `from_api_client_error()` + +Create an exception from HTTP client errors: + +```python +import httpx + +try: + response = await client.get("https://api.example.com") +except httpx.HTTPError as e: + raise WorkflowsException.from_api_client_error( + exc=e, + message="External API call failed", + code=ErrorCode.EXECUTION_ERROR, + ) +``` + +## Next Steps + +- [Workflows Guide](workflows) - Learn about workflow fundamentals +- [Activities Guide](activities) - Learn how to implement activities +- [Observability Guide](observability) - Monitor and trace your workflows diff --git a/.claude/skills/workflows/references/guides/workflows-plugins.mdx b/.claude/skills/workflows/references/guides/workflows-plugins.mdx new file mode 100644 index 000000000..d4468811a --- /dev/null +++ b/.claude/skills/workflows/references/guides/workflows-plugins.mdx @@ -0,0 +1,201 @@ +--- +id: workflows-plugins +title: Workflows Plugins +sidebar_position: 8 +--- + +# Workflows Plugins + +Mistral Workflows plugins provide reusable components that accelerate workflow development. They are standard Python packages that expose workflows, activities, and dependencies under the unified `mistralai.workflows.plugins` namespace. + +## Overview + +Plugins are development-time enablers that let you import curated, tested building blocks rather than implementing common patterns from scratch. They work like any Python package—install with `pip` and import into your code. + +```python +from mistralai.workflows.plugins.mistralai import mistralai_chat_complete +from mistralai.workflows.plugins.mistralai import Agent, Runner +``` + +## Official Plugins + +### Mistral AI Plugin + +**Package:** `mistralai-workflows-plugins-mistralai` + +Provides native Mistral AI integration for LLM operations, agent execution, session management, and MCP support within workflows. + +**Key activities:** + +| Activity | Description | +|----------|-------------| +| `mistralai_chat_complete` | Single-turn chat completion | +| `mistralai_chat_stream` | Streaming chat completion | +| `mistralai_chat_parse` | Chat completion with structured output parsing | +| `mistralai_embeddings` | Generate text embeddings | +| `mistralai_ocr` | Extract text from images and documents | +| `mistralai_create_agent` | Create a remote agent | +| `mistralai_update_agent` | Update a remote agent | +| `mistralai_start_conversation` | Start an agent conversation | +| `mistralai_start_conversation_stream` | Start an agent conversation with streaming | +| `mistralai_append_conversation` | Add messages to an existing conversation | +| `mistralai_append_conversation_stream` | Add messages to an existing conversation with streaming | + +**Key components:** + +| Component | Description | +|-----------|-------------| +| `Agent` | Agent definition with model, tools, and configuration | +| `Runner` | Orchestrates agent execution with conversation and tool loops | +| `LocalSession` | Local in-process agent session | +| `RemoteSession` | Remote stateful agent session | +| `MCPStdioConfig` | Configuration for local MCP servers (stdio) | +| `MCPSSEConfig` | Configuration for remote MCP servers (SSE) | +| `MCPConfig` | Union type alias for `MCPStdioConfig \| MCPSSEConfig` | +| `collect_mcp_tools` | Activity: collect tool definitions from one or more MCP servers | +| `execute_mcp_tool` | Activity: execute a named tool on its MCP server | +| `get_mistral_client` | Dependency: returns a configured `mistralai.Mistral` client | + +**Example — chat completion:** + +```python +from mistralai.workflows import workflow +from mistralai.workflows.plugins.mistralai import ( + ChatCompletionRequest, + UserMessage, + mistralai_chat_complete, +) + +@workflow() +async def summarize(text: str) -> str: + request = ChatCompletionRequest( + model="mistral-large-latest", + messages=[UserMessage(content=f"Summarize this text:\n\n{text}")], + ) + result = await mistralai_chat_complete(request) + return result.choices[0].message.content +``` + +For full documentation on `Agent`, `Runner`, sessions, MCP, and multi-agent handoffs, see the [Durable Agents guide](./durable-agents). + +### Webhook Plugin + +**Package:** `mistralai-workflows-plugins-webhook` + +Provides HTTP/webhook routing and fan-out for building event-driven workflows. Use it to receive webhooks from external services (GitHub, Slack, Linear, etc.) and route them to running workflow instances. + +**Key components:** + +| Component | Description | +|-----------|-------------| +| `HTTPRouterWorkflow` | Base class for webhook router workflows | +| `RouteDispatcher` | Dispatches incoming HTTP requests to handler methods | +| `SearchableWorkflow` | Mixin to expose search attributes for workflow targeting | +| `post` | Decorator to register a method as an HTTP POST handler | +| `SearchAttribute` | Key/value pair used to target running workflow instances | +| `search_workflow_execution_ids` | Find running workflow instance IDs matching search attributes | +| `send_signal` | Fan out a signal to multiple workflow instances | +| `WebhookFanOutResult` | Result of `send_signal` (list of target IDs and dispatched count) | +| `HTTPRequest` / `HTTPResponse` | Request and response types | + +Provider-specific helpers (experimental) are available under `webhook.github`, `webhook.slack`, and `webhook.linear`. + +**Example:** + +```python +from mistralai.workflows import workflow +from mistralai.workflows.plugins.webhook import ( + HTTPRouterWorkflow, + HTTPRequest, + HTTPResponse, + post, +) + +@workflow.define(name="my-webhook-router") +class MyWebhookRouter(HTTPRouterWorkflow): + @post("/") + async def handle(self, request: HTTPRequest) -> HTTPResponse: + # process the webhook payload + return HTTPResponse(status_code=200, body={"ok": True}) +``` + +### Nuage Plugin + +**Package:** `mistralai-workflows-plugins-nuage` + +Orchestrates AI coding agents inside sandboxed containers. Powers Le Chat's Vibe coding feature — running an agentic loop where an LLM reasons, invokes tools, and executes code in isolation. + +Key capabilities: sandboxed code execution (Demiurge), GitHub integration, and Le Chat streaming. + +See the [Nuage Plugin guide](./nuage-plugin) for full documentation, installation instructions, and configuration reference. + +## Installation + +Install the plugins you need alongside the main SDK: + +```bash +pip install mistralai-workflows +pip install mistralai-workflows-plugins-mistralai +pip install mistralai-workflows-plugins-webhook +``` + +See the [Nuage Plugin guide](./nuage-plugin) for installation instructions. + +## Creating Your Own Reusable Libraries + +You can create custom packages to share reusable workflows, activities, and dependencies within your organization. + +:::note +The `mistralai.workflows.plugins` namespace is reserved for Mistral-supported plugins. For your own reusable code, use your own top-level package name. +::: + +### Directory Structure + +``` +acme-workflows/ +├── pyproject.toml +├── acme_workflows/ +│ ├── __init__.py +│ ├── activities.py # Your reusable activities +│ └── workflows.py # Your reusable workflows +└── tests/ +``` + +### Build Configuration + +In your `pyproject.toml`: + +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "acme-workflows" +version = "0.1.0" +dependencies = [ + "mistralai-workflows>=2.0.0", +] +``` + +### Usage + +After installing your package, import directly: + +```python +from acme_workflows.activities import my_custom_activity +from acme_workflows.workflows import my_rag_pipeline +``` + +## Contributing Plugins to Mistral + +If you have built a reusable plugin that you believe would benefit the broader community, you can contribute it to the official `mistralai.workflows.plugins` namespace. + +To contribute: + +1. **Open an issue first** — Before investing time in a pull request, file an issue describing your plugin and its use case. This helps determine whether Mistral would be willing to accept and maintain your contribution. + +2. **Open a pull request** — If the issue is positively received, submit a PR to the Mistral workflows repository following the plugin structure documented in `workflow_sdk/plugins/CONTRIBUTING.md`. + +Contributed plugins become part of the official Mistral-supported plugin ecosystem and will be maintained alongside other official plugins. + diff --git a/.claude/skills/workflows/references/guides/workflows.mdx b/.claude/skills/workflows/references/guides/workflows.mdx new file mode 100644 index 000000000..bf3582bbd --- /dev/null +++ b/.claude/skills/workflows/references/guides/workflows.mdx @@ -0,0 +1,626 @@ +--- +id: workflows +title: Workflows +sidebar_position: 1 +--- + +# Workflows: The Brains of Your Application + +Workflows define the high-level business logic and coordinate activities in your application. + +## What is a Workflow? + +A workflow is a durable, deterministic process that orchestrates activities and manages execution state. Key characteristics: + +- Defined as Python classes +- Can run for seconds to years (with proper checkpointing) +- Maintains complete execution history +- Automatically recovers from failures +- Input/output limited to 2MB +- Timeout if synchronous CPU-bound Python code exceeds 2 seconds ([see more](./limitations)) + +## Workflow Determinism + +Workflows must be **deterministic**: given the same inputs, they must always produce the same +sequence of commands. This is a fundamental requirement of Temporal's replay mechanism: +when a worker restarts or a workflow is recovered, Temporal re-executes the workflow code +from the beginning, matching each command against the recorded event history. +If the code produces different commands on replay, the workflow fails with a non-determinism error. + +:::note +Determinism is **enforced by default**. Workflow code runs inside Temporal's Python sandbox, which intercepts non-deterministic calls and raises errors at runtime. You can opt out per-workflow with `enforce_determinism=False` or worker-wide with `DEFAULT_ENFORCE_DETERMINISM=0`. See [Determinism Enforcement](#determinism-enforcement-sandbox) below for details. +::: + +### Correct: Use Temporal's Deterministic APIs + +Always use these in workflow code: + +```python +from temporalio import workflow as temporal_wf + +## ✅ Correct - Use workflow.now() for current time +current_time = temporal_wf.now() + +## ✅ Correct - Use workflow.uuid4() for UUIDs +request_id = temporal_wf.uuid4() + +## ✅ Correct - Use workflow.random() for random values +random_value = temporal_wf.random() +``` + +### Dangerous: Standard Library Equivalents + +Don't use these directly in workflow code: + +```python +## ❌ Dangerous - use temporalio.workflow.now() instead +from datetime import datetime +current_time = datetime.now() + +## ❌ Dangerous - use temporalio.workflow.uuid4() instead +import uuid +request_id = uuid.uuid4() + +## ❌ Dangerous - use temporalio.workflow.random() instead +import random +rand_val = random.random() +``` + +Also dangerous in workflows: +- File system access (`open()`, `os.listdir()`, etc.) +- Direct HTTP calls or database queries +- Modifying global variables +- System calls (`os.environ`, `os.getcwd()`, etc.) + +### Move Non-Deterministic Work to Activities + +For operations like external API calls, database queries, or file I/O, use activities: + +```python +from mistralai.workflows import workflow +from temporalio import workflow as temporal_wf + +@workflow.activity +async def fetch_external_data(params: DataParams) -> ExternalData: + # ✅ Safe - Activities are not replayed + response = await http_client.get(params.url) + timestamp = datetime.now() # OK in activities + return ExternalData(data=response.json(), fetched_at=timestamp) + +@workflow.define(name="my_workflow") +class MyWorkflow: + @workflow.entrypoint + async def run(self, params: MyParams) -> MyResult: + # ✅ Correct - Non-deterministic work in activity + data = await temporal_wf.execute_activity( + fetch_external_data, + params, + start_to_close_timeout=timedelta(seconds=30), + ) + return MyResult(data=data) +``` + +### Determinism Enforcement (Sandbox) + +When determinism enforcement is enabled, your workflow code runs inside Temporal's Python sandbox. The sandbox: + +- **Re-imports modules** in an isolated environment so that side-effectful module-level code + is contained +- **Intercepts dangerous standard library calls** such as `datetime.now()`, `random.random()`, + `uuid.uuid4()`, `open()`, `os.environ`, and other non-deterministic operations +- **Restricts the asyncio event loop** to prevent spawning uncontrolled coroutines + +If your workflow code attempts any of these operations, the sandbox raises an error at runtime +rather than silently producing a non-determinism bug that surfaces only on replay. + +:::info +If you disable the sandbox, determinism is your responsibility. Your code will still break on replay if it's non-deterministic, you just won't get an immediate error telling you so. +You can find more details about Temporal's sandbox [here](https://docs.temporal.io/develop/python/python-sdk-sandbox). +::: + +When enabled, the SDK sets `sandboxed=True` on the underlying Temporal workflow definition. +No custom sandbox policy is applied, the standard Temporal sandbox behavior is used as-is. + +#### Disabling Per-Workflow + +Determinism enforcement is enabled by default. To opt out for a specific workflow, pass +`enforce_determinism=False` to the `@workflow.define` decorator: + +```python +from mistralai.workflows import workflow + +@workflow.define(name="my_workflow", enforce_determinism=False) +class MyWorkflow: + @workflow.entrypoint + async def run(self, input: str) -> str: + # This code runs WITHOUT the Temporal sandbox. + # You are responsible for ensuring determinism. + return f"Processed: {input}" +``` + +#### Disabling Worker-Wide + +Set the `DEFAULT_ENFORCE_DETERMINISM` environment variable to disable sandboxing for all +workflows on a worker by default: + +```bash +DEFAULT_ENFORCE_DETERMINISM=0 +``` + +This sets `config.worker.default_enforce_determinism` to `False`. + +#### Precedence + +The decorator-level setting takes priority over the environment variable: + +| `@workflow.define(enforce_determinism=...)` | `DEFAULT_ENFORCE_DETERMINISM` | Result | +|---|---|---| +| `True` | any | sandboxed | +| `False` | any | **not** sandboxed | +| not set (default) | `1` / `True` (default) | sandboxed | +| not set (default) | `0` / `False` | **not** sandboxed | + +#### Temporarily Bypassing the Sandbox + +:::warning +These escape hatches defeat the purpose of determinism enforcement. +Use them only when you understand the implications and have no alternative. +::: + +When determinism enforcement is enabled, you may occasionally need to perform an operation +that the sandbox blocks, for example importing a module that has non-deterministic side +effects at import time, or performing a one-off read that you know is safe. + +The SDK exposes two context managers under `workflow.unsafe`: + +**`workflow.unsafe.imports_passed_through()`** — Allows imports inside the context to bypass the sandbox's module re-import mechanism. +Use this when a third-party library performs side effects at import time that conflict +with the sandbox. + +```python +from mistralai.workflows import workflow + +@workflow.define(name="my_workflow") +class MyWorkflow: + @workflow.entrypoint + async def run(self, input: str) -> str: + with workflow.unsafe.imports_passed_through(): + import some_problematic_library + # Use the library normally after the import + return some_problematic_library.process(input) +``` + +**`workflow.unsafe.skip_determinism_enforcement()`** — Temporarily disables all sandbox restrictions within the context. +Code inside this block runs as if `enforce_determinism=False`. + +```python +from mistralai.workflows import workflow + +@workflow.define(name="my_workflow") +class MyWorkflow: + @workflow.entrypoint + async def run(self, input: str) -> str: + with workflow.unsafe.skip_determinism_enforcement(): + # Sandbox restrictions are lifted here. + # You are responsible for ensuring determinism. + import os + value = os.environ.get("SOME_CONFIG", "default") + return f"Processed: {input} with {value}" +``` + +Both context managers map directly to their Temporal equivalents +(`temporalio.workflow.unsafe.imports_passed_through()` and +`temporalio.workflow.unsafe.sandbox_unrestricted()` respectively). + +#### Recommendations + +1. **Keep enforcement enabled.** Determinism enforcement is on by default. Catching + non-determinism at development time is far cheaper than debugging replay failures + in production. Only disable it temporarily while migrating legacy workflows. +2. **Migrate existing workflows incrementally.** If you have workflows that are not yet + compliant, set `enforce_determinism=False` on those specific workflows while you fix + them. Avoid disabling enforcement worker-wide. +3. **Keep unsafe blocks small and documented.** When you must bypass the sandbox, wrap the + minimum amount of code and leave a comment explaining why. +4. **Move side effects to activities.** The best way to avoid sandbox issues is to keep + workflow code pure orchestration logic. All I/O, network calls, and non-deterministic + operations belong in activities. + +## Defining a Workflow + +Basic workflow structure: + +```python +import mistralai.workflows as workflows + +@workflows.workflow.define(name="report_workflow") +class MyWorkflow: + @workflows.workflow.entrypoint + async def run(self, report_type: str, include_details: bool = False) -> dict: + """Workflow implementation""" + # Orchestrate activities here + pass +``` + +:::warning +**All workflow entrypoint parameters and return types must have type annotations.** An entrypoint missing any type hint on its arguments or return value will fail validation at registration time. Always provide explicit types for every parameter and the return type. + +```python +## ❌ Invalid - missing type annotations +@workflows.workflow.define(name="my_workflow") +class BadWorkflow: + @workflows.workflow.entrypoint + async def run(self, data, count=1): + pass + +## ✅ Valid - all parameters and return type are annotated +@workflows.workflow.define(name="my_workflow") +class GoodWorkflow: + @workflows.workflow.entrypoint + async def run(self, data: str, count: int = 1) -> dict: + pass +``` +::: + +## Workflow Input + +The `run` method accepts any JSON-serializable types as parameters. + +### Primitive and multi-parameter inputs + +```python +@workflow.define(name="report_workflow") +class ReportWorkflow: + @workflow.entrypoint + async def run(self, report_type: str, include_details: bool = False) -> dict: + ... +``` + +Input: +```json +{"report_type": "daily", "include_details": false} +``` + +### Single Pydantic model + +When the entrypoint takes a single Pydantic `BaseModel`, its fields become the top-level input keys — there is no wrapper object: + +```python +from pydantic import BaseModel + +class ReportParams(BaseModel): + report_type: str + include_details: bool = False + +@workflow.define(name="report_workflow") +class ReportWorkflow: + @workflow.entrypoint + async def run(self, params: ReportParams) -> dict: + ... +``` + +Input: +```json +{"report_type": "daily", "include_details": true} +``` + +### Union of Pydantic models + +When a workflow can be triggered with different input shapes, use a union of `BaseModel` subclasses: + +```python +from pydantic import BaseModel, ConfigDict + +class PromptInput(BaseModel): + model_config = ConfigDict(extra="forbid") + prompt: str + +class CountInput(BaseModel): + model_config = ConfigDict(extra="forbid") + count: int + +@workflow.define(name="flexible_workflow") +class FlexibleWorkflow: + @workflow.entrypoint + async def run(self, params: PromptInput | CountInput) -> str: + if isinstance(params, PromptInput): + return f"prompt: {params.prompt}" + return f"count: {params.count}" +``` + +The SDK validates the input against each member in order and passes the first match to the handler: + +```json +{"prompt": "hello"} → PromptInput +{"count": 42} → CountInput +{"count": 42, "extra": "field"} → ValidationError +``` + +>Tip: Use `extra="forbid"` on each member model. It produces precise discrimination and clear error messages when the input doesn't match any expected shape. + +### Optional union (`| None`) + +Append `| None` (or use `Optional` from `typing`) to make the input optional: + +```python +@workflow.define(name="optional_workflow") +class OptionalWorkflow: + @workflow.entrypoint + async def run(self, params: PromptInput | CountInput | None) -> str: + if params is None: + return "no input" + if isinstance(params, PromptInput): + return f"prompt: {params.prompt}" + return f"count: {params.count}" +``` + +### Mixing BaseModel with primitive types + +Unions that combine a `BaseModel` with a non-model type (`str`, `int`, etc.) are not supported and will fail when the `@workflow.entrypoint` decorator is applied: + +```python +## ❌ Raises TypeError at class definition time +@workflow.define(name="my_workflow") +class MyWorkflow: + @workflow.entrypoint + async def run(self, params: PromptInput | str) -> str: + ... +``` + +``` +TypeError: Parameter 'params' of 'run' has unsupported union members: str. +Union inputs only support Pydantic BaseModel subclasses and None. +Use a dedicated BaseModel instead. +``` + +If you genuinely need a union that includes a non-model type, define a named `RootModel` subclass and use that instead: + +```python +from pydantic import BaseModel, RootModel + +class PromptInput(BaseModel): + prompt: str + +class PromptOrRaw(RootModel[PromptInput | str]): + pass + +@workflow.define(name="my_workflow") +class MyWorkflow: + @workflow.entrypoint + async def run(self, params: PromptOrRaw) -> str: + if isinstance(params.root, PromptInput): + return f"structured: {params.root.prompt}" + return f"raw: {params.root}" +``` + +The named subclass also produces a cleaner generated JSON schema. + +## Execution Timeout + +Every workflow has a maximum total execution time — `execution_timeout` — that caps its lifetime including all retries and [continue-as-new](#7-continue-as-new) iterations. + +Set it on the `@workflow.define` decorator: + +```python +from datetime import timedelta +from mistralai.workflows import workflow + +@workflow.define(name="my_workflow", execution_timeout=timedelta(hours=4)) +class MyWorkflow: + @workflow.entrypoint + async def run(self, params: MyParams) -> MyResult: + ... +``` + +When the workflow is started via the API, the platform uses this value as the hard cap. A workflow that is still running (or waiting) after `execution_timeout` has elapsed is cancelled with a `WORKFLOW_EXECUTION_TIMED_OUT` error. + +**Default: 1 hour.** Workflows that need to run longer must opt in explicitly: + +```python +@workflow.define(name="long_running_workflow", execution_timeout=timedelta(days=7)) +class LongRunningWorkflow: + ... +``` + +:::note +`execution_timeout` is a *total* wall-clock limit, not an activity timeout. Individual activity timeouts are controlled by `start_to_close_timeout` / `schedule_to_close_timeout` on each activity call. +::: + +## Core Workflow Features + +### 1. Signals + +Handle external events with signals: + +```python +@workflows.workflow.signal(name="approve", description="Approval signal") +async def approve_signal(self, data: ApprovalData): + self.approved = True +``` + +[Learn more about signals](./signals-queries-updates) + +### 2. Queries + +Expose workflow state through queries: + +```python +@workflows.workflow.query(name="get_status", description="Get current status") +def get_status(self) -> WorkflowStatus: + return WorkflowStatus( + progress=self.progress, + status=self.current_status + ) +``` + +[Learn more about queries](./signals-queries-updates) + +### 3. Updates + +Handle workflow updates: + +```python +@workflows.workflow.update(name="update_config", description="Update workflow configuration") +async def update_config(self, config: UpdateConfig) -> UpdateResult: + # Handle update + return UpdateResult(success=True) +``` + +[Learn more about updates](./signals-queries-updates) + +### 4. Schedules + +Define scheduled workflow executions using cron expressions: + +```python +from mistralai.workflows.models import ScheduleDefinition + +schedule = ScheduleDefinition( + input={"report_type": "daily", "include_details": False}, # Input parameters for scheduled runs + cron_expressions=["0 0 * * *"] # Run daily at midnight +) + +@workflows.workflow.define(name="report_workflow", schedules=[schedule]) +class ReportWorkflow: + async def run(self, report_type: str = "daily", include_details: bool = False): + # Generate report + pass +``` + +Key schedule features: + +- Cron-based scheduling with standard cron expressions +- Input parameters for scheduled executions +- Multiple cron expressions can be specified + +[Learn more about scheduling](./scheduling) + +### 5. Child Workflows + +Execute other workflows as children: + +```python +from datetime import timedelta +from mistralai.workflows import workflow + +result = await workflow.execute_workflow( + ChildWorkflow, + params=child_params, + execution_timeout=timedelta(hours=1) +) +``` + +You can also start a child workflow without waiting for its result (fire-and-forget) by passing `wait=False`: + +```python +handle = await workflow.execute_workflow( + ChildWorkflow, + params=child_params, + execution_timeout=timedelta(hours=1), + wait=False, +) +## Parent continues immediately — child runs independently +## Optionally await later: result = await handle +``` + +By default, `wait=False` sets the parent close policy to `ABANDON`, so the child continues running even if the parent completes. You can override this with the `parent_close_policy` parameter: + +```python +from mistralai.workflows import ParentClosePolicy + +handle = await workflow.execute_workflow( + ChildWorkflow, + params=child_params, + execution_timeout=timedelta(hours=1), + wait=False, + parent_close_policy=ParentClosePolicy.TERMINATE, +) +``` + +### 6. Waiting for Conditions + +Wait for conditions to be met: + +```python +from mistralai.workflows import workflow +await workflow.wait_condition( + lambda: self.ready, + timeout=timedelta(minutes=5) +) +``` + +### 7. Continue-As-New + +Reset workflow history for long-running or iterative workflows. Use this to prevent history from growing too large when processing large datasets or running indefinitely. + +**Important:** Your workflow's `run` method must accept a state parameter to restore its state when continuing as new. This parameter will receive the state passed to `continue_as_new()`. + +```python +import mistralai.workflows as workflows + +@workflows.workflow.define(name="long-running-processor") +class LongRunningProcessor: + @workflows.workflow.entrypoint + async def run(self, page: int = 0, total_processed: int = 0): # State parameters are required + # Process current page + + # Check if history is getting large + if workflows.workflow.should_continue_as_new(): + # Continue with fresh history + workflows.workflow.continue_as_new({"page": page + 1, "total_processed": total_processed + 100}) + + return await self.run(page + 1, total_processed + 100) +``` + +**When to use continue-as-new:** + +- Long-running workflows that iterate indefinitely +- When workflow history approaches size limits (~50K events) +- Workflows that need to run for weeks/months + +For complete working examples see: +[`workflow_with_continue_as_new.py`](https://github.com/mistralai/mistral-internal/blob/main/workflow_sdk/mistral_workflows/examples/workflow_with_continue_as_new.py) + +## Advanced Features + +### 1. Reset Mechanism + +You can "reset" a Workflow Execution to restart it from a specific point in its history. This is useful if your workflow gets stuck (for example, because of a non-deterministic error) or cannot complete. When you reset, the workflow ends its current run and starts again from the event you pick in the event history. + +All workflow events up to the reset point are copied to the new execution. The workflow then continues running from there using the latest version of your code. Any progress made after the reset event will be lost. + +Resetting should only be used after fixing the underlying problem. It's best practice to provide a reason for the reset, which is recorded in the workflow's event history. + +```python +await client.workflows.executions.reset_workflow_async( + execution_id="your-execution-id", + event_id=42, # Must be a WORKFLOW_TASK_COMPLETED event + reason="Bug fixed in activity logic", + exclude_signals=True, # Optional: skip replaying signals after this point + exclude_updates=True # Optional: skip replaying updates after this point +) +``` + +### 2. Workflow Execution Context + +Access workflow execution information: + +```python +from mistralai.workflows import workflow +execution_id = workflow.get_execution_id() +``` + +## Workflow vs Activity + +| Feature | Workflow | Activity | +| ----------- | -------------------- | ------------------ | +| Duration | Seconds to years | Seconds to minutes | +| State | Stateful | Stateless | +| Retries | Manual recovery | Automatic | +| Parallelism | Complex coordination | Single operation | + +## Next Steps + +- [Activity Guide](activities) - Learn how to implement work units +- [Observability Guide](observability) - Monitor and trace your workflows +- [Scheduling Guide](scheduling) - Learn about advanced scheduling options diff --git a/.claude/skills/workflows/references/pipeline_pattern.md b/.claude/skills/workflows/references/pipeline_pattern.md new file mode 100644 index 000000000..338bbf5f9 --- /dev/null +++ b/.claude/skills/workflows/references/pipeline_pattern.md @@ -0,0 +1,236 @@ +# Pipeline/Sequential Steps Pattern + +Build multi-step workflows with declarative step definitions, conditional execution, and configurable error handling. + +## Overview + +The pipeline pattern provides a structured way to: +- Define ordered sequences of workflow steps +- Execute steps as child workflows with deterministic IDs +- Handle errors per-step (raise, skip, or stop) +- Conditionally skip steps based on runtime context + +This pattern can be very useful to define a core workflow that can be extended by different variants. + +## Core Components + +### StepSpec + +Declarative definition of a pipeline step: + +```python +from dataclasses import dataclass +from enum import Enum +from typing import Any, Callable, Optional, Type +from pydantic import BaseModel + +# Error handling policies +class OnError(Enum): + RAISE = "raise" # Re-raise exception (default) + SKIP = "skip" # Log warning and continue to next step + STOP = "stop" # Log warning and stop pipeline (no error raised) + +# Context type for passing data between steps +Context = dict[str, Any] + +# Factory function signature for creating step parameters +ParamsFactory = Callable[[Any, Context, str, str], BaseModel] + +@dataclass(frozen=True) +class StepSpec: + """Declarative definition of a step in the pipeline.""" + task: "RegisteredTask" + when: Optional[Callable[[Context, Any], bool]] = None # Conditional execution + on_error: OnError = OnError.RAISE +``` + +### RegisteredTask + +Links a task type to its workflow class and parameter factory: + +```python +from enum import Enum + +class TaskRegistry(Enum): + """Registry of all available task types.""" + VALIDATE_INPUT = "VALIDATE_INPUT" + PROCESS_DATA = "PROCESS_DATA" + GENERATE_OUTPUT = "GENERATE_OUTPUT" + SEND_NOTIFICATION = "SEND_NOTIFICATION" + +@dataclass(frozen=True) +class RegisteredTask: + task_type: TaskRegistry + workflow_cls: Type # Abraxas workflow class + make_params: ParamsFactory # Creates Pydantic params from context +``` + +### Task Registry + +Central mapping of task types to their implementations: + +```python +BASE_TASKS = { + TaskRegistry.VALIDATE_INPUT: RegisteredTask( + task_type=TaskRegistry.VALIDATE_INPUT, + workflow_cls=ValidateInputTask, + make_params=lambda data, ctx, exec_id, process_type: ValidateParams( + data=data, + rules=ctx["validation_rules"], + ), + ), + TaskRegistry.PROCESS_DATA: RegisteredTask( + task_type=TaskRegistry.PROCESS_DATA, + workflow_cls=ProcessDataTask, + make_params=lambda data, ctx, exec_id, process_type: ProcessParams( + data=data, + config=ctx["processing_config"], + ), + ), +} +``` + +## Pipeline Implementation + +### Base Pipeline Class + +```python +import logging +from typing import Any, ClassVar, Generic, TypeVar + +import mistralai.workflows as workflows + +from .process_utils import Context, OnError, RegisteredTask, StepSpec +from .utils import get_child_workflow_execution_id + +logger = logging.getLogger(__name__) +T = TypeVar("T") + +class CoreProcess(Generic[T]): + """Base class for declarative pipelines.""" + + STEPS: ClassVar[list[StepSpec]] = [] + PROCESS_TYPE: str = "default" + + def __init__(self) -> None: + self.steps = self.STEPS + self.process_type = self.PROCESS_TYPE + + async def run_pipeline(self, input_object: T, ctx: Context, case_id: str) -> T: + """Execute all steps in sequence.""" + for step in self.steps: + step_label = step.task.task_type.name.lower() + + # Conditional execution + if step.when and not step.when(ctx, input_object): + logger.info(f"Skipping step {step_label}") + continue + + reg: RegisteredTask = step.task + execution_id = get_child_workflow_execution_id(task_name=step_label, case_id=case_id) + + logger.info(f"Running step {step_label} ...") + + try: + params = reg.make_params(input_object, ctx, execution_id, self.process_type) + input_object = await workflows.workflow.execute_workflow( + reg.workflow_cls, params, execution_id=execution_id + ) + logger.info(f"Step {step_label} OK") + + except Exception as exc: + logger.exception(f"Step {step_label} failed: {exc}") + + if step.on_error is OnError.RAISE: + raise + if step.on_error is OnError.STOP: + logger.warning(f"Stopping pipeline after '{step_label}'") + break + if step.on_error is OnError.SKIP: + logger.warning(f"Skipping failed step '{step_label}'") + continue + + return input_object +``` + +### Concrete Pipeline Definition + +```python +from typing import ClassVar + +class DataProcessingPipeline(CoreProcess[ProcessedData]): + """Pipeline for processing incoming data.""" + + STEPS: ClassVar[list[StepSpec]] = [ + StepSpec(task=BASE_TASKS[TaskRegistry.VALIDATE_INPUT]), + StepSpec(task=BASE_TASKS[TaskRegistry.PROCESS_DATA], on_error=OnError.SKIP), + StepSpec( + task=BASE_TASKS[TaskRegistry.SEND_NOTIFICATION], + when=lambda ctx, data: ctx.get("notify_on_complete", False), + ), + ] + + PROCESS_TYPE = "data_processing" + + def __init__(self, initial_data: InputData, config: Config) -> None: + super().__init__() + self.initial_data = initial_data + self.config = config + + async def run(self) -> ProcessedData: + ctx = { + "validation_rules": self.config.rules, + "processing_config": self.config.processing, + "notify_on_complete": self.config.notifications_enabled, + } + return await self.run_pipeline( + input_object=self.initial_data, ctx=ctx, case_id=self.initial_data.id + ) +``` + +## Usage Patterns + +### Conditional Step Execution + +```python +StepSpec( + task=BASE_TASKS[TaskRegistry.SEND_NOTIFICATION], + when=lambda ctx, data: data.requires_notification and ctx.get("notifications_enabled"), +) +``` + +### Error Handling Strategies + +```python +# Fail fast (default) - pipeline stops on first error +StepSpec(task=..., on_error=OnError.RAISE) + +# Skip failed steps - continue with remaining steps +StepSpec(task=..., on_error=OnError.SKIP) + +# Stop gracefully - no error raised, but pipeline ends +StepSpec(task=..., on_error=OnError.STOP) +``` + +### Extending Pipelines for Variants + +```python +class FrenchDataPipeline(DataProcessingPipeline): + """French-specific pipeline with additional steps.""" + + STEPS: ClassVar[list[StepSpec]] = [ + *DataProcessingPipeline.STEPS, + StepSpec(task=FRENCH_TASKS[TaskRegistry.FRENCH_VALIDATION]), + ] + + PROCESS_TYPE = "french_data_processing" +``` + +## Best Practices + +1. **Keep steps focused**: Each step should do one thing well +2. **Use context for shared data**: Pass data between steps via the context dict +3. **Choose error policies carefully**: Use SKIP for optional steps, RAISE for critical ones +4. **Use conditional execution**: Avoid empty/no-op workflow executions +5. **Log step transitions**: Makes debugging pipeline failures easier +6. **Generate deterministic execution IDs**: Enables idempotency and replay diff --git a/.claude/skills/workflows/references/workflow_testing.md b/.claude/skills/workflows/references/workflow_testing.md new file mode 100644 index 000000000..44ceb543e --- /dev/null +++ b/.claude/skills/workflows/references/workflow_testing.md @@ -0,0 +1,173 @@ +# Workflow Registration Testing + +Ensure all workflow classes are properly registered in workers to prevent production errors. + +## Overview + +A common production issue is creating a new workflow class but forgetting to register it in the worker. + +## Test All Decorated Classes Are Registered + +The most comprehensive test - scans the codebase for all `@workflow.define` decorators: + +```python +import ast +from pathlib import Path + +from pytest_mock import MockerFixture + +from core.workflows.worker import get_workflows + +# Root directory for scanning +PROJECT_ROOT = Path(__file__).parent.parent.parent.parent + + +def _find_workflow_decorated_classes() -> dict[str, str]: + """Scan codebase for all classes decorated with @workflows.workflow.define. + + Returns: + Dict mapping class names to their file paths. + """ + decorated_classes: dict[str, str] = {} + + # Directories containing workflow definitions + scan_dirs = [ + PROJECT_ROOT / "core", + PROJECT_ROOT / "plugins", + PROJECT_ROOT / "workflows", + ] + + def is_workflow_decorator(node: ast.expr) -> bool: + """Check if decorator matches @workflows.workflow.define pattern.""" + # Handle @workflows.workflow.define(...) + if isinstance(node, ast.Call): + node = node.func + + # Matches `import mistralai.workflows as workflows` → workflows.workflow.define + if isinstance(node, ast.Attribute) and node.attr == "define": + if isinstance(node.value, ast.Attribute) and node.value.attr == "workflow": + if isinstance(node.value.value, ast.Name): + return node.value.value.id == "workflows" + return False + + def scan_file(file_path: Path) -> None: + """Parse a Python file and extract workflow-decorated class names.""" + try: + source = file_path.read_text() + tree = ast.parse(source) + except (SyntaxError, UnicodeDecodeError): + return + + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + for decorator in node.decorator_list: + if is_workflow_decorator(decorator): + relative_path = str(file_path.relative_to(PROJECT_ROOT)) + decorated_classes[node.name] = relative_path + break + + for scan_path in scan_dirs: + if scan_path.is_file(): + scan_file(scan_path) + elif scan_path.is_dir(): + for py_file in scan_path.rglob("*.py"): + # Skip test files + if "/tests/" in str(py_file) or py_file.name.startswith("test_"): + continue + scan_file(py_file) + + return decorated_classes + + +def test_all_workflow_decorated_classes_are_registered(mocker: MockerFixture) -> None: + """Ensure all @workflow.define classes are registered in get_workflows(). + + This prevents the common error where a workflow is created but not + added to the worker registration. + """ + # Get workflows for dev mode + dev_workflows = get_workflows(dev_only=True) + + # Get dev environment workflows + mocker.patch("core.workflows.worker.settings.environment", "dev") + dev_env_workflows = get_workflows(dev_only=False) + + # Get production environment workflows + mocker.patch("core.workflows.worker.settings.environment", "production") + prod_env_workflows = get_workflows(dev_only=False) + + # Combine all registered workflows + registered_workflows = set(dev_workflows + dev_env_workflows + prod_env_workflows) + registered_names = {cls.__name__ for cls in registered_workflows} + + # Find all decorated classes in codebase + decorated_classes = _find_workflow_decorated_classes() + + # Check for missing registrations + missing = { + name: path + for name, path in decorated_classes.items() + if name not in registered_names + } + + if missing: + missing_details = "\n".join( + f" - {name} (defined in {path})" + for name, path in sorted(missing.items()) + ) + raise AssertionError( + f"The following workflow classes are decorated with @workflow.define " + f"but are NOT registered in get_workflows():\n{missing_details}\n\n" + f"Please add them to core/workflows/worker.py" + ) +``` + +## Unit Testing with `create_test_worker` + +The SDK provides `create_test_worker` in `mistralai.workflows.testing` for running workflows against an in-memory Temporal environment. It handles DI scoping, sandbox setup, and pre-registers event-emitting activities. + +### Fixtures + +Import the SDK fixtures in your `conftest.py`: + +```python +# conftest.py +from mistralai.workflows.testing.fixtures import * # noqa: F401,F403 +``` + +This provides `temporal_env` (in-memory Temporal with time-skipping) and auto-use fixtures for test config, DI cache clearing, and search attribute mocking. + +### Example + +```python +from mistralai.workflows.testing import create_test_worker + +async def test_my_workflow(temporal_env): + async with create_test_worker(temporal_env, [MyWorkflow], [my_activity]) as worker: + handle = await temporal_env.client.start_workflow( + "my-workflow", + {"input_field": "value"}, + id="test-id", + task_queue="test-task-queue", + ) + result = await handle.result() + assert result == {"output_field": "expected"} +``` + +## CI Integration + +Add to your CI pipeline: + +```yaml +# .github/workflows/test.yml +- name: Run workflow registration tests + run: pytest tests/core/workflows/test_worker.py -v +``` + +## Best Practices + +1. **Run tests in CI**: Catch missing registrations before deployment +2. **Test all environments**: Both dev and production workflow lists +3. **Skip test files**: Don't flag test workflow classes as missing +4. **Clear error messages**: Include file paths to help locate unregistered classes +6. **Mock environment settings**: Test both dev and production code paths diff --git a/.claude/skills/workflows/scripts/test_workflow.py b/.claude/skills/workflows/scripts/test_workflow.py new file mode 100644 index 000000000..ad3e99ec3 --- /dev/null +++ b/.claude/skills/workflows/scripts/test_workflow.py @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +"""Workflow test runner -- starts a real worker, executes via the API, reports the result. + +Usage: + python test_workflow.py --input '{}' + python test_workflow.py --input '{}' --interactions '[{"choice": "WFL"}]' + python test_workflow.py --input '{}' --timeout 60 --workflow-name my-wf + +For interactive workflows (those extending InteractiveWorkflow), pass --interactions +with a JSON array. Each element is submitted in order to the next wait_for_input() call. + +Exit codes: 0 = passed, 1 = failed/timed out, 2 = bad arguments. +""" + +from __future__ import annotations + +import argparse +import asyncio +import importlib.util +import inspect +import json +import sys +import traceback +from pathlib import Path +from typing import Any + +# SDK imports (deferred to avoid import errors when just running --help) +_sdk_imported = False + + +def _ensure_sdk(): + global _sdk_imported + if _sdk_imported: + return + global workflows, get_mistral_client, get_workflow_definition, BaseModel + import mistralai.workflows as _wf + from mistralai.workflows.client import get_mistral_client as _gmc + from mistralai.workflows.core.definition.workflow_definition import ( + get_workflow_definition as _gwd, + ) + from pydantic import BaseModel as _BM + + workflows = _wf + get_mistral_client = _gmc + get_workflow_definition = _gwd + BaseModel = _BM + _sdk_imported = True + + +# --------------------------------------------------------------------------- +# Discovery +# --------------------------------------------------------------------------- + + +def _import_module(file_path: Path) -> Any: + """Import a Python module from a filesystem path.""" + spec = importlib.util.spec_from_file_location(file_path.stem, file_path) + if spec is None or spec.loader is None: + raise ImportError(f"Cannot create module spec for {file_path}") + mod = importlib.util.module_from_spec(spec) + sys.modules[file_path.stem] = mod + spec.loader.exec_module(mod) + return mod + + +def _find_workflow_classes(module: Any) -> list[type]: + """Return all @workflow.define classes in *module*.""" + return [obj for _, obj in inspect.getmembers(module, inspect.isclass) if hasattr(obj, "__workflows_workflow_def")] + + +def _workflow_name(cls: type) -> str: + return get_workflow_definition(cls).name + + +def _is_interactive(cls: type) -> bool: + return issubclass(cls, workflows.InteractiveWorkflow) + + +def _discover_workflow(workflow_file: Path, name_override: str | None) -> tuple[type, str, bool]: + """Find and select the workflow class. Returns (cls, name, interactive).""" + module = _import_module(workflow_file) + found = _find_workflow_classes(module) + + if not found: + raise SystemExit(f"No workflow classes found in {workflow_file}. Ensure the file has a class decorated with @workflow.define.") + + if name_override: + matches = [w for w in found if _workflow_name(w) == name_override] + if not matches: + available = ", ".join(_workflow_name(w) for w in found) + raise SystemExit(f"Workflow '{name_override}' not found. Available: {available}") + cls = matches[0] + else: + if len(found) > 1: + names = ", ".join(_workflow_name(w) for w in found) + print( + f"Multiple workflows found: {names}. Using the first one. Pass --workflow-name to select.", + file=sys.stderr, + ) + cls = found[0] + + return cls, _workflow_name(cls), _is_interactive(cls) + + +# --------------------------------------------------------------------------- +# Input helpers +# --------------------------------------------------------------------------- + + +def _build_input(input_data: dict) -> dict | None: + """Return the input dict for the API client, or None if empty.""" + if not input_data: + return None + return input_data + + +# --------------------------------------------------------------------------- +# Interactions (for interactive workflows) +# --------------------------------------------------------------------------- + + +async def _poll_and_submit_interactions( + client: Any, + execution_id: str, + interactions: list[dict], + poll_timeout: float = 60.0, + poll_interval: float = 0.5, +) -> None: + """Poll __get_pending_inputs and submit each interaction response in order.""" + + class _Payload(BaseModel): + task_id: str + input: dict + + for i, response_data in enumerate(interactions, 1): + task_id = await _wait_for_pending_input(client, execution_id, i, poll_timeout, poll_interval) + + print(f" Interaction {i}: submitting {json.dumps(response_data)}") + try: + payload = _Payload(task_id=task_id, input=response_data) + resp = await asyncio.wait_for( + client.workflows.executions.update_workflow_execution_async( + execution_id=execution_id, + name="__submit_input", + input=payload.model_dump(mode="json"), + ), + timeout=30, + ) + except TimeoutError: + print( + f" Interaction {i}: update timed out (workflow may have failed to process the input)", + file=sys.stderr, + ) + raise + + error = resp.result.get("error") if isinstance(resp.result, dict) else None + if error: + raise RuntimeError(f"Interaction {i} rejected: {error}") + print(f" Interaction {i}: accepted") + + +async def _wait_for_pending_input( + client: Any, + execution_id: str, + index: int, + timeout: float, + interval: float, +) -> str: + """Block until a pending input appears, return its task_id.""" + start = asyncio.get_event_loop().time() + while True: + try: + resp = await client.workflows.executions.query_workflow_execution_async(execution_id=execution_id, name="__get_pending_inputs") + pending = resp.result.get("pending_inputs", []) + if pending: + task_id = pending[0]["task_id"] + label = pending[0].get("label", "") + print(f" Interaction {index}: pending input found (task={task_id[:8]}..., label={label!r})") + return task_id + except Exception: + pass + + if asyncio.get_event_loop().time() - start > timeout: + raise TimeoutError(f"Timeout waiting for pending input #{index} ({timeout}s)") + await asyncio.sleep(interval) + + +# --------------------------------------------------------------------------- +# Execution +# --------------------------------------------------------------------------- + + +async def _execute_with_retry(client: Any, wf_name: str, input_dict: dict | None, retries: int = 10) -> Any: + """Start the workflow, retrying on registration-propagation errors.""" + for attempt in range(retries): + try: + return await client.workflows.execute_workflow_async( + workflow_identifier=wf_name, + input=input_dict, + ) + except Exception: + if attempt == retries - 1: + raise + await asyncio.sleep(1) + + +async def _await_result( + client: Any, + execution_id: str, + interactions: list[dict] | None, + interactive: bool, + timeout: int, +) -> dict: + """Wait for workflow completion, submitting interactions if needed. + + Uses asyncio.wait with FIRST_EXCEPTION so that interaction errors + (e.g. validation failures) surface immediately instead of blocking + until the overall timeout. + """ + if not (interactive and interactions): + final = await asyncio.wait_for( + client.workflows.wait_for_workflow_completion_async(execution_id, polling_interval=2), + timeout=timeout, + ) + return final.result + + # Run interactions and completion polling concurrently. + interaction_task = asyncio.create_task(_poll_and_submit_interactions(client, execution_id, interactions, poll_timeout=timeout)) + completion_task = asyncio.create_task(client.workflows.wait_for_workflow_completion_async(execution_id, polling_interval=2)) + + done, pending = await asyncio.wait( + [interaction_task, completion_task], + timeout=timeout, + return_when=asyncio.FIRST_EXCEPTION, + ) + + for t in pending: + t.cancel() + try: + await t + except (asyncio.CancelledError, Exception): + pass + + if not done: + raise TimeoutError + + # Surface errors -- interaction errors take priority. + if interaction_task in done and interaction_task.exception(): + raise interaction_task.exception() + if completion_task in done and completion_task.exception(): + raise completion_task.exception() + + if completion_task in done: + return completion_task.result().result + + raise TimeoutError + + +# --------------------------------------------------------------------------- +# Runner +# --------------------------------------------------------------------------- + +# How long to wait after starting the worker before executing. +# The worker needs time to register the workflow with the API and +# start polling the task queue. 8s is empirically reliable. +_WORKER_READY_DELAY = 8 + + +async def run_workflow( + workflow_file: Path, + input_data: dict, + timeout_seconds: int, + workflow_name_override: str | None, + interactions: list[dict] | None = None, +) -> dict: + """Start a real worker, execute the workflow, and return the result.""" + _ensure_sdk() + + # -- discover -- + workflow_cls, wf_name, interactive = _discover_workflow(workflow_file, workflow_name_override) + + print(f"Workflow: {wf_name} ({workflow_cls.__name__})") + print(f"Interactive: {interactive}") + print(f"Input: {json.dumps(input_data)}") + if interactions: + print(f"Interactions: {len(interactions)} response(s) queued") + print(f"Timeout: {timeout_seconds}s") + print() + + if interactive and not interactions: + print( + "WARNING: Interactive workflow but no --interactions provided.\n The workflow will hang at wait_for_input().\n", + file=sys.stderr, + ) + + # -- API client -- + client = get_mistral_client() + + # -- start worker -- + print("Starting worker...") + worker_task = await workflows.run_worker([workflow_cls], detach=True) + if worker_task is None: + raise RuntimeError("run_worker(detach=True) returned None") + print("Worker started.") + + print("Waiting for worker to be ready...", end="", flush=True) + await asyncio.sleep(_WORKER_READY_DELAY) + print(" ready.\n") + + execution_id: str | None = None + try: + # -- execute -- + execution = await _execute_with_retry(client, wf_name, _build_input(input_data)) + execution_id = execution.execution_id + print(f"Execution: {execution_id}") + print(f"Status: {execution.status}\n") + + # -- wait for result -- + return await _await_result(client, execution_id, interactions, interactive, timeout_seconds) + + except TimeoutError: + if execution_id: + print(f"\nTerminating execution {execution_id}...", file=sys.stderr) + try: + await client.workflows.executions.terminate_workflow_execution_async(execution_id=execution_id) + print("Execution terminated.", file=sys.stderr) + except Exception as e: + print(f"Failed to terminate: {e}", file=sys.stderr) + raise + + finally: + if worker_task and not worker_task.done(): + worker_task.cancel() + try: + await worker_task + except asyncio.CancelledError: + pass + + +# --------------------------------------------------------------------------- +# CLI +# --------------------------------------------------------------------------- + + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Run a workflow with a real worker and the Workflows API.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__, + ) + parser.add_argument( + "workflow_file", + type=Path, + help="Path to the Python file containing the workflow.", + ) + parser.add_argument( + "--input", + required=True, + dest="input_json", + help="JSON string with the workflow input.", + ) + parser.add_argument( + "--timeout", + type=int, + default=30, + help="Max seconds before the workflow is killed (default: 30).", + ) + parser.add_argument( + "--workflow-name", + default=None, + help="Workflow name (if the file contains multiple workflows).", + ) + parser.add_argument( + "--interactions", + default=None, + dest="interactions_json", + help=('JSON array of interaction responses for interactive workflows. Example: \'[{"choice": "WFL"}]\''), + ) + return parser.parse_args() + + +def _parse_json(raw: str, label: str) -> Any: + try: + return json.loads(raw) + except json.JSONDecodeError as e: + print(f"Error: invalid JSON in {label}: {e}", file=sys.stderr) + raise SystemExit(2) + + +def main() -> None: + args = _parse_args() + + if not args.workflow_file.is_file(): + print(f"Error: {args.workflow_file} does not exist.", file=sys.stderr) + raise SystemExit(2) + + input_data = _parse_json(args.input_json, "--input") + + interactions = None + if args.interactions_json: + interactions = _parse_json(args.interactions_json, "--interactions") + if not isinstance(interactions, list): + print("Error: --interactions must be a JSON array.", file=sys.stderr) + raise SystemExit(2) + + # Load .env if present. + try: + from dotenv import load_dotenv + + load_dotenv(override=True) + except ImportError: + pass + + # Add workflow's directory to sys.path for relative imports. + parent = str(args.workflow_file.resolve().parent) + if parent not in sys.path: + sys.path.insert(0, parent) + + try: + result = asyncio.run( + run_workflow( + args.workflow_file.resolve(), + input_data, + args.timeout, + args.workflow_name, + interactions, + ) + ) + print("PASSED") + print(json.dumps(result, indent=2, default=str)) + except SystemExit: + raise + except TimeoutError: + print("FAILED: workflow timed out", file=sys.stderr) + raise SystemExit(1) + except Exception: + print("FAILED:", file=sys.stderr) + traceback.print_exc() + raise SystemExit(1) + + +if __name__ == "__main__": + main() diff --git a/CHANGELOG.md b/CHANGELOG.md index 0101bf2a2..c8e60e05a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Changed + +- **Mistral Workflows integration extracted into a dedicated package.** The optional `pipelex[mistralai-workflows]` extra and the `pipelex.plugins.mistralai_workflows.*` modules have been removed from `pipelex`. Install the new package instead: `pip install pipelex-mistralai-workflows`, and import from `pipelex_mistralai_workflows.*`. The framework-agnostic runtime-bridge core (boundary types, `run_pipe_via_bridge`, `PipelexExecutionMode`, `ensure_pipelex_booted`) has been promoted from `pipelex.plugins.mistralai_workflows.*` to `pipelex.runtime_bridge.*` so any host runtime — not just Mistral Workflows — can embed Pipelex. No behavior changes; activities, boundary types, and execution modes are identical. + ### Fixed - **`pipelex build structures` now emits domain-qualified class names and cross-references.** `ConceptFactory` registers each concept's structure class under `make_qualified_structure_class_name(domain, concept_code)` (e.g. `expense_validator__SpendingLimitCheck`), but the CLI generator was passing the bare `concept_code` to `StructureGenerator`. Generated files therefore contained `class ConceptCode(StructuredContent)` and unqualified cross-imports/types, while the registry expected the qualified name. `PipeFunc` validation against `concept.structure_class_name` then rejected the mismatch with `output concept expects structure class 'domain__X', but the function return type is 'X'`, breaking library load for any project that had regenerated structures. Fixed in `pipelex/cli/commands/build/structures_cmd.py`: the class-definition call sites now call `make_qualified_structure_class_name(blueprint.domain, concept_code)`; `_build_concept_ref_to_class_info` qualifies cross-reference class names while keeping the file stem unqualified so output filenames stay `domain__concept_code.py`; the `refines:` branch resolves the refined concept's domain via `QualifiedRef.parse_stripping_cross_package` and qualifies the base-class name for non-native refines, mirroring `ConceptFactory._handle_refines`. diff --git a/TODOS.md b/TODOS.md new file mode 100644 index 000000000..c1e7a4287 --- /dev/null +++ b/TODOS.md @@ -0,0 +1,140 @@ +# Mistral Workflows ↔ Pipelex — Plugin Extraction TODOS + +## Status + +Streams A, B, C **complete and verified**. Both repos green: + +- `pipelex-mistralai-workflows`: `make agent-check` clean, `make agent-test` + passes (layer-2 Mistral activity, layer-3 Temporal, fundamentals, + dry-run-all). +- `pipelex` (`_workflows/`): `make agent-check` clean (pyright + mypy + across the source tree), `make agent-test` passes, all §A11 + `git grep` invariants satisfied. + +Release/landing is **not** in scope for now. The dev-only +`[tool.uv.sources]` editable override in +`pipelex-mistralai-workflows/pyproject.toml` stays in place; both repos +are usable side-by-side via that override. + +## Gotcha to remember + +Mistral's `get_effective_task_queue()` returns `worker.deployment_name` +(not `temporal.task_queue`) whenever `deployment_name` is set and doesn't +match the configured task queue. Any `DEPLOYMENT_NAME=...` in `.env` +silently routes activities to that deployment name; an in-process test +worker polling `TEST_TASK_QUEUE` then hangs forever. The +`override_mistralai_task_queue` fixture in all 3 layer-2 test files +clears `mistralai_config.worker.deployment_name = None` to make the test +environment deterministic regardless of host env vars. Leave it in place +even if Mistral relaxes the routing rule in a future release. + +--- + +## End state delivered + +### `_workflows/` (pipelex) + +- New `pipelex/runtime_bridge/` package: `bridge.py`, `bootstrap.py` + (`ensure_pipelex_booted` only — `get_pipelex_dependency` removed), + `execution_mode.py`, `exceptions.py` (`PipelexRuntimeBridgeError` base + + `MissingPipelexTemporalExtraError` + `PipelexBridgeRuntimeError`). + `MistralWorkflowsNotInstalledError` deleted entirely. Library-id prefix + is `runtime_bridge_`. Install hint reads `pip install 'pipelex[temporal]'`. +- `pipelex/plugins/mistralai_workflows/` deleted. +- `tests/{unit,integration}/pipelex/runtime_bridge/` populated with the + layer-1 tests + `conftest.py` + `test_data/` (domain string + `mistralai_workflows_bridge_test` and function name + `mistralai_workflows_bridge_echo` kept verbatim across both repos). + `tests/{unit,integration}/pipelex/plugins/mistralai_workflows/` deleted. +- `pyproject.toml`: `mistralai-workflows` extra removed; the + `[[tool.mypy.overrides]]` block for `mistralai.workflows.*` removed. +- `docs/under-the-hood/mistralai-workflows-{plugin,recipes}.md` deleted; + the four matching `mkdocs.yml` lines removed. +- `CHANGELOG.md` `[Unreleased]` rewritten as a single Changed bullet + describing the migration. + +### `pipelex-mistralai-workflows/` + +- Starter content stripped (`hello_world.{py,mthds}`, `tests/test_pipelines/`, + `tests/e2e/test_pipelex_mistralai_workflows.py`). +- `pyproject.toml`: `version = "0.1.0"`, slim deps + (`pipelex>=0.27.0` + `mistralai-workflows>=3.3.0`), `[temporal]` extra + (`pipelex[temporal]>=0.27.0`), pruned markers (`gha_disabled`, + `dry_runnable`, `temporal`), mypy override for `mistralai.workflows.*`, + `pythonpath = ["tests"]` under `[tool.pytest]` so the + `from integration.test_data.bridge_funcs import ...` import resolves at + runtime (project rule forbids `tests/__init__.py`). +- `[tool.uv.sources] pipelex = { path = "../_workflows", editable = true }` — + **dev-only override**. Strip if/when publishing to PyPI. +- `README.md`, `CLAUDE.md`, `CHANGELOG.md` rewritten. +- `pipelex_mistralai_workflows/` package: `activities.py` (with + `pipelex_run_pipe` + `pipelex_run_pipe_offloaded`), `streaming.py` + (`pipelex_run_pipe_streaming` + `PipelexPipeRunStreamingState`), + `streaming_event_forwarder.py` (writer_id + `"mistralai-workflows-streaming"` kept verbatim), `dependency.py` + (single `pipelex_dependency()` callable shaped for + `mistralai.workflows.Depends(...)`). +- `tests/integration/`: 5 layer-2/3 test files + merged `conftest.py` + (scaffold's `check_pipelex_initialized` + `reset_pipelex_config_fixture` + plus `bridge_test_library` class-scoped fixture from pipelex) + copied + `test_data/` (`bridge_test.mthds` + `bridge_funcs.py`). +- CI (`tests-check.yml`) already runs `make install` → + `uv sync --all-extras`, which installs the `[temporal]` extra. No edits + needed. +- `uv.lock` refreshed; `mistralai-workflows==3.4.0` resolved. + +## Decisions locked (do not re-derive) + +- **§0.1.** Framework-agnostic core lives at `pipelex.runtime_bridge.*` + (the earlier `pipelex.embedding` proposal was rejected). +- **§0.2.** Split assignments: `bridge.py`, `execution_mode.py`, + `bootstrap.py::ensure_pipelex_booted`, agnostic exceptions live in + `pipelex.runtime_bridge`. `activities.py`, `streaming.py`, + `streaming_event_forwarder.py`, the Mistral-shaped dependency wrapper + live in `pipelex_mistralai_workflows`. + `MistralWorkflowsPluginError` + `MistralWorkflowsNotInstalledError` + deleted entirely. +- **§0.3.** New repo version is `0.1.0`. +- **§0.4.** New repo pins `pipelex>=0.27.0`; editable `[tool.uv.sources]` + override for local dev (strip if/when publishing). +- **§0.5.** Mistral dependency wrapper is `pipelex_dependency()` — boots + Pipelex, returns the singleton, designed for `Depends(pipelex_dependency)`. + No `LibraryCrate` snapshot helper added (deferred, revisit after first + user feedback). +- **§0.6.** Cookbook entry deferred. + +## Reference docs (consult before touching Mistral-facing code) + +- `.claude/skills/workflows/SKILL.md` and especially: + - `references/guides/workflows-plugins.mdx` — plugin contract. + - `references/guides/dependency-injection.mdx` — `Depends(...)` shape. + - `references/guides/streaming.mdx` + + `references/guides/streaming-consumption.mdx` — Task API, + `update_state`, event subscription. + - `references/guides/handling-large-data.mdx` — `OffloadableField` and + the offloading interceptor (relevant to D3's import-drift risk). +- Mistral docs: + +--- + +## Open risks to watch + +- **Version coupling.** A breaking change to the `pipelex.runtime_bridge` + public surface is a breaking change for `pipelex-mistralai-workflows`. +- **OffloadableField import drift.** `pipelex_mistralai_workflows/activities.py` + imports `OffloadableField, OffloadableModel` from + `mistralai.workflows.core.encoding.fields_offloader`. If a Mistral + upgrade moves the path, fix in the plugin pkg. +- **CI test parity.** Layer-2/3 tests now run only in + `pipelex-mistralai-workflows` CI. Keep both repos' matrices green. + +--- + +## Resume guide + +1. Read **§Status** + **§Gotcha to remember** above. That's the whole + in-flight context. +2. After any further code change: `make agent-check && make agent-test` + in whichever repo you touched. Note: `make cleanderived` deletes + `tests/integration/pipelex/fixtures/_generated_model_sets.py`; run + `make rtm` after `cleanderived` or pyright will fail. diff --git a/pipelex/plugins/mistral/mistral_config.py b/pipelex/plugins/mistral/mistral_config.py index 1c257cb77..9a937eb2f 100644 --- a/pipelex/plugins/mistral/mistral_config.py +++ b/pipelex/plugins/mistral/mistral_config.py @@ -9,7 +9,7 @@ from pipelex.types import StrEnum if TYPE_CHECKING: - from mistralai.models import MistralPromptMode + from mistralai.client.models import MistralPromptMode from pipelex.cogt.llm.llm_job_components import ReasoningEffort diff --git a/pipelex/plugins/mistral/mistral_extract_worker.py b/pipelex/plugins/mistral/mistral_extract_worker.py index 1034ed830..833d6ad9f 100644 --- a/pipelex/plugins/mistral/mistral_extract_worker.py +++ b/pipelex/plugins/mistral/mistral_extract_worker.py @@ -1,6 +1,7 @@ from typing import Any -from mistralai import Mistral, MistralError +from mistralai.client import Mistral +from mistralai.client.errors import MistralError from typing_extensions import override from pipelex.cogt.exceptions import ExtractCapabilityError, ExtractJobFailureError, InferenceErrorCategory, SdkTypeError diff --git a/pipelex/plugins/mistral/mistral_factory.py b/pipelex/plugins/mistral/mistral_factory.py index 1644975fb..5cc76f36b 100644 --- a/pipelex/plugins/mistral/mistral_factory.py +++ b/pipelex/plugins/mistral/mistral_factory.py @@ -4,15 +4,16 @@ from typing import TYPE_CHECKING import aiofiles -import mistralai -from mistralai import Mistral -from mistralai.models import ( +from mistralai.client import Mistral +from mistralai.client.models import ( + ChatCompletionRequestMessage, ContentChunk, DocumentURLChunk, DocumentURLChunkTypedDict, ImageURLChunk, ImageURLChunkTypedDict, - Messages, + OCRImageObject, + OCRResponse, SystemMessage, TextChunk, UsageInfo, @@ -55,9 +56,9 @@ def make_mistral_client( # Message ######################################################### - async def make_simple_messages(self, llm_job: LLMJob) -> list[Messages]: + async def make_simple_messages(self, llm_job: LLMJob) -> list[ChatCompletionRequestMessage]: """Makes a list of messages with a system message (if provided) and followed by a user message.""" - messages: list[Messages] = [] + messages: list[ChatCompletionRequestMessage] = [] user_content: list[ContentChunk] = [] if user_text := llm_job.llm_prompt.user_text: user_content.append(TextChunk(text=user_text)) @@ -181,7 +182,7 @@ def make_nb_tokens_by_category(self, usage: UsageInfo) -> NbTokensByCategoryDict @classmethod async def make_extract_output_from_mistral_response( cls, - mistral_extract_response: mistralai.OCRResponse, + mistral_extract_response: OCRResponse, ) -> ExtractOutput: """Convert Mistral OCR response to ExtractOutput. @@ -262,7 +263,7 @@ def _clean_mistral_image_base64(cls, base64_str: str) -> str: @classmethod def make_extracted_image_from_page_from_mistral_ocr_image_obj( cls, - mistral_ocr_image_obj: mistralai.OCRImageObject, + mistral_ocr_image_obj: OCRImageObject, ) -> ExtractedImageFromPage: if not mistral_ocr_image_obj.image_base64: msg = "Mistral OCR image object does not have an image base64" diff --git a/pipelex/plugins/mistral/mistral_llm_worker.py b/pipelex/plugins/mistral/mistral_llm_worker.py index 7bc229a18..9d6a945a6 100644 --- a/pipelex/plugins/mistral/mistral_llm_worker.py +++ b/pipelex/plugins/mistral/mistral_llm_worker.py @@ -1,8 +1,9 @@ from typing import TYPE_CHECKING, Any -from mistralai import Mistral, MistralError -from mistralai.models import MistralPromptMode, TextChunk, ThinkChunk -from mistralai.types import UNSET +from mistralai.client import Mistral +from mistralai.client.errors import MistralError +from mistralai.client.models import MistralPromptMode, TextChunk, ThinkChunk +from mistralai.client.types import UNSET from typing_extensions import override from pipelex import log @@ -24,8 +25,8 @@ from pipelex.urls import URLs if TYPE_CHECKING: - from mistralai.models import ChatCompletionResponse - from mistralai.types import OptionalNullable + from mistralai.client.models import ChatCompletionResponse + from mistralai.client.types import OptionalNullable class MistralLLMWorker(LLMWorkerInternalAbstract): @@ -176,7 +177,11 @@ async def _gen_text( if not response.choices: msg = "Mistral response.choices is None" raise LLMCompletionError(msg) - mistral_response_content = response.choices[0].message.content + message = response.choices[0].message + if message is None: + msg = "Mistral response.choices[0].message is None" + raise LLMCompletionError(msg) + mistral_response_content = message.content result_text: str if isinstance(mistral_response_content, str): result_text = mistral_response_content diff --git a/pipelex/plugins/mistral/mistral_llms.py b/pipelex/plugins/mistral/mistral_llms.py index 2d57da586..7edb3c427 100644 --- a/pipelex/plugins/mistral/mistral_llms.py +++ b/pipelex/plugins/mistral/mistral_llms.py @@ -1,11 +1,11 @@ -from mistralai.models import Data +from mistralai.client.models import BaseModelCard, FTModelCard from pipelex.hub import get_models_manager from pipelex.plugins.mistral.mistral_exceptions import MistralModelListingError from pipelex.plugins.mistral.mistral_factory import MistralFactory -def mistral_list_available_models() -> list[Data]: +def mistral_list_available_models() -> list[BaseModelCard | FTModelCard]: backend = get_models_manager().get_required_inference_backend("mistral") mistral_client = MistralFactory.make_mistral_client(backend=backend) models_list_response = mistral_client.models.list() @@ -16,4 +16,5 @@ def mistral_list_available_models() -> list[Data]: if not models_list: msg = "No models found" raise MistralModelListingError(msg) - return sorted(models_list, key=lambda model: model.id) + known_models = [model for model in models_list if isinstance(model, (BaseModelCard, FTModelCard))] + return sorted(known_models, key=lambda model: model.id) diff --git a/pipelex/runtime_bridge/__init__.py b/pipelex/runtime_bridge/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pipelex/runtime_bridge/bootstrap.py b/pipelex/runtime_bridge/bootstrap.py new file mode 100644 index 000000000..12d4b07c6 --- /dev/null +++ b/pipelex/runtime_bridge/bootstrap.py @@ -0,0 +1,25 @@ +"""Idempotent Pipelex boot helpers for use inside any host runtime that embeds Pipelex. + +Pipelex's own ``Pipelex.make()`` raises if a singleton already exists. The +bridge boundary is a hot path that can be reached from many concurrent +activities (Mistral Workflows, raw Temporal, future plugins), so we wrap the +boot in an idempotent guard so callers don't have to think about it. +""" + +from typing import Any + +from pipelex.pipelex import Pipelex + + +def ensure_pipelex_booted( + config_overrides: dict[str, Any] | None = None, +) -> None: + """Boot Pipelex on first call; no-op if already initialized. + + Idempotent. Safe to call from inside an activity; safe to call from a + worker entry-point before activities start. If a Pipelex singleton was + already created externally (e.g. via the user's worker bootstrap), this + function adopts that singleton without re-initializing. + """ + if Pipelex.get_optional_instance() is None: + Pipelex.make(config_overrides=config_overrides) diff --git a/pipelex/runtime_bridge/bridge.py b/pipelex/runtime_bridge/bridge.py new file mode 100644 index 000000000..d3215f6c9 --- /dev/null +++ b/pipelex/runtime_bridge/bridge.py @@ -0,0 +1,339 @@ +"""Framework-agnostic Pipelex runtime-bridge surface for host runtimes. + +This module contains the boundary types (``PipelexPipeRunInput`` / +``PipelexPipeRunOutput``) and the dispatch entry-point +(``run_pipe_via_bridge``) used by host runtimes (Mistral Workflows, raw +Temporal, future plugins) to invoke Pipelex pipes from inside their own +activities. It deliberately does NOT import any host-runtime-specific +modules at module top-level so that callers can use the bridge directly +(Tier 3 usage) and so that unit tests can exercise it without optional +host-runtime deps installed. + +The Temporal extra is lazy-imported only inside the temporal-mode branches. +""" + +from __future__ import annotations + +from contextlib import asynccontextmanager +from typing import TYPE_CHECKING, Any, AsyncGenerator +from uuid import uuid4 + +import shortuuid +from pydantic import BaseModel, ConfigDict, Field + +from pipelex.core.memory.working_memory import MAIN_STUFF_NAME +from pipelex.core.memory.working_memory_factory import WorkingMemoryFactory +from pipelex.hub import ( + get_library_manager, + get_required_pipe, + set_current_library, + teardown_current_library, +) +from pipelex.libraries.library_crate import LibraryCrate +from pipelex.pipe_run.delivery_assignment import DeliveryAssignment +from pipelex.pipe_run.exceptions import PipeJobError, PipeRouterError, PipeRunError +from pipelex.pipe_run.pipe_job_factory import PipeJobFactory +from pipelex.pipe_run.pipe_router import PipeRouter +from pipelex.pipe_run.pipe_run import PipeRun +from pipelex.pipe_run.pipe_run_params_factory import PipeRunParamsFactory +from pipelex.pipeline.exceptions import PipeExecutionError, PipelineExecutionError +from pipelex.pipeline.job_metadata import JobMetadata +from pipelex.runtime_bridge.bootstrap import ensure_pipelex_booted +from pipelex.runtime_bridge.exceptions import ( + MissingPipelexTemporalExtraError, + PipelexBridgeRuntimeError, +) +from pipelex.runtime_bridge.execution_mode import PipelexExecutionMode +from pipelex.system.telemetry.otel_constants import OTelConstants + +if TYPE_CHECKING: + from pipelex.core.memory.working_memory import WorkingMemory + from pipelex.core.pipes.pipe_output import PipeOutput + from pipelex.graph.graph_context import GraphContext + from pipelex.pipe_run.pipe_job import PipeJob + + +class PipelexPipeRunInput(BaseModel): + """JSON-safe input crossing the host-runtime / Temporal boundary.""" + + model_config = ConfigDict(extra="forbid") + + pipe_code: str + inputs: dict[str, Any] = Field(default_factory=dict) + output_name: str | None = None + pipeline_run_id: str | None = None + user_id: str | None = None + library_crate_dump: dict[str, Any] | None = None + execution_mode: PipelexExecutionMode = PipelexExecutionMode.DIRECT + delivery_assignment_dump: dict[str, Any] | None = None + + +class PipelexPipeRunOutput(BaseModel): + """JSON-safe output crossing the host-runtime / Temporal boundary.""" + + model_config = ConfigDict(extra="forbid") + + output_dict: dict[str, Any] + main_stuff_name: str | None = None + pipeline_run_id: str + workflow_id: str | None = None + is_completed: bool + graph_spec_dump: dict[str, Any] | None = None + + +async def run_pipe_via_bridge( + input_payload: PipelexPipeRunInput, + graph_context: GraphContext | None = None, +) -> PipelexPipeRunOutput: + """Run a Pipelex pipe from inside a host-runtime activity. + + Booting Pipelex on first call (no-op if already initialized); validating + the input; opening a per-call scoped library if a ``library_crate_dump`` + is provided; then dispatching to the requested execution mode. + + The optional ``graph_context`` is plumbed into ``JobMetadata`` so callers + (e.g. a streaming activity) that already opened a ``GraphTracerManager`` + tracer for this pipeline run get per-step trace events flowing through + the configured event log. ``graph_context`` is only honored for + ``DIRECT`` execution mode — TEMPORAL modes already have their own + event-log infrastructure via ``pipeline_run_setup`` and a passed-in + context would be ignored anyway. + """ + ensure_pipelex_booted() + _validate_input(input_payload) + + library_crate = _decode_library_crate(input_payload.library_crate_dump) + delivery_assignment = _decode_delivery_assignment(input_payload.delivery_assignment_dump) + + async with _scoped_library_for_crate(library_crate): + pipe_job = build_pipe_job_from_input( + input_payload=input_payload, + library_crate=library_crate, + graph_context=graph_context, + ) + + match input_payload.execution_mode: + case PipelexExecutionMode.DIRECT: + return await _run_direct(pipe_job=pipe_job, delivery_assignment=delivery_assignment) + case PipelexExecutionMode.TEMPORAL_BLOCKING: + _require_pipelex_temporal_extra() + return await _run_temporal_blocking(pipe_job=pipe_job, delivery_assignment=delivery_assignment) + case PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET: + _require_pipelex_temporal_extra() + return await _run_temporal_fire_and_forget(pipe_job=pipe_job, delivery_assignment=delivery_assignment) + + +def build_pipe_job_from_input( + input_payload: PipelexPipeRunInput, + library_crate: LibraryCrate | None, + graph_context: GraphContext | None = None, +) -> PipeJob: + """Hydrate a PipeJob from JSON-safe input. + + Looks up the pipe in the active library; the caller is responsible for + making sure the active library contains the pipe (by passing a + ``library_crate_dump`` or pre-loading the library at boot). + + The optional ``graph_context`` is plumbed into ``JobMetadata`` so a + caller (e.g. a streaming activity) that has already opened a + ``GraphTracerManager`` tracer for this pipeline run can have per-step + ``PipeStartEvent`` / ``PipeEndSuccessEvent`` events flow through the + pipe execution. When ``None``, no tracing happens (current default). + """ + pipe = get_required_pipe(pipe_code=input_payload.pipe_code) + + pipeline_run_id = input_payload.pipeline_run_id or shortuuid.uuid() + + working_memory: WorkingMemory + if input_payload.inputs: + working_memory = WorkingMemoryFactory.make_from_pipeline_inputs( + pipeline_inputs=input_payload.inputs, + search_domain_codes=[pipe.domain_code], + ) + else: + working_memory = WorkingMemoryFactory.make_empty() + + job_metadata = JobMetadata( + user_id=input_payload.user_id or OTelConstants.DEFAULT_USER_ID, + pipeline_run_id=pipeline_run_id, + graph_context=graph_context, + ) + pipe_run_params = PipeRunParamsFactory.make_run_params() + + return PipeJobFactory.make_pipe_job( + pipe=pipe, + pipe_run_params=pipe_run_params, + job_metadata=job_metadata, + working_memory=working_memory, + output_name=input_payload.output_name, + library_crate=library_crate, + ) + + +def serialize_pipe_output(pipe_output: PipeOutput) -> dict[str, Any]: + """Dehydrate a PipeOutput's working memory to a JSON-safe dict. + + Always uses ``WorkingMemory.dump_for_temporal()`` — the same format Pipelex + uses internally for Temporal transit. The shape is stable regardless of + whether a ``library_crate`` was attached: + ``{"root": {stuff_name: {"content": {...}, ...}}, "aliases": {...}}``. + + Type metadata embedded by ``dump_for_temporal`` lets callers reconstruct a + typed ``WorkingMemory`` when they have the matching class registry in + scope (e.g. via ``hydrate_working_memory``). + """ + return pipe_output.working_memory.dump_for_temporal() + + +def _validate_input(input_payload: PipelexPipeRunInput) -> None: + if input_payload.execution_mode is PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET and input_payload.delivery_assignment_dump is None: + msg = ( + "PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET requires a delivery_assignment_dump; " + "otherwise the pipe completion would be silently dropped." + ) + raise PipelexBridgeRuntimeError(msg) + + +def _decode_library_crate(library_crate_dump: dict[str, Any] | None) -> LibraryCrate | None: + if library_crate_dump is None: + return None + return LibraryCrate.model_validate(library_crate_dump) + + +def _decode_delivery_assignment(delivery_assignment_dump: dict[str, Any] | None) -> DeliveryAssignment | None: + if delivery_assignment_dump is None: + return None + return DeliveryAssignment.model_validate(delivery_assignment_dump) + + +@asynccontextmanager +async def _scoped_library_for_crate(library_crate: LibraryCrate | None) -> AsyncGenerator[str | None, None]: # noqa: RUF029 + """Open a per-call scoped library for the duration of a pipe run. + + When ``library_crate`` is None, this is a no-op: callers fall back to the + library that was loaded into the active class registry at boot. When + provided, opens a fresh library, loads the crate into it, sets it as the + current library for the duration of the pipe execution, and tears it down + on the way out. + """ + if library_crate is None: + yield None + return + + library_manager = get_library_manager() + library_id = f"runtime_bridge_{uuid4().hex[:8]}" + library_manager.open_library(library_id=library_id) + set_current_library(library_id=library_id) + try: + library_manager.load_from_crate(library_id=library_id, crate=library_crate) + yield library_id + finally: + library_manager.teardown(library_id=library_id) + teardown_current_library() + + +async def _run_direct( + pipe_job: PipeJob, + delivery_assignment: DeliveryAssignment | None, +) -> PipelexPipeRunOutput: + pipe_run = PipeRun(pipe_router=PipeRouter()) + try: + pipe_output = await pipe_run.run(pipe_job=pipe_job, delivery_assignment=delivery_assignment) + except (PipeRunError, PipeJobError, PipeRouterError, PipeExecutionError, PipelineExecutionError) as exc: + msg = f"Pipe execution failed in DIRECT mode for pipe '{pipe_job.pipe.code}': {exc}" + raise PipelexBridgeRuntimeError(msg) from exc + + return _serialize_completed_output( + pipe_output=pipe_output, + pipe_job=pipe_job, + workflow_id=None, + ) + + +async def _run_temporal_blocking( + pipe_job: PipeJob, + delivery_assignment: DeliveryAssignment | None, +) -> PipelexPipeRunOutput: + from pipelex.temporal.tprl_pipe.temporal_pipe_run import make_temporal_pipe_run # noqa: PLC0415 + + temporal_pipe_run = make_temporal_pipe_run() + try: + pipe_output = await temporal_pipe_run.run(pipe_job=pipe_job, delivery_assignment=delivery_assignment) + except (PipeRunError, PipeJobError, PipeRouterError, PipeExecutionError, PipelineExecutionError) as exc: + msg = f"Pipe execution failed in TEMPORAL_BLOCKING mode for pipe '{pipe_job.pipe.code}': {exc}" + raise PipelexBridgeRuntimeError(msg) from exc + + return _serialize_completed_output( + pipe_output=pipe_output, + pipe_job=pipe_job, + workflow_id=pipe_output.pipeline_run_id, + ) + + +async def _run_temporal_fire_and_forget( + pipe_job: PipeJob, + delivery_assignment: DeliveryAssignment | None, +) -> PipelexPipeRunOutput: + from pipelex.temporal.tprl_pipe.temporal_pipe_run import make_temporal_pipe_run # noqa: PLC0415 + + temporal_pipe_run = make_temporal_pipe_run() + try: + workflow_id, _handle = await temporal_pipe_run.start(pipe_job=pipe_job, delivery_assignment=delivery_assignment) + except (PipeRunError, PipeJobError, PipeRouterError, PipeExecutionError, PipelineExecutionError) as exc: + msg = f"Pipe dispatch failed in TEMPORAL_FIRE_AND_FORGET mode for pipe '{pipe_job.pipe.code}': {exc}" + raise PipelexBridgeRuntimeError(msg) from exc + + return PipelexPipeRunOutput( + output_dict={}, + main_stuff_name=None, + pipeline_run_id=pipe_job.job_metadata.pipeline_run_id, + workflow_id=workflow_id, + is_completed=False, + graph_spec_dump=None, + ) + + +def _serialize_completed_output( + pipe_output: PipeOutput, + pipe_job: PipeJob, # noqa: ARG001 — kept for symmetry with future per-crate serialization tweaks + workflow_id: str | None, +) -> PipelexPipeRunOutput: + output_dict = serialize_pipe_output(pipe_output=pipe_output) + + main_stuff_name = _resolve_main_stuff_root_key(pipe_output=pipe_output) + + graph_spec_dump = pipe_output.graph_spec.model_dump(mode="json") if pipe_output.graph_spec is not None else None + + return PipelexPipeRunOutput( + output_dict=output_dict, + main_stuff_name=main_stuff_name, + pipeline_run_id=pipe_output.pipeline_run_id, + workflow_id=workflow_id, + is_completed=True, + graph_spec_dump=graph_spec_dump, + ) + + +def _resolve_main_stuff_root_key(pipe_output: PipeOutput) -> str | None: + """Return the actual ``root`` dict key under which the main stuff lives. + + The main stuff can either sit directly at ``root[MAIN_STUFF_NAME]`` or be + referenced via ``aliases[MAIN_STUFF_NAME]`` pointing at its real name. + Callers indexing the output_dict need the actual root key, not the + stuff's display ``stuff_name``. + """ + working_memory = pipe_output.working_memory + if MAIN_STUFF_NAME in working_memory.root: + return MAIN_STUFF_NAME + aliased_target = working_memory.aliases.get(MAIN_STUFF_NAME) + if aliased_target is not None and aliased_target in working_memory.root: + return aliased_target + return None + + +def _require_pipelex_temporal_extra() -> None: + try: + import temporalio # noqa: F401, PLC0415 + except ImportError as exc: + msg = "TEMPORAL_* execution modes require the pipelex[temporal] extra. Install with: pip install 'pipelex[temporal]'" + raise MissingPipelexTemporalExtraError(msg) from exc diff --git a/pipelex/runtime_bridge/exceptions.py b/pipelex/runtime_bridge/exceptions.py new file mode 100644 index 000000000..ba2faa12d --- /dev/null +++ b/pipelex/runtime_bridge/exceptions.py @@ -0,0 +1,13 @@ +from pipelex.base_exceptions import PipelexError + + +class PipelexRuntimeBridgeError(PipelexError): + """Base for errors raised by the Pipelex runtime-bridge surface.""" + + +class MissingPipelexTemporalExtraError(PipelexRuntimeBridgeError): + """Raised when a TEMPORAL_* execution mode is requested without the pipelex[temporal] extra.""" + + +class PipelexBridgeRuntimeError(PipelexRuntimeBridgeError): + """Raised when a pipe execution dispatched through the bridge fails.""" diff --git a/pipelex/runtime_bridge/execution_mode.py b/pipelex/runtime_bridge/execution_mode.py new file mode 100644 index 000000000..2dd4a7b73 --- /dev/null +++ b/pipelex/runtime_bridge/execution_mode.py @@ -0,0 +1,37 @@ +from pipelex.types import StrEnum + + +class PipelexExecutionMode(StrEnum): + """How a Pipelex pipe runs inside a host runtime activity. + + DIRECT: in-process; no Temporal involved on Pipelex's side; activity blocks + until the pipe completes. Fastest feedback, simplest ops. + TEMPORAL_BLOCKING: dispatch the pipe as a Pipelex Temporal workflow; the + activity awaits completion. Pipe runs durably on Pipelex's worker + fleet. Requires the pipelex[temporal] extra. + TEMPORAL_FIRE_AND_FORGET: dispatch the pipe as a Pipelex Temporal workflow + and return immediately with the workflow_id. Activity does NOT wait; + completion is signalled out-of-band via DeliveryAssignment (webhook / + storage). Same dep requirements as TEMPORAL_BLOCKING. + ``delivery_assignment_dump`` is required. + """ + + DIRECT = "direct" + TEMPORAL_BLOCKING = "temporal_blocking" + TEMPORAL_FIRE_AND_FORGET = "temporal_fire_and_forget" + + @property + def requires_pipelex_temporal(self) -> bool: + match self: + case PipelexExecutionMode.DIRECT: + return False + case PipelexExecutionMode.TEMPORAL_BLOCKING | PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET: + return True + + @property + def is_fire_and_forget(self) -> bool: + match self: + case PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET: + return True + case PipelexExecutionMode.DIRECT | PipelexExecutionMode.TEMPORAL_BLOCKING: + return False diff --git a/pyproject.toml b/pyproject.toml index 122c0981a..bfc9b1504 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Evotis S.A.S.", email = "oss@pipelex.com" }] maintainers = [{ name = "Pipelex staff", email = "oss@pipelex.com" }] license = "MIT" readme = "README.md" -requires-python = ">=3.10,<3.15" +requires-python = ">=3.12,<3.15" classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", @@ -84,10 +84,10 @@ google-genai = [ ] huggingface = ["huggingface_hub>=0.23,<1.0.0"] linkup = ["linkup-sdk>=0.12.0"] -mistralai = ["mistralai>=1.12.0"] +mistralai = ["mistralai>=2.4.4"] dynamodb = ["boto3>=1.34.131"] s3 = ["boto3>=1.34.131", "aioboto3>=13.4.0"] -temporal = ["temporalio==1.23.0", "aiohttp>=3.9.0"] +temporal = ["temporalio==1.24.0", "aiohttp>=3.9.0"] docs = [ "mike>=2.1.3", "mkdocs>=1.6.1", @@ -292,6 +292,7 @@ exclude_lines = [ [tool.ruff] exclude = [ + ".claude/skills/workflows", ".cursor", ".git", ".github", @@ -439,6 +440,11 @@ convention = "google" [tool.uv] required-version = ">=0.7.2" +[tool.uv.sources] +# Temporary: pin to fork that adds mistralai 2.x support. Revert to PyPI release once +# https://github.com/567-labs/instructor/pull/2298 is merged and published. +instructor = { git = "https://github.com/Ian321/instructor.git", rev = "4ea22d2396ca35514929f27faed866115e8b3583" } + [tool.hatch.build.targets.wheel] packages = ["pipelex"] exclude = ["pipelex/cli/dev_cli"] diff --git a/tests/integration/pipelex/runtime_bridge/conftest.py b/tests/integration/pipelex/runtime_bridge/conftest.py new file mode 100644 index 000000000..ae1e1d47b --- /dev/null +++ b/tests/integration/pipelex/runtime_bridge/conftest.py @@ -0,0 +1,35 @@ +from collections.abc import Generator +from pathlib import Path + +import pytest + +from pipelex.hub import get_func_registry, get_library_manager, set_current_library +from tests.integration.pipelex.runtime_bridge.test_data.bridge_funcs import mistralai_workflows_bridge_echo + +TEST_DATA_DIR = Path(__file__).parent / "test_data" + + +@pytest.fixture(scope="class") +def bridge_test_library() -> Generator[str, None, None]: + """Open a class-scoped library populated with the bridge test pipe. + + The pipe ``mistralai_workflows_bridge_test.bridge_func_pipe`` is registered + in the active library, and the matching Python function is registered in + the FuncRegistry. Both are torn down on exit. + """ + func_registry = get_func_registry() + func_registry.register_function(mistralai_workflows_bridge_echo) + + library_manager = get_library_manager() + library_id, _ = library_manager.open_library() + set_current_library(library_id=library_id) + library_manager.load_libraries( + library_id=library_id, + library_dirs=[TEST_DATA_DIR], + ) + try: + yield library_id + finally: + library_manager.teardown(library_id=library_id) + if func_registry.has_function("mistralai_workflows_bridge_echo"): + func_registry.unregister_function_by_name("mistralai_workflows_bridge_echo") diff --git a/tests/integration/pipelex/runtime_bridge/test_bridge_direct.py b/tests/integration/pipelex/runtime_bridge/test_bridge_direct.py new file mode 100644 index 000000000..20d6e45d9 --- /dev/null +++ b/tests/integration/pipelex/runtime_bridge/test_bridge_direct.py @@ -0,0 +1,119 @@ +"""Layer-1 integration tests for the runtime-bridge in DIRECT mode. + +These tests do NOT depend on any host-runtime optional package — they +exercise only the framework-agnostic core (``run_pipe_via_bridge`` with a +real loaded pipe). The Mistral Workflows activity wrapper is covered +separately in the ``pipelex-mistralai-workflows`` package, which DOES +require the optional dep. +""" + +from typing import Any + +import pytest + +from pipelex.hub import get_library_manager +from pipelex.runtime_bridge.bridge import PipelexPipeRunInput, run_pipe_via_bridge +from pipelex.runtime_bridge.execution_mode import PipelexExecutionMode + +PIPE_REF = "mistralai_workflows_bridge_test.bridge_func_pipe" + + +@pytest.mark.asyncio(loop_scope="class") +class TestBridgeDirect: + async def test_direct_mode_with_globally_loaded_library( + self, + bridge_test_library: str, # noqa: ARG002 + ) -> None: + """Bridge runs a pipe found in the active library when no crate is provided.""" + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code=PIPE_REF, + inputs={"input_text": "hello world"}, + execution_mode=PipelexExecutionMode.DIRECT, + ) + ) + + assert result.is_completed is True + assert result.workflow_id is None + assert result.main_stuff_name is not None + main_stuff_dump = result.output_dict["root"][result.main_stuff_name] + assert main_stuff_dump["content"]["text"] == "hello world" + + async def test_direct_mode_with_library_crate_dump( + self, + bridge_test_library: str, + ) -> None: + """Bridge round-trips through ``library_crate_dump`` end-to-end. + + Captures a LibraryCrate from the loaded library, pipes it through the + bridge as a JSON-safe dict, and verifies the pipe still resolves and + runs against the per-call scoped library that the bridge opens. + """ + crate = get_library_manager().get_crate(library_id=bridge_test_library) + assert crate is not None + crate_dump: dict[str, Any] = crate.model_dump(mode="json") + + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code=PIPE_REF, + inputs={"input_text": "via crate"}, + library_crate_dump=crate_dump, + execution_mode=PipelexExecutionMode.DIRECT, + ) + ) + + assert result.is_completed is True + assert result.main_stuff_name is not None + main_stuff_dump = result.output_dict["root"][result.main_stuff_name] + assert main_stuff_dump["content"]["text"] == "via crate" + + async def test_direct_mode_uses_caller_pipeline_run_id( + self, + bridge_test_library: str, # noqa: ARG002 + ) -> None: + """Caller-supplied ``pipeline_run_id`` propagates to the PipeJob.""" + caller_run_id = "caller-supplied-run-id" + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code=PIPE_REF, + inputs={"input_text": "trace me"}, + pipeline_run_id=caller_run_id, + execution_mode=PipelexExecutionMode.DIRECT, + ) + ) + + assert result.is_completed is True + assert result.pipeline_run_id == caller_run_id + + async def test_direct_mode_dynamic_concept_round_trips_via_library_crate_dump( + self, + bridge_test_library: str, + ) -> None: + """A concept with an inline structure round-trips through ``library_crate_dump``. + + ``EchoEnvelope`` is defined inline in the bridge_test bundle. The bridge + dehydrates the library to a JSON-safe crate dump, opens a per-call + scoped library on the receiving side, and re-hydrates the concept so + ``PipeCompose`` can construct a ``StructuredContent`` matching the + dynamic shape. + """ + envelope_pipe_ref = "mistralai_workflows_bridge_test.bridge_envelope_pipe" + crate = get_library_manager().get_crate(library_id=bridge_test_library) + assert crate is not None + crate_dump: dict[str, Any] = crate.model_dump(mode="json") + + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code=envelope_pipe_ref, + inputs={"input_text": "wrapped"}, + library_crate_dump=crate_dump, + execution_mode=PipelexExecutionMode.DIRECT, + ) + ) + + assert result.is_completed is True + assert result.main_stuff_name is not None + main_stuff = result.output_dict["root"][result.main_stuff_name] + content = main_stuff["content"] + assert content["text"] == "wrapped" + assert content["origin"] == "mistralai_workflows_bridge" diff --git a/tests/integration/pipelex/runtime_bridge/test_data/bridge_funcs.py b/tests/integration/pipelex/runtime_bridge/test_data/bridge_funcs.py new file mode 100644 index 000000000..e82e05d00 --- /dev/null +++ b/tests/integration/pipelex/runtime_bridge/test_data/bridge_funcs.py @@ -0,0 +1,14 @@ +"""Test functions registered for the runtime-bridge integration tests.""" + +from pipelex.core.memory.working_memory import WorkingMemory +from pipelex.core.stuffs.text_content import TextContent + + +def mistralai_workflows_bridge_echo(working_memory: WorkingMemory) -> TextContent: + """Echo the ``input_text`` stuff back as a TextContent output. + + Used by tests/integration/pipelex/runtime_bridge to validate end-to-end + pipe execution through the bridge without invoking inference. + """ + input_text = working_memory.get_stuff_as_str("input_text") + return TextContent(text=input_text) diff --git a/tests/integration/pipelex/runtime_bridge/test_data/bridge_test.mthds b/tests/integration/pipelex/runtime_bridge/test_data/bridge_test.mthds new file mode 100644 index 000000000..9cc1f048c --- /dev/null +++ b/tests/integration/pipelex/runtime_bridge/test_data/bridge_test.mthds @@ -0,0 +1,56 @@ +domain = "mistralai_workflows_bridge_test" +description = "Test pipes for the mistralai_workflows plugin bridge" + +[concept.EchoEnvelope] +description = "Custom dynamic concept used to exercise library_crate_dump round-trip for inline-structured concepts." + +[concept.EchoEnvelope.structure] +text = { type = "text", required = true, description = "The echoed text" } +origin = { type = "text", required = true, description = "Origin marker for the echo" } + +[pipe.bridge_func_pipe] +type = "PipeFunc" +description = "Echoes the input text back as output (DIRECT mode only — PipeFunc is not Temporal-compatible)" +output = "Text" +function_name = "mistralai_workflows_bridge_echo" + +[pipe.bridge_compose_pipe] +type = "PipeCompose" +description = "Echoes the input_text via a Jinja2 template (Temporal-compatible)" +inputs = { input_text = "Text" } +output = "Text" +template = "{{ input_text.text }}" + +[pipe.bridge_envelope_pipe] +type = "PipeCompose" +description = "Composes the input_text into a structured EchoEnvelope, exercising dynamic-concept round-trip via library_crate_dump" +inputs = { input_text = "Text" } +output = "EchoEnvelope" + +[pipe.bridge_envelope_pipe.construct] +text = { from = "input_text.text" } +origin = "mistralai_workflows_bridge" + +[pipe.bridge_seq_step_one] +type = "PipeCompose" +description = "First step of bridge_sequence_pipe — uppercases the input text" +inputs = { input_text = "Text" } +output = "Text" +template = "{{ input_text.text | upper }}" + +[pipe.bridge_seq_step_two] +type = "PipeCompose" +description = "Second step of bridge_sequence_pipe — wraps the result with markers" +inputs = { uppercased = "Text" } +output = "Text" +template = "[STEP2:{{ uppercased.text }}]" + +[pipe.bridge_sequence_pipe] +type = "PipeSequence" +description = "Two-step sequence used by Phase 2.1 streaming tests to assert per-step events" +inputs = { input_text = "Text" } +output = "Text" +steps = [ + { pipe = "bridge_seq_step_one", result = "uppercased" }, + { pipe = "bridge_seq_step_two", result = "final_text" }, +] diff --git a/tests/unit/pipelex/plugins/mistral/test_mistral_reasoning.py b/tests/unit/pipelex/plugins/mistral/test_mistral_reasoning.py index ad973c9d3..13cdc466d 100644 --- a/tests/unit/pipelex/plugins/mistral/test_mistral_reasoning.py +++ b/tests/unit/pipelex/plugins/mistral/test_mistral_reasoning.py @@ -101,7 +101,7 @@ def test_thinking_mode_adaptive_raises_capability_error(self, mocker: MockerFixt def test_no_reasoning_params_returns_unset(self, mocker: MockerFixture): """When neither reasoning_effort nor reasoning_budget is set, returns UNSET.""" - from mistralai.types import UNSET # noqa: PLC0415 + from mistralai.client.types import UNSET # noqa: PLC0415 worker = _make_worker(mocker, thinking_mode=ThinkingMode.MANUAL) job_params = LLMJobParams(temperature=0.5) diff --git a/tests/unit/pipelex/plugins/mistral/test_mistral_worker_error_handling.py b/tests/unit/pipelex/plugins/mistral/test_mistral_worker_error_handling.py index 230e501d7..341d48c6a 100644 --- a/tests/unit/pipelex/plugins/mistral/test_mistral_worker_error_handling.py +++ b/tests/unit/pipelex/plugins/mistral/test_mistral_worker_error_handling.py @@ -6,7 +6,7 @@ import httpx import pytest -from mistralai import MistralError +from mistralai.client.errors import MistralError if TYPE_CHECKING: from pytest_mock import MockerFixture diff --git a/tests/unit/pipelex/plugins/test_plugin_pipelex_storage_images.py b/tests/unit/pipelex/plugins/test_plugin_pipelex_storage_images.py index 071305e91..0f511b487 100644 --- a/tests/unit/pipelex/plugins/test_plugin_pipelex_storage_images.py +++ b/tests/unit/pipelex/plugins/test_plugin_pipelex_storage_images.py @@ -6,7 +6,7 @@ import pytest import pytest_asyncio from google.genai import types as genai_types -from mistralai.models import ImageURLChunk +from mistralai.client.models import ImageURLChunk from pytest_mock import MockerFixture from pipelex.cogt.image.prompt_image import PromptImageUri diff --git a/tests/unit/pipelex/runtime_bridge/test_dispatch.py b/tests/unit/pipelex/runtime_bridge/test_dispatch.py new file mode 100644 index 000000000..6c9f3d92a --- /dev/null +++ b/tests/unit/pipelex/runtime_bridge/test_dispatch.py @@ -0,0 +1,121 @@ +import pytest +from pytest_mock import MockerFixture + +from pipelex.core.memory.working_memory_factory import WorkingMemoryFactory +from pipelex.core.pipes.pipe_output import PipeOutput +from pipelex.pipe_run.pipe_job import PipeJob +from pipelex.pipe_run.pipe_run import PipeRun +from pipelex.pipe_run.pipe_run_params_factory import PipeRunParamsFactory +from pipelex.pipeline.job_metadata import JobMetadata +from pipelex.runtime_bridge.bridge import PipelexPipeRunInput, run_pipe_via_bridge +from pipelex.runtime_bridge.execution_mode import PipelexExecutionMode + + +def _make_fake_pipe_job(mocker: MockerFixture, pipe_code: str, pipeline_run_id: str) -> PipeJob: + """Build a PipeJob without triggering Pydantic's PipeAbstract validation. + + Tests at the dispatch layer don't care about the concrete pipe — only + that the bridge routes the right pipe_job to the right PipeRun. Using + ``model_construct`` lets us pass a MagicMock as ``pipe`` without + constructing a full PipeAbstract subclass. + """ + fake_pipe = mocker.MagicMock() + fake_pipe.code = pipe_code + fake_pipe.domain_code = "fake_domain" + return PipeJob.model_construct( + pipe=fake_pipe, + working_memory=WorkingMemoryFactory.make_empty(), + pipe_run_params=PipeRunParamsFactory.make_run_params(), + job_metadata=JobMetadata(user_id="anonymous", pipeline_run_id=pipeline_run_id), + library_crate=None, + ) + + +@pytest.mark.asyncio +class TestDispatch: + async def test_direct_mode_calls_pipe_run_with_pipe_job(self, mocker: MockerFixture) -> None: + fake_job = _make_fake_pipe_job(mocker=mocker, pipe_code="fake_pipe", pipeline_run_id="caller-run-id") + mocker.patch( + "pipelex.runtime_bridge.bridge.build_pipe_job_from_input", + return_value=fake_job, + ) + + fake_output = PipeOutput( + working_memory=WorkingMemoryFactory.make_empty(), + pipeline_run_id="injected-run-id", + ) + mock_run = mocker.patch.object(PipeRun, "run", new_callable=mocker.AsyncMock, return_value=fake_output) + + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code="fake_pipe", + execution_mode=PipelexExecutionMode.DIRECT, + pipeline_run_id="caller-run-id", + ) + ) + + assert mock_run.await_count == 1 + await_args = mock_run.await_args + assert await_args is not None + call_kwargs: dict[str, object] = dict(await_args.kwargs) + assert call_kwargs["delivery_assignment"] is None + assert call_kwargs["pipe_job"] is fake_job + + assert result.is_completed is True + assert result.pipeline_run_id == "injected-run-id" + assert result.workflow_id is None + assert result.graph_spec_dump is None + + async def test_temporal_blocking_dispatches_to_temporal_pipe_run(self, mocker: MockerFixture) -> None: + fake_job = _make_fake_pipe_job(mocker=mocker, pipe_code="fake_pipe", pipeline_run_id="caller-run-id") + mocker.patch( + "pipelex.runtime_bridge.bridge.build_pipe_job_from_input", + return_value=fake_job, + ) + + fake_output = PipeOutput( + working_memory=WorkingMemoryFactory.make_empty(), + pipeline_run_id="temporal-run-id", + ) + fake_temporal_run = mocker.AsyncMock(return_value=fake_output) + fake_factory = mocker.patch("pipelex.temporal.tprl_pipe.temporal_pipe_run.make_temporal_pipe_run") + fake_factory.return_value.run = fake_temporal_run + + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code="fake_pipe", + execution_mode=PipelexExecutionMode.TEMPORAL_BLOCKING, + ) + ) + + fake_factory.assert_called_once() + assert fake_temporal_run.await_count == 1 + assert result.is_completed is True + assert result.workflow_id == "temporal-run-id" + + async def test_temporal_fire_and_forget_returns_workflow_id_without_completion(self, mocker: MockerFixture) -> None: + fake_job = _make_fake_pipe_job(mocker=mocker, pipe_code="fake_pipe", pipeline_run_id="caller-run-id") + mocker.patch( + "pipelex.runtime_bridge.bridge.build_pipe_job_from_input", + return_value=fake_job, + ) + + fake_handle = mocker.MagicMock() + fake_start = mocker.AsyncMock(return_value=("wf-id-42", fake_handle)) + fake_factory = mocker.patch("pipelex.temporal.tprl_pipe.temporal_pipe_run.make_temporal_pipe_run") + fake_factory.return_value.start = fake_start + + result = await run_pipe_via_bridge( + PipelexPipeRunInput( + pipe_code="fake_pipe", + execution_mode=PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET, + delivery_assignment_dump={"webhooks": [], "storage": None}, + pipeline_run_id="caller-run-id", + ) + ) + + fake_start.assert_awaited_once() + assert result.is_completed is False + assert result.workflow_id == "wf-id-42" + assert result.pipeline_run_id == "caller-run-id" + assert result.output_dict == {} diff --git a/tests/unit/pipelex/runtime_bridge/test_execution_mode.py b/tests/unit/pipelex/runtime_bridge/test_execution_mode.py new file mode 100644 index 000000000..6a1ea927d --- /dev/null +++ b/tests/unit/pipelex/runtime_bridge/test_execution_mode.py @@ -0,0 +1,18 @@ +from pipelex.runtime_bridge.execution_mode import PipelexExecutionMode + + +class TestPipelexExecutionMode: + def test_string_values_are_stable(self): + assert PipelexExecutionMode.DIRECT == "direct" + assert PipelexExecutionMode.TEMPORAL_BLOCKING == "temporal_blocking" + assert PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET == "temporal_fire_and_forget" + + def test_requires_pipelex_temporal(self): + assert PipelexExecutionMode.DIRECT.requires_pipelex_temporal is False + assert PipelexExecutionMode.TEMPORAL_BLOCKING.requires_pipelex_temporal is True + assert PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET.requires_pipelex_temporal is True + + def test_is_fire_and_forget(self): + assert PipelexExecutionMode.DIRECT.is_fire_and_forget is False + assert PipelexExecutionMode.TEMPORAL_BLOCKING.is_fire_and_forget is False + assert PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET.is_fire_and_forget is True diff --git a/tests/unit/pipelex/runtime_bridge/test_input_models.py b/tests/unit/pipelex/runtime_bridge/test_input_models.py new file mode 100644 index 000000000..b710ba8d7 --- /dev/null +++ b/tests/unit/pipelex/runtime_bridge/test_input_models.py @@ -0,0 +1,69 @@ +import pytest +from pydantic import ValidationError + +from pipelex.runtime_bridge.bridge import PipelexPipeRunInput, PipelexPipeRunOutput +from pipelex.runtime_bridge.execution_mode import PipelexExecutionMode + + +class TestInputOutputModels: + def test_input_defaults_match_design(self): + payload = PipelexPipeRunInput(pipe_code="some_pipe") + assert payload.pipe_code == "some_pipe" + assert payload.inputs == {} + assert payload.output_name is None + assert payload.pipeline_run_id is None + assert payload.user_id is None + assert payload.library_crate_dump is None + assert payload.execution_mode is PipelexExecutionMode.DIRECT + assert payload.delivery_assignment_dump is None + + def test_input_forbids_extra_fields(self): + with pytest.raises(ValidationError): + PipelexPipeRunInput.model_validate( + { + "pipe_code": "some_pipe", + "unexpected": "field", + } + ) + + def test_input_requires_pipe_code(self): + with pytest.raises(ValidationError): + PipelexPipeRunInput.model_validate({}) + + def test_input_round_trip_via_json(self): + original = PipelexPipeRunInput( + pipe_code="some_pipe", + inputs={"foo": "bar"}, + execution_mode=PipelexExecutionMode.TEMPORAL_BLOCKING, + pipeline_run_id="run-123", + user_id="alice", + ) + round_tripped = PipelexPipeRunInput.model_validate(original.model_dump(mode="json")) + assert round_tripped == original + + def test_output_required_fields(self): + with pytest.raises(ValidationError): + PipelexPipeRunOutput.model_validate({"output_dict": {}}) # missing pipeline_run_id and is_completed + + def test_output_forbids_extra_fields(self): + with pytest.raises(ValidationError): + PipelexPipeRunOutput.model_validate( + { + "output_dict": {}, + "pipeline_run_id": "run-1", + "is_completed": True, + "rogue_field": 42, + } + ) + + def test_output_round_trip_via_json(self): + original = PipelexPipeRunOutput( + output_dict={"foo": "bar"}, + main_stuff_name="main", + pipeline_run_id="run-1", + workflow_id=None, + is_completed=True, + graph_spec_dump=None, + ) + round_tripped = PipelexPipeRunOutput.model_validate(original.model_dump(mode="json")) + assert round_tripped == original diff --git a/tests/unit/pipelex/runtime_bridge/test_validation.py b/tests/unit/pipelex/runtime_bridge/test_validation.py new file mode 100644 index 000000000..3d114dd78 --- /dev/null +++ b/tests/unit/pipelex/runtime_bridge/test_validation.py @@ -0,0 +1,75 @@ +import pytest + +from pipelex.libraries.library_crate import LibraryCrate +from pipelex.pipe_run.delivery_assignment import DeliveryAssignment +from pipelex.runtime_bridge.bridge import ( + PipelexPipeRunInput, + _decode_delivery_assignment, # noqa: PLC2701 # pyright: ignore[reportPrivateUsage] + _decode_library_crate, # noqa: PLC2701 # pyright: ignore[reportPrivateUsage] + _validate_input, # noqa: PLC2701 # pyright: ignore[reportPrivateUsage] + run_pipe_via_bridge, +) +from pipelex.runtime_bridge.exceptions import PipelexBridgeRuntimeError +from pipelex.runtime_bridge.execution_mode import PipelexExecutionMode + + +class TestBridgeValidationAndDecoding: + def test_validate_input_passes_for_direct_without_delivery(self): + payload = PipelexPipeRunInput(pipe_code="any", execution_mode=PipelexExecutionMode.DIRECT) + _validate_input(payload) # must not raise + + def test_validate_input_passes_for_temporal_blocking_without_delivery(self): + payload = PipelexPipeRunInput(pipe_code="any", execution_mode=PipelexExecutionMode.TEMPORAL_BLOCKING) + _validate_input(payload) # must not raise + + def test_validate_input_rejects_fire_and_forget_without_delivery(self): + payload = PipelexPipeRunInput( + pipe_code="any", + execution_mode=PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET, + ) + with pytest.raises(PipelexBridgeRuntimeError, match="TEMPORAL_FIRE_AND_FORGET"): + _validate_input(payload) + + def test_validate_input_accepts_fire_and_forget_with_delivery(self): + payload = PipelexPipeRunInput( + pipe_code="any", + execution_mode=PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET, + delivery_assignment_dump={"webhooks": [], "storage": None}, + ) + _validate_input(payload) # must not raise + + def test_decode_library_crate_returns_none_for_none(self): + assert _decode_library_crate(None) is None + + def test_decode_library_crate_round_trips_empty(self): + empty = LibraryCrate() + decoded = _decode_library_crate(empty.model_dump(mode="json")) + assert decoded is not None + assert decoded.concepts == empty.concepts + assert decoded.pipes == empty.pipes + + def test_decode_delivery_assignment_returns_none_for_none(self): + assert _decode_delivery_assignment(None) is None + + def test_decode_delivery_assignment_round_trips(self): + assignment = DeliveryAssignment.model_validate( + { + "storage": {"key_prefix": "runs/abc"}, + "webhooks": [{"url": "https://example.test/hook"}], + } + ) + decoded = _decode_delivery_assignment(assignment.model_dump(mode="json")) + assert decoded is not None + assert decoded.storage is not None + assert decoded.storage.key_prefix == "runs/abc/" # storage validator appends trailing / + assert len(decoded.webhooks) == 1 + assert decoded.webhooks[0].url == "https://example.test/hook" + + @pytest.mark.asyncio + async def test_run_pipe_via_bridge_rejects_fire_and_forget_without_delivery(self): + payload = PipelexPipeRunInput( + pipe_code="any", + execution_mode=PipelexExecutionMode.TEMPORAL_FIRE_AND_FORGET, + ) + with pytest.raises(PipelexBridgeRuntimeError, match="TEMPORAL_FIRE_AND_FORGET"): + await run_pipe_via_bridge(payload) diff --git a/uv.lock b/uv.lock index b40eb7a3a..f908d7f1a 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.10, <3.15" +requires-python = ">=3.12, <3.15" resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", "python_full_version >= '3.14' and sys_platform == 'emscripten'", @@ -8,13 +8,9 @@ resolution-markers = [ "python_full_version == '3.13.*' and sys_platform == 'win32'", "python_full_version == '3.13.*' and sys_platform == 'emscripten'", "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11'", + "python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version < '3.13' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] [[package]] @@ -23,8 +19,7 @@ version = "1.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "packaging" }, { name = "psutil" }, { name = "pyyaml" }, @@ -97,7 +92,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, @@ -106,40 +100,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/85/cebc47ee74d8b408749073a1a46c6fcba13d170dc8af7e61996c6c9394ac/aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b", size = 750547, upload-time = "2026-03-31T21:56:30.024Z" }, - { url = "https://files.pythonhosted.org/packages/05/98/afd308e35b9d3d8c9ec54c0918f1d722c86dc17ddfec272fcdbcce5a3124/aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5", size = 503535, upload-time = "2026-03-31T21:56:31.935Z" }, - { url = "https://files.pythonhosted.org/packages/6f/4d/926c183e06b09d5270a309eb50fbde7b09782bfd305dec1e800f329834fb/aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670", size = 497830, upload-time = "2026-03-31T21:56:33.654Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d6/f47d1c690f115a5c2a5e8938cce4a232a5be9aac5c5fb2647efcbbbda333/aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274", size = 1682474, upload-time = "2026-03-31T21:56:35.513Z" }, - { url = "https://files.pythonhosted.org/packages/01/44/056fd37b1bb52eac760303e5196acc74d9d546631b035704ae5927f7b4ac/aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a", size = 1655259, upload-time = "2026-03-31T21:56:37.843Z" }, - { url = "https://files.pythonhosted.org/packages/91/9f/78eb1a20c1c28ae02f6a3c0f4d7b0dcc66abce5290cadd53d78ce3084175/aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d", size = 1736204, upload-time = "2026-03-31T21:56:39.822Z" }, - { url = "https://files.pythonhosted.org/packages/de/6c/d20d7de23f0b52b8c1d9e2033b2db1ac4dacbb470bb74c56de0f5f86bb4f/aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796", size = 1826198, upload-time = "2026-03-31T21:56:41.378Z" }, - { url = "https://files.pythonhosted.org/packages/2f/86/a6f3ff1fd795f49545a7c74b2c92f62729135d73e7e4055bf74da5a26c82/aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95", size = 1681329, upload-time = "2026-03-31T21:56:43.374Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/84cd3dab6b7b4f3e6fe9459a961acb142aaab846417f6e8905110d7027e5/aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5", size = 1560023, upload-time = "2026-03-31T21:56:45.031Z" }, - { url = "https://files.pythonhosted.org/packages/41/2c/db61b64b0249e30f954a65ab4cb4970ced57544b1de2e3c98ee5dc24165f/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a", size = 1652372, upload-time = "2026-03-31T21:56:47.075Z" }, - { url = "https://files.pythonhosted.org/packages/25/6f/e96988a6c982d047810c772e28c43c64c300c943b0ed5c1c0c4ce1e1027c/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73", size = 1662031, upload-time = "2026-03-31T21:56:48.835Z" }, - { url = "https://files.pythonhosted.org/packages/b7/26/a56feace81f3d347b4052403a9d03754a0ab23f7940780dada0849a38c92/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297", size = 1708118, upload-time = "2026-03-31T21:56:50.833Z" }, - { url = "https://files.pythonhosted.org/packages/78/6e/b6173a8ff03d01d5e1a694bc06764b5dad1df2d4ed8f0ceec12bb3277936/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074", size = 1548667, upload-time = "2026-03-31T21:56:52.81Z" }, - { url = "https://files.pythonhosted.org/packages/16/13/13296ffe2c132d888b3fe2c195c8b9c0c24c89c3fa5cc2c44464dc23b22e/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e", size = 1724490, upload-time = "2026-03-31T21:56:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/7a/b4/1f1c287f4a79782ef36e5a6e62954c85343bc30470d862d30bd5f26c9fa2/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7", size = 1667109, upload-time = "2026-03-31T21:56:56.21Z" }, - { url = "https://files.pythonhosted.org/packages/ef/42/8461a2aaf60a8f4ea4549a4056be36b904b0eb03d97ca9a8a2604681a500/aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9", size = 439478, upload-time = "2026-03-31T21:56:58.292Z" }, - { url = "https://files.pythonhosted.org/packages/e5/71/06956304cb5ee439dfe8d86e1b2e70088bd88ed1ced1f42fb29e5d855f0e/aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76", size = 462047, upload-time = "2026-03-31T21:57:00.257Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f5/a20c4ac64aeaef1679e25c9983573618ff765d7aa829fa2b84ae7573169e/aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6", size = 757513, upload-time = "2026-03-31T21:57:02.146Z" }, - { url = "https://files.pythonhosted.org/packages/75/0a/39fa6c6b179b53fcb3e4b3d2b6d6cad0180854eda17060c7218540102bef/aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d", size = 506748, upload-time = "2026-03-31T21:57:04.275Z" }, - { url = "https://files.pythonhosted.org/packages/87/ec/e38ce072e724fd7add6243613f8d1810da084f54175353d25ccf9f9c7e5a/aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c", size = 501673, upload-time = "2026-03-31T21:57:06.208Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/3bc7525d7e2beaa11b309a70d48b0d3cfc3c2089ec6a7d0820d59c657053/aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb", size = 1763757, upload-time = "2026-03-31T21:57:07.882Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ab/e87744cf18f1bd78263aba24924d4953b41086bd3a31d22452378e9028a0/aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6", size = 1720152, upload-time = "2026-03-31T21:57:09.946Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f3/ed17a6f2d742af17b50bae2d152315ed1b164b07a5fd5cc1754d99e4dfa5/aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13", size = 1818010, upload-time = "2026-03-31T21:57:12.157Z" }, - { url = "https://files.pythonhosted.org/packages/53/06/ecbc63dc937192e2a5cb46df4d3edb21deb8225535818802f210a6ea5816/aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174", size = 1907251, upload-time = "2026-03-31T21:57:14.023Z" }, - { url = "https://files.pythonhosted.org/packages/7e/a5/0521aa32c1ddf3aa1e71dcc466be0b7db2771907a13f18cddaa45967d97b/aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc", size = 1759969, upload-time = "2026-03-31T21:57:16.146Z" }, - { url = "https://files.pythonhosted.org/packages/f6/78/a38f8c9105199dd3b9706745865a8a59d0041b6be0ca0cc4b2ccf1bab374/aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6", size = 1616871, upload-time = "2026-03-31T21:57:17.856Z" }, - { url = "https://files.pythonhosted.org/packages/6f/41/27392a61ead8ab38072105c71aa44ff891e71653fe53d576a7067da2b4e8/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49", size = 1739844, upload-time = "2026-03-31T21:57:19.679Z" }, - { url = "https://files.pythonhosted.org/packages/6e/55/5564e7ae26d94f3214250009a0b1c65a0c6af4bf88924ccb6fdab901de28/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8", size = 1731969, upload-time = "2026-03-31T21:57:22.006Z" }, - { url = "https://files.pythonhosted.org/packages/6d/c5/705a3929149865fc941bcbdd1047b238e4a72bcb215a9b16b9d7a2e8d992/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d", size = 1795193, upload-time = "2026-03-31T21:57:24.256Z" }, - { url = "https://files.pythonhosted.org/packages/a6/19/edabed62f718d02cff7231ca0db4ef1c72504235bc467f7b67adb1679f48/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c", size = 1606477, upload-time = "2026-03-31T21:57:26.364Z" }, - { url = "https://files.pythonhosted.org/packages/de/fc/76f80ef008675637d88d0b21584596dc27410a990b0918cb1e5776545b5b/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac", size = 1813198, upload-time = "2026-03-31T21:57:28.316Z" }, - { url = "https://files.pythonhosted.org/packages/e5/67/5b3ac26b80adb20ea541c487f73730dc8fa107d632c998f25bbbab98fcda/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3", size = 1752321, upload-time = "2026-03-31T21:57:30.549Z" }, - { url = "https://files.pythonhosted.org/packages/88/06/e4a2e49255ea23fa4feeb5ab092d90240d927c15e47b5b5c48dff5a9ce29/aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06", size = 439069, upload-time = "2026-03-31T21:57:32.388Z" }, - { url = "https://files.pythonhosted.org/packages/c0/43/8c7163a596dab4f8be12c190cf467a1e07e4734cf90eebb39f7f5d53fc6a/aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8", size = 462859, upload-time = "2026-03-31T21:57:34.455Z" }, { url = "https://files.pythonhosted.org/packages/be/6f/353954c29e7dcce7cf00280a02c75f30e133c00793c7a2ed3776d7b2f426/aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9", size = 748876, upload-time = "2026-03-31T21:57:36.319Z" }, { url = "https://files.pythonhosted.org/packages/f5/1b/428a7c64687b3b2e9cd293186695affc0e1e54a445d0361743b231f11066/aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416", size = 499557, upload-time = "2026-03-31T21:57:38.236Z" }, { url = "https://files.pythonhosted.org/packages/29/47/7be41556bfbb6917069d6a6634bb7dd5e163ba445b783a90d40f5ac7e3a7/aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2", size = 500258, upload-time = "2026-03-31T21:57:39.923Z" }, @@ -252,7 +212,7 @@ wheels = [ [[package]] name = "anthropic" -version = "0.99.0" +version = "0.100.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -264,9 +224,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/c9/e8a3a1caeab575e80551b30b084096b5a430abc52739a526a1daaadd038c/anthropic-0.99.0.tar.gz", hash = "sha256:16f41e00f215ed2d193b146be3dd567c4319c32ed3af6c8725d68ba875257c1c", size = 727239, upload-time = "2026-05-05T16:03:07.986Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/2d/24caf0ff727cba2ed863925017c8f93463a2ea6224a0efe5626e672bc3d2/anthropic-0.100.0.tar.gz", hash = "sha256:650dee9e023afb16395939ee4104bbc21f966b380210119fb91122c12099c79a", size = 758255, upload-time = "2026-05-06T15:07:13.578Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/84/d0917506744e1707cf55659a57f1e3ff952eda5636df0ffffe3e884b7c61/anthropic-0.99.0-py3-none-any.whl", hash = "sha256:c44469b746ab2ef19a4c52dcbdb98e17bc95c60bebdd18ec40d76d2d23592b49", size = 700564, upload-time = "2026-05-05T16:03:06.059Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a0/c775c59ab9445ecabb57ef3d5c24027de060139189a9e312ef9ef889a665/anthropic-0.100.0-py3-none-any.whl", hash = "sha256:1c15769efa15d8fd5c1ebf900e25c57e3ee540f8554a29aa56e4edefffe2951d", size = 753596, upload-time = "2026-05-06T15:07:12.106Z" }, ] [[package]] @@ -280,7 +240,6 @@ name = "anyio" version = "4.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] @@ -302,21 +261,18 @@ wheels = [ name = "astroid" version = "4.0.4" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/07/63/0adf26577da5eff6eb7a177876c1cfa213856be9926a000f65c4add9692b/astroid-4.0.4.tar.gz", hash = "sha256:986fed8bcf79fb82c78b18a53352a0b287a73817d6dbcfba3162da36667c49a0", size = 406358, upload-time = "2026-02-07T23:35:07.509Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b0/cf/1c5f42b110e57bc5502eb80dbc3b03d256926062519224835ef08134f1f9/astroid-4.0.4-py3-none-any.whl", hash = "sha256:52f39653876c7dec3e3afd4c2696920e05c83832b9737afc21928f2d2eb7a753", size = 276445, upload-time = "2026-02-07T23:35:05.344Z" }, ] [[package]] -name = "async-timeout" -version = "5.0.1" +name = "asynciolimiter" +version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/95/e419550994947b564302c6d6641462d1c154e535df7e6a4bedc2801ec6d5/asynciolimiter-1.2.0.tar.gz", hash = "sha256:ac1a237c3dbd3c33041c9f9fc1a687c8e6b5268af69da84399967173a344b265", size = 8343, upload-time = "2025-03-18T08:44:43.489Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, + { url = "https://files.pythonhosted.org/packages/ee/91/2fd273f5c9d041e987cb03f487722355527c412870ece6f803fe2799f2a7/asynciolimiter-1.2.0-py3-none-any.whl", hash = "sha256:0d255de14459f961c8baee7f91e114a6ffb9ce5615e9b19c0049e8ae7e2ac84c", size = 8372, upload-time = "2025-03-18T08:44:42.2Z" }, ] [[package]] @@ -355,24 +311,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148, upload-time = "2022-10-05T19:19:30.546Z" }, ] -[[package]] -name = "backports-asyncio-runner" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, -] - -[[package]] -name = "backports-strenum" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/c7/2ed54c32fed313591ffb21edbd48db71e68827d43a61938e5a0bc2b6ec91/backports_strenum-1.3.1.tar.gz", hash = "sha256:77c52407342898497714f0596e86188bb7084f89063226f4ba66863482f42414", size = 7257, upload-time = "2023-12-09T14:36:40.937Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/50/56cf20e2ee5127b603b81d5a69580a1a325083e2b921aa8f067da83927c0/backports_strenum-1.3.1-py3-none-any.whl", hash = "sha256:cdcfe36dc897e2615dc793b7d3097f54d359918fc448754a517e6f23044ccf83", size = 8304, upload-time = "2023-12-09T14:36:39.905Z" }, -] - [[package]] name = "backrefs" version = "7.0" @@ -410,21 +348,9 @@ dependencies = [ { name = "pathspec" }, { name = "platformdirs" }, { name = "pytokens" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", size = 666155, upload-time = "2026-03-12T03:36:03.593Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/a8/11170031095655d36ebc6664fe0897866f6023892396900eec0e8fdc4299/black-26.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:86a8b5035fce64f5dcd1b794cf8ec4d31fe458cf6ce3986a30deb434df82a1d2", size = 1866562, upload-time = "2026-03-12T03:39:58.639Z" }, - { url = "https://files.pythonhosted.org/packages/69/ce/9e7548d719c3248c6c2abfd555d11169457cbd584d98d179111338423790/black-26.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5602bdb96d52d2d0672f24f6ffe5218795736dd34807fd0fd55ccd6bf206168b", size = 1703623, upload-time = "2026-03-12T03:40:00.347Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0a/8d17d1a9c06f88d3d030d0b1d4373c1551146e252afe4547ed601c0e697f/black-26.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c54a4a82e291a1fee5137371ab488866b7c86a3305af4026bdd4dc78642e1ac", size = 1768388, upload-time = "2026-03-12T03:40:01.765Z" }, - { url = "https://files.pythonhosted.org/packages/52/79/c1ee726e221c863cde5164f925bacf183dfdf0397d4e3f94889439b947b4/black-26.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:6e131579c243c98f35bce64a7e08e87fb2d610544754675d4a0e73a070a5aa3a", size = 1412969, upload-time = "2026-03-12T03:40:03.252Z" }, - { url = "https://files.pythonhosted.org/packages/73/a5/15c01d613f5756f68ed8f6d4ec0a1e24b82b18889fa71affd3d1f7fad058/black-26.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:5ed0ca58586c8d9a487352a96b15272b7fa55d139fc8496b519e78023a8dab0a", size = 1220345, upload-time = "2026-03-12T03:40:04.892Z" }, - { url = "https://files.pythonhosted.org/packages/17/57/5f11c92861f9c92eb9dddf515530bc2d06db843e44bdcf1c83c1427824bc/black-26.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:28ef38aee69e4b12fda8dba75e21f9b4f979b490c8ac0baa7cb505369ac9e1ff", size = 1851987, upload-time = "2026-03-12T03:40:06.248Z" }, - { url = "https://files.pythonhosted.org/packages/54/aa/340a1463660bf6831f9e39646bf774086dbd8ca7fc3cded9d59bbdf4ad0a/black-26.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bf162ed91a26f1adba8efda0b573bc6924ec1408a52cc6f82cb73ec2b142c", size = 1689499, upload-time = "2026-03-12T03:40:07.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/01/b726c93d717d72733da031d2de10b92c9fa4c8d0c67e8a8a372076579279/black-26.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:474c27574d6d7037c1bc875a81d9be0a9a4f9ee95e62800dab3cfaadbf75acd5", size = 1754369, upload-time = "2026-03-12T03:40:09.279Z" }, - { url = "https://files.pythonhosted.org/packages/e3/09/61e91881ca291f150cfc9eb7ba19473c2e59df28859a11a88248b5cbbc4d/black-26.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e9d0d86df21f2e1677cc4bd090cd0e446278bcbbe49bf3659c308c3e402843e", size = 1413613, upload-time = "2026-03-12T03:40:10.943Z" }, - { url = "https://files.pythonhosted.org/packages/16/73/544f23891b22e7efe4d8f812371ab85b57f6a01b2fc45e3ba2e52ba985b8/black-26.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:9a5e9f45e5d5e1c5b5c29b3bd4265dcc90e8b92cf4534520896ed77f791f4da5", size = 1219719, upload-time = "2026-03-12T03:40:12.597Z" }, { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", size = 1895920, upload-time = "2026-03-12T03:40:13.921Z" }, { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", size = 1718499, upload-time = "2026-03-12T03:40:15.239Z" }, { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", size = 1794994, upload-time = "2026-03-12T03:40:17.124Z" }, @@ -464,7 +390,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore-stubs" }, { name = "types-s3transfer" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/bb/3766f6dcb09369732b575c49bd26458ee133348b07ae4b61c2feec1cae0d/boto3_stubs-1.43.4.tar.gz", hash = "sha256:09e6dfdc3b7db02b7c9bab2dae748b0179acad7ced72ee62b79a5e80fd588caa", size = 102637, upload-time = "2026-05-05T19:53:33.221Z" } wheels = [ @@ -524,31 +449,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, - { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, - { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, - { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, - { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, - { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, @@ -603,38 +503,6 @@ version = "3.4.7" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d", size = 315182, upload-time = "2026-04-02T09:25:40.673Z" }, - { url = "https://files.pythonhosted.org/packages/24/47/b192933e94b546f1b1fe4df9cc1f84fcdbf2359f8d1081d46dd029b50207/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8", size = 209329, upload-time = "2026-04-02T09:25:42.354Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b4/01fa81c5ca6141024d89a8fc15968002b71da7f825dd14113207113fabbd/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790", size = 231230, upload-time = "2026-04-02T09:25:44.281Z" }, - { url = "https://files.pythonhosted.org/packages/20/f7/7b991776844dfa058017e600e6e55ff01984a063290ca5622c0b63162f68/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc", size = 225890, upload-time = "2026-04-02T09:25:45.475Z" }, - { url = "https://files.pythonhosted.org/packages/20/e7/bed0024a0f4ab0c8a9c64d4445f39b30c99bd1acd228291959e3de664247/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393", size = 216930, upload-time = "2026-04-02T09:25:46.58Z" }, - { url = "https://files.pythonhosted.org/packages/e2/ab/b18f0ab31cdd7b3ddb8bb76c4a414aeb8160c9810fdf1bc62f269a539d87/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153", size = 202109, upload-time = "2026-04-02T09:25:48.031Z" }, - { url = "https://files.pythonhosted.org/packages/82/e5/7e9440768a06dfb3075936490cb82dbf0ee20a133bf0dd8551fa096914ec/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af", size = 214684, upload-time = "2026-04-02T09:25:49.245Z" }, - { url = "https://files.pythonhosted.org/packages/71/94/8c61d8da9f062fdf457c80acfa25060ec22bf1d34bbeaca4350f13bcfd07/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34", size = 212785, upload-time = "2026-04-02T09:25:50.671Z" }, - { url = "https://files.pythonhosted.org/packages/66/cd/6e9889c648e72c0ab2e5967528bb83508f354d706637bc7097190c874e13/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1", size = 203055, upload-time = "2026-04-02T09:25:51.802Z" }, - { url = "https://files.pythonhosted.org/packages/92/2e/7a951d6a08aefb7eb8e1b54cdfb580b1365afdd9dd484dc4bee9e5d8f258/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752", size = 232502, upload-time = "2026-04-02T09:25:53.388Z" }, - { url = "https://files.pythonhosted.org/packages/58/d5/abcf2d83bf8e0a1286df55cd0dc1d49af0da4282aa77e986df343e7de124/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53", size = 214295, upload-time = "2026-04-02T09:25:54.765Z" }, - { url = "https://files.pythonhosted.org/packages/47/3a/7d4cd7ed54be99973a0dc176032cba5cb1f258082c31fa6df35cff46acfc/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616", size = 227145, upload-time = "2026-04-02T09:25:55.904Z" }, - { url = "https://files.pythonhosted.org/packages/1d/98/3a45bf8247889cf28262ebd3d0872edff11565b2a1e3064ccb132db3fbb0/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a", size = 218884, upload-time = "2026-04-02T09:25:57.074Z" }, - { url = "https://files.pythonhosted.org/packages/ad/80/2e8b7f8915ed5c9ef13aa828d82738e33888c485b65ebf744d615040c7ea/charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374", size = 148343, upload-time = "2026-04-02T09:25:58.199Z" }, - { url = "https://files.pythonhosted.org/packages/35/1b/3b8c8c77184af465ee9ad88b5aea46ea6b2e1f7b9dc9502891e37af21e30/charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943", size = 159174, upload-time = "2026-04-02T09:25:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/be/c1/feb40dca40dbb21e0a908801782d9288c64fc8d8e562c2098e9994c8c21b/charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008", size = 147805, upload-time = "2026-04-02T09:26:00.756Z" }, - { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, - { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, - { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, - { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, - { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, - { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, - { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, - { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, - { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, - { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, @@ -741,35 +609,6 @@ version = "7.13.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/33/e8c48488c29a73fd089f9d71f9653c1be7478f2ad6b5bc870db11a55d23d/coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5", size = 219255, upload-time = "2026-03-17T10:29:51.081Z" }, - { url = "https://files.pythonhosted.org/packages/da/bd/b0ebe9f677d7f4b74a3e115eec7ddd4bcf892074963a00d91e8b164a6386/coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf", size = 219772, upload-time = "2026-03-17T10:29:52.867Z" }, - { url = "https://files.pythonhosted.org/packages/48/cc/5cb9502f4e01972f54eedd48218bb203fe81e294be606a2bc93970208013/coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8", size = 246532, upload-time = "2026-03-17T10:29:54.688Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d8/3217636d86c7e7b12e126e4f30ef1581047da73140614523af7495ed5f2d/coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4", size = 248333, upload-time = "2026-03-17T10:29:56.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/30/2002ac6729ba2d4357438e2ed3c447ad8562866c8c63fc16f6dfc33afe56/coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d", size = 250211, upload-time = "2026-03-17T10:29:57.938Z" }, - { url = "https://files.pythonhosted.org/packages/6c/85/552496626d6b9359eb0e2f86f920037c9cbfba09b24d914c6e1528155f7d/coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930", size = 252125, upload-time = "2026-03-17T10:29:59.388Z" }, - { url = "https://files.pythonhosted.org/packages/44/21/40256eabdcbccdb6acf6b381b3016a154399a75fe39d406f790ae84d1f3c/coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d", size = 247219, upload-time = "2026-03-17T10:30:01.199Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e8/96e2a6c3f21a0ea77d7830b254a1542d0328acc8d7bdf6a284ba7e529f77/coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40", size = 248248, upload-time = "2026-03-17T10:30:03.317Z" }, - { url = "https://files.pythonhosted.org/packages/da/ba/8477f549e554827da390ec659f3c38e4b6d95470f4daafc2d8ff94eaa9c2/coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878", size = 246254, upload-time = "2026-03-17T10:30:04.832Z" }, - { url = "https://files.pythonhosted.org/packages/55/59/bc22aef0e6aa179d5b1b001e8b3654785e9adf27ef24c93dc4228ebd5d68/coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400", size = 250067, upload-time = "2026-03-17T10:30:06.535Z" }, - { url = "https://files.pythonhosted.org/packages/de/1b/c6a023a160806a5137dca53468fd97530d6acad24a22003b1578a9c2e429/coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0", size = 246521, upload-time = "2026-03-17T10:30:08.486Z" }, - { url = "https://files.pythonhosted.org/packages/2d/3f/3532c85a55aa2f899fa17c186f831cfa1aa434d88ff792a709636f64130e/coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0", size = 247126, upload-time = "2026-03-17T10:30:09.966Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/b9d56af4a24ef45dfbcda88e06870cb7d57b2b0bfa3a888d79b4c8debd76/coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58", size = 221860, upload-time = "2026-03-17T10:30:11.393Z" }, - { url = "https://files.pythonhosted.org/packages/9f/cc/d938417e7a4d7f0433ad4edee8bb2acdc60dc7ac5af19e2a07a048ecbee3/coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e", size = 222788, upload-time = "2026-03-17T10:30:12.886Z" }, - { url = "https://files.pythonhosted.org/packages/4b/37/d24c8f8220ff07b839b2c043ea4903a33b0f455abe673ae3c03bbdb7f212/coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d", size = 219381, upload-time = "2026-03-17T10:30:14.68Z" }, - { url = "https://files.pythonhosted.org/packages/35/8b/cd129b0ca4afe886a6ce9d183c44d8301acbd4ef248622e7c49a23145605/coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587", size = 219880, upload-time = "2026-03-17T10:30:16.231Z" }, - { url = "https://files.pythonhosted.org/packages/55/2f/e0e5b237bffdb5d6c530ce87cc1d413a5b7d7dfd60fb067ad6d254c35c76/coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642", size = 250303, upload-time = "2026-03-17T10:30:17.748Z" }, - { url = "https://files.pythonhosted.org/packages/92/be/b1afb692be85b947f3401375851484496134c5554e67e822c35f28bf2fbc/coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b", size = 252218, upload-time = "2026-03-17T10:30:19.804Z" }, - { url = "https://files.pythonhosted.org/packages/da/69/2f47bb6fa1b8d1e3e5d0c4be8ccb4313c63d742476a619418f85740d597b/coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686", size = 254326, upload-time = "2026-03-17T10:30:21.321Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d0/79db81da58965bd29dabc8f4ad2a2af70611a57cba9d1ec006f072f30a54/coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743", size = 256267, upload-time = "2026-03-17T10:30:23.094Z" }, - { url = "https://files.pythonhosted.org/packages/e5/32/d0d7cc8168f91ddab44c0ce4806b969df5f5fdfdbb568eaca2dbc2a04936/coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75", size = 250430, upload-time = "2026-03-17T10:30:25.311Z" }, - { url = "https://files.pythonhosted.org/packages/4d/06/a055311d891ddbe231cd69fdd20ea4be6e3603ffebddf8704b8ca8e10a3c/coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209", size = 252017, upload-time = "2026-03-17T10:30:27.284Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f6/d0fd2d21e29a657b5f77a2fe7082e1568158340dceb941954f776dce1b7b/coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a", size = 250080, upload-time = "2026-03-17T10:30:29.481Z" }, - { url = "https://files.pythonhosted.org/packages/4e/ab/0d7fb2efc2e9a5eb7ddcc6e722f834a69b454b7e6e5888c3a8567ecffb31/coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e", size = 253843, upload-time = "2026-03-17T10:30:31.301Z" }, - { url = "https://files.pythonhosted.org/packages/ba/6f/7467b917bbf5408610178f62a49c0ed4377bb16c1657f689cc61470da8ce/coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd", size = 249802, upload-time = "2026-03-17T10:30:33.358Z" }, - { url = "https://files.pythonhosted.org/packages/75/2c/1172fb689df92135f5bfbbd69fc83017a76d24ea2e2f3a1154007e2fb9f8/coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8", size = 250707, upload-time = "2026-03-17T10:30:35.2Z" }, - { url = "https://files.pythonhosted.org/packages/67/21/9ac389377380a07884e3b48ba7a620fcd9dbfaf1d40565facdc6b36ec9ef/coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf", size = 221880, upload-time = "2026-03-17T10:30:36.775Z" }, - { url = "https://files.pythonhosted.org/packages/af/7f/4cd8a92531253f9d7c1bbecd9fa1b472907fb54446ca768c59b531248dc5/coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9", size = 222816, upload-time = "2026-03-17T10:30:38.891Z" }, - { url = "https://files.pythonhosted.org/packages/12/a6/1d3f6155fb0010ca68eba7fe48ca6c9da7385058b77a95848710ecf189b1/coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028", size = 221483, upload-time = "2026-03-17T10:30:40.463Z" }, { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" }, { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" }, { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" }, @@ -848,18 +687,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, ] -[package.optional-dependencies] -toml = [ - { name = "tomli", marker = "python_full_version <= '3.11'" }, -] - [[package]] name = "cryptography" version = "48.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" } wheels = [ @@ -905,12 +738,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" }, { url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" }, { url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" }, - { url = "https://files.pythonhosted.org/packages/be/d2/024b5e06be9d44cb021fb0e1a03d34d63989cf56a0fe62f3dfbab695b9b4/cryptography-48.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:84cf79f0dc8b36ac5da873481716e87aef31fcfa0444f9e1d8b4b2cece142855", size = 3950391, upload-time = "2026-05-04T22:59:17.415Z" }, - { url = "https://files.pythonhosted.org/packages/bc/17/3861e17c56fa0fd37491a14a8673fdb77c57fc5693cafe745ea8b06dba75/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:fdfef35d751d510fcef5252703621574364fec16418c4a1e5e1055248401054b", size = 4637126, upload-time = "2026-05-04T22:59:20.197Z" }, - { url = "https://files.pythonhosted.org/packages/f0/0a/7e226dbff530f21480727eb764973a7bff2b912f8e15cd4f129e71b56d1d/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0890f502ddf7d9c6426129c3f49f5c0a39278ed7cd6322c8755ffca6ee675a13", size = 4667270, upload-time = "2026-05-04T22:59:22.647Z" }, - { url = "https://files.pythonhosted.org/packages/3b/f2/5a72274ca9f1b2a8b44a662ee0bf1b435909deb473d6f97bcd035bcdbc71/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:ecde28a596bead48b0cfd2a1b4416c3d43074c2d785e3a398d7ec1fc4d0f7fbb", size = 4636797, upload-time = "2026-05-04T22:59:24.912Z" }, - { url = "https://files.pythonhosted.org/packages/b4/e1/48cedb2fe63626e91ded1edad159e2a4fb8b6906c4425eb7749673077ce7/cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:4defde8685ae324a9eb9d818717e93b4638ef67070ac9bc15b8ca85f63048355", size = 4666800, upload-time = "2026-05-04T22:59:27.474Z" }, - { url = "https://files.pythonhosted.org/packages/a2/ca/7e8365deec19afb2b2c7be7c1c0aa8f99633b54e90c570999acda93260fc/cryptography-48.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:db63bf618e5dea46c07de12e900fe1cdd2541e6dc9dbae772a70b7d4d4765f6a", size = 3739536, upload-time = "2026-05-04T22:59:29.61Z" }, ] [[package]] @@ -918,13 +745,9 @@ name = "cuda-bindings" version = "13.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cuda-pathfinder", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, + { name = "cuda-pathfinder", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/fe/7351d7e586a8b4c9f89731bfe4cf0148223e8f9903ff09571f78b3fb0682/cuda_bindings-13.2.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b395f79cb89ce0cd8effff07c4a1e20101b873c256a1aeb286e8fd7bd0f556", size = 5744254, upload-time = "2026-03-11T00:12:29.798Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ef/184aa775e970fc089942cd9ec6302e6e44679d4c14549c6a7ea45bf7f798/cuda_bindings-13.2.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6f3682ec3c4769326aafc67c2ba669d97d688d0b7e63e659d36d2f8b72f32d6", size = 6329075, upload-time = "2026-03-11T00:12:32.319Z" }, - { url = "https://files.pythonhosted.org/packages/e0/a9/3a8241c6e19483ac1f1dcf5c10238205dcb8a6e9d0d4d4709240dff28ff4/cuda_bindings-13.2.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:721104c603f059780d287969be3d194a18d0cc3b713ed9049065a1107706759d", size = 5730273, upload-time = "2026-03-11T00:12:37.18Z" }, - { url = "https://files.pythonhosted.org/packages/e9/94/2748597f47bb1600cd466b20cab4159f1530a3a33fe7f70fee199b3abb9e/cuda_bindings-13.2.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1eba9504ac70667dd48313395fe05157518fd6371b532790e96fbb31bbb5a5e1", size = 6313924, upload-time = "2026-03-11T00:12:39.462Z" }, { url = "https://files.pythonhosted.org/packages/52/c8/b2589d68acf7e3d63e2be330b84bc25712e97ed799affbca7edd7eae25d6/cuda_bindings-13.2.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e865447abfb83d6a98ad5130ed3c70b1fc295ae3eeee39fd07b4ddb0671b6788", size = 5722404, upload-time = "2026-03-11T00:12:44.041Z" }, { url = "https://files.pythonhosted.org/packages/1f/92/f899f7bbb5617bb65ec52a6eac1e9a1447a86b916c4194f8a5001b8cde0c/cuda_bindings-13.2.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46d8776a55d6d5da9dd6e9858fba2efcda2abe6743871dee47dd06eb8cb6d955", size = 6320619, upload-time = "2026-03-11T00:12:45.939Z" }, { url = "https://files.pythonhosted.org/packages/df/93/eef988860a3ca985f82c4f3174fc0cdd94e07331ba9a92e8e064c260337f/cuda_bindings-13.2.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6629ca2df6f795b784752409bcaedbd22a7a651b74b56a165ebc0c9dcbd504d0", size = 5614610, upload-time = "2026-03-11T00:12:50.337Z" }, @@ -953,37 +776,37 @@ wheels = [ [package.optional-dependencies] cublas = [ - { name = "nvidia-cublas", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cublas", marker = "sys_platform == 'linux'" }, ] cudart = [ - { name = "nvidia-cuda-runtime", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime", marker = "sys_platform == 'linux'" }, ] cufft = [ - { name = "nvidia-cufft", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cufft", marker = "sys_platform == 'linux'" }, ] cufile = [ { name = "nvidia-cufile", marker = "sys_platform == 'linux'" }, ] cupti = [ - { name = "nvidia-cuda-cupti", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti", marker = "sys_platform == 'linux'" }, ] curand = [ - { name = "nvidia-curand", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-curand", marker = "sys_platform == 'linux'" }, ] cusolver = [ - { name = "nvidia-cusolver", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cusolver", marker = "sys_platform == 'linux'" }, ] cusparse = [ - { name = "nvidia-cusparse", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cusparse", marker = "sys_platform == 'linux'" }, ] nvjitlink = [ - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink", marker = "sys_platform == 'linux'" }, ] nvrtc = [ - { name = "nvidia-cuda-nvrtc", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc", marker = "sys_platform == 'linux'" }, ] nvtx = [ - { name = "nvidia-nvtx", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, + { name = "nvidia-nvtx", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -999,7 +822,6 @@ dependencies = [ { name = "jinja2" }, { name = "pydantic" }, { name = "pyyaml" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6f/9c/5379be8daf9ff2fbbb9a7efcf68c037b089e5b76f360c4f9ca730916e2ee/datamodel_code_generator-0.56.1.tar.gz", hash = "sha256:697abd90cc4eb2c65f130be79a83a24746c3f2d0e15e6eb9dbf17b96784449be", size = 840372, upload-time = "2026-04-16T17:09:53.537Z" } wheels = [ @@ -1068,8 +890,7 @@ dependencies = [ { name = "jsonref" }, { name = "jsonschema" }, { name = "latex2mathml" }, - { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "pandas", version = "3.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pandas" }, { name = "pillow" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1103,8 +924,7 @@ dependencies = [ { name = "docling-core" }, { name = "huggingface-hub" }, { name = "jsonlines" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "pillow" }, { name = "pydantic" }, { name = "rtree" }, @@ -1132,14 +952,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/a7/b8/e68f8ec44692d2f913210dd46cb3e7e6e1959053bb05d5c94c5331010f3c/docling_parse-5.10.1.tar.gz", hash = "sha256:10a3d2ba211134f6d1fa9b6be8ef690eb0b1a03b043473a3ef8408ad7b4a857a", size = 6651696, upload-time = "2026-04-24T15:02:19.106Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/ba/0520b9b74c73dc6c970e23ddb54d900c4195290fa49bfb35530f9619efdf/docling_parse-5.10.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:88eaa801a44d518c110e50d381beefe480f7f7d6485779947f4ed918d55be000", size = 9110525, upload-time = "2026-04-24T15:01:22.767Z" }, - { url = "https://files.pythonhosted.org/packages/5a/ff/cbff26277fb93839456b0f4d163c6d55fbe02ccc9089cddc67c14fc301bf/docling_parse-5.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:643ad0b95db00acc674dc7941f6314b60aa2de8a35c15f04d5c42d89a75a1414", size = 9833595, upload-time = "2026-04-24T15:01:25.209Z" }, - { url = "https://files.pythonhosted.org/packages/01/c5/efcdb4e6d4bb581c448a3981b7983eaddf862cb2eac9e0cda980e39aa9f2/docling_parse-5.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bdf7df582e5e7d50dbc61138545a6dcc6c00878db9521d0fa58aa1ef4bb26ea", size = 10106212, upload-time = "2026-04-24T15:01:28.039Z" }, - { url = "https://files.pythonhosted.org/packages/53/c6/8028ca5e196e19deab3299e49e0701a656e355b0860f33c76cbc2a9ff843/docling_parse-5.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:4427ec4a5cc42a92aaab9104375180df70f2c1206c0261ba33dc9640f3744837", size = 10909812, upload-time = "2026-04-24T15:01:30.671Z" }, - { url = "https://files.pythonhosted.org/packages/38/5d/6ed2d12f7c9db1f714093306141e437b6a199b72c11bae82d9980bd22a23/docling_parse-5.10.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:8a4b52d966b9b9e8400290e1400c549cf73e52e1636f7345e2b8b7f7e10c04c4", size = 9111237, upload-time = "2026-04-24T15:01:33.57Z" }, - { url = "https://files.pythonhosted.org/packages/8e/ff/022881eb3ec824527851e6a7640d99251815b89772e1a14087cd7e47e0bd/docling_parse-5.10.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:31912b95f29db264c9c6b32b4884160ab01ea919307f860493f562cf8c7f9ea1", size = 9780134, upload-time = "2026-04-24T15:01:36.388Z" }, - { url = "https://files.pythonhosted.org/packages/26/c2/f9e956aacbf9c88ac228b5abf08962ba2ec88e2b3810703f212e8d0f6df7/docling_parse-5.10.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f70d4364fbc9dd62cd4f75e0cff93e3618e06bf96686575f7d2e8c5a6fa4f823", size = 10158640, upload-time = "2026-04-24T15:01:38.797Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/2e3bb89731e354a1a565194267b70a245f52a45f3590b4757a01ede69c39/docling_parse-5.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3c90a8b28a9ce012e55e3dd2ae632fc735e5827759cd36fbb8cbbb7da361aec3", size = 10910184, upload-time = "2026-04-24T15:01:42.134Z" }, { url = "https://files.pythonhosted.org/packages/3e/4a/27e213493bac0877a030f030d44152ba9ef676aebc5890f4dd3e8037592e/docling_parse-5.10.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8f58e1bf1c6cdf1bfe0594f0903b4b9c33dfc3c2dbba61681f8533158ed640a6", size = 9112936, upload-time = "2026-04-24T15:01:44.878Z" }, { url = "https://files.pythonhosted.org/packages/ee/b3/85737cecca0e5ed9dc13370e78862054075f64eb988024069296898ec741/docling_parse-5.10.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59880a29231083c17a73533e09abc0610f10a99343762d795de4ceac5b15dfbf", size = 9780913, upload-time = "2026-04-24T15:01:47.626Z" }, { url = "https://files.pythonhosted.org/packages/17/fa/11dd3328ab708143a291ae53d388a5170095a90b8dc8428e5274e2c09194/docling_parse-5.10.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:478ada90c52b704a04a3c8b4171e3385bb8b5b2f02b9d57c7a5bb06d9cac34fa", size = 10159004, upload-time = "2026-04-24T15:01:50.366Z" }, @@ -1185,8 +997,7 @@ standard = [ { name = "huggingface-hub" }, { name = "lxml" }, { name = "marko" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "openpyxl" }, { name = "pillow" }, { name = "polyfactory" }, @@ -1197,8 +1008,7 @@ standard = [ { name = "rapidocr" }, { name = "rich" }, { name = "rtree" }, - { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "scipy" }, { name = "torch" }, { name = "torchvision" }, { name = "typer" }, @@ -1232,18 +1042,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl", hash = "sha256:279ab641905e9f11129f56a8a78f493518515b83402b860f6f06dd7c011fdfa8", size = 6063, upload-time = "2025-12-02T11:51:41.665Z" }, ] -[[package]] -name = "exceptiongroup" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, -] - [[package]] name = "execnet" version = "2.1.2" @@ -1306,38 +1104,6 @@ version = "1.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, - { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, - { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, - { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, - { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, - { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, - { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, - { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, - { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, - { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, - { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, - { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, - { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, - { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, @@ -1534,16 +1300,6 @@ version = "1.8.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/ac/6f7bc93886a823ab545948c2dd48143027b2355ad1944c7cf852b338dc91/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff", size = 31296, upload-time = "2025-12-16T00:19:07.261Z" }, - { url = "https://files.pythonhosted.org/packages/f7/97/a5accde175dee985311d949cfcb1249dcbb290f5ec83c994ea733311948f/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288", size = 30870, upload-time = "2025-12-16T00:29:17.669Z" }, - { url = "https://files.pythonhosted.org/packages/3d/63/bec827e70b7a0d4094e7476f863c0dbd6b5f0f1f91d9c9b32b76dcdfeb4e/google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d", size = 33214, upload-time = "2025-12-16T00:40:19.618Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/11b70614df04c289128d782efc084b9035ef8466b3d0a8757c1b6f5cf7ac/google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092", size = 33589, upload-time = "2025-12-16T00:40:20.7Z" }, - { url = "https://files.pythonhosted.org/packages/3e/00/a08a4bc24f1261cc5b0f47312d8aebfbe4b53c2e6307f1b595605eed246b/google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733", size = 34437, upload-time = "2025-12-16T00:35:19.437Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ef/21ccfaab3d5078d41efe8612e0ed0bfc9ce22475de074162a91a25f7980d/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8", size = 31298, upload-time = "2025-12-16T00:20:32.241Z" }, - { url = "https://files.pythonhosted.org/packages/c5/b8/f8413d3f4b676136e965e764ceedec904fe38ae8de0cdc52a12d8eb1096e/google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7", size = 30872, upload-time = "2025-12-16T00:33:58.785Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15", size = 33243, upload-time = "2025-12-16T00:40:21.46Z" }, - { url = "https://files.pythonhosted.org/packages/71/03/4820b3bd99c9653d1a5210cb32f9ba4da9681619b4d35b6a052432df4773/google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a", size = 33608, upload-time = "2025-12-16T00:40:22.204Z" }, - { url = "https://files.pythonhosted.org/packages/7c/43/acf61476a11437bf9733fb2f70599b1ced11ec7ed9ea760fdd9a77d0c619/google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2", size = 34439, upload-time = "2025-12-16T00:35:20.458Z" }, { url = "https://files.pythonhosted.org/packages/e9/5f/7307325b1198b59324c0fa9807cafb551afb65e831699f2ce211ad5c8240/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113", size = 31300, upload-time = "2025-12-16T00:21:56.723Z" }, { url = "https://files.pythonhosted.org/packages/21/8e/58c0d5d86e2220e6a37befe7e6a94dd2f6006044b1a33edf1ff6d9f7e319/google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb", size = 30867, upload-time = "2025-12-16T00:38:31.302Z" }, { url = "https://files.pythonhosted.org/packages/ce/a9/a780cc66f86335a6019f557a8aaca8fbb970728f0efd2430d15ff1beae0e/google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411", size = 33364, upload-time = "2025-12-16T00:40:22.96Z" }, @@ -1559,8 +1315,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/56/15/c25671c7aad70f8179d858c55a6ae8404902abe0cdcf32a29d581792b491/google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2", size = 33381, upload-time = "2025-12-16T00:40:26.268Z" }, { url = "https://files.pythonhosted.org/packages/42/fa/f50f51260d7b0ef5d4898af122d8a7ec5a84e2984f676f746445f783705f/google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21", size = 33734, upload-time = "2025-12-16T00:40:27.028Z" }, { url = "https://files.pythonhosted.org/packages/08/a5/7b059810934a09fb3ccb657e0843813c1fee1183d3bc2c8041800374aa2c/google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2", size = 34878, upload-time = "2025-12-16T00:35:23.142Z" }, - { url = "https://files.pythonhosted.org/packages/52/c5/c171e4d8c44fec1422d801a6d2e5d7ddabd733eeda505c79730ee9607f07/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93", size = 28615, upload-time = "2025-12-16T00:40:29.298Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/7d75fe37a7a6ed171a2cf17117177e7aab7e6e0d115858741b41e9dd4254/google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c", size = 28800, upload-time = "2025-12-16T00:40:30.322Z" }, ] [[package]] @@ -1751,7 +1505,7 @@ wheels = [ [[package]] name = "instructor" version = "1.15.1" -source = { registry = "https://pypi.org/simple" } +source = { git = "https://github.com/Ian321/instructor.git?rev=4ea22d2396ca35514929f27faed866115e8b3583#4ea22d2396ca35514929f27faed866115e8b3583" } dependencies = [ { name = "aiohttp" }, { name = "docstring-parser" }, @@ -1765,10 +1519,6 @@ dependencies = [ { name = "tenacity" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/a4/832cfb15420360e26d2d85bd9d5fe1e4b839d52587574d389bc31284bf6f/instructor-1.15.1.tar.gz", hash = "sha256:c72406469d9025b742e83cf0c13e914b317db2089d08d889944e74fcd659ef94", size = 69948370, upload-time = "2026-04-03T01:51:30.107Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/c8/36c5d9b80aaf40ba9a7084a8fc18c967db6bf248a4cc8d0f0816b14284be/instructor-1.15.1-py3-none-any.whl", hash = "sha256:be81d17ba2b154a04ab4720808f24f9d6b598f80992f82eaf9cc79006099cf6c", size = 178156, upload-time = "2026-04-03T01:51:23.098Z" }, -] [package.optional-dependencies] google-genai = [ @@ -1776,15 +1526,6 @@ google-genai = [ { name = "jsonref" }, ] -[[package]] -name = "invoke" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/de/bd/b461d3424a24c80490313fd77feeb666ca4f6a28c7e72713e3d9095719b4/invoke-2.2.1.tar.gz", hash = "sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707", size = 304762, upload-time = "2025-10-11T00:36:35.172Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/4b/b99e37f88336009971405cbb7630610322ed6fbfa31e1d7ab3fbf3049a2d/invoke-2.2.1-py3-none-any.whl", hash = "sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8", size = 160287, upload-time = "2025-10-11T00:36:33.703Z" }, -] - [[package]] name = "isort" version = "7.0.0" @@ -1808,99 +1549,74 @@ wheels = [ [[package]] name = "jiter" -version = "0.13.0" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/5e/4ec91646aee381d01cdb9974e30882c9cd3b8c5d1079d6b5ff4af522439a/jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4", size = 164847, upload-time = "2026-02-02T12:37:56.441Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/5a/41da76c5ea07bec1b0472b6b2fdb1b651074d504b19374d7e130e0cdfb25/jiter-0.13.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2ffc63785fd6c7977defe49b9824ae6ce2b2e2b77ce539bdaf006c26da06342e", size = 311164, upload-time = "2026-02-02T12:35:17.688Z" }, - { url = "https://files.pythonhosted.org/packages/40/cb/4a1bf994a3e869f0d39d10e11efb471b76d0ad70ecbfb591427a46c880c2/jiter-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4a638816427006c1e3f0013eb66d391d7a3acda99a7b0cf091eff4497ccea33a", size = 320296, upload-time = "2026-02-02T12:35:19.828Z" }, - { url = "https://files.pythonhosted.org/packages/09/82/acd71ca9b50ecebadc3979c541cd717cce2fe2bc86236f4fa597565d8f1a/jiter-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19928b5d1ce0ff8c1ee1b9bdef3b5bfc19e8304f1b904e436caf30bc15dc6cf5", size = 352742, upload-time = "2026-02-02T12:35:21.258Z" }, - { url = "https://files.pythonhosted.org/packages/71/03/d1fc996f3aecfd42eb70922edecfb6dd26421c874503e241153ad41df94f/jiter-0.13.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:309549b778b949d731a2f0e1594a3f805716be704a73bf3ad9a807eed5eb5721", size = 363145, upload-time = "2026-02-02T12:35:24.653Z" }, - { url = "https://files.pythonhosted.org/packages/f1/61/a30492366378cc7a93088858f8991acd7d959759fe6138c12a4644e58e81/jiter-0.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcdabaea26cb04e25df3103ce47f97466627999260290349a88c8136ecae0060", size = 487683, upload-time = "2026-02-02T12:35:26.162Z" }, - { url = "https://files.pythonhosted.org/packages/20/4e/4223cffa9dbbbc96ed821c5aeb6bca510848c72c02086d1ed3f1da3d58a7/jiter-0.13.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a377af27b236abbf665a69b2bdd680e3b5a0bd2af825cd3b81245279a7606c", size = 373579, upload-time = "2026-02-02T12:35:27.582Z" }, - { url = "https://files.pythonhosted.org/packages/fe/c9/b0489a01329ab07a83812d9ebcffe7820a38163c6d9e7da644f926ff877c/jiter-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe49d3ff6db74321f144dff9addd4a5874d3105ac5ba7c5b77fac099cfae31ae", size = 362904, upload-time = "2026-02-02T12:35:28.925Z" }, - { url = "https://files.pythonhosted.org/packages/05/af/53e561352a44afcba9a9bc67ee1d320b05a370aed8df54eafe714c4e454d/jiter-0.13.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2113c17c9a67071b0f820733c0893ed1d467b5fcf4414068169e5c2cabddb1e2", size = 392380, upload-time = "2026-02-02T12:35:30.385Z" }, - { url = "https://files.pythonhosted.org/packages/76/2a/dd805c3afb8ed5b326c5ae49e725d1b1255b9754b1b77dbecdc621b20773/jiter-0.13.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ab1185ca5c8b9491b55ebf6c1e8866b8f68258612899693e24a92c5fdb9455d5", size = 517939, upload-time = "2026-02-02T12:35:31.865Z" }, - { url = "https://files.pythonhosted.org/packages/20/2a/7b67d76f55b8fe14c937e7640389612f05f9a4145fc28ae128aaa5e62257/jiter-0.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9621ca242547edc16400981ca3231e0c91c0c4c1ab8573a596cd9bb3575d5c2b", size = 551696, upload-time = "2026-02-02T12:35:33.306Z" }, - { url = "https://files.pythonhosted.org/packages/85/9c/57cdd64dac8f4c6ab8f994fe0eb04dc9fd1db102856a4458fcf8a99dfa62/jiter-0.13.0-cp310-cp310-win32.whl", hash = "sha256:a7637d92b1c9d7a771e8c56f445c7f84396d48f2e756e5978840ecba2fac0894", size = 204592, upload-time = "2026-02-02T12:35:34.58Z" }, - { url = "https://files.pythonhosted.org/packages/a7/38/f4f3ea5788b8a5bae7510a678cdc747eda0c45ffe534f9878ff37e7cf3b3/jiter-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c1b609e5cbd2f52bb74fb721515745b407df26d7b800458bd97cb3b972c29e7d", size = 206016, upload-time = "2026-02-02T12:35:36.435Z" }, - { url = "https://files.pythonhosted.org/packages/71/29/499f8c9eaa8a16751b1c0e45e6f5f1761d180da873d417996cc7bddc8eef/jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096", size = 311157, upload-time = "2026-02-02T12:35:37.758Z" }, - { url = "https://files.pythonhosted.org/packages/50/f6/566364c777d2ab450b92100bea11333c64c38d32caf8dc378b48e5b20c46/jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911", size = 319729, upload-time = "2026-02-02T12:35:39.246Z" }, - { url = "https://files.pythonhosted.org/packages/73/dd/560f13ec5e4f116d8ad2658781646cca91b617ae3b8758d4a5076b278f70/jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701", size = 354766, upload-time = "2026-02-02T12:35:40.662Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0d/061faffcfe94608cbc28a0d42a77a74222bdf5055ccdbe5fd2292b94f510/jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c", size = 362587, upload-time = "2026-02-02T12:35:42.025Z" }, - { url = "https://files.pythonhosted.org/packages/92/c9/c66a7864982fd38a9773ec6e932e0398d1262677b8c60faecd02ffb67bf3/jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4", size = 487537, upload-time = "2026-02-02T12:35:43.459Z" }, - { url = "https://files.pythonhosted.org/packages/6c/86/84eb4352cd3668f16d1a88929b5888a3fe0418ea8c1dfc2ad4e7bf6e069a/jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165", size = 373717, upload-time = "2026-02-02T12:35:44.928Z" }, - { url = "https://files.pythonhosted.org/packages/6e/09/9fe4c159358176f82d4390407a03f506a8659ed13ca3ac93a843402acecf/jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018", size = 362683, upload-time = "2026-02-02T12:35:46.636Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5e/85f3ab9caca0c1d0897937d378b4a515cae9e119730563572361ea0c48ae/jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411", size = 392345, upload-time = "2026-02-02T12:35:48.088Z" }, - { url = "https://files.pythonhosted.org/packages/12/4c/05b8629ad546191939e6f0c2f17e29f542a398f4a52fb987bc70b6d1eb8b/jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5", size = 517775, upload-time = "2026-02-02T12:35:49.482Z" }, - { url = "https://files.pythonhosted.org/packages/4d/88/367ea2eb6bc582c7052e4baf5ddf57ebe5ab924a88e0e09830dfb585c02d/jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3", size = 551325, upload-time = "2026-02-02T12:35:51.104Z" }, - { url = "https://files.pythonhosted.org/packages/f3/12/fa377ffb94a2f28c41afaed093e0d70cfe512035d5ecb0cad0ae4792d35e/jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1", size = 204709, upload-time = "2026-02-02T12:35:52.467Z" }, - { url = "https://files.pythonhosted.org/packages/cb/16/8e8203ce92f844dfcd3d9d6a5a7322c77077248dbb12da52d23193a839cd/jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654", size = 204560, upload-time = "2026-02-02T12:35:53.925Z" }, - { url = "https://files.pythonhosted.org/packages/44/26/97cc40663deb17b9e13c3a5cf29251788c271b18ee4d262c8f94798b8336/jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5", size = 189608, upload-time = "2026-02-02T12:35:55.304Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/7687e4f87086829955013ca12a9233523349767f69653ebc27036313def9/jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663", size = 307958, upload-time = "2026-02-02T12:35:57.165Z" }, - { url = "https://files.pythonhosted.org/packages/c3/27/e57f9a783246ed95481e6749cc5002a8a767a73177a83c63ea71f0528b90/jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505", size = 318597, upload-time = "2026-02-02T12:35:58.591Z" }, - { url = "https://files.pythonhosted.org/packages/cf/52/e5719a60ac5d4d7c5995461a94ad5ef962a37c8bf5b088390e6fad59b2ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152", size = 348821, upload-time = "2026-02-02T12:36:00.093Z" }, - { url = "https://files.pythonhosted.org/packages/61/db/c1efc32b8ba4c740ab3fc2d037d8753f67685f475e26b9d6536a4322bcdd/jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726", size = 364163, upload-time = "2026-02-02T12:36:01.937Z" }, - { url = "https://files.pythonhosted.org/packages/55/8a/fb75556236047c8806995671a18e4a0ad646ed255276f51a20f32dceaeec/jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0", size = 483709, upload-time = "2026-02-02T12:36:03.41Z" }, - { url = "https://files.pythonhosted.org/packages/7e/16/43512e6ee863875693a8e6f6d532e19d650779d6ba9a81593ae40a9088ff/jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089", size = 370480, upload-time = "2026-02-02T12:36:04.791Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4c/09b93e30e984a187bc8aaa3510e1ec8dcbdcd71ca05d2f56aac0492453aa/jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93", size = 360735, upload-time = "2026-02-02T12:36:06.994Z" }, - { url = "https://files.pythonhosted.org/packages/1a/1b/46c5e349019874ec5dfa508c14c37e29864ea108d376ae26d90bee238cd7/jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08", size = 391814, upload-time = "2026-02-02T12:36:08.368Z" }, - { url = "https://files.pythonhosted.org/packages/15/9e/26184760e85baee7162ad37b7912797d2077718476bf91517641c92b3639/jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2", size = 513990, upload-time = "2026-02-02T12:36:09.993Z" }, - { url = "https://files.pythonhosted.org/packages/e9/34/2c9355247d6debad57a0a15e76ab1566ab799388042743656e566b3b7de1/jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228", size = 548021, upload-time = "2026-02-02T12:36:11.376Z" }, - { url = "https://files.pythonhosted.org/packages/ac/4a/9f2c23255d04a834398b9c2e0e665382116911dc4d06b795710503cdad25/jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394", size = 203024, upload-time = "2026-02-02T12:36:12.682Z" }, - { url = "https://files.pythonhosted.org/packages/09/ee/f0ae675a957ae5a8f160be3e87acea6b11dc7b89f6b7ab057e77b2d2b13a/jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92", size = 205424, upload-time = "2026-02-02T12:36:13.93Z" }, - { url = "https://files.pythonhosted.org/packages/1b/02/ae611edf913d3cbf02c97cdb90374af2082c48d7190d74c1111dde08bcdd/jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9", size = 186818, upload-time = "2026-02-02T12:36:15.308Z" }, - { url = "https://files.pythonhosted.org/packages/91/9c/7ee5a6ff4b9991e1a45263bfc46731634c4a2bde27dfda6c8251df2d958c/jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf", size = 306897, upload-time = "2026-02-02T12:36:16.748Z" }, - { url = "https://files.pythonhosted.org/packages/7c/02/be5b870d1d2be5dd6a91bdfb90f248fbb7dcbd21338f092c6b89817c3dbf/jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a", size = 317507, upload-time = "2026-02-02T12:36:18.351Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/b25d2ec333615f5f284f3a4024f7ce68cfa0604c322c6808b2344c7f5d2b/jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb", size = 350560, upload-time = "2026-02-02T12:36:19.746Z" }, - { url = "https://files.pythonhosted.org/packages/be/ec/74dcb99fef0aca9fbe56b303bf79f6bd839010cb18ad41000bf6cc71eec0/jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2", size = 363232, upload-time = "2026-02-02T12:36:21.243Z" }, - { url = "https://files.pythonhosted.org/packages/1b/37/f17375e0bb2f6a812d4dd92d7616e41917f740f3e71343627da9db2824ce/jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f", size = 483727, upload-time = "2026-02-02T12:36:22.688Z" }, - { url = "https://files.pythonhosted.org/packages/77/d2/a71160a5ae1a1e66c1395b37ef77da67513b0adba73b993a27fbe47eb048/jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159", size = 370799, upload-time = "2026-02-02T12:36:24.106Z" }, - { url = "https://files.pythonhosted.org/packages/01/99/ed5e478ff0eb4e8aa5fd998f9d69603c9fd3f32de3bd16c2b1194f68361c/jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663", size = 359120, upload-time = "2026-02-02T12:36:25.519Z" }, - { url = "https://files.pythonhosted.org/packages/16/be/7ffd08203277a813f732ba897352797fa9493faf8dc7995b31f3d9cb9488/jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa", size = 390664, upload-time = "2026-02-02T12:36:26.866Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/e0787856196d6d346264d6dcccb01f741e5f0bd014c1d9a2ebe149caf4f3/jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820", size = 513543, upload-time = "2026-02-02T12:36:28.217Z" }, - { url = "https://files.pythonhosted.org/packages/65/50/ecbd258181c4313cf79bca6c88fb63207d04d5bf5e4f65174114d072aa55/jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68", size = 547262, upload-time = "2026-02-02T12:36:29.678Z" }, - { url = "https://files.pythonhosted.org/packages/27/da/68f38d12e7111d2016cd198161b36e1f042bd115c169255bcb7ec823a3bf/jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72", size = 200630, upload-time = "2026-02-02T12:36:31.808Z" }, - { url = "https://files.pythonhosted.org/packages/25/65/3bd1a972c9a08ecd22eb3b08a95d1941ebe6938aea620c246cf426ae09c2/jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc", size = 202602, upload-time = "2026-02-02T12:36:33.679Z" }, - { url = "https://files.pythonhosted.org/packages/15/fe/13bd3678a311aa67686bb303654792c48206a112068f8b0b21426eb6851e/jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b", size = 185939, upload-time = "2026-02-02T12:36:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/49/19/a929ec002ad3228bc97ca01dbb14f7632fffdc84a95ec92ceaf4145688ae/jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10", size = 316616, upload-time = "2026-02-02T12:36:36.579Z" }, - { url = "https://files.pythonhosted.org/packages/52/56/d19a9a194afa37c1728831e5fb81b7722c3de18a3109e8f282bfc23e587a/jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef", size = 346850, upload-time = "2026-02-02T12:36:38.058Z" }, - { url = "https://files.pythonhosted.org/packages/36/4a/94e831c6bf287754a8a019cb966ed39ff8be6ab78cadecf08df3bb02d505/jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6", size = 358551, upload-time = "2026-02-02T12:36:39.417Z" }, - { url = "https://files.pythonhosted.org/packages/a2/ec/a4c72c822695fa80e55d2b4142b73f0012035d9fcf90eccc56bc060db37c/jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d", size = 201950, upload-time = "2026-02-02T12:36:40.791Z" }, - { url = "https://files.pythonhosted.org/packages/b6/00/393553ec27b824fbc29047e9c7cd4a3951d7fbe4a76743f17e44034fa4e4/jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d", size = 185852, upload-time = "2026-02-02T12:36:42.077Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f5/f1997e987211f6f9bd71b8083047b316208b4aca0b529bb5f8c96c89ef3e/jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0", size = 308804, upload-time = "2026-02-02T12:36:43.496Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8f/5482a7677731fd44881f0204981ce2d7175db271f82cba2085dd2212e095/jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91", size = 318787, upload-time = "2026-02-02T12:36:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b9/7257ac59778f1cd025b26a23c5520a36a424f7f1b068f2442a5b499b7464/jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09", size = 353880, upload-time = "2026-02-02T12:36:47.365Z" }, - { url = "https://files.pythonhosted.org/packages/c3/87/719eec4a3f0841dad99e3d3604ee4cba36af4419a76f3cb0b8e2e691ad67/jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607", size = 366702, upload-time = "2026-02-02T12:36:48.871Z" }, - { url = "https://files.pythonhosted.org/packages/d2/65/415f0a75cf6921e43365a1bc227c565cb949caca8b7532776e430cbaa530/jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66", size = 486319, upload-time = "2026-02-02T12:36:53.006Z" }, - { url = "https://files.pythonhosted.org/packages/54/a2/9e12b48e82c6bbc6081fd81abf915e1443add1b13d8fc586e1d90bb02bb8/jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2", size = 372289, upload-time = "2026-02-02T12:36:54.593Z" }, - { url = "https://files.pythonhosted.org/packages/4e/c1/e4693f107a1789a239c759a432e9afc592366f04e901470c2af89cfd28e1/jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad", size = 360165, upload-time = "2026-02-02T12:36:56.112Z" }, - { url = "https://files.pythonhosted.org/packages/17/08/91b9ea976c1c758240614bd88442681a87672eebc3d9a6dde476874e706b/jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d", size = 389634, upload-time = "2026-02-02T12:36:57.495Z" }, - { url = "https://files.pythonhosted.org/packages/18/23/58325ef99390d6d40427ed6005bf1ad54f2577866594bcf13ce55675f87d/jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df", size = 514933, upload-time = "2026-02-02T12:36:58.909Z" }, - { url = "https://files.pythonhosted.org/packages/5b/25/69f1120c7c395fd276c3996bb8adefa9c6b84c12bb7111e5c6ccdcd8526d/jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d", size = 548842, upload-time = "2026-02-02T12:37:00.433Z" }, - { url = "https://files.pythonhosted.org/packages/18/05/981c9669d86850c5fbb0d9e62bba144787f9fba84546ba43d624ee27ef29/jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6", size = 202108, upload-time = "2026-02-02T12:37:01.718Z" }, - { url = "https://files.pythonhosted.org/packages/8d/96/cdcf54dd0b0341db7d25413229888a346c7130bd20820530905fdb65727b/jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f", size = 204027, upload-time = "2026-02-02T12:37:03.075Z" }, - { url = "https://files.pythonhosted.org/packages/fb/f9/724bcaaab7a3cd727031fe4f6995cb86c4bd344909177c186699c8dec51a/jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d", size = 187199, upload-time = "2026-02-02T12:37:04.414Z" }, - { url = "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0", size = 318423, upload-time = "2026-02-02T12:37:05.806Z" }, - { url = "https://files.pythonhosted.org/packages/4f/3b/f77d342a54d4ebcd128e520fc58ec2f5b30a423b0fd26acdfc0c6fef8e26/jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40", size = 351438, upload-time = "2026-02-02T12:37:07.189Z" }, - { url = "https://files.pythonhosted.org/packages/76/b3/ba9a69f0e4209bd3331470c723c2f5509e6f0482e416b612431a5061ed71/jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202", size = 364774, upload-time = "2026-02-02T12:37:08.579Z" }, - { url = "https://files.pythonhosted.org/packages/b3/16/6cdb31fa342932602458dbb631bfbd47f601e03d2e4950740e0b2100b570/jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0", size = 487238, upload-time = "2026-02-02T12:37:10.066Z" }, - { url = "https://files.pythonhosted.org/packages/ed/b1/956cc7abaca8d95c13aa8d6c9b3f3797241c246cd6e792934cc4c8b250d2/jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95", size = 372892, upload-time = "2026-02-02T12:37:11.656Z" }, - { url = "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59", size = 360309, upload-time = "2026-02-02T12:37:13.244Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d7/eabe3cf46715854ccc80be2cd78dd4c36aedeb30751dbf85a1d08c14373c/jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe", size = 389607, upload-time = "2026-02-02T12:37:14.881Z" }, - { url = "https://files.pythonhosted.org/packages/df/2d/03963fc0804e6109b82decfb9974eb92df3797fe7222428cae12f8ccaa0c/jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939", size = 514986, upload-time = "2026-02-02T12:37:16.326Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/8c83b45eb3eb1c1e18d841fe30b4b5bc5619d781267ca9bc03e005d8fd0a/jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9", size = 548756, upload-time = "2026-02-02T12:37:17.736Z" }, - { url = "https://files.pythonhosted.org/packages/47/66/eea81dfff765ed66c68fd2ed8c96245109e13c896c2a5015c7839c92367e/jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6", size = 201196, upload-time = "2026-02-02T12:37:19.101Z" }, - { url = "https://files.pythonhosted.org/packages/ff/32/4ac9c7a76402f8f00d00842a7f6b83b284d0cf7c1e9d4227bc95aa6d17fa/jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8", size = 204215, upload-time = "2026-02-02T12:37:20.495Z" }, - { url = "https://files.pythonhosted.org/packages/f9/8e/7def204fea9f9be8b3c21a6f2dd6c020cf56c7d5ff753e0e23ed7f9ea57e/jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024", size = 187152, upload-time = "2026-02-02T12:37:22.124Z" }, - { url = "https://files.pythonhosted.org/packages/79/b3/3c29819a27178d0e461a8571fb63c6ae38be6dc36b78b3ec2876bbd6a910/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c", size = 307016, upload-time = "2026-02-02T12:37:42.755Z" }, - { url = "https://files.pythonhosted.org/packages/eb/ae/60993e4b07b1ac5ebe46da7aa99fdbb802eb986c38d26e3883ac0125c4e0/jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2", size = 305024, upload-time = "2026-02-02T12:37:44.774Z" }, - { url = "https://files.pythonhosted.org/packages/77/fa/2227e590e9cf98803db2811f172b2d6460a21539ab73006f251c66f44b14/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434", size = 339337, upload-time = "2026-02-02T12:37:46.668Z" }, - { url = "https://files.pythonhosted.org/packages/2d/92/015173281f7eb96c0ef580c997da8ef50870d4f7f4c9e03c845a1d62ae04/jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d", size = 346395, upload-time = "2026-02-02T12:37:48.09Z" }, - { url = "https://files.pythonhosted.org/packages/80/60/e50fa45dd7e2eae049f0ce964663849e897300433921198aef94b6ffa23a/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a", size = 305169, upload-time = "2026-02-02T12:37:50.376Z" }, - { url = "https://files.pythonhosted.org/packages/d2/73/a009f41c5eed71c49bec53036c4b33555afcdee70682a18c6f66e396c039/jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f", size = 303808, upload-time = "2026-02-02T12:37:52.092Z" }, - { url = "https://files.pythonhosted.org/packages/c4/10/528b439290763bff3d939268085d03382471b442f212dca4ff5f12802d43/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59", size = 337384, upload-time = "2026-02-02T12:37:53.582Z" }, - { url = "https://files.pythonhosted.org/packages/67/8a/a342b2f0251f3dac4ca17618265d93bf244a2a4d089126e81e4c1056ac50/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19", size = 343768, upload-time = "2026-02-02T12:37:55.055Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/6e/c1/0cddc6eb17d4c53a99840953f95dd3accdc5cfc7a337b0e9b26476276be9/jiter-0.14.0.tar.gz", hash = "sha256:e8a39e66dac7153cf3f964a12aad515afa8d74938ec5cc0018adcdae5367c79e", size = 165725, upload-time = "2026-04-10T14:28:42.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/68/7390a418f10897da93b158f2d5a8bd0bcd73a0f9ec3bb36917085bb759ef/jiter-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:2fb2ce3a7bc331256dfb14cefc34832366bb28a9aca81deaf43bbf2a5659e607", size = 316295, upload-time = "2026-04-10T14:26:24.887Z" }, + { url = "https://files.pythonhosted.org/packages/60/a0/5854ac00ff63551c52c6c89534ec6aba4b93474e7924d64e860b1c94165b/jiter-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5252a7ca23785cef5d02d4ece6077a1b556a410c591b379f82091c3001e14844", size = 315898, upload-time = "2026-04-10T14:26:26.601Z" }, + { url = "https://files.pythonhosted.org/packages/41/a1/4f44832650a16b18e8391f1bf1d6ca4909bc738351826bcc198bba4357f4/jiter-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c409578cbd77c338975670ada777add4efd53379667edf0aceea730cabede6fb", size = 343730, upload-time = "2026-04-10T14:26:28.326Z" }, + { url = "https://files.pythonhosted.org/packages/48/64/a329e9d469f86307203594b1707e11ae51c3348d03bfd514a5f997870012/jiter-0.14.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ede4331a1899d604463369c730dbb961ffdc5312bc7f16c41c2896415b1304a", size = 370102, upload-time = "2026-04-10T14:26:30.089Z" }, + { url = "https://files.pythonhosted.org/packages/94/c1/5e3dfc59635aa4d4c7bd20a820ac1d09b8ed851568356802cf1c08edb3cf/jiter-0.14.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92cd8b6025981a041f5310430310b55b25ca593972c16407af8837d3d7d2ca01", size = 461335, upload-time = "2026-04-10T14:26:31.911Z" }, + { url = "https://files.pythonhosted.org/packages/e3/1b/dd157009dbc058f7b00108f545ccb72a2d56461395c4fc7b9cfdccb00af4/jiter-0.14.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:351bf6eda4e3a7ceb876377840c702e9a3e4ecc4624dbfb2d6463c67ae52637d", size = 378536, upload-time = "2026-04-10T14:26:33.595Z" }, + { url = "https://files.pythonhosted.org/packages/91/78/256013667b7c10b8834f8e6e54cd3e562d4c6e34227a1596addccc05e38c/jiter-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1dcfbeb93d9ecd9ca128bbf8910120367777973fa193fb9a39c31237d8df165", size = 353859, upload-time = "2026-04-10T14:26:35.098Z" }, + { url = "https://files.pythonhosted.org/packages/de/d9/137d65ade9093a409fe80955ce60b12bb753722c986467aeda47faf450ad/jiter-0.14.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:ae039aaef8de3f8157ecc1fdd4d85043ac4f57538c245a0afaecb8321ec951c3", size = 357626, upload-time = "2026-04-10T14:26:36.685Z" }, + { url = "https://files.pythonhosted.org/packages/2e/48/76750835b87029342727c1a268bea8878ab988caf81ee4e7b880900eeb5a/jiter-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7d9d51eb96c82a9652933bd769fe6de66877d6eb2b2440e281f2938c51b5643e", size = 393172, upload-time = "2026-04-10T14:26:38.097Z" }, + { url = "https://files.pythonhosted.org/packages/a6/60/456c4e81d5c8045279aefe60e9e483be08793828800a4e64add8fdde7f2a/jiter-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d824ca4148b705970bf4e120924a212fdfca9859a73e42bd7889a63a4ea6bb98", size = 520300, upload-time = "2026-04-10T14:26:39.532Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9f/2020e0984c235f678dced38fe4eec3058cf528e6af36ebf969b410305941/jiter-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff3a6465b3a0f54b1a430f45c3c0ba7d61ceb45cbc3e33f9e1a7f638d690baf3", size = 553059, upload-time = "2026-04-10T14:26:40.991Z" }, + { url = "https://files.pythonhosted.org/packages/ef/32/e2d298e1a22a4bbe6062136d1c7192db7dba003a6975e51d9a9eecabc4c2/jiter-0.14.0-cp312-cp312-win32.whl", hash = "sha256:5dec7c0a3e98d2a3f8a2e67382d0d7c3ac60c69103a4b271da889b4e8bb1e129", size = 206030, upload-time = "2026-04-10T14:26:42.517Z" }, + { url = "https://files.pythonhosted.org/packages/36/ac/96369141b3d8a4a8e4590e983085efe1c436f35c0cda940dd76d942e3e40/jiter-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:fc7e37b4b8bc7e80a63ad6cfa5fc11fab27dbfea4cc4ae644b1ab3f273dc348f", size = 201603, upload-time = "2026-04-10T14:26:44.328Z" }, + { url = "https://files.pythonhosted.org/packages/01/c3/75d847f264647017d7e3052bbcc8b1e24b95fa139c320c5f5066fa7a0bdd/jiter-0.14.0-cp312-cp312-win_arm64.whl", hash = "sha256:ee4a72f12847ef29b072aee9ad5474041ab2924106bdca9fcf5d7d965853e057", size = 191525, upload-time = "2026-04-10T14:26:46Z" }, + { url = "https://files.pythonhosted.org/packages/97/2a/09f70020898507a89279659a1afe3364d57fc1b2c89949081975d135f6f5/jiter-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:af72f204cf4d44258e5b4c1745130ac45ddab0e71a06333b01de660ab4187a94", size = 315502, upload-time = "2026-04-10T14:26:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/d6/be/080c96a45cd74f9fce5db4fd68510b88087fb37ffe2541ff73c12db92535/jiter-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4b77da71f6e819be5fbcec11a453fde5b1d0267ef6ed487e2a392fd8e14e4e3a", size = 314870, upload-time = "2026-04-10T14:26:49.149Z" }, + { url = "https://files.pythonhosted.org/packages/7d/5e/2d0fee155826a968a832cc32438de5e2a193292c8721ca70d0b53e58245b/jiter-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f4ea612fe8b84b8b04e51d0e78029ecf3466348e25973f953de6e6a59aa4c1", size = 343406, upload-time = "2026-04-10T14:26:50.762Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/bf9ee0d3a4f8dc0d679fc1337f874fe60cdbf841ebbb304b374e1c9aaceb/jiter-0.14.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62fe2451f8fcc0240261e6a4df18ecbcd58327857e61e625b2393ea3b468aac9", size = 369415, upload-time = "2026-04-10T14:26:52.188Z" }, + { url = "https://files.pythonhosted.org/packages/0f/83/8e8561eadba31f4d3948a5b712fb0447ec71c3560b57a855449e7b8ddc98/jiter-0.14.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6112f26f5afc75bcb475787d29da3aa92f9d09c7858f632f4be6ffe607be82e9", size = 461456, upload-time = "2026-04-10T14:26:53.611Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c9/c5299e826a5fe6108d172b344033f61c69b1bb979dd8d9ddd4278a160971/jiter-0.14.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:215a6cb8fb7dc702aa35d475cc00ddc7f970e5c0b1417fb4b4ac5d82fa2a29db", size = 378488, upload-time = "2026-04-10T14:26:55.211Z" }, + { url = "https://files.pythonhosted.org/packages/5d/37/c16d9d15c0a471b8644b1abe3c82668092a707d9bedcf076f24ff2e380cd/jiter-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ab96a30fb3cb2c7e0cd33f7616c8860da5f5674438988a54ac717caccdbaa", size = 353242, upload-time = "2026-04-10T14:26:56.705Z" }, + { url = "https://files.pythonhosted.org/packages/58/ea/8050cb0dc654e728e1bfacbc0c640772f2181af5dedd13ae70145743a439/jiter-0.14.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:3a99c1387b1f2928f799a9de899193484d66206a50e98233b6b088a7f0c1edb2", size = 356823, upload-time = "2026-04-10T14:26:58.281Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/cf71506d270e5f84d97326bf220e47aed9b95e9a4a060758fb07772170ab/jiter-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ab18d11074485438695f8d34a1b6da61db9754248f96d51341956607a8f39985", size = 392564, upload-time = "2026-04-10T14:27:00.018Z" }, + { url = "https://files.pythonhosted.org/packages/b0/cc/8c6c74a3efb5bd671bfd14f51e8a73375464ca914b1551bc3b40e26ac2c9/jiter-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:801028dcfc26ac0895e4964cbc0fd62c73be9fd4a7d7b1aaf6e5790033a719b7", size = 520322, upload-time = "2026-04-10T14:27:01.664Z" }, + { url = "https://files.pythonhosted.org/packages/41/24/68d7b883ec959884ddf00d019b2e0e82ba81b167e1253684fa90519ce33c/jiter-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ad425b087aafb4a1c7e1e98a279200743b9aaf30c3e0ba723aec93f061bd9bc8", size = 552619, upload-time = "2026-04-10T14:27:03.316Z" }, + { url = "https://files.pythonhosted.org/packages/b6/89/b1a0985223bbf3150ff9e8f46f98fc9360c1de94f48abe271bbe1b465682/jiter-0.14.0-cp313-cp313-win32.whl", hash = "sha256:882bcb9b334318e233950b8be366fe5f92c86b66a7e449e76975dfd6d776a01f", size = 205699, upload-time = "2026-04-10T14:27:04.662Z" }, + { url = "https://files.pythonhosted.org/packages/4c/19/3f339a5a7f14a11730e67f6be34f9d5105751d547b615ef593fa122a5ded/jiter-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:9b8c571a5dba09b98bd3462b5a53f27209a5cbbe85670391692ede71974e979f", size = 201323, upload-time = "2026-04-10T14:27:06.139Z" }, + { url = "https://files.pythonhosted.org/packages/50/56/752dd89c84be0e022a8ea3720bcfa0a8431db79a962578544812ce061739/jiter-0.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:34f19dcc35cb1abe7c369b3756babf8c7f04595c0807a848df8f26ef8298ef92", size = 191099, upload-time = "2026-04-10T14:27:07.564Z" }, + { url = "https://files.pythonhosted.org/packages/91/28/292916f354f25a1fe8cf2c918d1415c699a4a659ae00be0430e1c5d9ffea/jiter-0.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e89bcd7d426a75bb4952c696b267075790d854a07aad4c9894551a82c5b574ab", size = 320880, upload-time = "2026-04-10T14:27:09.326Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c7/b002a7d8b8957ac3d469bd59c18ef4b1595a5216ae0de639a287b9816023/jiter-0.14.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b25beaa0d4447ea8c7ae0c18c688905d34840d7d0b937f2f7bdd52162c98a40", size = 346563, upload-time = "2026-04-10T14:27:11.287Z" }, + { url = "https://files.pythonhosted.org/packages/f9/3b/f8d07580d8706021d255a6356b8fab13ee4c869412995550ce6ed4ddf97d/jiter-0.14.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a8758dd413c51e3b7f6557cdc6921faf70b14106f45f969f091f5cda990ea", size = 357928, upload-time = "2026-04-10T14:27:12.729Z" }, + { url = "https://files.pythonhosted.org/packages/47/5b/ac1a974da29e35507230383110ffec59998b290a8732585d04e19a9eb5ba/jiter-0.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e1a7eead856a5038a8d291f1447176ab0b525c77a279a058121b5fccee257f6f", size = 203519, upload-time = "2026-04-10T14:27:14.125Z" }, + { url = "https://files.pythonhosted.org/packages/96/6d/9fc8433d667d2454271378a79747d8c76c10b51b482b454e6190e511f244/jiter-0.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e692633a12cda97e352fdcd1c4acc971b1c28707e1e33aeef782b0cbf051975", size = 190113, upload-time = "2026-04-10T14:27:16.638Z" }, + { url = "https://files.pythonhosted.org/packages/4f/1e/354ed92461b165bd581f9ef5150971a572c873ec3b68a916d5aa91da3cc2/jiter-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:6f396837fc7577871ca8c12edaf239ed9ccef3bbe39904ae9b8b63ce0a48b140", size = 315277, upload-time = "2026-04-10T14:27:18.109Z" }, + { url = "https://files.pythonhosted.org/packages/a6/95/8c7c7028aa8636ac21b7a55faef3e34215e6ed0cbf5ae58258427f621aa3/jiter-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a4d50ea3d8ba4176f79754333bd35f1bbcd28e91adc13eb9b7ca91bc52a6cef9", size = 315923, upload-time = "2026-04-10T14:27:19.603Z" }, + { url = "https://files.pythonhosted.org/packages/47/40/e2a852a44c4a089f2681a16611b7ce113224a80fd8504c46d78491b47220/jiter-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce17f8a050447d1b4153bda4fb7d26e6a9e74eb4f4a41913f30934c5075bf615", size = 344943, upload-time = "2026-04-10T14:27:21.262Z" }, + { url = "https://files.pythonhosted.org/packages/fc/1f/670f92adee1e9895eac41e8a4d623b6da68c4d46249d8b556b60b63f949e/jiter-0.14.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4f1c4b125e1652aefbc2e2c1617b60a160ab789d180e3d423c41439e5f32850", size = 369725, upload-time = "2026-04-10T14:27:22.766Z" }, + { url = "https://files.pythonhosted.org/packages/01/2f/541c9ba567d05de1c4874a0f8f8c5e3fd78e2b874266623da9a775cf46e0/jiter-0.14.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be808176a6a3a14321d18c603f2d40741858a7c4fc982f83232842689fe86dd9", size = 461210, upload-time = "2026-04-10T14:27:24.315Z" }, + { url = "https://files.pythonhosted.org/packages/ce/a9/c31cbec09627e0d5de7aeaec7690dba03e090caa808fefd8133137cf45bc/jiter-0.14.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26679d58ba816f88c3849306dd58cb863a90a1cf352cdd4ef67e30ccf8a77994", size = 380002, upload-time = "2026-04-10T14:27:26.155Z" }, + { url = "https://files.pythonhosted.org/packages/50/02/3c05c1666c41904a2f607475a73e7a4763d1cbde2d18229c4f85b22dc253/jiter-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80381f5a19af8fa9aef743f080e34f6b25ebd89656475f8cf0470ec6157052aa", size = 354678, upload-time = "2026-04-10T14:27:27.701Z" }, + { url = "https://files.pythonhosted.org/packages/7d/97/e15b33545c2b13518f560d695f974b9891b311641bdcf178d63177e8801e/jiter-0.14.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:004df5fdb8ecbd6d99f3227df18ba1a259254c4359736a2e6f036c944e02d7c5", size = 358920, upload-time = "2026-04-10T14:27:29.256Z" }, + { url = "https://files.pythonhosted.org/packages/ad/d2/8b1461def6b96ba44530df20d07ef7a1c7da22f3f9bf1727e2d611077bf1/jiter-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cff5708f7ed0fa098f2b53446c6fa74c48469118e5cd7497b4f1cd569ab06928", size = 394512, upload-time = "2026-04-10T14:27:31.344Z" }, + { url = "https://files.pythonhosted.org/packages/e3/88/837566dd6ed6e452e8d3205355afd484ce44b2533edfa4ed73a298ea893e/jiter-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:2492e5f06c36a976d25c7cc347a60e26d5470178d44cde1b9b75e60b4e519f28", size = 521120, upload-time = "2026-04-10T14:27:33.299Z" }, + { url = "https://files.pythonhosted.org/packages/89/6b/b00b45c4d1b4c031777fe161d620b755b5b02cdade1e316dcb46e4471d63/jiter-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:7609cfbe3a03d37bfdbf5052012d5a879e72b83168a363deae7b3a26564d57de", size = 553668, upload-time = "2026-04-10T14:27:34.868Z" }, + { url = "https://files.pythonhosted.org/packages/ad/d8/6fe5b42011d19397433d345716eac16728ac241862a2aac9c91923c7509a/jiter-0.14.0-cp314-cp314-win32.whl", hash = "sha256:7282342d32e357543565286b6450378c3cd402eea333fc1ebe146f1fabb306fc", size = 207001, upload-time = "2026-04-10T14:27:36.455Z" }, + { url = "https://files.pythonhosted.org/packages/e5/43/5c2e08da1efad5e410f0eaaabeadd954812612c33fbbd8fd5328b489139d/jiter-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:bd77945f38866a448e73b0b7637366afa814d4617790ecd88a18ca74377e6c02", size = 202187, upload-time = "2026-04-10T14:27:38Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1f/6e39ac0b4cdfa23e606af5b245df5f9adaa76f35e0c5096790da430ca506/jiter-0.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:f2d4c61da0821ee42e0cdf5489da60a6d074306313a377c2b35af464955a3611", size = 192257, upload-time = "2026-04-10T14:27:39.504Z" }, + { url = "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1bf7ff85517dd2f20a5750081d2b75083c1b269cf75afc7511bdf1f9548beb3b", size = 323441, upload-time = "2026-04-10T14:27:41.039Z" }, + { url = "https://files.pythonhosted.org/packages/83/6e/7b3314398d8983f06b557aa21b670511ec72d3b79a68ee5e4d9bff972286/jiter-0.14.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8ef8791c3e78d6c6b157c6d360fbb5c715bebb8113bc6a9303c5caff012754a", size = 348109, upload-time = "2026-04-10T14:27:42.552Z" }, + { url = "https://files.pythonhosted.org/packages/ae/4f/8dc674bcd7db6dba566de73c08c763c337058baff1dbeb34567045b27cdc/jiter-0.14.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e74663b8b10da1fe0f4e4703fd7980d24ad17174b6bb35d8498d6e3ebce2ae6a", size = 368328, upload-time = "2026-04-10T14:27:44.574Z" }, + { url = "https://files.pythonhosted.org/packages/3b/5f/188e09a1f20906f98bbdec44ed820e19f4e8eb8aff88b9d1a5a497587ff3/jiter-0.14.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1aca29ba52913f78362ec9c2da62f22cdc4c3083313403f90c15460979b84d9b", size = 463301, upload-time = "2026-04-10T14:27:46.717Z" }, + { url = "https://files.pythonhosted.org/packages/ac/f0/19046ef965ed8f349e8554775bb12ff4352f443fbe12b95d31f575891256/jiter-0.14.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8b39b7d87a952b79949af5fef44d2544e58c21a28da7f1bae3ef166455c61746", size = 378891, upload-time = "2026-04-10T14:27:48.32Z" }, + { url = "https://files.pythonhosted.org/packages/c4/c3/da43bd8431ee175695777ee78cf0e93eacbb47393ff493f18c45231b427d/jiter-0.14.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d918a68b26e9fab068c2b5453577ef04943ab2807b9a6275df2a812599a310", size = 360749, upload-time = "2026-04-10T14:27:49.88Z" }, + { url = "https://files.pythonhosted.org/packages/72/26/e054771be889707c6161dbdec9c23d33a9ec70945395d70f07cfea1e9a6f/jiter-0.14.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:b08997c35aee1201c1a5361466a8fb9162d03ae7bf6568df70b6c859f1e654a4", size = 358526, upload-time = "2026-04-10T14:27:51.504Z" }, + { url = "https://files.pythonhosted.org/packages/c3/0f/7bea65ea2a6d91f2bf989ff11a18136644392bf2b0497a1fa50934c30a9c/jiter-0.14.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:260bf7ca20704d58d41f669e5e9fe7fe2fa72901a6b324e79056f5d52e9c9be2", size = 393926, upload-time = "2026-04-10T14:27:53.368Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a1/b1ff7d70deef61ac0b7c6c2f12d2ace950cdeecb4fdc94500a0926802857/jiter-0.14.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:37826e3df29e60f30a382f9294348d0238ef127f4b5d7f5f8da78b5b9e050560", size = 521052, upload-time = "2026-04-10T14:27:55.058Z" }, + { url = "https://files.pythonhosted.org/packages/0b/7b/3b0649983cbaf15eda26a414b5b1982e910c67bd6f7b1b490f3cfc76896a/jiter-0.14.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:645be49c46f2900937ba0eaf871ad5183c96858c0af74b6becc7f4e367e36e06", size = 553716, upload-time = "2026-04-10T14:27:57.269Z" }, + { url = "https://files.pythonhosted.org/packages/97/f8/33d78c83bd93ae0c0af05293a6660f88a1977caef39a6d72a84afab94ce0/jiter-0.14.0-cp314-cp314t-win32.whl", hash = "sha256:2f7877ed45118de283786178eceaf877110abacd04fde31efff3940ae9672674", size = 207957, upload-time = "2026-04-10T14:27:59.285Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ac/2b760516c03e2227826d1f7025d89bf6bf6357a28fe75c2a2800873c50bf/jiter-0.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:14c0cb10337c49f5eafe8e7364daca5e29a020ea03580b8f8e6c597fed4e1588", size = 204690, upload-time = "2026-04-10T14:28:00.962Z" }, + { url = "https://files.pythonhosted.org/packages/dc/2e/a44c20c58aeed0355f2d326969a181696aeb551a25195f47563908a815be/jiter-0.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:5419d4aa2024961da9fe12a9cfe7484996735dca99e8e090b5c88595ef1951ff", size = 191338, upload-time = "2026-04-10T14:28:02.853Z" }, + { url = "https://files.pythonhosted.org/packages/21/42/9042c3f3019de4adcb8c16591c325ec7255beea9fcd33a42a43f3b0b1000/jiter-0.14.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:fbd9e482663ca9d005d051330e4d2d8150bb208a209409c10f7e7dfdf7c49da9", size = 308810, upload-time = "2026-04-10T14:28:34.673Z" }, + { url = "https://files.pythonhosted.org/packages/60/cf/a7e19b308bd86bb04776803b1f01a5f9a287a4c55205f4708827ee487fbf/jiter-0.14.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:33a20d838b91ef376b3a56896d5b04e725c7df5bc4864cc6569cf046a8d73b6d", size = 308443, upload-time = "2026-04-10T14:28:36.658Z" }, + { url = "https://files.pythonhosted.org/packages/ca/44/e26ede3f0caeff93f222559cb0cc4ca68579f07d009d7b6010c5b586f9b1/jiter-0.14.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:432c4db5255d86a259efde91e55cb4c8d18c0521d844c9e2e7efcce3899fb016", size = 343039, upload-time = "2026-04-10T14:28:38.356Z" }, + { url = "https://files.pythonhosted.org/packages/da/e9/1f9ada30cef7b05e74bb06f52127e7a724976c225f46adb65c37b1dadfb6/jiter-0.14.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67f00d94b281174144d6532a04b66a12cb866cbdc47c3af3bfe2973677f9861a", size = 349613, upload-time = "2026-04-10T14:28:40.066Z" }, ] [[package]] @@ -1930,6 +1646,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, ] +[[package]] +name = "jsonpatch" +version = "1.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpointer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, +] + +[[package]] +name = "jsonpath-python" +version = "1.1.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/db/2f4ecc24da35c6142b39c353d5b7c16eef955cc94b35a48d3fa47996d7c3/jsonpath_python-1.1.5.tar.gz", hash = "sha256:ceea2efd9e56add09330a2c9631ea3d55297b9619348c1055e5bfb9cb0b8c538", size = 87352, upload-time = "2026-03-17T06:16:40.597Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/50/1a313fb700526b134c71eb8a225d8b83be0385dbb0204337b4379c698cef/jsonpath_python-1.1.5-py3-none-any.whl", hash = "sha256:a60315404d70a65e76c9a782c84e50600480221d94a58af47b7b4d437351cb4b", size = 14090, upload-time = "2026-03-17T06:16:39.152Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/c7/af399a2e7a67fd18d63c40c5e62d3af4e67b836a2107468b6a5ea24c4304/jsonpointer-3.1.1.tar.gz", hash = "sha256:0b801c7db33a904024f6004d526dcc53bbb8a4a0f4e32bfd10beadf60adf1900", size = 9068, upload-time = "2026-03-23T22:32:32.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl", hash = "sha256:8ff8b95779d071ba472cf5bc913028df06031797532f08a7d5b602d8b2a488ca", size = 7659, upload-time = "2026-03-23T22:32:31.568Z" }, +] + [[package]] name = "jsonref" version = "1.1.0" @@ -1993,31 +1739,6 @@ version = "0.10.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/39/cb/c1945e506893b5b8577fb45a60c80e3ffe4a82092a04a6f29b0b951d9a24/librt-0.10.0.tar.gz", hash = "sha256:1aba1e8aa4e3307a7be68a74149545fde7451964dc0235a8bec5704a17bdda42", size = 191799, upload-time = "2026-05-05T16:31:23.535Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/18/827e5c1262a88c2602e86f99aee0f288ffea3280dbd2ff448858ef9dc6e9/librt-0.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dc99f9642100b86e5f6bb14cdc9970009e31a9ef7d64df6704b7018451524a3", size = 76461, upload-time = "2026-05-05T16:29:00.422Z" }, - { url = "https://files.pythonhosted.org/packages/ee/90/54254e30287f5a5abec6fef22d976987476e966be5fdff51fe8c2d5d73d1/librt-0.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8298cedfcfaff3790000bd057aaaa3df1b0ab54cf7b48eeab16184cbb1bc66b9", size = 79740, upload-time = "2026-05-05T16:29:01.926Z" }, - { url = "https://files.pythonhosted.org/packages/4c/20/e93264b52113669d98d3b63ff94d4ce0c4dd49ae0503f1788440a884e5f0/librt-0.10.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee7dbe312dbf76468255b79a7ba311236fde620f2f7055fc09d421e31340314e", size = 243472, upload-time = "2026-05-05T16:29:03.373Z" }, - { url = "https://files.pythonhosted.org/packages/35/ad/34a5141178e8b18a4cfa45d1a0d523c84397e2abd5d06fea2d846da687e8/librt-0.10.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:56ed90c48c19249012dadfd79a1bc13bd5168ea60a70722d330a3a600c0b1852", size = 232073, upload-time = "2026-05-05T16:29:04.815Z" }, - { url = "https://files.pythonhosted.org/packages/97/1f/67240e910cd9f9ab1498c1470738345fc29dce5dc9719db1e0e09d1e861f/librt-0.10.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d74ca0f4b2b09c117f913d4df01f6b934dff8a271096b35167d5264a31649f0", size = 256956, upload-time = "2026-05-05T16:29:06.516Z" }, - { url = "https://files.pythonhosted.org/packages/22/50/3a2b3482c27d607f6e8216d913c6bc592b9a2141d96990309452340a78e3/librt-0.10.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8eb2daa9375f93c0e55ff5e44a4bbe98f39e5fe52e1abf9c97acb67743b61bf8", size = 250593, upload-time = "2026-05-05T16:29:08.324Z" }, - { url = "https://files.pythonhosted.org/packages/e7/1c/07dba133d79f93322fa17514062f1a2a50d6bdfb7baec4acf78193d7fad1/librt-0.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7b09b90e634e6dff57978cd358070046071e2b120501f10787aeb35425f504f6", size = 263582, upload-time = "2026-05-05T16:29:09.866Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ac/033f2c6d6ab0b48f15f02e5bf065521b11a51922806017f8b6274df30d69/librt-0.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2cf22fd379d60c739b800d4295ed34045f8b04aa8df9c12bd2f8f43f7fe672b7", size = 259307, upload-time = "2026-05-05T16:29:11.675Z" }, - { url = "https://files.pythonhosted.org/packages/6e/10/679046cd75d5a52c0104c890d8f69574ef4e619c683e59c15584d03a2457/librt-0.10.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:74c798793fcf29a84d442278ebe0bb1fff79fe58ac4106eeff7019cbba861423", size = 257342, upload-time = "2026-05-05T16:29:13.14Z" }, - { url = "https://files.pythonhosted.org/packages/1e/d5/dbaac9c0884f78a53dda22b9ec92bb788e1400e762ed7623fa96928c8da5/librt-0.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dc4f1573401e8dbe6c26511fe027620b0fb30ae9a7ab814e02e510626b8b5f9c", size = 280141, upload-time = "2026-05-05T16:29:14.922Z" }, - { url = "https://files.pythonhosted.org/packages/cc/81/71f18cf8eb340d9fda011498870910f6a8697aeb50833005d3d8107653fd/librt-0.10.0-cp310-cp310-win32.whl", hash = "sha256:e1428275f5fe3d4db6822e58d8b005a5b28ffca55e8433ebc051247fbe46429f", size = 62257, upload-time = "2026-05-05T16:29:16.226Z" }, - { url = "https://files.pythonhosted.org/packages/df/52/6bcebc2f870c4836bcb372be885fae7f17a1d25037d3a8250ef79fbe0124/librt-0.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:0708e9408f585b0f065081680583a577652099680ccf820c7538904322b679c3", size = 70321, upload-time = "2026-05-05T16:29:17.41Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a3/1472717d2325adacc8d335ba2e4078015c09d75b599f3cf48e967b3d306e/librt-0.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01b4500ca3a625450c032a9142a8e843923ce263fa8a92ad1b38927cabe2fe72", size = 76045, upload-time = "2026-05-05T16:29:18.731Z" }, - { url = "https://files.pythonhosted.org/packages/a6/31/bfe32355d4b369aef3d7aa442df663bb5558c2ffa2de286cb2956346bc24/librt-0.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6b7e42d1b3e300d20bfc87e72ffd62f0a92a2cb3c35f7bf90df90c9d2a49f74c", size = 79466, upload-time = "2026-05-05T16:29:20.052Z" }, - { url = "https://files.pythonhosted.org/packages/e9/f1/83f8a2c715ba2cac9b7387a5a5cea25f717f7184320cfe48b36bed9c58e9/librt-0.10.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8ef7b8c61ce3a1b597cd3e15348ff1574325165c2e7ce09a718154cde2a7950", size = 242283, upload-time = "2026-05-05T16:29:21.596Z" }, - { url = "https://files.pythonhosted.org/packages/cc/94/c3a4ce94857f0004a542f86662806383611858f522722db58efaec0a1472/librt-0.10.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:e73c84f72d1fa0d6eaa7a1930b436ba8d2c90c58d77bfabb09995a69ad35f6c0", size = 230735, upload-time = "2026-05-05T16:29:23.335Z" }, - { url = "https://files.pythonhosted.org/packages/d1/41/e962bb26c7728eb7b3a69e490d0c800fd9968a6970e390c1f18ddb56093d/librt-0.10.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9728cb98713bd862fb8f4fd6a642d1896c86058a41d77c70f3d5cee75e725275", size = 256606, upload-time = "2026-05-05T16:29:24.91Z" }, - { url = "https://files.pythonhosted.org/packages/66/3a/4e46a707b1ecc993fd691071623b9beab89703a63bd21cc7807e06c28209/librt-0.10.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:648b7e941d20acd72f9652115e0e53facd98156d61f9ebf7a812bdef8bdccea9", size = 249739, upload-time = "2026-05-05T16:29:26.648Z" }, - { url = "https://files.pythonhosted.org/packages/b2/f5/dc5b7eb294656ad23d4ff4cf8514208d54fe1026b909d726a0dc026689c9/librt-0.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c3e33747c068e86a9007c20fdb777eb5ba8d3d19136d7812f88e69a713041b6f", size = 261414, upload-time = "2026-05-05T16:29:28.702Z" }, - { url = "https://files.pythonhosted.org/packages/58/e4/990ed8d12c7f114ac8f8ccd47f7d9bd9704ef61acfcb1df4a05047da7710/librt-0.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d509c745bf7e77d1107cf05e6abb249dc03fad13eb39f2286a49deedaeb2bcd7", size = 256614, upload-time = "2026-05-05T16:29:30.357Z" }, - { url = "https://files.pythonhosted.org/packages/60/eb/52d2726c7fb22818507dc3cc166c8f36dd4a4b68a7be67f12006ac8777c1/librt-0.10.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:786ad5a15e99d0e0e74f3adbeecc198a5ac58f340be07e984723d1e0074838de", size = 255144, upload-time = "2026-05-05T16:29:32.106Z" }, - { url = "https://files.pythonhosted.org/packages/bc/df/bd5591a78f7531fce4b6eb9962aadc6adc9560a01570442a884b6e554abe/librt-0.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:075582d877a97ee3d8e77bda3689dbe617b14f6469224a2d80b4b6c38e3951aa", size = 279121, upload-time = "2026-05-05T16:29:33.688Z" }, - { url = "https://files.pythonhosted.org/packages/fd/df/7c2b838dfc89a1762dd156d8b0c39848a7a2845d725a50be5a6e021fb8ba/librt-0.10.0-cp311-cp311-win32.whl", hash = "sha256:75ecdc3f5a90065aa2af2e574706c5495adc392520762dcf10b1aa716f0b8090", size = 62593, upload-time = "2026-05-05T16:29:35.152Z" }, - { url = "https://files.pythonhosted.org/packages/91/19/22ff572981049a9d436a083dbea1572d0f5dc068b7353637d2dd9977c8f1/librt-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:b6f6084884131d8a52cb9d7095ff2aa52c1e786d9fdaefab1fb4515415e9e083", size = 70914, upload-time = "2026-05-05T16:29:36.407Z" }, - { url = "https://files.pythonhosted.org/packages/12/22/1697cc64f4a5c7e9bce55e99c6d234a346beaedaefcd1e2ca90dd285f98c/librt-0.10.0-cp311-cp311-win_arm64.whl", hash = "sha256:0140bd62151160047e89b2730cb6f8506cdac5127baa1afb9231e4dd3fe7f681", size = 61176, upload-time = "2026-05-05T16:29:37.62Z" }, { url = "https://files.pythonhosted.org/packages/12/8e/cbb5b6f6e45e65c10a42449a69eaccc44d73e6a081ea752fbc5221c6dc1c/librt-0.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b4b58a44b407e91f633dafee008de9ddea6aa2a555ed94929c099260910bd0ba", size = 77327, upload-time = "2026-05-05T16:29:38.919Z" }, { url = "https://files.pythonhosted.org/packages/e9/3d/8233cbee8e99e6a8992f02bfc2dec8d787509566a511d1fde2574ee7473f/librt-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:950b79b11762531bdf45a9df909d2f9a2a8445c70c88665c01d14c8511a27dc5", size = 79971, upload-time = "2026-05-05T16:29:40.96Z" }, { url = "https://files.pythonhosted.org/packages/87/6f/5264b298cef2b72fc97d2dde56c66181eda35204bf5dcd1ed0c3d0a0a782/librt-0.10.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4538453f51be197633b425912c150e25b0667252d3741c53e8368176d98d9d37", size = 246559, upload-time = "2026-05-05T16:29:42.701Z" }, @@ -2091,38 +1812,6 @@ version = "6.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/28/30/9abc9e34c657c33834eaf6cd02124c61bdf5944d802aa48e69be8da3585d/lxml-6.1.0.tar.gz", hash = "sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13", size = 4197006, upload-time = "2026-04-18T04:32:51.613Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/6e/ee8fc0e01202eb3dd2b9e1ea4f0910d72425d35c66187c63931d7a3ea73f/lxml-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec", size = 8540733, upload-time = "2026-04-18T04:27:33.185Z" }, - { url = "https://files.pythonhosted.org/packages/54/e8/325fe9b942824c773dffe1baf0c35b046a763851fdff4393af4450bceeb7/lxml-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec", size = 4602805, upload-time = "2026-04-18T04:27:36.097Z" }, - { url = "https://files.pythonhosted.org/packages/2d/81/221aa3ea4a40370bb0358fa454cbe7e5a837e522f7630c24dfef3f9a73b0/lxml-6.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551", size = 5002652, upload-time = "2026-04-18T04:27:30.603Z" }, - { url = "https://files.pythonhosted.org/packages/c6/e1/fdbfb9019542f1875c093576df7f37adc2983c8ba7ecf17e5f14490bc107/lxml-6.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd", size = 5155332, upload-time = "2026-04-18T04:27:33.507Z" }, - { url = "https://files.pythonhosted.org/packages/56/b1/4087c782fff397cd03abf9c551069be59bb04a7e548c50fb7b9c4cdaca28/lxml-6.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215", size = 5057226, upload-time = "2026-04-18T04:27:37.567Z" }, - { url = "https://files.pythonhosted.org/packages/5d/66/516c79dec8417f3a972327330254c0b5fac93d5c3ecfd8a5b43650a5a4d9/lxml-6.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4", size = 5287588, upload-time = "2026-04-18T04:27:41.4Z" }, - { url = "https://files.pythonhosted.org/packages/94/1d/e578f4cbeb42b9df9f29b0d44a45a7cdfa3a5ae300dd59ec68e3602d29bb/lxml-6.1.0-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea", size = 5412438, upload-time = "2026-04-18T04:27:45.589Z" }, - { url = "https://files.pythonhosted.org/packages/47/5b/2aa68307d6d15959e84d4882f9c04f2da63127eac463e1594166f681ef77/lxml-6.1.0-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6", size = 4770997, upload-time = "2026-04-18T04:27:49.853Z" }, - { url = "https://files.pythonhosted.org/packages/ae/c9/3e51fc1228310a836b4eb32595ae00154ab12197fca944676a3ab3b163ea/lxml-6.1.0-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3", size = 5359678, upload-time = "2026-04-18T04:31:56.184Z" }, - { url = "https://files.pythonhosted.org/packages/b5/91/ab8bc834f977fbbd310e697b120787c153db026f9151e02a88d2645d4e5b/lxml-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7", size = 5107890, upload-time = "2026-04-18T04:32:00.387Z" }, - { url = "https://files.pythonhosted.org/packages/bb/10/8a143cfa3ac99cb5b0523ff6d0429a9c9dddf25ffeae09caa3866c7964d9/lxml-6.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16", size = 4803977, upload-time = "2026-04-18T04:32:05.099Z" }, - { url = "https://files.pythonhosted.org/packages/45/fd/ee02faf52fa39c2fe32f824628958b9aa86dff21343dc3161f0e3c6ccd15/lxml-6.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1", size = 5350277, upload-time = "2026-04-18T04:32:09.176Z" }, - { url = "https://files.pythonhosted.org/packages/85/8c/b3481364b8554b5d36d540189a87fc71e94b0b01c24f8f152bd662dd2e45/lxml-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a", size = 5309717, upload-time = "2026-04-18T04:32:13.303Z" }, - { url = "https://files.pythonhosted.org/packages/74/e8/a6b21927077a9127afa17473b6576b322616f34ac50ee4f577e763b75ec0/lxml-6.1.0-cp310-cp310-win32.whl", hash = "sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544", size = 3598491, upload-time = "2026-04-18T04:27:24.288Z" }, - { url = "https://files.pythonhosted.org/packages/ea/82/14dea800d041274d96c07d49ff9191f011d1427450850de19bf541e2cc12/lxml-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a", size = 4020906, upload-time = "2026-04-18T04:27:27.53Z" }, - { url = "https://files.pythonhosted.org/packages/f2/ba/d3539aaf4d9d21456b9a7b902816623227d05d63e7c5aafd8834c4b9bed6/lxml-6.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776", size = 3667787, upload-time = "2026-04-18T04:27:29.407Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5d/3bccad330292946f97962df9d5f2d3ae129cce6e212732a781e856b91e07/lxml-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9", size = 8526232, upload-time = "2026-04-18T04:27:40.389Z" }, - { url = "https://files.pythonhosted.org/packages/a7/51/adc8826570a112f83bb4ddb3a2ab510bbc2ccd62c1b9fe1f34fae2d90b57/lxml-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50", size = 4595448, upload-time = "2026-04-18T04:27:44.208Z" }, - { url = "https://files.pythonhosted.org/packages/54/84/5a9ec07cbe1d2334a6465f863b949a520d2699a755738986dcd3b6b89e3f/lxml-6.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5", size = 4923771, upload-time = "2026-04-18T04:32:17.402Z" }, - { url = "https://files.pythonhosted.org/packages/a7/23/851cfa33b6b38adb628e45ad51fb27105fa34b2b3ba9d1d4aa7a9428dfe0/lxml-6.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e", size = 5068101, upload-time = "2026-04-18T04:32:21.437Z" }, - { url = "https://files.pythonhosted.org/packages/b0/38/41bf99c2023c6b79916ba057d83e9db21d642f473cac210201222882d38b/lxml-6.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512", size = 5002573, upload-time = "2026-04-18T04:32:25.373Z" }, - { url = "https://files.pythonhosted.org/packages/c2/20/053aa10bdc39747e1e923ce2d45413075e84f70a136045bb09e5eaca41d3/lxml-6.1.0-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c", size = 5202816, upload-time = "2026-04-18T04:32:29.393Z" }, - { url = "https://files.pythonhosted.org/packages/9a/da/bc710fad8bf04b93baee752c192eaa2210cd3a84f969d0be7830fea55802/lxml-6.1.0-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5", size = 5329999, upload-time = "2026-04-18T04:32:34.019Z" }, - { url = "https://files.pythonhosted.org/packages/b3/cb/bf035dedbdf7fab49411aa52e4236f3445e98d38647d85419e6c0d2806b9/lxml-6.1.0-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289", size = 4659643, upload-time = "2026-04-18T04:32:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4f/22be31f33727a5e4c7b01b0a874503026e50329b259d3587e0b923cf964b/lxml-6.1.0-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a", size = 5265963, upload-time = "2026-04-18T04:32:41.881Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2b/d44d0e5c79226017f4ab8c87a802ebe4f89f97e6585a8e4166dffcdd7b6e/lxml-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3", size = 5045444, upload-time = "2026-04-18T04:32:44.512Z" }, - { url = "https://files.pythonhosted.org/packages/d3/c3/3f034fec1594c331a6dbf9491238fdcc9d66f68cc529e109ec75b97197e1/lxml-6.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9", size = 4712703, upload-time = "2026-04-18T04:32:47.16Z" }, - { url = "https://files.pythonhosted.org/packages/12/16/0b83fccc158218aca75a7aa33e97441df737950734246b9fffa39301603d/lxml-6.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11", size = 5252745, upload-time = "2026-04-18T04:32:50.427Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ee/12e6c1b39a77666c02eaa77f94a870aaf63c4ac3a497b2d52319448b01c6/lxml-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4", size = 5226822, upload-time = "2026-04-18T04:32:53.437Z" }, - { url = "https://files.pythonhosted.org/packages/34/20/c7852904858b4723af01d2fc14b5d38ff57cb92f01934a127ebd9a9e51aa/lxml-6.1.0-cp311-cp311-win32.whl", hash = "sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3", size = 3594026, upload-time = "2026-04-18T04:27:31.903Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/d60c732b56da5085175c07c74b2df4e6d181b0c9a61e1691474f06ef4b39/lxml-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7", size = 4025114, upload-time = "2026-04-18T04:27:34.077Z" }, - { url = "https://files.pythonhosted.org/packages/c2/df/c84dcc175fd690823436d15b41cb920cd5ba5e14cd8bfb00949d5903b320/lxml-6.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39", size = 3667742, upload-time = "2026-04-18T04:27:38.45Z" }, { url = "https://files.pythonhosted.org/packages/d2/d4/9326838b59dc36dfae42eec9656b97520f9997eee1de47b8316aaeed169c/lxml-6.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d", size = 8570663, upload-time = "2026-04-18T04:27:48.253Z" }, { url = "https://files.pythonhosted.org/packages/d8/a4/053745ce1f8303ccbb788b86c0db3a91b973675cefc42566a188637b7c40/lxml-6.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93", size = 4624024, upload-time = "2026-04-18T04:27:52.594Z" }, { url = "https://files.pythonhosted.org/packages/90/97/a517944b20f8fd0932ad2109482bee4e29fe721416387a363306667941f6/lxml-6.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d", size = 4930895, upload-time = "2026-04-18T04:32:56.29Z" }, @@ -2195,12 +1884,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c2/ca/77123e4d77df3cb1e968ade7b1f808f5d3a5c1c96b18a33895397de292c1/lxml-6.1.0-cp314-cp314t-win32.whl", hash = "sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2", size = 3897377, upload-time = "2026-04-18T04:32:07.656Z" }, { url = "https://files.pythonhosted.org/packages/64/ce/3554833989d074267c063209bae8b09815e5656456a2d332b947806b05ff/lxml-6.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5", size = 4392701, upload-time = "2026-04-18T04:32:12.113Z" }, { url = "https://files.pythonhosted.org/packages/2b/a0/9b916c68c0e57752c07f8f64b30138d9d4059dbeb27b90274dedbea128ff/lxml-6.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac", size = 3817120, upload-time = "2026-04-18T04:32:15.803Z" }, - { url = "https://files.pythonhosted.org/packages/f2/88/55143966481409b1740a3ac669e611055f49efd68087a5ce41582325db3e/lxml-6.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842", size = 3930134, upload-time = "2026-04-18T04:32:35.008Z" }, - { url = "https://files.pythonhosted.org/packages/b5/97/28b985c2983938d3cb696dd5501423afb90a8c3e869ef5d3c62569282c0f/lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c", size = 4210749, upload-time = "2026-04-18T04:36:03.626Z" }, - { url = "https://files.pythonhosted.org/packages/29/67/dfab2b7d58214921935ccea7ce9b3df9b7d46f305d12f0f532ac7cf6b804/lxml-6.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de", size = 4318463, upload-time = "2026-04-18T04:36:06.309Z" }, - { url = "https://files.pythonhosted.org/packages/32/a2/4ac7eb32a4d997dd352c32c32399aae27b3f268d440e6f9cfa405b575d2f/lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635", size = 4251124, upload-time = "2026-04-18T04:36:09.056Z" }, - { url = "https://files.pythonhosted.org/packages/33/ef/d6abd850bb4822f9b720cfe36b547a558e694881010ff7d012191e8769c6/lxml-6.1.0-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037", size = 4401758, upload-time = "2026-04-18T04:36:11.803Z" }, - { url = "https://files.pythonhosted.org/packages/40/44/3ee09a5b60cb44c4f2fbc1c9015cfd6ff5afc08f991cab295d3024dcbf2d/lxml-6.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace", size = 3508860, upload-time = "2026-04-18T04:32:48.619Z" }, ] [[package]] @@ -2214,14 +1897,14 @@ wheels = [ [[package]] name = "markdown-it-py" -version = "4.0.0" +version = "4.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5c/f3aedc83549aae71cd52b9e9687fe896e3dc6e966ba20eba04718605d198/markdown_it_py-4.1.0.tar.gz", hash = "sha256:760e3f87b2787c044c5138a5ba107b7c2be26c03b13cc7f8fe42756b65b1df6c", size = 81613, upload-time = "2026-05-06T16:32:13.649Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/a8/88/802c82060c54bc7dde21eb0033e337838b8181a1323254aa9ec41cbfc3d1/markdown_it_py-4.1.0-py3-none-any.whl", hash = "sha256:d4939a62a2dd0cd9cb80a191a711ba1d39bac8ed5ef9e9966895b0171c01c46d", size = 90955, upload-time = "2026-05-06T16:32:12.184Z" }, ] [[package]] @@ -2239,28 +1922,6 @@ version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, - { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, - { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, - { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, - { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, - { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, - { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, - { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, - { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, @@ -2364,23 +2025,47 @@ wheels = [ [[package]] name = "mistralai" -version = "1.12.4" +version = "2.4.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "eval-type-backport" }, { name = "httpx" }, - { name = "invoke" }, + { name = "jsonpath-python" }, { name = "opentelemetry-api" }, - { name = "opentelemetry-exporter-otlp-proto-http" }, - { name = "opentelemetry-sdk" }, + { name = "opentelemetry-semantic-conventions" }, { name = "pydantic" }, { name = "python-dateutil" }, - { name = "pyyaml" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/12/c3476c53e907255b5f485f085ba50dd9a84b40fe662e9a888d6ded26fa7b/mistralai-1.12.4.tar.gz", hash = "sha256:e52b53bab58025dcd208eeac13e3c3df5778d4112eeca1f08124096c7738929f", size = 243129, upload-time = "2026-02-20T17:55:13.73Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/f0/80dfabf224be4419c6c112f3950676f5af3dcde582d225c03ca0196a4b32/mistralai-2.4.4.tar.gz", hash = "sha256:cd8a27a230e5458b62237a6c4f7b52f5be86909fbc18694360ceb21dac932eda", size = 420936, upload-time = "2026-04-30T12:26:38.775Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/f9/98d825105c450b9c67c27026caa374112b7e466c18331601d02ca278a01b/mistralai-1.12.4-py3-none-any.whl", hash = "sha256:7b69fcbc306436491ad3377fbdead527c9f3a0ce145ec029bf04c6308ff2cca6", size = 509321, upload-time = "2026-02-20T17:55:15.27Z" }, + { url = "https://files.pythonhosted.org/packages/0f/74/0f6188190e79eef4363754c71414c1a791537b1e506cbee615bb581cb05f/mistralai-2.4.4-py3-none-any.whl", hash = "sha256:43dd3b1f0f4f960a723359165c4da0d035590b27c050028322934fe4f189f14e", size = 990545, upload-time = "2026-04-30T12:26:40.702Z" }, +] + +[[package]] +name = "mistralai-workflows" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asynciolimiter" }, + { name = "httpx" }, + { name = "jsonpatch" }, + { name = "mistralai" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-instrumentation-asyncio" }, + { name = "opentelemetry-instrumentation-httpx" }, + { name = "opentelemetry-sdk" }, + { name = "orjson" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "structlog" }, + { name = "temporalio" }, + { name = "tenacity" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/ab/b7952d7f9ec11eb326b6ff3912d9378a7fa0b09767d7ec1c862bcfc95564/mistralai_workflows-3.3.0.tar.gz", hash = "sha256:e462bbed75840d9099728c39bd92f7a562f88e4cc0c97305c369cfa4e5019613", size = 505490, upload-time = "2026-04-23T16:02:14.85Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/8c/17ed0974d2ea5e75dd9690b35178cf0b51b32b3b9156d2d6375da7239b0d/mistralai_workflows-3.3.0-py3-none-any.whl", hash = "sha256:bedd37e16ef5d95eb9551415a5a2bfb5c92d6b2ae8c0e92883d0870da7b49645", size = 390405, upload-time = "2026-04-23T16:02:13.19Z" }, ] [[package]] @@ -2573,23 +2258,6 @@ version = "1.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4d/f2/bfb55a6236ed8725a96b0aa3acbd0ec17588e6a2c3b62a93eb513ed8783f/msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e", size = 173581, upload-time = "2025-10-08T09:15:56.596Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/a2/3b68a9e769db68668b25c6108444a35f9bd163bb848c0650d516761a59c0/msgpack-1.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0051fffef5a37ca2cd16978ae4f0aef92f164df86823871b5162812bebecd8e2", size = 81318, upload-time = "2025-10-08T09:14:38.722Z" }, - { url = "https://files.pythonhosted.org/packages/5b/e1/2b720cc341325c00be44e1ed59e7cfeae2678329fbf5aa68f5bda57fe728/msgpack-1.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a605409040f2da88676e9c9e5853b3449ba8011973616189ea5ee55ddbc5bc87", size = 83786, upload-time = "2025-10-08T09:14:40.082Z" }, - { url = "https://files.pythonhosted.org/packages/71/e5/c2241de64bfceac456b140737812a2ab310b10538a7b34a1d393b748e095/msgpack-1.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b696e83c9f1532b4af884045ba7f3aa741a63b2bc22617293a2c6a7c645f251", size = 398240, upload-time = "2025-10-08T09:14:41.151Z" }, - { url = "https://files.pythonhosted.org/packages/b7/09/2a06956383c0fdebaef5aa9246e2356776f12ea6f2a44bd1368abf0e46c4/msgpack-1.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:365c0bbe981a27d8932da71af63ef86acc59ed5c01ad929e09a0b88c6294e28a", size = 406070, upload-time = "2025-10-08T09:14:42.821Z" }, - { url = "https://files.pythonhosted.org/packages/0e/74/2957703f0e1ef20637d6aead4fbb314330c26f39aa046b348c7edcf6ca6b/msgpack-1.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:41d1a5d875680166d3ac5c38573896453bbbea7092936d2e107214daf43b1d4f", size = 393403, upload-time = "2025-10-08T09:14:44.38Z" }, - { url = "https://files.pythonhosted.org/packages/a5/09/3bfc12aa90f77b37322fc33e7a8a7c29ba7c8edeadfa27664451801b9860/msgpack-1.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354e81bcdebaab427c3df4281187edc765d5d76bfb3a7c125af9da7a27e8458f", size = 398947, upload-time = "2025-10-08T09:14:45.56Z" }, - { url = "https://files.pythonhosted.org/packages/4b/4f/05fcebd3b4977cb3d840f7ef6b77c51f8582086de5e642f3fefee35c86fc/msgpack-1.1.2-cp310-cp310-win32.whl", hash = "sha256:e64c8d2f5e5d5fda7b842f55dec6133260ea8f53c4257d64494c534f306bf7a9", size = 64769, upload-time = "2025-10-08T09:14:47.334Z" }, - { url = "https://files.pythonhosted.org/packages/d0/3e/b4547e3a34210956382eed1c85935fff7e0f9b98be3106b3745d7dec9c5e/msgpack-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:db6192777d943bdaaafb6ba66d44bf65aa0e9c5616fa1d2da9bb08828c6b39aa", size = 71293, upload-time = "2025-10-08T09:14:48.665Z" }, - { url = "https://files.pythonhosted.org/packages/2c/97/560d11202bcd537abca693fd85d81cebe2107ba17301de42b01ac1677b69/msgpack-1.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e86a607e558d22985d856948c12a3fa7b42efad264dca8a3ebbcfa2735d786c", size = 82271, upload-time = "2025-10-08T09:14:49.967Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/28a41024ccbd67467380b6fb440ae916c1e4f25e2cd4c63abe6835ac566e/msgpack-1.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:283ae72fc89da59aa004ba147e8fc2f766647b1251500182fac0350d8af299c0", size = 84914, upload-time = "2025-10-08T09:14:50.958Z" }, - { url = "https://files.pythonhosted.org/packages/71/46/b817349db6886d79e57a966346cf0902a426375aadc1e8e7a86a75e22f19/msgpack-1.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61c8aa3bd513d87c72ed0b37b53dd5c5a0f58f2ff9f26e1555d3bd7948fb7296", size = 416962, upload-time = "2025-10-08T09:14:51.997Z" }, - { url = "https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:454e29e186285d2ebe65be34629fa0e8605202c60fbc7c4c650ccd41870896ef", size = 426183, upload-time = "2025-10-08T09:14:53.477Z" }, - { url = "https://files.pythonhosted.org/packages/25/98/6a19f030b3d2ea906696cedd1eb251708e50a5891d0978b012cb6107234c/msgpack-1.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7bc8813f88417599564fafa59fd6f95be417179f76b40325b500b3c98409757c", size = 411454, upload-time = "2025-10-08T09:14:54.648Z" }, - { url = "https://files.pythonhosted.org/packages/b7/cd/9098fcb6adb32187a70b7ecaabf6339da50553351558f37600e53a4a2a23/msgpack-1.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bafca952dc13907bdfdedfc6a5f579bf4f292bdd506fadb38389afa3ac5b208e", size = 422341, upload-time = "2025-10-08T09:14:56.328Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ae/270cecbcf36c1dc85ec086b33a51a4d7d08fc4f404bdbc15b582255d05ff/msgpack-1.1.2-cp311-cp311-win32.whl", hash = "sha256:602b6740e95ffc55bfb078172d279de3773d7b7db1f703b2f1323566b878b90e", size = 64747, upload-time = "2025-10-08T09:14:57.882Z" }, - { url = "https://files.pythonhosted.org/packages/2a/79/309d0e637f6f37e83c711f547308b91af02b72d2326ddd860b966080ef29/msgpack-1.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:d198d275222dc54244bf3327eb8cbe00307d220241d9cec4d306d49a44e85f68", size = 71633, upload-time = "2025-10-08T09:14:59.177Z" }, - { url = "https://files.pythonhosted.org/packages/73/4d/7c4e2b3d9b1106cd0aa6cb56cc57c6267f59fa8bfab7d91df5adc802c847/msgpack-1.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:86f8136dfa5c116365a8a651a7d7484b65b13339731dd6faebb9a0242151c406", size = 64755, upload-time = "2025-10-08T09:15:00.48Z" }, { url = "https://files.pythonhosted.org/packages/ad/bd/8b0d01c756203fbab65d265859749860682ccd2a59594609aeec3a144efa/msgpack-1.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70a0dff9d1f8da25179ffcf880e10cf1aad55fdb63cd59c9a49a1b82290062aa", size = 81939, upload-time = "2025-10-08T09:15:01.472Z" }, { url = "https://files.pythonhosted.org/packages/34/68/ba4f155f793a74c1483d4bdef136e1023f7bcba557f0db4ef3db3c665cf1/msgpack-1.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:446abdd8b94b55c800ac34b102dffd2f6aa0ce643c55dfc017ad89347db3dbdb", size = 85064, upload-time = "2025-10-08T09:15:03.764Z" }, { url = "https://files.pythonhosted.org/packages/f2/60/a064b0345fc36c4c3d2c743c82d9100c40388d77f0b48b2f04d6041dbec1/msgpack-1.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63eea553c69ab05b6747901b97d620bb2a690633c77f23feb0c6a947a8a7b8f", size = 417131, upload-time = "2025-10-08T09:15:05.136Z" }, @@ -2633,11 +2301,9 @@ name = "mthds" version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backports-strenum", marker = "python_full_version < '3.11'" }, { name = "httpx" }, { name = "pydantic" }, { name = "semantic-version" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomlkit" }, { name = "typing-extensions" }, ] @@ -2650,47 +2316,8 @@ wheels = [ name = "multidict" version = "6.7.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" }, - { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" }, - { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" }, - { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" }, - { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" }, - { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" }, - { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" }, - { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" }, - { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" }, - { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" }, - { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" }, - { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" }, - { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" }, - { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" }, - { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, - { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, - { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, - { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, - { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, - { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, - { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, - { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, - { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, - { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, - { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, - { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, - { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, - { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, @@ -2793,12 +2420,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/a2/f2/e783ac7f2aeeed14e9e12801f22529cc7e6b7ab80928d6dcce4e9f00922d/multiprocess-0.70.19.tar.gz", hash = "sha256:952021e0e6c55a4a9fe4cd787895b86e239a40e76802a789d6305398d3975897", size = 2079989, upload-time = "2026-01-19T06:47:39.744Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/b6/10832f96b499690854e574360be342a282f5f7dba58eff791299ff6c0637/multiprocess-0.70.19-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:02e5c35d7d6cd2bdc89c1858867f7bde4012837411023a4696c148c1bdd7c80e", size = 135131, upload-time = "2026-01-19T06:47:20.479Z" }, - { url = "https://files.pythonhosted.org/packages/99/50/faef2d8106534b0dc4a0b772668a1a99682696ebf17d3c0f13f2ed6a656a/multiprocess-0.70.19-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:79576c02d1207ec405b00cabf2c643c36070800cca433860e14539df7818b2aa", size = 135131, upload-time = "2026-01-19T06:47:21.879Z" }, - { url = "https://files.pythonhosted.org/packages/94/b1/0b71d18b76bf423c2e8ee00b31db37d17297ab3b4db44e188692afdca628/multiprocess-0.70.19-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c6b6d78d43a03b68014ca1f0b7937d965393a670c5de7c29026beb2258f2f896", size = 135134, upload-time = "2026-01-19T06:47:23.262Z" }, - { url = "https://files.pythonhosted.org/packages/7e/aa/714635c727dbfc251139226fa4eaf1b07f00dc12d9cd2eb25f931adaf873/multiprocess-0.70.19-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1bbf1b69af1cf64cd05f65337d9215b88079ec819cd0ea7bac4dab84e162efe7", size = 144743, upload-time = "2026-01-19T06:47:24.562Z" }, - { url = "https://files.pythonhosted.org/packages/0f/e1/155f6abf5e6b5d9cef29b6d0167c180846157a4aca9b9bee1a217f67c959/multiprocess-0.70.19-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:5be9ec7f0c1c49a4f4a6fd20d5dda4aeabc2d39a50f4ad53720f1cd02b3a7c2e", size = 144738, upload-time = "2026-01-19T06:47:26.636Z" }, - { url = "https://files.pythonhosted.org/packages/af/cb/f421c2869d75750a4f32301cc20c4b63fab6376e9a75c8e5e655bdeb3d9b/multiprocess-0.70.19-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1c3dce098845a0db43b32a0b76a228ca059a668071cfeaa0f40c36c0b1585d45", size = 144741, upload-time = "2026-01-19T06:47:27.985Z" }, { url = "https://files.pythonhosted.org/packages/e3/45/8004d1e6b9185c1a444d6b55ac5682acf9d98035e54386d967366035a03a/multiprocess-0.70.19-py310-none-any.whl", hash = "sha256:97404393419dcb2a8385910864eedf47a3cadf82c66345b44f036420eb0b5d87", size = 134948, upload-time = "2026-01-19T06:47:32.325Z" }, { url = "https://files.pythonhosted.org/packages/86/c2/dec9722dc3474c164a0b6bcd9a7ed7da542c98af8cabce05374abab35edd/multiprocess-0.70.19-py311-none-any.whl", hash = "sha256:928851ae7973aea4ce0eaf330bbdafb2e01398a91518d5c8818802845564f45c", size = 144457, upload-time = "2026-01-19T06:47:33.711Z" }, { url = "https://files.pythonhosted.org/packages/71/70/38998b950a97ea279e6bd657575d22d1a2047256caf707d9a10fbce4f065/multiprocess-0.70.19-py312-none-any.whl", hash = "sha256:3a56c0e85dd5025161bac5ce138dcac1e49174c7d8e74596537e729fd5c53c28", size = 150281, upload-time = "2026-01-19T06:47:35.037Z" }, @@ -2815,23 +2436,10 @@ dependencies = [ { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" }, - { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" }, - { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" }, - { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" }, - { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" }, - { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" }, - { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" }, - { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" }, - { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" }, - { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" }, - { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" }, { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, @@ -2862,36 +2470,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] -[[package]] -name = "networkx" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, -] - [[package]] name = "networkx" version = "3.6.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, @@ -2899,14 +2481,14 @@ wheels = [ [[package]] name = "nexus-rpc" -version = "1.3.0" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/f2/d54f5c03d8f4672ccc0875787a385f53dcb61f98a8ae594b5620e85b9cb3/nexus_rpc-1.3.0.tar.gz", hash = "sha256:e56d3b57b60d707ce7a72f83f23f106b86eca1043aa658e44582ab5ff30ab9ad", size = 75650, upload-time = "2025-12-08T22:59:13.002Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/d5/cd1ffb202b76ebc1b33c1332a3416e55a39929006982adc2b1eb069aaa9b/nexus_rpc-1.4.0.tar.gz", hash = "sha256:3b8b373d4865671789cc43623e3dc0bcbf192562e40e13727e17f1c149050fba", size = 82367, upload-time = "2026-02-25T22:01:34.053Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/74/0afd841de3199c148146c1d43b4bfb5605b2f1dc4c9a9087fe395091ea5a/nexus_rpc-1.3.0-py3-none-any.whl", hash = "sha256:aee0707b4861b22d8124ecb3f27d62dafbe8777dc50c66c91e49c006f971b92d", size = 28873, upload-time = "2025-12-08T22:59:12.024Z" }, + { url = "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl", hash = "sha256:14c953d3519113f8ccec533a9efdb6b10c28afef75d11cdd6d422640c40b3a49", size = 29645, upload-time = "2026-02-25T22:01:33.122Z" }, ] [[package]] @@ -2918,102 +2500,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] -[[package]] -name = "numpy" -version = "2.2.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, - { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, - { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, - { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, - { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, - { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, - { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, - { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, -] - [[package]] name = "numpy" version = "2.4.4" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/c6/4218570d8c8ecc9704b5157a3348e486e84ef4be0ed3e38218ab473c83d2/numpy-2.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f983334aea213c99992053ede6168500e5f086ce74fbc4acc3f2b00f5762e9db", size = 16976799, upload-time = "2026-03-29T13:18:15.438Z" }, - { url = "https://files.pythonhosted.org/packages/dd/92/b4d922c4a5f5dab9ed44e6153908a5c665b71acf183a83b93b690996e39b/numpy-2.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72944b19f2324114e9dc86a159787333b77874143efcf89a5167ef83cfee8af0", size = 14971552, upload-time = "2026-03-29T13:18:18.606Z" }, - { url = "https://files.pythonhosted.org/packages/8a/dc/df98c095978fa6ee7b9a9387d1d58cbb3d232d0e69ad169a4ce784bde4fd/numpy-2.4.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:86b6f55f5a352b48d7fbfd2dbc3d5b780b2d79f4d3c121f33eb6efb22e9a2015", size = 5476566, upload-time = "2026-03-29T13:18:21.532Z" }, - { url = "https://files.pythonhosted.org/packages/28/34/b3fdcec6e725409223dd27356bdf5a3c2cc2282e428218ecc9cb7acc9763/numpy-2.4.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:ba1f4fc670ed79f876f70082eff4f9583c15fb9a4b89d6188412de4d18ae2f40", size = 6806482, upload-time = "2026-03-29T13:18:23.634Z" }, - { url = "https://files.pythonhosted.org/packages/68/62/63417c13aa35d57bee1337c67446761dc25ea6543130cf868eace6e8157b/numpy-2.4.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a87ec22c87be071b6bdbd27920b129b94f2fc964358ce38f3822635a3e2e03d", size = 15973376, upload-time = "2026-03-29T13:18:26.677Z" }, - { url = "https://files.pythonhosted.org/packages/cf/c5/9fcb7e0e69cef59cf10c746b84f7d58b08bc66a6b7d459783c5a4f6101a6/numpy-2.4.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df3775294accfdd75f32c74ae39fcba920c9a378a2fc18a12b6820aa8c1fb502", size = 16925137, upload-time = "2026-03-29T13:18:30.14Z" }, - { url = "https://files.pythonhosted.org/packages/7e/43/80020edacb3f84b9efdd1591120a4296462c23fd8db0dde1666f6ef66f13/numpy-2.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d4e437e295f18ec29bc79daf55e8a47a9113df44d66f702f02a293d93a2d6dd", size = 17329414, upload-time = "2026-03-29T13:18:33.733Z" }, - { url = "https://files.pythonhosted.org/packages/fd/06/af0658593b18a5f73532d377188b964f239eb0894e664a6c12f484472f97/numpy-2.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6aa3236c78803afbcb255045fbef97a9e25a1f6c9888357d205ddc42f4d6eba5", size = 18658397, upload-time = "2026-03-29T13:18:37.511Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ce/13a09ed65f5d0ce5c7dd0669250374c6e379910f97af2c08c57b0608eee4/numpy-2.4.4-cp311-cp311-win32.whl", hash = "sha256:30caa73029a225b2d40d9fae193e008e24b2026b7ee1a867b7ee8d96ca1a448e", size = 6239499, upload-time = "2026-03-29T13:18:40.372Z" }, - { url = "https://files.pythonhosted.org/packages/bd/63/05d193dbb4b5eec1eca73822d80da98b511f8328ad4ae3ca4caf0f4db91d/numpy-2.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:6bbe4eb67390b0a0265a2c25458f6b90a409d5d069f1041e6aff1e27e3d9a79e", size = 12614257, upload-time = "2026-03-29T13:18:42.95Z" }, - { url = "https://files.pythonhosted.org/packages/87/c5/8168052f080c26fa984c413305012be54741c9d0d74abd7fbeeccae3889f/numpy-2.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:fcfe2045fd2e8f3cb0ce9d4ba6dba6333b8fa05bb8a4939c908cd43322d14c7e", size = 10486775, upload-time = "2026-03-29T13:18:45.835Z" }, { url = "https://files.pythonhosted.org/packages/28/05/32396bec30fb2263770ee910142f49c1476d08e8ad41abf8403806b520ce/numpy-2.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b", size = 16689272, upload-time = "2026-03-29T13:18:49.223Z" }, { url = "https://files.pythonhosted.org/packages/c5/f3/a983d28637bfcd763a9c7aafdb6d5c0ebf3d487d1e1459ffdb57e2f01117/numpy-2.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e", size = 14699573, upload-time = "2026-03-29T13:18:52.629Z" }, { url = "https://files.pythonhosted.org/packages/9b/fd/e5ecca1e78c05106d98028114f5c00d3eddb41207686b2b7de3e477b0e22/numpy-2.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842", size = 5204782, upload-time = "2026-03-29T13:18:55.579Z" }, @@ -3067,13 +2559,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" }, { url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" }, { url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" }, - { url = "https://files.pythonhosted.org/packages/6b/33/8fae8f964a4f63ed528264ddf25d2b683d0b663e3cba26961eb838a7c1bd/numpy-2.4.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:58c8b5929fcb8287cbd6f0a3fae19c6e03a5c48402ae792962ac465224a629a4", size = 16854491, upload-time = "2026-03-29T13:21:38.03Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d0/1aabee441380b981cf8cdda3ae7a46aa827d1b5a8cce84d14598bc94d6d9/numpy-2.4.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:eea7ac5d2dce4189771cedb559c738a71512768210dc4e4753b107a2048b3d0e", size = 14895830, upload-time = "2026-03-29T13:21:41.509Z" }, - { url = "https://files.pythonhosted.org/packages/a5/b8/aafb0d1065416894fccf4df6b49ef22b8db045187949545bced89c034b8e/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:51fc224f7ca4d92656d5a5eb315f12eb5fe2c97a66249aa7b5f562528a3be38c", size = 5400927, upload-time = "2026-03-29T13:21:44.747Z" }, - { url = "https://files.pythonhosted.org/packages/d6/77/063baa20b08b431038c7f9ff5435540c7b7265c78cf56012a483019ca72d/numpy-2.4.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:28a650663f7314afc3e6ec620f44f333c386aad9f6fc472030865dc0ebb26ee3", size = 6715557, upload-time = "2026-03-29T13:21:47.406Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a8/379542d45a14f149444c5c4c4e7714707239ce9cc1de8c2803958889da14/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19710a9ca9992d7174e9c52f643d4272dcd1558c5f7af7f6f8190f633bd651a7", size = 15804253, upload-time = "2026-03-29T13:21:50.753Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c8/f0a45426d6d21e7ea3310a15cf90c43a14d9232c31a837702dba437f3373/numpy-2.4.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b2aec6af35c113b05695ebb5749a787acd63cafc83086a05771d1e1cd1e555f", size = 16753552, upload-time = "2026-03-29T13:21:54.344Z" }, - { url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" }, ] [[package]] @@ -3117,7 +2602,7 @@ name = "nvidia-cudnn-cu13" version = "9.19.0.56" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, + { name = "nvidia-cublas", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/f1/84/26025437c1e6b61a707442184fa0c03d083b661adf3a3eecfd6d21677740/nvidia_cudnn_cu13-9.19.0.56-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:6ed29ffaee1176c612daf442e4dd6cfeb6a0caa43ddcbeb59da94953030b1be4", size = 433781201, upload-time = "2026-02-03T20:40:53.805Z" }, @@ -3129,7 +2614,7 @@ name = "nvidia-cufft" version = "12.0.0.61" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, + { name = "nvidia-nvjitlink", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, @@ -3159,9 +2644,9 @@ name = "nvidia-cusolver" version = "12.0.4.66" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, - { name = "nvidia-cusparse", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, + { name = "nvidia-cublas", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "nvidia-cusparse", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "nvidia-nvjitlink", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, @@ -3173,7 +2658,7 @@ name = "nvidia-cusparse" version = "12.6.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, + { name = "nvidia-nvjitlink", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, @@ -3249,7 +2734,7 @@ wheels = [ [[package]] name = "openai" -version = "2.34.0" +version = "2.35.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -3261,9 +2746,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7b/89/f1e78f5f828f4e97a6ebca8f45c6b35667da12b074ac490dc8362b882279/openai-2.34.0.tar.gz", hash = "sha256:828b4efcbb126352c2b5eb97d33ae890c92a71ab72511aefc1b7fe64aeccb07b", size = 759556, upload-time = "2026-05-04T17:34:08.721Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/4c/35a5216fe5f1cd4d7002b037ba47cff10b71cbd4bddcb601262c664d08de/openai-2.35.0.tar.gz", hash = "sha256:607f62257d6be167240c6b82db052fabf940e3c4d9ad3e8629364e837a601395", size = 751972, upload-time = "2026-05-06T16:36:55.166Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/40/f090499f10514515081d09cb9da09f25b821eb20497e9423afe4f07b4ecf/openai-2.34.0-py3-none-any.whl", hash = "sha256:c996a71b1a210f3569844572ad4c609307e978515fb76877cf449b72596e549e", size = 1316535, upload-time = "2026-05-04T17:34:06.773Z" }, + { url = "https://files.pythonhosted.org/packages/58/b7/c43595f7f441cbc62ac3144a080d71952566b213f7a21bca0564d69e39fd/openai-2.35.0-py3-none-any.whl", hash = "sha256:164fd0477d001e784369f7cd81ccadb8db3c22f16b33973d8f95e3095c7f71d8", size = 1300139, upload-time = "2026-05-06T16:36:53.108Z" }, ] [[package]] @@ -3271,8 +2756,7 @@ name = "opencv-python" version = "4.13.0.92" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/fc/6f/5a28fef4c4a382be06afe3938c64cc168223016fa520c5abaf37e8862aa5/opencv_python-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:caf60c071ec391ba51ed00a4a920f996d0b64e3e46068aac1f646b5de0326a19", size = 46247052, upload-time = "2026-02-05T07:01:25.046Z" }, @@ -3299,32 +2783,32 @@ wheels = [ [[package]] name = "opentelemetry-api" -version = "1.41.1" +version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/fc/b7564cbef36601aef0d6c9bc01f7badb64be8e862c2e1c3c5c3b43b53e4f/opentelemetry_api-1.41.1.tar.gz", hash = "sha256:0ad1814d73b875f84494387dae86ce0b12c68556331ce6ce8fe789197c949621", size = 71416, upload-time = "2026-04-24T13:15:38.262Z" } +sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/59/3e7118ed140f76b0982ba4321bdaed1997a0473f9720de2d10788a577033/opentelemetry_api-1.41.1-py3-none-any.whl", hash = "sha256:a22df900e75c76dc08440710e51f52f1aa6b451b429298896023e60db5b3139f", size = 69007, upload-time = "2026-04-24T13:15:15.662Z" }, + { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-common" -version = "1.41.1" +version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/fa/f9e3bd3c4d692b3ce9a2880a167d1f79681a1bea11f00d5bf76adc03e6ea/opentelemetry_exporter_otlp_proto_common-1.41.1.tar.gz", hash = "sha256:0e253156ea9c36b0bd3d2440c5c9ba7dd1f3fb64ba7a08fc85fbac536b56e1fb", size = 20409, upload-time = "2026-04-24T13:15:40.924Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/9d/22d241b66f7bbde88a3bfa6847a351d2c46b84de23e71222c6aae25c7050/opentelemetry_exporter_otlp_proto_common-1.39.1.tar.gz", hash = "sha256:763370d4737a59741c89a67b50f9e39271639ee4afc999dadfe768541c027464", size = 20409, upload-time = "2025-12-11T13:32:40.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/48/bce76d3ea772b609757e9bc844e02ab408a6446609bf74fb562062ba6b71/opentelemetry_exporter_otlp_proto_common-1.41.1-py3-none-any.whl", hash = "sha256:10da74dad6a49344b9b7b21b6182e3060373a235fde1528616d5f01f92e66aa9", size = 18366, upload-time = "2026-04-24T13:15:18.917Z" }, + { url = "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl", hash = "sha256:08f8a5862d64cc3435105686d0216c1365dc5701f86844a8cd56597d0c764fde", size = 18366, upload-time = "2025-12-11T13:32:20.2Z" }, ] [[package]] name = "opentelemetry-exporter-otlp-proto-http" -version = "1.41.1" +version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, @@ -3335,48 +2819,156 @@ dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/5b/9d3c7f70cca10136ba82a81e738dee626c8e7fc61c6887ea9a58bf34c606/opentelemetry_exporter_otlp_proto_http-1.41.1.tar.gz", hash = "sha256:4747a9604c8550ab38c6fd6180e2fcb80de3267060bef2c306bad3cb443302bc", size = 24139, upload-time = "2026-04-24T13:15:42.977Z" } +sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288, upload-time = "2025-12-11T13:32:42.029Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641, upload-time = "2025-12-11T13:32:22.248Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706, upload-time = "2025-12-11T13:36:42.515Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096, upload-time = "2025-12-11T13:35:33.067Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation-asyncio" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/7f/a108a095fa56c715559a9e441f7fb7b0741cbfb4e363acfb69a7f12648b4/opentelemetry_instrumentation_asyncio-0.60b1.tar.gz", hash = "sha256:0ddb8ada367c7102662c42433740779a055eace08d65079c86ef65e75d1a66b3", size = 14050, upload-time = "2025-12-11T13:36:48.233Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/50/6be23a04742c69e53bfc417134ee0955d0572ce1540242023de73aa74e18/opentelemetry_instrumentation_asyncio-0.60b1-py3-none-any.whl", hash = "sha256:9f326c6947a23dccc02a07ab432b0c62b62bf7312a7608c38771014217199316", size = 14747, upload-time = "2025-12-11T13:35:42.567Z" }, +] + +[[package]] +name = "opentelemetry-instrumentation-httpx" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-http" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/08/11208bcfcab4fc2023252c3f322aa397fd9ad948355fea60f5fc98648603/opentelemetry_instrumentation_httpx-0.60b1.tar.gz", hash = "sha256:a506ebaf28c60112cbe70ad4f0338f8603f148938cb7b6794ce1051cd2b270ae", size = 20611, upload-time = "2025-12-11T13:37:01.661Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/4d/ef07ff2fc630849f2080ae0ae73a61f67257905b7ac79066640bfa0c5739/opentelemetry_exporter_otlp_proto_http-1.41.1-py3-none-any.whl", hash = "sha256:1a21e8f49c7a946d935551e90947d6c3eb39236723c6624401da0f33d68edcb4", size = 22673, upload-time = "2026-04-24T13:15:21.313Z" }, + { url = "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl", hash = "sha256:f37636dd742ad2af83d896ba69601ed28da51fa4e25d1ab62fde89ce413e275b", size = 15701, upload-time = "2025-12-11T13:36:04.56Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.41.1" +version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/e8/633c6d8a9c8840338b105907e55c32d3da1983abab5e52f899f72a82c3d1/opentelemetry_proto-1.41.1.tar.gz", hash = "sha256:4b9d2eb631237ea43b80e16c073af438554e32bc7e9e3f8ca4a9582f900020e5", size = 45670, upload-time = "2026-04-24T13:15:49.768Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/1e/5cd77035e3e82070e2265a63a760f715aacd3cb16dddc7efee913f297fcc/opentelemetry_proto-1.41.1-py3-none-any.whl", hash = "sha256:0496713b804d127a4147e32849fbaf5683fac8ee98550e8e7679cd706c289720", size = 72076, upload-time = "2026-04-24T13:15:32.542Z" }, + { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, ] [[package]] name = "opentelemetry-sdk" -version = "1.41.1" +version = "1.39.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/d0/54ee30dab82fb0acda23d144502771ff76ef8728459c83c3e89ef9fb1825/opentelemetry_sdk-1.41.1.tar.gz", hash = "sha256:724b615e1215b5aeacda0abb8a6a8922c9a1853068948bd0bd225a56d0c792e6", size = 230180, upload-time = "2026-04-24T13:15:50.991Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/e7/a1420b698aad018e1cf60fdbaaccbe49021fb415e2a0d81c242f4c518f54/opentelemetry_sdk-1.41.1-py3-none-any.whl", hash = "sha256:edee379c126c1bce952b0c812b48fe8ff35b30df0eecf17e98afa4d598b7d85d", size = 180213, upload-time = "2026-04-24T13:15:33.767Z" }, + { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.62b1" +version = "0.60b1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/de/911ac9e309052aca1b20b2d5549d3db45d1011e1a610e552c6ccdd1b64f8/opentelemetry_semantic_conventions-0.62b1.tar.gz", hash = "sha256:c5cc6e04a7f8c7cdd30be2ed81499fa4e75bfbd52c9cb70d40af1f9cd3619802", size = 145750, upload-time = "2026-04-24T13:15:52.236Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/a6/83dc2ab6fa397ee66fba04fe2e74bdf7be3b3870005359ceb7689103c058/opentelemetry_semantic_conventions-0.62b1-py3-none-any.whl", hash = "sha256:cf506938103d331fbb78eded0d9788095f7fd59016f2bda813c3324e5a74a93c", size = 231620, upload-time = "2026-04-24T13:15:35.454Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, +] + +[[package]] +name = "opentelemetry-util-http" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/fc/c47bb04a1d8a941a4061307e1eddfa331ed4d0ab13d8a9781e6db256940a/opentelemetry_util_http-0.60b1.tar.gz", hash = "sha256:0d97152ca8c8a41ced7172d29d3622a219317f74ae6bb3027cfbdcf22c3cc0d6", size = 11053, upload-time = "2025-12-11T13:37:25.115Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947, upload-time = "2025-12-11T13:36:37.151Z" }, +] + +[[package]] +name = "orjson" +version = "3.11.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", size = 5599163, upload-time = "2026-05-06T15:11:08.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/6d/11867a3ffa3a3608d84a4de51ef4dd0896d6b5cc9132fbe1daf593e677bc/orjson-3.11.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9ef6fe90aadef185c7b128859f40beb24720b4ecea95379fc9000931179c3a49", size = 228515, upload-time = "2026-05-06T15:09:57.265Z" }, + { url = "https://files.pythonhosted.org/packages/24/75/05912954c8b288f34fcf5cd4b9b071cb4f6e77b9961e175e56ebb258089f/orjson-3.11.9-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e5c9b8f28e726e97d97696c826bc7bea5d71cecd63576dba92924a32c1961291", size = 128409, upload-time = "2026-05-06T15:09:59.063Z" }, + { url = "https://files.pythonhosted.org/packages/ab/86/1c3a47df3bc8191ea9ac51603bbb872a95167a364320c269f2557911f406/orjson-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a473dbb4162108b27901492546f83c76fdcea3d0eadff00ae7a07e18dcce09", size = 132106, upload-time = "2026-05-06T15:10:00.798Z" }, + { url = "https://files.pythonhosted.org/packages/d7/cf/b33b5f3e695ae7d63feef9d915c37cc3b8f465493dcd4f8e0b4c697a2366/orjson-3.11.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:011382e2a60fda9d46f1cdee31068cfc52ffe952b587d683ec0463002802a0f4", size = 127864, upload-time = "2026-05-06T15:10:02.15Z" }, + { url = "https://files.pythonhosted.org/packages/31/6a/6cf69385a58208024fcb8c014e2141b8ce838aba6492b589f8acfff97fab/orjson-3.11.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2d3dc759490128c5c1711a53eeaa8ee1d437fd0038ffd2b6008abf46db3f882", size = 135213, upload-time = "2026-05-06T15:10:03.515Z" }, + { url = "https://files.pythonhosted.org/packages/e8/f8/0b1bd3e8f2efcdd376af5c8cfd79eaf13f018080c0089c80ebd724e3c7fb/orjson-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8ea516b3726d190e1b4297e6f4e7a8650347ae053868a18163b4dd3641d1fff", size = 145994, upload-time = "2026-05-06T15:10:05.083Z" }, + { url = "https://files.pythonhosted.org/packages/f3/59/dab79f61044c529d2c81aecdc589b1f833a1c8dec11ba3b1c2498a02ca7e/orjson-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380cdce7ba24989af81d0a7013d0aaec5d0e2a21734c0e2681b1bc4f141957fe", size = 132744, upload-time = "2026-05-06T15:10:06.853Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a4/82b7a2fe5d8a67a59ed831b24d59a3d46ea7d207b66e1602d376541d94a6/orjson-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4fa4f0af7fa18951f7ab3fc2148e223af211bf03f59e1c6034ec3f97f21d61", size = 134014, upload-time = "2026-05-06T15:10:08.213Z" }, + { url = "https://files.pythonhosted.org/packages/50/c7/375e83a76851b73b2e39f3bcf0e5a19e2b89bad13e5bca97d0b293d27f24/orjson-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a8f5f8bc7ce7d59f08d9f99fa510c06496164a24cb5f3d34537dbd9ca30132e2", size = 141509, upload-time = "2026-05-06T15:10:09.595Z" }, + { url = "https://files.pythonhosted.org/packages/7f/7c/49d5d82a3d3097f641f094f552131f1e2723b0b8cb0fa2874ab65ecfffa6/orjson-3.11.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4d7fde5501b944f83b3e665e1b31343ff6e154b15560a16b7130ea1e594a4206", size = 415127, upload-time = "2026-05-06T15:10:11.049Z" }, + { url = "https://files.pythonhosted.org/packages/3a/dc/7446c538590d55f455647e5f3c61fc33f7108714e7afcffa6a2a033f8350/orjson-3.11.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cde1a448023ba7d5bb4c01c5afb48894380b5e4956e0627266526587ef4e535f", size = 148025, upload-time = "2026-05-06T15:10:12.842Z" }, + { url = "https://files.pythonhosted.org/packages/df/e5/4d2d8af06f788329b4f78f8cc3679bb395392fcaa1e4d8d3c33e85308fa4/orjson-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:71e63adb0e1f1ed5d9e168f50a91ceb93ae6420731d222dc7da5c69409aa47aa", size = 136943, upload-time = "2026-05-06T15:10:14.405Z" }, + { url = "https://files.pythonhosted.org/packages/06/69/850264ccf6d80f6b174620d30a87f65c9b1490aba33fe6b62798e618cad3/orjson-3.11.9-cp312-cp312-win32.whl", hash = "sha256:2d057a602cdd19a0ad680417527c45b6961a095081c0f46fe0e03e304aac6470", size = 131606, upload-time = "2026-05-06T15:10:15.791Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d5/973a43fc9c55e20f2051e9830997649f669be0cb3ca52192087c0143f118/orjson-3.11.9-cp312-cp312-win_amd64.whl", hash = "sha256:59e403b1cc5a676da8eaf31f6254801b7341b3e29efa85f92b48d272637e77be", size = 127101, upload-time = "2026-05-06T15:10:17.129Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ae/495470f0e4a18f73fa10b7f6b84b464ec4cc5291c4e0c7c2a6c400bef006/orjson-3.11.9-cp312-cp312-win_arm64.whl", hash = "sha256:9af678d6488357948f1f84c6cd1c1d397c014e1ae2f98ae082a44eb48f602624", size = 126736, upload-time = "2026-05-06T15:10:18.645Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/93fcc25907235c344ae73122f8a4e01d2d393ef062b4af7d2e2487a32c37/orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021", size = 228458, upload-time = "2026-05-06T15:10:20.079Z" }, + { url = "https://files.pythonhosted.org/packages/8f/27/b1e6dadb3c080313c03fdd8067b85e6a0460c7d8d6a1c3984ef77b904e4d/orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c", size = 128368, upload-time = "2026-05-06T15:10:21.549Z" }, + { url = "https://files.pythonhosted.org/packages/21/0f/c9ede0bf052f6b4051e64a7d4fa91b725cccf8321a6a786e86eb03519f00/orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81", size = 132070, upload-time = "2026-05-06T15:10:23.371Z" }, + { url = "https://files.pythonhosted.org/packages/fd/26/d398e28048dc18205bbe812f2c88cb9b40313db2470778e25964796458fe/orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a", size = 127892, upload-time = "2026-05-06T15:10:24.714Z" }, + { url = "https://files.pythonhosted.org/packages/66/60/52b0054c4c700d5aa7fc5b7ca96917400d8f061307778578e67a10e25852/orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10", size = 135217, upload-time = "2026-05-06T15:10:26.084Z" }, + { url = "https://files.pythonhosted.org/packages/d5/97/1e3dc2b2a28b7b2528f403d2fc1d79ec5f39af3bc143ab65d3ec26426385/orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362", size = 145980, upload-time = "2026-05-06T15:10:28.062Z" }, + { url = "https://files.pythonhosted.org/packages/fc/39/31fbfe7850f2de32dee7e7e5c09f26d403ab01e440ac96001c6b01ad3c99/orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97", size = 132738, upload-time = "2026-05-06T15:10:29.727Z" }, + { url = "https://files.pythonhosted.org/packages/a1/08/dca0082dd2a194acb93e5457e73455388e2e2ca464a2672449a9ddbb679d/orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218", size = 134033, upload-time = "2026-05-06T15:10:31.152Z" }, + { url = "https://files.pythonhosted.org/packages/11/d4/5bdb0626801230139987385554c5d4c42255218ac906525bf4347f22cd95/orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9", size = 141492, upload-time = "2026-05-06T15:10:32.641Z" }, + { url = "https://files.pythonhosted.org/packages/fa/88/a21fb53b3ede6703aede6dce4710ed4111e5b201cfa6bbff5e544f9d47d7/orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677", size = 415087, upload-time = "2026-05-06T15:10:34.438Z" }, + { url = "https://files.pythonhosted.org/packages/3d/57/1b30daf70f0d8180e9a73cefbfbdd99e4bf19eb020466502b01fba7e0e50/orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4", size = 148031, upload-time = "2026-05-06T15:10:36.358Z" }, + { url = "https://files.pythonhosted.org/packages/04/83/45fbb6d962e260807f99441db9613cee868ceda4baceda59b3720a563f97/orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0", size = 136915, upload-time = "2026-05-06T15:10:38.013Z" }, + { url = "https://files.pythonhosted.org/packages/5f/cc/2d10025f9056d376e4127ec05a5808b218d46f035fdc08178a5411b34250/orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32", size = 131613, upload-time = "2026-05-06T15:10:39.569Z" }, + { url = "https://files.pythonhosted.org/packages/67/bd/2775ff28bfe883b9aa1ff348300542eb2ef1ee18d8ae0e3a49846817a865/orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979", size = 127086, upload-time = "2026-05-06T15:10:41.262Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/d26799e580939e32a7da9a39531bc9e58e15ca32ffaa6a8cb3e9bb0d22cd/orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254", size = 126696, upload-time = "2026-05-06T15:10:42.651Z" }, + { url = "https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6ef1979adc4bc243523f1a2ba91418030a8e29b0a99cbe7e0e2d6807d4dce6e", size = 228465, upload-time = "2026-05-06T15:10:44.097Z" }, + { url = "https://files.pythonhosted.org/packages/64/62/3e0e0c14c957133bcd855395c62b55ed4e3b0af23ffea11b032cb1dcbdb1/orjson-3.11.9-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:f36b7f32c7c0db4a719f1fc5824db4a9c6f8bd1a354debb91faf26ebf3a4c71e", size = 128364, upload-time = "2026-05-06T15:10:45.839Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5a/07d8aa117211a8ed7630bda80c8c0b14d04e0f8dcf99bcf49656e4a710eb/orjson-3.11.9-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08f4d8ebb44925c794e535b2bebc507cebf32209df81de22ae285fb0d8d66de0", size = 132063, upload-time = "2026-05-06T15:10:47.267Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ec/4acaf21483e18aa945be74a474c74b434f284b549f275a0a39b9f98956e9/orjson-3.11.9-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6cc7923789694fd58f001cbcac7e47abc13af4d560ebbfcf3b41a8b1a0748124", size = 122356, upload-time = "2026-05-06T15:10:48.765Z" }, + { url = "https://files.pythonhosted.org/packages/13/d8/5f0555e7638801323b7a75850f92e7dfa891bc84fe27a1ba4449170d1200/orjson-3.11.9-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea5c46eb2d3af39e806b986f4b09d5c2706a1f5afde3cbf7544ce6616127173c", size = 129592, upload-time = "2026-05-06T15:10:50.13Z" }, + { url = "https://files.pythonhosted.org/packages/b6/30/ed9860412a3603ceb3c5955bfd72d28b9d0e7ba6ed81add14f83d7114236/orjson-3.11.9-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5d89a2ed90731df3be64bab0aa44f78bff39fdc9d71c291f4a8023aa46425b7", size = 140491, upload-time = "2026-05-06T15:10:51.582Z" }, + { url = "https://files.pythonhosted.org/packages/d0/17/adc514dea7ac7c505527febf884934b815d34f0c7b8693c1a8b39c5c4a57/orjson-3.11.9-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25e4aed0312d292c09f61af25bba34e0b2c88546041472b09088c39a4d828af1", size = 127309, upload-time = "2026-05-06T15:10:53.329Z" }, + { url = "https://files.pythonhosted.org/packages/76/3e/c0b690253f0b82d86e99949af13533363acfb5432ecb5d53dd5b3bce9c34/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaea64f3f467d22e70eeed68bdccb3bc4f83f650446c4a03c59f2cba28a108db", size = 134030, upload-time = "2026-05-06T15:10:54.988Z" }, + { url = "https://files.pythonhosted.org/packages/c1/7a/bc82a0bb25e9faaf92dc4d9ef002732efc09737706af83e346788641d4a7/orjson-3.11.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a028425d1b440c5d92a6be1e1a020739dfe67ea87d96c6dbe828c1b30041728b", size = 141482, upload-time = "2026-05-06T15:10:56.663Z" }, + { url = "https://files.pythonhosted.org/packages/01/55/e69188b939f77d5d32a9833745ace31ea5ccae3ab613a1ec185d3cd2c4fb/orjson-3.11.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b192c6cf397e4455b11523c5cf2b18ed084c1bbd61b6c0926344d2129481972", size = 415178, upload-time = "2026-05-06T15:10:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1a/b8a5a7ac527e80b9cb11d51e3f6689b709279183264b9ec5c7bc680bb8b5/orjson-3.11.9-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ea407d4ccf5891d667d045fecae97a7a1e5e87b3b97f97ae1803c2e741130be0", size = 148089, upload-time = "2026-05-06T15:11:00.441Z" }, + { url = "https://files.pythonhosted.org/packages/97/4e/00503f64204bf859b37213a63927028f30fb6268cd8677fb0a5ad48155e1/orjson-3.11.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f63aaf97afd9f6dec5b1a68e1b8da12bfccb4cb9a9a65c3e0b6c847849e7586", size = 136921, upload-time = "2026-05-06T15:11:02.176Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ba/a23b82a0a8d0ed7bed4e5f5035aae751cad4ff6a1e8d2ecd14d8860f5929/orjson-3.11.9-cp314-cp314-win32.whl", hash = "sha256:e30ab17845bb9fa54ccf67fa4f9f5282652d54faa6d17452f47d0f369d038673", size = 131638, upload-time = "2026-05-06T15:11:03.696Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c3/0c6798456bade745c75c452342dabacce5798196483e77e643be1f53877d/orjson-3.11.9-cp314-cp314-win_amd64.whl", hash = "sha256:32ef5f4283a3be81913947d19608eacb7c6608026851123790cd9cc8982af34b", size = 127078, upload-time = "2026-05-06T15:11:05.123Z" }, + { url = "https://files.pythonhosted.org/packages/16/21/5a3f1e8913103b703a436a5664238e5b965ec392b555fe68943ea3691e6b/orjson-3.11.9-cp314-cp314-win_arm64.whl", hash = "sha256:eebdbdeef0094e4f5aefa20dcd4eb2368ab5e7a3b4edea27f1e7b2892e009cf9", size = 126687, upload-time = "2026-05-06T15:11:06.602Z" }, ] [[package]] @@ -3397,103 +2989,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, ] -[[package]] -name = "pandas" -version = "2.3.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "python-dateutil", marker = "python_full_version < '3.11'" }, - { name = "pytz", marker = "python_full_version < '3.11'" }, - { name = "tzdata", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fa/7ac648108144a095b4fb6aa3de1954689f7af60a14cf25583f4960ecb878/pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523", size = 11578790, upload-time = "2025-09-29T23:18:30.065Z" }, - { url = "https://files.pythonhosted.org/packages/9b/35/74442388c6cf008882d4d4bdfc4109be87e9b8b7ccd097ad1e7f006e2e95/pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45", size = 10833831, upload-time = "2025-09-29T23:38:56.071Z" }, - { url = "https://files.pythonhosted.org/packages/fe/e4/de154cbfeee13383ad58d23017da99390b91d73f8c11856f2095e813201b/pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66", size = 12199267, upload-time = "2025-09-29T23:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/bf/c9/63f8d545568d9ab91476b1818b4741f521646cbdd151c6efebf40d6de6f7/pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b", size = 12789281, upload-time = "2025-09-29T23:18:56.834Z" }, - { url = "https://files.pythonhosted.org/packages/f2/00/a5ac8c7a0e67fd1a6059e40aa08fa1c52cc00709077d2300e210c3ce0322/pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791", size = 13240453, upload-time = "2025-09-29T23:19:09.247Z" }, - { url = "https://files.pythonhosted.org/packages/27/4d/5c23a5bc7bd209231618dd9e606ce076272c9bc4f12023a70e03a86b4067/pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151", size = 13890361, upload-time = "2025-09-29T23:19:25.342Z" }, - { url = "https://files.pythonhosted.org/packages/8e/59/712db1d7040520de7a4965df15b774348980e6df45c129b8c64d0dbe74ef/pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c", size = 11348702, upload-time = "2025-09-29T23:19:38.296Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" }, - { url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" }, - { url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" }, - { url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" }, - { url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" }, - { url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" }, - { url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" }, - { url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" }, - { url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" }, - { url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" }, - { url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" }, - { url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" }, - { url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" }, - { url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" }, - { url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" }, - { url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" }, - { url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" }, - { url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" }, - { url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" }, - { url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" }, - { url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" }, - { url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" }, - { url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" }, - { url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" }, - { url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" }, - { url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" }, -] - [[package]] name = "pandas" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, - { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/99/b342345300f13440fe9fe385c3c481e2d9a595ee3bab4d3219247ac94e9a/pandas-3.0.2.tar.gz", hash = "sha256:f4753e73e34c8d83221ba58f232433fca2748be8b18dbca02d242ed153945043", size = 4645855, upload-time = "2026-03-31T06:48:30.816Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/35/6411db530c618e0e0005187e35aa02ce60ae4c4c4d206964a2f978217c27/pandas-3.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a727a73cbdba2f7458dc82449e2315899d5140b449015d822f515749a46cbbe0", size = 10326926, upload-time = "2026-03-31T06:46:08.29Z" }, - { url = "https://files.pythonhosted.org/packages/c4/d3/b7da1d5d7dbdc5ef52ed7debd2b484313b832982266905315dad5a0bf0b1/pandas-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbbd4aa20ca51e63b53bbde6a0fa4254b1aaabb74d2f542df7a7959feb1d760c", size = 9926987, upload-time = "2026-03-31T06:46:11.724Z" }, - { url = "https://files.pythonhosted.org/packages/52/77/9b1c2d6070b5dbe239a7bc889e21bfa58720793fb902d1e070695d87c6d0/pandas-3.0.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:339dda302bd8369dedeae979cb750e484d549b563c3f54f3922cb8ff4978c5eb", size = 10757067, upload-time = "2026-03-31T06:46:14.903Z" }, - { url = "https://files.pythonhosted.org/packages/20/17/ec40d981705654853726e7ac9aea9ddbb4a5d9cf54d8472222f4f3de06c2/pandas-3.0.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:61c2fd96d72b983a9891b2598f286befd4ad262161a609c92dc1652544b46b76", size = 11258787, upload-time = "2026-03-31T06:46:17.683Z" }, - { url = "https://files.pythonhosted.org/packages/90/e3/3f1126d43d3702ca8773871a81c9f15122a1f412342cc56284ffda5b1f70/pandas-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c934008c733b8bbea273ea308b73b3156f0181e5b72960790b09c18a2794fe1e", size = 11771616, upload-time = "2026-03-31T06:46:20.532Z" }, - { url = "https://files.pythonhosted.org/packages/2e/cf/0f4e268e1f5062e44a6bda9f925806721cd4c95c2b808a4c82ebe914f96b/pandas-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:60a80bb4feacbef5e1447a3f82c33209c8b7e07f28d805cfd1fb951e5cb443aa", size = 12337623, upload-time = "2026-03-31T06:46:23.754Z" }, - { url = "https://files.pythonhosted.org/packages/44/a0/97a6339859d4acb2536efb24feb6708e82f7d33b2ed7e036f2983fcced82/pandas-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:ed72cb3f45190874eb579c64fa92d9df74e98fd63e2be7f62bce5ace0ade61df", size = 9897372, upload-time = "2026-03-31T06:46:26.703Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/781516b808a99ddf288143cec46b342b3016c3414d137da1fdc3290d8860/pandas-3.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:f12b1a9e332c01e09510586f8ca9b108fd631fd656af82e452d7315ef6df5f9f", size = 9154922, upload-time = "2026-03-31T06:46:30.284Z" }, { url = "https://files.pythonhosted.org/packages/f3/b0/c20bd4d6d3f736e6bd6b55794e9cd0a617b858eaad27c8f410ea05d953b7/pandas-3.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:232a70ebb568c0c4d2db4584f338c1577d81e3af63292208d615907b698a0f18", size = 10347921, upload-time = "2026-03-31T06:46:33.36Z" }, { url = "https://files.pythonhosted.org/packages/35/d0/4831af68ce30cc2d03c697bea8450e3225a835ef497d0d70f31b8cdde965/pandas-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:970762605cff1ca0d3f71ed4f3a769ea8f85fc8e6348f6e110b8fea7e6eb5a14", size = 9888127, upload-time = "2026-03-31T06:46:36.253Z" }, { url = "https://files.pythonhosted.org/packages/61/a9/16ea9346e1fc4a96e2896242d9bc674764fb9049b0044c0132502f7a771e/pandas-3.0.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aff4e6f4d722e0652707d7bcb190c445fe58428500c6d16005b02401764b1b3d", size = 10399577, upload-time = "2026-03-31T06:46:39.224Z" }, @@ -3550,28 +3056,6 @@ version = "12.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/aa/d0b28e1c811cd4d5f5c2bfe2e022292bd255ae5744a3b9ac7d6c8f72dd75/pillow-12.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f", size = 5354355, upload-time = "2026-04-01T14:42:15.402Z" }, - { url = "https://files.pythonhosted.org/packages/27/8e/1d5b39b8ae2bd7650d0c7b6abb9602d16043ead9ebbfef4bc4047454da2a/pillow-12.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97", size = 4695871, upload-time = "2026-04-01T14:42:18.234Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c5/dcb7a6ca6b7d3be41a76958e90018d56c8462166b3ef223150360850c8da/pillow-12.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff", size = 6269734, upload-time = "2026-04-01T14:42:20.608Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f1/aa1bb13b2f4eba914e9637893c73f2af8e48d7d4023b9d3750d4c5eb2d0c/pillow-12.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec", size = 8076080, upload-time = "2026-04-01T14:42:23.095Z" }, - { url = "https://files.pythonhosted.org/packages/a1/2a/8c79d6a53169937784604a8ae8d77e45888c41537f7f6f65ed1f407fe66d/pillow-12.2.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136", size = 6382236, upload-time = "2026-04-01T14:42:25.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/42/bbcb6051030e1e421d103ce7a8ecadf837aa2f39b8f82ef1a8d37c3d4ebc/pillow-12.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c", size = 7070220, upload-time = "2026-04-01T14:42:28.68Z" }, - { url = "https://files.pythonhosted.org/packages/3f/e1/c2a7d6dd8cfa6b231227da096fd2d58754bab3603b9d73bf609d3c18b64f/pillow-12.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3", size = 6493124, upload-time = "2026-04-01T14:42:31.579Z" }, - { url = "https://files.pythonhosted.org/packages/5f/41/7c8617da5d32e1d2f026e509484fdb6f3ad7efaef1749a0c1928adbb099e/pillow-12.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa", size = 7194324, upload-time = "2026-04-01T14:42:34.615Z" }, - { url = "https://files.pythonhosted.org/packages/2d/de/a777627e19fd6d62f84070ee1521adde5eeda4855b5cf60fe0b149118bca/pillow-12.2.0-cp310-cp310-win32.whl", hash = "sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032", size = 6376363, upload-time = "2026-04-01T14:42:37.19Z" }, - { url = "https://files.pythonhosted.org/packages/e7/34/fc4cb5204896465842767b96d250c08410f01f2f28afc43b257de842eed5/pillow-12.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5", size = 7083523, upload-time = "2026-04-01T14:42:39.62Z" }, - { url = "https://files.pythonhosted.org/packages/2d/a0/32852d36bc7709f14dc3f64f929a275e958ad8c19a6deba9610d458e28b3/pillow-12.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024", size = 2463318, upload-time = "2026-04-01T14:42:42.063Z" }, - { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, - { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, - { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, - { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, - { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, - { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, @@ -3633,13 +3117,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, - { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, - { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, - { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, ] [[package]] @@ -3648,7 +3125,6 @@ version = "0.27.0" source = { editable = "." } dependencies = [ { name = "aiofiles" }, - { name = "backports-strenum", marker = "python_full_version < '3.11'" }, { name = "datamodel-code-generator" }, { name = "filetype" }, { name = "httpx" }, @@ -3658,8 +3134,7 @@ dependencies = [ { name = "kajson" }, { name = "markdown" }, { name = "mthds" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "networkx" }, { name = "openai" }, { name = "opentelemetry-api" }, { name = "opentelemetry-exporter-otlp-proto-http" }, @@ -3754,6 +3229,9 @@ linkup = [ mistralai = [ { name = "mistralai" }, ] +mistralai-workflows = [ + { name = "mistralai-workflows" }, +] s3 = [ { name = "aioboto3" }, { name = "boto3" }, @@ -3788,8 +3266,8 @@ requires-dist = [ { name = "google-genai", marker = "extra == 'google-genai'" }, { name = "httpx", specifier = ">=0.23.0,<1.0.0" }, { name = "huggingface-hub", marker = "extra == 'huggingface'", specifier = ">=0.23,<1.0.0" }, - { name = "instructor", specifier = ">=1.8.3,!=1.11.*,!=1.12.*" }, - { name = "instructor", extras = ["google-genai"], marker = "extra == 'google-genai'" }, + { name = "instructor", git = "https://github.com/Ian321/instructor.git?rev=4ea22d2396ca35514929f27faed866115e8b3583" }, + { name = "instructor", extras = ["google-genai"], marker = "extra == 'google-genai'", git = "https://github.com/Ian321/instructor.git?rev=4ea22d2396ca35514929f27faed866115e8b3583" }, { name = "jinja2", specifier = ">=3.1.4" }, { name = "json2html", specifier = ">=1.3.0" }, { name = "kajson", specifier = "==0.5.0" }, @@ -3797,7 +3275,8 @@ requires-dist = [ { name = "lxml", marker = "extra == 'docling'", specifier = ">=6.1.0" }, { name = "markdown", specifier = ">=3.6" }, { name = "mike", marker = "extra == 'docs'", specifier = ">=2.1.3" }, - { name = "mistralai", marker = "extra == 'mistralai'", specifier = ">=1.12.0" }, + { name = "mistralai", marker = "extra == 'mistralai'", specifier = ">=2.4.4" }, + { name = "mistralai-workflows", marker = "extra == 'mistralai-workflows'", specifier = ">=3.3.0" }, { name = "mkdocs", marker = "extra == 'docs'", specifier = ">=1.6.1" }, { name = "mkdocs-glightbox", marker = "extra == 'docs'", specifier = ">=0.4.0" }, { name = "mkdocs-llmstxt-md", marker = "extra == 'docs'", specifier = ">=0.2.0" }, @@ -3836,7 +3315,7 @@ requires-dist = [ { name = "ruff", marker = "extra == 'dev'", specifier = "==0.14.13" }, { name = "semantic-version", specifier = ">=2.10.0" }, { name = "shortuuid", specifier = ">=1.0.13" }, - { name = "temporalio", marker = "extra == 'temporal'", specifier = "==1.23.0" }, + { name = "temporalio", marker = "extra == 'temporal'", specifier = "==1.24.0" }, { name = "tomli", specifier = ">=2.3.0" }, { name = "tomlkit", specifier = ">=0.13.2" }, { name = "typer", specifier = ">=0.16.0" }, @@ -3847,7 +3326,7 @@ requires-dist = [ { name = "types-pyyaml", marker = "extra == 'dev'", specifier = ">=6.0.12.20250326" }, { name = "typing-extensions", specifier = ">=4.13.2" }, ] -provides-extras = ["anthropic", "bedrock", "docling", "fal", "gcp-storage", "google", "google-genai", "huggingface", "linkup", "mistralai", "dynamodb", "s3", "temporal", "docs", "dev"] +provides-extras = ["anthropic", "bedrock", "docling", "fal", "gcp-storage", "google", "google-genai", "huggingface", "linkup", "mistralai", "mistralai-workflows", "dynamodb", "s3", "temporal", "docs", "dev"] [[package]] name = "pipelex-tools" @@ -3937,36 +3416,6 @@ version = "0.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, - { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, - { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, - { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, - { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, - { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, - { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, - { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, - { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, - { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, - { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, - { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, - { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, @@ -4136,18 +3585,6 @@ version = "1.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/21/3c06205bb407e1f79b73b7b4dfb3950bd9537c4f625a68ab5cc41177f5bc/pyclipper-1.4.0.tar.gz", hash = "sha256:9882bd889f27da78add4dd6f881d25697efc740bf840274e749988d25496c8e1", size = 54489, upload-time = "2025-12-01T13:15:35.015Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/9f/a10173d32ecc2ce19a04d018163f3ca22a04c0c6ad03b464dcd32f9152a8/pyclipper-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bafad70d2679c187120e8c44e1f9a8b06150bad8c0aecf612ad7dfbfa9510f73", size = 264510, upload-time = "2025-12-01T13:14:46.551Z" }, - { url = "https://files.pythonhosted.org/packages/e0/c2/5490ddc4a1f7ceeaa0258f4266397e720c02db515b2ca5bc69b85676f697/pyclipper-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b74a9dd44b22a7fd35d65fb1ceeba57f3817f34a97a28c3255556362e491447", size = 139498, upload-time = "2025-12-01T13:14:48.31Z" }, - { url = "https://files.pythonhosted.org/packages/3b/0a/bea9102d1d75634b1a5702b0e92982451a1eafca73c4845d3dbe27eba13d/pyclipper-1.4.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a4d2736fb3c42e8eb1d38bf27a720d1015526c11e476bded55138a977c17d9d", size = 970974, upload-time = "2025-12-01T13:14:49.799Z" }, - { url = "https://files.pythonhosted.org/packages/8b/1b/097f8776d5b3a10eb7b443b632221f4ed825d892e79e05682f4b10a1a59c/pyclipper-1.4.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3b3630051b53ad2564cb079e088b112dd576e3d91038338ad1cc7915e0f14dc", size = 943315, upload-time = "2025-12-01T13:14:51.266Z" }, - { url = "https://files.pythonhosted.org/packages/fd/4d/17d6a3f1abf0f368d58f2309e80ee3761afb1fd1342f7780ab32ba4f0b1d/pyclipper-1.4.0-cp310-cp310-win32.whl", hash = "sha256:8d42b07a2f6cfe2d9b87daf345443583f00a14e856927782fde52f3a255e305a", size = 95286, upload-time = "2025-12-01T13:14:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/53/ca/b30138427ed122ec9b47980b943164974a2ec606fa3f71597033b9a9f9a6/pyclipper-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:6a97b961f182b92d899ca88c1bb3632faea2e00ce18d07c5f789666ebb021ca4", size = 104227, upload-time = "2025-12-01T13:14:54.013Z" }, - { url = "https://files.pythonhosted.org/packages/de/e3/64cf7794319b088c288706087141e53ac259c7959728303276d18adc665d/pyclipper-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:adcb7ca33c5bdc33cd775e8b3eadad54873c802a6d909067a57348bcb96e7a2d", size = 264281, upload-time = "2025-12-01T13:14:55.47Z" }, - { url = "https://files.pythonhosted.org/packages/34/cd/44ec0da0306fa4231e76f1c2cb1fa394d7bde8db490a2b24d55b39865f69/pyclipper-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd24849d2b94ec749ceac7c34c9f01010d23b6e9d9216cf2238b8481160e703d", size = 139426, upload-time = "2025-12-01T13:14:56.683Z" }, - { url = "https://files.pythonhosted.org/packages/ad/88/d8f6c6763ea622fe35e19c75d8b39ed6c55191ddc82d65e06bc46b26cb8e/pyclipper-1.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1b6c8d75ba20c6433c9ea8f1a0feb7e4d3ac06a09ad1fd6d571afc1ddf89b869", size = 989649, upload-time = "2025-12-01T13:14:58.28Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e9/ea7d68c8c4af3842d6515bedcf06418610ad75f111e64c92c1d4785a1513/pyclipper-1.4.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:58e29d7443d7cc0e83ee9daf43927730386629786d00c63b04fe3b53ac01462c", size = 962842, upload-time = "2025-12-01T13:15:00.044Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b7/0b4a272d8726e51ab05e2b933d8cc47f29757fb8212e38b619e170e6015c/pyclipper-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a8d2b5fb75ebe57e21ce61e79a9131edec2622ff23cc665e4d1d1f201bc1a801", size = 95098, upload-time = "2025-12-01T13:15:01.359Z" }, - { url = "https://files.pythonhosted.org/packages/3a/76/4901de2919198bb2bd3d989f86d4a1dff363962425bb2d63e24e6c990042/pyclipper-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:e9b973467d9c5fa9bc30bb6ac95f9f4d7c3d9fc25f6cf2d1cc972088e5955c01", size = 104362, upload-time = "2025-12-01T13:15:02.439Z" }, { url = "https://files.pythonhosted.org/packages/90/1b/7a07b68e0842324d46c03e512d8eefa9cb92ba2a792b3b4ebf939dafcac3/pyclipper-1.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:222ac96c8b8281b53d695b9c4fedc674f56d6d4320ad23f1bdbd168f4e316140", size = 265676, upload-time = "2025-12-01T13:15:04.15Z" }, { url = "https://files.pythonhosted.org/packages/6b/dd/8bd622521c05d04963420ae6664093f154343ed044c53ea260a310c8bb4d/pyclipper-1.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f3672dbafbb458f1b96e1ee3e610d174acb5ace5bd2ed5d1252603bb797f2fc6", size = 140458, upload-time = "2025-12-01T13:15:05.76Z" }, { url = "https://files.pythonhosted.org/packages/7a/06/6e3e241882bf7d6ab23d9c69ba4e85f1ec47397cbbeee948a16cf75e21ed/pyclipper-1.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1f807e2b4760a8e5c6d6b4e8c1d71ef52b7fe1946ff088f4fa41e16a881a5ca", size = 978235, upload-time = "2025-12-01T13:15:06.993Z" }, @@ -4170,7 +3607,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/df/c4a72d3f62f0ba03ec440c4fff56cd2d674a4334d23c5064cbf41c9583f6/pyclipper-1.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a9f11ad133257c52c40d50de7a0ca3370a0cdd8e3d11eec0604ad3c34ba549e9", size = 141706, upload-time = "2025-12-01T13:15:30.134Z" }, { url = "https://files.pythonhosted.org/packages/c5/0b/cf55df03e2175e1e2da9db585241401e0bc98f76bee3791bed39d0313449/pyclipper-1.4.0-cp314-cp314t-win32.whl", hash = "sha256:bbc827b77442c99deaeee26e0e7f172355ddb097a5e126aea206d447d3b26286", size = 105308, upload-time = "2025-12-01T13:15:31.225Z" }, { url = "https://files.pythonhosted.org/packages/8f/dc/53df8b6931d47080b4fe4ee8450d42e660ee1c5c1556c7ab73359182b769/pyclipper-1.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:29dae3e0296dff8502eeb7639fcfee794b0eec8590ba3563aee28db269da6b04", size = 117608, upload-time = "2025-12-01T13:15:32.69Z" }, - { url = "https://files.pythonhosted.org/packages/18/59/81050abdc9e5b90ffc2c765738c5e40e9abd8e44864aaa737b600f16c562/pyclipper-1.4.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98b2a40f98e1fc1b29e8a6094072e7e0c7dfe901e573bf6cfc6eb7ce84a7ae87", size = 126495, upload-time = "2025-12-01T13:15:33.743Z" }, ] [[package]] @@ -4206,35 +3642,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/08/f1ba952f1c8ae5581c70fa9c6da89f247b83e3dd8c09c035d5d7931fc23d/pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4", size = 2113146, upload-time = "2026-05-06T13:37:36.537Z" }, - { url = "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5", size = 1949769, upload-time = "2026-05-06T13:37:46.365Z" }, - { url = "https://files.pythonhosted.org/packages/64/ba/bfb1d928fd5b49e1258935ff104ae356e9fd89384a55bf9f847e9193ad40/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba", size = 1974958, upload-time = "2026-05-06T13:37:28.611Z" }, - { url = "https://files.pythonhosted.org/packages/4e/74/76223bfb117b64af743c9b6670d1364516f5c0604f96b48f3272f6af6cc6/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b", size = 2042118, upload-time = "2026-05-06T13:36:55.216Z" }, - { url = "https://files.pythonhosted.org/packages/cb/7b/848732968bc8f48f3187542f08358b9d842db564147b256669426ebb1652/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c", size = 2222876, upload-time = "2026-05-06T13:38:25.455Z" }, - { url = "https://files.pythonhosted.org/packages/b5/2f/e90b63ee2e14bd8d3db8f705a6d75d64e6ee1b7c2c8833747ce706e1e0ce/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50", size = 2286703, upload-time = "2026-05-06T13:37:53.304Z" }, - { url = "https://files.pythonhosted.org/packages/ba/1e/acc4d70f88a0a277e4a1fa77ebb985ceabaf900430f875bf9338e11c9420/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd", size = 2092042, upload-time = "2026-05-06T13:38:46.981Z" }, - { url = "https://files.pythonhosted.org/packages/a9/da/0a422b57bf8504102bf3c4ccea9c41bab5a5cee6a54650acf8faf67f5a24/pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01", size = 2117231, upload-time = "2026-05-06T13:39:23.146Z" }, - { url = "https://files.pythonhosted.org/packages/bd/2a/2ac13c3af305843e23c5078c53d135656b3f05a2fd78cb7bbbb12e97b473/pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d", size = 2168388, upload-time = "2026-05-06T13:40:08.06Z" }, - { url = "https://files.pythonhosted.org/packages/72/04/2beacf7e1607e93eefe4aed1b4709f079b905fb77530179d4f7c71745f22/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4", size = 2184769, upload-time = "2026-05-06T13:38:13.901Z" }, - { url = "https://files.pythonhosted.org/packages/9e/29/d2b9fd9f539133548eaf622c06a4ce176cb46ac59f32d0359c4abc0de047/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f", size = 2319312, upload-time = "2026-05-06T13:39:08.24Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/0f7a5b85fec6075bea96e3ef9187de38fccced0de92c1e7feda8d5cc7bb9/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39", size = 2361817, upload-time = "2026-05-06T13:38:43.2Z" }, - { url = "https://files.pythonhosted.org/packages/25/a4/73363fec545fd3ec025490bdda2743c56d0dd5b6266b1a53bbe9e4265375/pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d", size = 1987085, upload-time = "2026-05-06T13:39:25.497Z" }, - { url = "https://files.pythonhosted.org/packages/01/aa/62f082da2c91fac1c234bc9ee0066257ce83f0604abd72e4c9d5991f2d84/pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf", size = 2074311, upload-time = "2026-05-06T13:39:59.922Z" }, - { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, - { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, - { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, - { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, - { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, - { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, - { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, - { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, - { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, - { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, - { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, - { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, @@ -4295,22 +3702,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, - { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, - { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, - { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, - { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, - { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, - { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, - { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, ] [[package]] @@ -4353,7 +3748,6 @@ dependencies = [ { name = "isort" }, { name = "mccabe" }, { name = "platformdirs" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomlkit" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/d2/b081da1a8930d00e3fc06352a1d449aaf815d4982319fab5d8cdb2e9ab35/pylint-4.0.4.tar.gz", hash = "sha256:d9b71674e19b1c36d79265b5887bf8e55278cbe236c9e95d22dc82cf044fdbd2", size = 1571735, upload-time = "2025-11-30T13:29:04.315Z" } @@ -4422,12 +3816,10 @@ version = "9.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } wheels = [ @@ -4439,7 +3831,6 @@ name = "pytest-asyncio" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, { name = "pytest" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] @@ -4453,7 +3844,7 @@ name = "pytest-cov" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "coverage", extra = ["toml"] }, + { name = "coverage" }, { name = "pluggy" }, { name = "pytest" }, ] @@ -4567,16 +3958,6 @@ version = "0.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/24/f206113e05cb8ef51b3850e7ef88f20da6f4bf932190ceb48bd3da103e10/pytokens-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a44ed93ea23415c54f3face3b65ef2b844d96aeb3455b8a69b3df6beab6acc5", size = 161522, upload-time = "2026-01-30T01:02:50.393Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e9/06a6bf1b90c2ed81a9c7d2544232fe5d2891d1cd480e8a1809ca354a8eb2/pytokens-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:add8bf86b71a5d9fb5b89f023a80b791e04fba57960aa790cc6125f7f1d39dfe", size = 246945, upload-time = "2026-01-30T01:02:52.399Z" }, - { url = "https://files.pythonhosted.org/packages/69/66/f6fb1007a4c3d8b682d5d65b7c1fb33257587a5f782647091e3408abe0b8/pytokens-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:670d286910b531c7b7e3c0b453fd8156f250adb140146d234a82219459b9640c", size = 259525, upload-time = "2026-01-30T01:02:53.737Z" }, - { url = "https://files.pythonhosted.org/packages/04/92/086f89b4d622a18418bac74ab5db7f68cf0c21cf7cc92de6c7b919d76c88/pytokens-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e691d7f5186bd2842c14813f79f8884bb03f5995f0575272009982c5ac6c0f7", size = 262693, upload-time = "2026-01-30T01:02:54.871Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7b/8b31c347cf94a3f900bdde750b2e9131575a61fdb620d3d3c75832262137/pytokens-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:27b83ad28825978742beef057bfe406ad6ed524b2d28c252c5de7b4a6dd48fa2", size = 103567, upload-time = "2026-01-30T01:02:56.414Z" }, - { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" }, - { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" }, - { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" }, - { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" }, - { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" }, { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, @@ -4600,26 +3981,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] -[[package]] -name = "pytz" -version = "2026.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" }, -] - [[package]] name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, - { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, - { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, @@ -4637,24 +4003,6 @@ version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, @@ -4713,8 +4061,7 @@ version = "3.8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorlog" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "omegaconf" }, { name = "opencv-python" }, { name = "pillow" }, @@ -4749,39 +4096,6 @@ version = "2026.4.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/3a246dbf05666918bd3664d9d787f84a9108f6f43cc953a077e4a7dfdb7e/regex-2026.4.4.tar.gz", hash = "sha256:e08270659717f6973523ce3afbafa53515c4dc5dcad637dc215b6fd50f689423", size = 416000, upload-time = "2026-04-03T20:56:28.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/59/fd98f8fd54b3feaa76a855324c676c17668c5a1121ec91b7ec96b01bf865/regex-2026.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:74fa82dcc8143386c7c0392e18032009d1db715c25f4ba22d23dc2e04d02a20f", size = 489403, upload-time = "2026-04-03T20:52:39.742Z" }, - { url = "https://files.pythonhosted.org/packages/6c/64/d0f222f68e3579d50babf0e4fcc9c9639ef0587fecc00b15e1e46bfc32fa/regex-2026.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a85b620a388d6c9caa12189233109e236b3da3deffe4ff11b84ae84e218a274f", size = 291208, upload-time = "2026-04-03T20:52:42.943Z" }, - { url = "https://files.pythonhosted.org/packages/16/7f/3fab9709b0b0060ba81a04b8a107b34147cd14b9c5551b772154d6505504/regex-2026.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2895506ebe32cc63eeed8f80e6eae453171cfccccab35b70dc3129abec35a5b8", size = 289214, upload-time = "2026-04-03T20:52:44.648Z" }, - { url = "https://files.pythonhosted.org/packages/14/bc/f5dcf04fd462139dcd75495c02eee22032ef741cfa151386a39c3f5fc9b5/regex-2026.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6780f008ee81381c737634e75c24e5a6569cc883c4f8e37a37917ee79efcafd9", size = 785505, upload-time = "2026-04-03T20:52:46.35Z" }, - { url = "https://files.pythonhosted.org/packages/37/36/8a906e216d5b4de7ec3788c1d589b45db40c1c9580cd7b326835cfc976d4/regex-2026.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:88e9b048345c613f253bea4645b2fe7e579782b82cac99b1daad81e29cc2ed8e", size = 852129, upload-time = "2026-04-03T20:52:48.661Z" }, - { url = "https://files.pythonhosted.org/packages/a5/bb/bad2d79be0917a6ef31f5e0f161d9265cb56fd90a3ae1d2e8d991882a48b/regex-2026.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:be061028481186ba62a0f4c5f1cc1e3d5ab8bce70c89236ebe01023883bc903b", size = 899578, upload-time = "2026-04-03T20:52:50.61Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b9/7cd0ceb58cd99c70806241636640ae15b4a3fe62e22e9b99afa67a0d7965/regex-2026.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d2228c02b368d69b724c36e96d3d1da721561fb9cc7faa373d7bf65e07d75cb5", size = 793634, upload-time = "2026-04-03T20:52:53Z" }, - { url = "https://files.pythonhosted.org/packages/2c/fb/c58e3ea40ed183806ccbac05c29a3e8c2f88c1d3a66ed27860d5cad7c62d/regex-2026.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0540e5b733618a2f84e9cb3e812c8afa82e151ca8e19cf6c4e95c5a65198236f", size = 786210, upload-time = "2026-04-03T20:52:54.713Z" }, - { url = "https://files.pythonhosted.org/packages/54/a9/53790fc7a6c948a7be2bc7214fd9cabdd0d1ba561b0f401c91f4ff0357f0/regex-2026.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cf9b1b2e692d4877880388934ac746c99552ce6bf40792a767fd42c8c99f136d", size = 769930, upload-time = "2026-04-03T20:52:56.825Z" }, - { url = "https://files.pythonhosted.org/packages/e3/3c/29ca44729191c79f5476538cd0fa04fa2553b3c45508519ecea4c7afa8f6/regex-2026.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:011bb48bffc1b46553ac704c975b3348717f4e4aa7a67522b51906f99da1820c", size = 774892, upload-time = "2026-04-03T20:52:58.934Z" }, - { url = "https://files.pythonhosted.org/packages/3e/db/6ae74ef8a4cfead341c367e4eed45f71fb1aaba35827a775eed4f1ba4f74/regex-2026.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8512fcdb43f1bf18582698a478b5ab73f9c1667a5b7548761329ef410cd0a760", size = 848816, upload-time = "2026-04-03T20:53:00.684Z" }, - { url = "https://files.pythonhosted.org/packages/53/9a/f7f2c1c6b610d7c6de1c3dc5951effd92c324b1fde761af2044b4721020f/regex-2026.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:867bddc63109a0276f5a31999e4c8e0eb7bbbad7d6166e28d969a2c1afeb97f9", size = 758363, upload-time = "2026-04-03T20:53:02.155Z" }, - { url = "https://files.pythonhosted.org/packages/dd/55/e5386d393bbf8b43c8b084703a46d635e7b2bdc6e0f5909a2619ea1125f1/regex-2026.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1b9a00b83f3a40e09859c78920571dcb83293c8004079653dd22ec14bbfa98c7", size = 837122, upload-time = "2026-04-03T20:53:03.727Z" }, - { url = "https://files.pythonhosted.org/packages/01/da/cc78710ea2e60b10bacfcc9beb18c67514200ab03597b3b2b319995785c2/regex-2026.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e355be718caf838aa089870259cf1776dc2a4aa980514af9d02c59544d9a8b22", size = 782140, upload-time = "2026-04-03T20:53:05.608Z" }, - { url = "https://files.pythonhosted.org/packages/a2/5f/c7bcba41529105d6c2ca7080ecab7184cd00bee2e1ad1fdea80e618704ea/regex-2026.4.4-cp310-cp310-win32.whl", hash = "sha256:33bfda9684646d323414df7abe5692c61d297dbb0530b28ec66442e768813c59", size = 266225, upload-time = "2026-04-03T20:53:07.342Z" }, - { url = "https://files.pythonhosted.org/packages/eb/26/a745729c2c49354ec4f4bce168f29da932ca01b4758227686cc16c7dde1b/regex-2026.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:0709f22a56798457ae317bcce42aacee33c680068a8f14097430d9f9ba364bee", size = 278393, upload-time = "2026-04-03T20:53:08.65Z" }, - { url = "https://files.pythonhosted.org/packages/87/8b/4327eeb9dbb4b098ebecaf02e9f82b79b6077beeb54c43d9a0660cf7c44c/regex-2026.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:ee9627de8587c1a22201cb16d0296ab92b4df5cdcb5349f4e9744d61db7c7c98", size = 270470, upload-time = "2026-04-03T20:53:10.018Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/617356cbecdb452812a5d42f720d6d5096b360d4a4c1073af700ea140ad2/regex-2026.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4c36a85b00fadb85db9d9e90144af0a980e1a3d2ef9cd0f8a5bef88054657c6", size = 489415, upload-time = "2026-04-03T20:53:11.645Z" }, - { url = "https://files.pythonhosted.org/packages/20/e6/bf057227144d02e3ba758b66649e87531d744dda5f3254f48660f18ae9d8/regex-2026.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dcb5453ecf9cd58b562967badd1edbf092b0588a3af9e32ee3d05c985077ce87", size = 291205, upload-time = "2026-04-03T20:53:13.289Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3b/637181b787dd1a820ba1c712cee2b4144cd84a32dc776ca067b12b2d70c8/regex-2026.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6aa809ed4dc3706cc38594d67e641601bd2f36d5555b2780ff074edfcb136cf8", size = 289225, upload-time = "2026-04-03T20:53:16.002Z" }, - { url = "https://files.pythonhosted.org/packages/05/21/bac05d806ed02cd4b39d9c8e5b5f9a2998c94c3a351b7792e80671fa5315/regex-2026.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33424f5188a7db12958246a54f59a435b6cb62c5cf9c8d71f7cc49475a5fdada", size = 792434, upload-time = "2026-04-03T20:53:17.414Z" }, - { url = "https://files.pythonhosted.org/packages/d9/17/c65d1d8ae90b772d5758eb4014e1e011bb2db353fc4455432e6cc9100df7/regex-2026.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d346fccdde28abba117cc9edc696b9518c3307fbfcb689e549d9b5979018c6d", size = 861730, upload-time = "2026-04-03T20:53:18.903Z" }, - { url = "https://files.pythonhosted.org/packages/ad/64/933321aa082a2c6ee2785f22776143ba89840189c20d3b6b1d12b6aae16b/regex-2026.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:415a994b536440f5011aa77e50a4274d15da3245e876e5c7f19da349caaedd87", size = 906495, upload-time = "2026-04-03T20:53:20.561Z" }, - { url = "https://files.pythonhosted.org/packages/01/ea/4c8d306e9c36ac22417336b1e02e7b358152c34dc379673f2d331143725f/regex-2026.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21e5eb86179b4c67b5759d452ea7c48eb135cd93308e7a260aa489ed2eb423a4", size = 799810, upload-time = "2026-04-03T20:53:22.961Z" }, - { url = "https://files.pythonhosted.org/packages/29/ce/7605048f00e1379eba89d610c7d644d8f695dc9b26d3b6ecfa3132b872ff/regex-2026.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:312ec9dd1ae7d96abd8c5a36a552b2139931914407d26fba723f9e53c8186f86", size = 774242, upload-time = "2026-04-03T20:53:25.015Z" }, - { url = "https://files.pythonhosted.org/packages/e9/77/283e0d5023fde22cd9e86190d6d9beb21590a452b195ffe00274de470691/regex-2026.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0d2b28aa1354c7cd7f71b7658c4326f7facac106edd7f40eda984424229fd59", size = 781257, upload-time = "2026-04-03T20:53:26.918Z" }, - { url = "https://files.pythonhosted.org/packages/8b/fb/7f3b772be101373c8626ed34c5d727dcbb8abd42a7b1219bc25fd9a3cc04/regex-2026.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:349d7310eddff40429a099c08d995c6d4a4bfaf3ff40bd3b5e5cb5a5a3c7d453", size = 854490, upload-time = "2026-04-03T20:53:29.065Z" }, - { url = "https://files.pythonhosted.org/packages/85/30/56547b80f34f4dd2986e1cdd63b1712932f63b6c4ce2f79c50a6cd79d1c2/regex-2026.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e7ab63e9fe45a9ec3417509e18116b367e89c9ceb6219222a3396fa30b147f80", size = 763544, upload-time = "2026-04-03T20:53:30.917Z" }, - { url = "https://files.pythonhosted.org/packages/ac/2f/ce060fdfea8eff34a8997603532e44cdb7d1f35e3bc253612a8707a90538/regex-2026.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fe896e07a5a2462308297e515c0054e9ec2dd18dfdc9427b19900b37dfe6f40b", size = 844442, upload-time = "2026-04-03T20:53:32.463Z" }, - { url = "https://files.pythonhosted.org/packages/e5/44/810cb113096a1dacbe82789fbfab2823f79d19b7f1271acecb7009ba9b88/regex-2026.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb59c65069498dbae3c0ef07bbe224e1eaa079825a437fb47a479f0af11f774f", size = 789162, upload-time = "2026-04-03T20:53:34.039Z" }, - { url = "https://files.pythonhosted.org/packages/20/96/9647dd7f2ecf6d9ce1fb04dfdb66910d094e10d8fe53e9c15096d8aa0bd2/regex-2026.4.4-cp311-cp311-win32.whl", hash = "sha256:2a5d273181b560ef8397c8825f2b9d57013de744da9e8257b8467e5da8599351", size = 266227, upload-time = "2026-04-03T20:53:35.601Z" }, - { url = "https://files.pythonhosted.org/packages/33/80/74e13262460530c3097ff343a17de9a34d040a5dc4de9cf3a8241faab51c/regex-2026.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:9542ccc1e689e752594309444081582f7be2fdb2df75acafea8a075108566735", size = 278399, upload-time = "2026-04-03T20:53:37.021Z" }, - { url = "https://files.pythonhosted.org/packages/1c/3c/39f19f47f19dcefa3403f09d13562ca1c0fd07ab54db2bc03148f3f6b46a/regex-2026.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:b5f9fb784824a042be3455b53d0b112655686fdb7a91f88f095f3fee1e2a2a54", size = 270473, upload-time = "2026-04-03T20:53:38.633Z" }, { url = "https://files.pythonhosted.org/packages/e5/28/b972a4d3df61e1d7bcf1b59fdb3cddef22f88b6be43f161bb41ebc0e4081/regex-2026.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c07ab8794fa929e58d97a0e1796b8b76f70943fa39df225ac9964615cf1f9d52", size = 490434, upload-time = "2026-04-03T20:53:40.219Z" }, { url = "https://files.pythonhosted.org/packages/84/20/30041446cf6dc3e0eab344fc62770e84c23b6b68a3b657821f9f80cb69b4/regex-2026.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c785939dc023a1ce4ec09599c032cc9933d258a998d16ca6f2b596c010940eb", size = 292061, upload-time = "2026-04-03T20:53:41.862Z" }, { url = "https://files.pythonhosted.org/packages/62/c8/3baa06d75c98c46d4cc4262b71fd2edb9062b5665e868bca57859dadf93a/regex-2026.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b1ce5c81c9114f1ce2f9288a51a8fd3aeea33a0cc440c415bf02da323aa0a76", size = 289628, upload-time = "2026-04-03T20:53:43.701Z" }, @@ -4938,35 +4252,6 @@ version = "0.30.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, - { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, - { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, - { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, - { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, - { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, - { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, - { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, - { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, - { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, - { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, - { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, - { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, - { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, - { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, - { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, - { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, - { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, - { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, - { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, - { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, - { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, - { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, - { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, @@ -5040,18 +4325,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" }, { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" }, { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" }, - { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, - { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, - { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, - { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, - { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, - { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, - { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, - { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, - { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, - { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] [[package]] @@ -5128,112 +4401,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, ] [package.optional-dependencies] torch = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "packaging" }, { name = "torch" }, ] -[[package]] -name = "scipy" -version = "1.15.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, - { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, - { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, - { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, - { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, - { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, - { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, - { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, - { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, - { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, - { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, - { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, - { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, - { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, - { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, - { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, - { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, - { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, - { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, - { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, - { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, - { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, - { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, - { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, - { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, - { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, -] - [[package]] name = "scipy" version = "1.17.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", -] dependencies = [ - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, - { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, - { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, - { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, - { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, - { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, - { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, - { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, - { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, @@ -5292,24 +4477,6 @@ version = "0.4.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b3/1a/ce7768c1bff5cf07e3e12f904d54a63c3f85f78e3b299c0b561839d0238e/selectolax-0.4.8.tar.gz", hash = "sha256:cd703165b9a346be255e2ca5b4219e01009911977ac8a474d8ccb7e32e9a4fae", size = 4875521, upload-time = "2026-05-04T15:10:44.935Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/89/0933738d60eb6e0d872e68c7d473d6efe9e99a0f7eec8a970febb4c319c5/selectolax-0.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2166f893420119151bb644f79c145f6d75f1f0435f98b071d9e663f273890551", size = 2206038, upload-time = "2026-05-04T15:08:46.836Z" }, - { url = "https://files.pythonhosted.org/packages/e6/1d/a8457a0fb898d9803aabdbe2028841f03889ba1d95771164c1bdce9fd1ef/selectolax-0.4.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4542a35f5ea993ae8bdb5850346f65848794afabc83976e576dcab07a6699020", size = 2256699, upload-time = "2026-05-04T15:08:48.989Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a9/a30c621ae96d50c8ef15de3ca0f35c4b2878d5e1e270dcb6a9d1c1299e85/selectolax-0.4.8-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c65d50ab4654c55a3fa17db17cae39405a688693aad0681d8cd8bf8c1b01b588", size = 2339298, upload-time = "2026-05-04T15:08:51.035Z" }, - { url = "https://files.pythonhosted.org/packages/8e/85/f4f06a30e63bbbaa42685122b7b0718c43ccb37b6e58f8a160b563b6fc37/selectolax-0.4.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:239fb539f67a43cbd543d48a09314eb955b5f3fe1b9ede4e1a31feb7ccfdd6b0", size = 2389018, upload-time = "2026-05-04T15:08:52.791Z" }, - { url = "https://files.pythonhosted.org/packages/40/47/50b43a9047f230f34e1851cc7beb63123376f40c7eb1d48e24b2eabbd5eb/selectolax-0.4.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6753fe6132c4dfbc984ce9b48777f7f7282c63b3943e558459a6b8847da962e", size = 2344273, upload-time = "2026-05-04T15:08:54.748Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/b34159afe1fcd69a866ab5484d3b73b299f1fbaf27726536881bdc6499e3/selectolax-0.4.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:059056df901766278018a1064dd4e49a6111a01fef02a7e668352fe716c80c84", size = 2397489, upload-time = "2026-05-04T15:08:56.597Z" }, - { url = "https://files.pythonhosted.org/packages/72/46/ac5703fafdf12c4b00c76a9c3b7d4a0d9fa1878865fa865d8997203a7e88/selectolax-0.4.8-cp310-cp310-win32.whl", hash = "sha256:c7a10112c6f96f3db34e757d8e82e7441fd76c7361dc0d8f19a9c383bd4afd26", size = 1764576, upload-time = "2026-05-04T15:08:58.455Z" }, - { url = "https://files.pythonhosted.org/packages/e6/97/6bdb3f557242838394eb971fba0b0212f982537dc354aadd4624638f6750/selectolax-0.4.8-cp310-cp310-win_amd64.whl", hash = "sha256:4be603bbe70f6c036b189bd2a7227ab2fd7d47d360c2282a3623712cf3e2f23d", size = 1856985, upload-time = "2026-05-04T15:09:00.123Z" }, - { url = "https://files.pythonhosted.org/packages/b8/65/623fe0540be1e8df84074c0be9136e5be786f17ece3a7ee33bfc2e3ba12d/selectolax-0.4.8-cp310-cp310-win_arm64.whl", hash = "sha256:903abf55ffcd2b5a8f8918925e9c532ffeae09b752c39371569a5350dc1c1157", size = 1811972, upload-time = "2026-05-04T15:09:01.795Z" }, - { url = "https://files.pythonhosted.org/packages/1e/d8/fd9c0dc417b0e131153925af812be188f6e29139998bddfe3f9f5b275733/selectolax-0.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e334eb5d1a8ed41c539d5fbc170bfbecbaa5312c6f3358cb36b606565f748a8c", size = 2211435, upload-time = "2026-05-04T15:09:03.826Z" }, - { url = "https://files.pythonhosted.org/packages/82/74/d2c2a2448d7355fedcf24583ab9c3083bf0dbd13fb9bad98a166517ac65f/selectolax-0.4.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:241b99d10ebf1df8b7b57fd90a3479abfd987ef04acb6253c4d3571b570346c9", size = 2262297, upload-time = "2026-05-04T15:09:05.426Z" }, - { url = "https://files.pythonhosted.org/packages/62/fc/25939114a8706a8b17b066c594da929fbb9dcdee1fd2bb078befa5ebf2f2/selectolax-0.4.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1269dcb740b7a1eaefabce6b189324a5bd9c93a39b25b54a888b4ea0cf10290d", size = 2342920, upload-time = "2026-05-04T15:09:07.043Z" }, - { url = "https://files.pythonhosted.org/packages/63/bb/3d3e0a9350a81f3cf38e0bf69c4ad0c17e2f4bfe142c98202294fe0cfa92/selectolax-0.4.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f8414beca1e821cd260d94c8fe687f9a8ae4ef765e2b4710d8bd233ec32cde26", size = 2393930, upload-time = "2026-05-04T15:09:09.088Z" }, - { url = "https://files.pythonhosted.org/packages/af/8a/a955323a52cbae720e515bb7c3b4042c506b28fedf79a25501a0750d8140/selectolax-0.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbaac0b708e539358343305534be59cc47875f2b62b50b33af50f5a1ecf7bff2", size = 2347656, upload-time = "2026-05-04T15:09:11.128Z" }, - { url = "https://files.pythonhosted.org/packages/7f/c5/b141cd0f136a6a41d945869d27e303a96ee76e2feb70045b70754949dd65/selectolax-0.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dc2781ef2a6ac8aeed10f729aaafff056053e2430e0effa291a8cc74fdf2fdee", size = 2403976, upload-time = "2026-05-04T15:09:13.031Z" }, - { url = "https://files.pythonhosted.org/packages/40/a4/fb9830ab5973c957f28d651968d3d2e32729bb4e6e43cb313bd2c7b7a035/selectolax-0.4.8-cp311-cp311-win32.whl", hash = "sha256:ed66d2531b58ff7117c84f8d6d62d2d0d8a426f04d10ca45bd3744c7af71acd1", size = 1763669, upload-time = "2026-05-04T15:09:14.601Z" }, - { url = "https://files.pythonhosted.org/packages/74/c4/b8fadb6d43b7c1de1a703f4b064fb9eee65a8342bec0605cc65e02c68fdd/selectolax-0.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:f96959cecb10e70fd93e89e2c4522cfa671f5443427f4ccc12285604b6239c85", size = 1859140, upload-time = "2026-05-04T15:09:16.511Z" }, - { url = "https://files.pythonhosted.org/packages/06/60/2c38d657b6fcdbdb42eb0e37c87fc328f517c6890d6eb196cdb69ab32355/selectolax-0.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:787370345153cde7cd65f2271a00d7608b77993e1951f2f941a3c2ef92b942e0", size = 1811847, upload-time = "2026-05-04T15:09:18.095Z" }, { url = "https://files.pythonhosted.org/packages/12/3c/9cf255f11d04cf203b61f5a85fb273bc85778c3ab5d2ad98ce892f7df3b4/selectolax-0.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbcd4cb837dec4b16a3ab6a8b2ec4388ea20c050092b68536dc9a60ce8f19b56", size = 2236812, upload-time = "2026-05-04T15:09:20.193Z" }, { url = "https://files.pythonhosted.org/packages/9c/6b/4c343f767fa61131fc03b3de278dfcff024485996d7d6c917b55b0f9ce16/selectolax-0.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1cdcf946dd46e11640ca0a0361945c3ed65627ba4bd219ccf84a53fab28c072", size = 2287194, upload-time = "2026-05-04T15:09:22.15Z" }, { url = "https://files.pythonhosted.org/packages/9f/7d/5a47a0d102709297b6b09473a58c7e9727955a0d6e0c8eba9b27574e3680/selectolax-0.4.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:074254670a8a00b36202ab0cd99ce8fb2a25b3b2f10072891a35a6a85c53f679", size = 2369192, upload-time = "2026-05-04T15:09:23.768Z" }, @@ -5384,27 +4551,10 @@ name = "shapely" version = "2.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9", size = 315489, upload-time = "2025-09-24T13:51:41.432Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/89/c3548aa9b9812a5d143986764dededfa48d817714e947398bdda87c77a72/shapely-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7ae48c236c0324b4e139bea88a306a04ca630f49be66741b340729d380d8f52f", size = 1825959, upload-time = "2025-09-24T13:50:00.682Z" }, - { url = "https://files.pythonhosted.org/packages/ce/8a/7ebc947080442edd614ceebe0ce2cdbd00c25e832c240e1d1de61d0e6b38/shapely-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eba6710407f1daa8e7602c347dfc94adc02205ec27ed956346190d66579eb9ea", size = 1629196, upload-time = "2025-09-24T13:50:03.447Z" }, - { url = "https://files.pythonhosted.org/packages/c8/86/c9c27881c20d00fc409e7e059de569d5ed0abfcec9c49548b124ebddea51/shapely-2.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef4a456cc8b7b3d50ccec29642aa4aeda959e9da2fe9540a92754770d5f0cf1f", size = 2951065, upload-time = "2025-09-24T13:50:05.266Z" }, - { url = "https://files.pythonhosted.org/packages/50/8a/0ab1f7433a2a85d9e9aea5b1fbb333f3b09b309e7817309250b4b7b2cc7a/shapely-2.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e38a190442aacc67ff9f75ce60aec04893041f16f97d242209106d502486a142", size = 3058666, upload-time = "2025-09-24T13:50:06.872Z" }, - { url = "https://files.pythonhosted.org/packages/bb/c6/5a30ffac9c4f3ffd5b7113a7f5299ccec4713acd5ee44039778a7698224e/shapely-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:40d784101f5d06a1fd30b55fc11ea58a61be23f930d934d86f19a180909908a4", size = 3966905, upload-time = "2025-09-24T13:50:09.417Z" }, - { url = "https://files.pythonhosted.org/packages/9c/72/e92f3035ba43e53959007f928315a68fbcf2eeb4e5ededb6f0dc7ff1ecc3/shapely-2.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f6f6cd5819c50d9bcf921882784586aab34a4bd53e7553e175dece6db513a6f0", size = 4129260, upload-time = "2025-09-24T13:50:11.183Z" }, - { url = "https://files.pythonhosted.org/packages/42/24/605901b73a3d9f65fa958e63c9211f4be23d584da8a1a7487382fac7fdc5/shapely-2.1.2-cp310-cp310-win32.whl", hash = "sha256:fe9627c39c59e553c90f5bc3128252cb85dc3b3be8189710666d2f8bc3a5503e", size = 1544301, upload-time = "2025-09-24T13:50:12.521Z" }, - { url = "https://files.pythonhosted.org/packages/e1/89/6db795b8dd3919851856bd2ddd13ce434a748072f6fdee42ff30cbd3afa3/shapely-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:1d0bfb4b8f661b3b4ec3565fa36c340bfb1cda82087199711f86a88647d26b2f", size = 1722074, upload-time = "2025-09-24T13:50:13.909Z" }, - { url = "https://files.pythonhosted.org/packages/8f/8d/1ff672dea9ec6a7b5d422eb6d095ed886e2e523733329f75fdcb14ee1149/shapely-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91121757b0a36c9aac3427a651a7e6567110a4a67c97edf04f8d55d4765f6618", size = 1820038, upload-time = "2025-09-24T13:50:15.628Z" }, - { url = "https://files.pythonhosted.org/packages/4f/ce/28fab8c772ce5db23a0d86bf0adaee0c4c79d5ad1db766055fa3dab442e2/shapely-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:16a9c722ba774cf50b5d4541242b4cce05aafd44a015290c82ba8a16931ff63d", size = 1626039, upload-time = "2025-09-24T13:50:16.881Z" }, - { url = "https://files.pythonhosted.org/packages/70/8b/868b7e3f4982f5006e9395c1e12343c66a8155c0374fdc07c0e6a1ab547d/shapely-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cc4f7397459b12c0b196c9efe1f9d7e92463cbba142632b4cc6d8bbbbd3e2b09", size = 3001519, upload-time = "2025-09-24T13:50:18.606Z" }, - { url = "https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:136ab87b17e733e22f0961504d05e77e7be8c9b5a8184f685b4a91a84efe3c26", size = 3110842, upload-time = "2025-09-24T13:50:21.77Z" }, - { url = "https://files.pythonhosted.org/packages/af/61/8e389c97994d5f331dcffb25e2fa761aeedfb52b3ad9bcdd7b8671f4810a/shapely-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:16c5d0fc45d3aa0a69074979f4f1928ca2734fb2e0dde8af9611e134e46774e7", size = 4021316, upload-time = "2025-09-24T13:50:23.626Z" }, - { url = "https://files.pythonhosted.org/packages/d3/d4/9b2a9fe6039f9e42ccf2cb3e84f219fd8364b0c3b8e7bbc857b5fbe9c14c/shapely-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ddc759f72b5b2b0f54a7e7cde44acef680a55019eb52ac63a7af2cf17cb9cd2", size = 4178586, upload-time = "2025-09-24T13:50:25.443Z" }, - { url = "https://files.pythonhosted.org/packages/16/f6/9840f6963ed4decf76b08fd6d7fed14f8779fb7a62cb45c5617fa8ac6eab/shapely-2.1.2-cp311-cp311-win32.whl", hash = "sha256:2fa78b49485391224755a856ed3b3bd91c8455f6121fee0db0e71cefb07d0ef6", size = 1543961, upload-time = "2025-09-24T13:50:26.968Z" }, - { url = "https://files.pythonhosted.org/packages/38/1e/3f8ea46353c2a33c1669eb7327f9665103aa3a8dfe7f2e4ef714c210b2c2/shapely-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:c64d5c97b2f47e3cd9b712eaced3b061f2b71234b3fc263e0fcf7d889c6559dc", size = 1722856, upload-time = "2025-09-24T13:50:28.497Z" }, { url = "https://files.pythonhosted.org/packages/24/c0/f3b6453cf2dfa99adc0ba6675f9aaff9e526d2224cbd7ff9c1a879238693/shapely-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe2533caae6a91a543dec62e8360fe86ffcdc42a7c55f9dfd0128a977a896b94", size = 1833550, upload-time = "2025-09-24T13:50:30.019Z" }, { url = "https://files.pythonhosted.org/packages/86/07/59dee0bc4b913b7ab59ab1086225baca5b8f19865e6101db9ebb7243e132/shapely-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ba4d1333cc0bc94381d6d4308d2e4e008e0bd128bdcff5573199742ee3634359", size = 1643556, upload-time = "2025-09-24T13:50:32.291Z" }, { url = "https://files.pythonhosted.org/packages/26/29/a5397e75b435b9895cd53e165083faed5d12fd9626eadec15a83a2411f0f/shapely-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bd308103340030feef6c111d3eb98d50dc13feea33affc8a6f9fa549e9458a3", size = 2988308, upload-time = "2025-09-24T13:50:33.862Z" }, @@ -5492,6 +4642,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, ] +[[package]] +name = "structlog" +version = "25.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/52/9ba0f43b686e7f3ddfeaa78ac3af750292662284b3661e91ad5494f21dbc/structlog-25.5.0.tar.gz", hash = "sha256:098522a3bebed9153d4570c6d0288abf80a031dfdb2048d59a49e9dc2190fc98", size = 1460830, upload-time = "2025-10-27T08:28:23.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl", hash = "sha256:a8453e9b9e636ec59bd9e79bbd4a72f025981b3ba0f5837aebf48f02f37a7f9f", size = 72510, upload-time = "2025-10-27T08:28:21.535Z" }, +] + [[package]] name = "sympy" version = "1.14.0" @@ -5515,22 +4674,21 @@ wheels = [ [[package]] name = "temporalio" -version = "1.23.0" +version = "1.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, - { name = "python-dateutil", marker = "python_full_version < '3.11'" }, { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/67/48/ba7413e2fab8dcd277b9df00bafa572da24e9ca32de2f38d428dc3a2825c/temporalio-1.23.0.tar.gz", hash = "sha256:72750494b00eb73ded9db76195e3a9b53ff548780f73d878ec3f807ee3191410", size = 1933051, upload-time = "2026-02-18T17:48:22.353Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/b1/7d9b3104ab7994e7d49e765b92495aaff44810b1e066c874c284a93ebd55/temporalio-1.24.0.tar.gz", hash = "sha256:e534e2e71b4a721193ec4ff3dae521146d093554bd47a64f5605d4ca33e56718", size = 2040485, upload-time = "2026-03-23T15:33:33.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/71/26c8f21dca9092201b3b9cb7aff42460b4864b5999aa4c6a4343ac66f1fd/temporalio-1.23.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6b69ac8d75f2d90e66f4edce4316f6a33badc4a30b22efc50e9eddaa9acdc216", size = 12311037, upload-time = "2026-02-18T17:47:47.628Z" }, - { url = "https://files.pythonhosted.org/packages/ec/47/43102816139f2d346680cb7cc1e53da5f6968355ac65b4d35d4edbfca896/temporalio-1.23.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:1bbbb2f9c3cdd09451565163f6d741e51f109694c49435d475fdfa42b597219d", size = 11821906, upload-time = "2026-02-18T17:47:55.314Z" }, - { url = "https://files.pythonhosted.org/packages/00/b0/899ff28464a0e17adf17476bdfac8faf4ea41870358ff2d14737e43f9e66/temporalio-1.23.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf6570e0ee696f99a38d855da4441a890c7187357c16505ed458ac9ef274ed70", size = 12063601, upload-time = "2026-02-18T17:48:03.994Z" }, - { url = "https://files.pythonhosted.org/packages/ed/17/b8c6d2ec3e113c6a788322513a5ff635bdd54b3791d092ed0e273467748a/temporalio-1.23.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b82d6cca54c9f376b50e941dd10d12f7fe5b692a314fb087be72cd2898646a79", size = 12394579, upload-time = "2026-02-18T17:48:11.65Z" }, - { url = "https://files.pythonhosted.org/packages/b4/b7/f9ef7fd5ee65aef7d59ab1e95cb1b45df2fe49c17e3aa4d650ae3322f015/temporalio-1.23.0-cp310-abi3-win_amd64.whl", hash = "sha256:43c3b99a46dd329761a256f3855710c4a5b322afc879785e468bdd0b94faace6", size = 12834494, upload-time = "2026-02-18T17:48:19.071Z" }, + { url = "https://files.pythonhosted.org/packages/84/a9/30517c21d6155bce1c3dc0e420db48da0231230dbc683f40ab6d5fe22b37/temporalio-1.24.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:7f11e7b4f4d09bafba499b43188353e23dc128b1fe3f3160014476e3dce70760", size = 12223918, upload-time = "2026-03-23T15:33:05.045Z" }, + { url = "https://files.pythonhosted.org/packages/73/d0/11aa103bde794524008c1850a84e06cde98698395ca1f8b12e1bd2390aa8/temporalio-1.24.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:5cff75a0ca922575b808a7fca1b0de38f6eea061f49e026664b8be9d5bb06ab8", size = 11708887, upload-time = "2026-03-23T15:33:11.67Z" }, + { url = "https://files.pythonhosted.org/packages/1d/f4/774b56100e6bb94e3757ec96fb5c2bc62d42defc7d6de0ee35a12273827a/temporalio-1.24.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee7c13b6724dd0c304aa846aecf6da72a8550f4ade40a0a7f6dcc1c92ef35710", size = 12028303, upload-time = "2026-03-23T15:33:18.022Z" }, + { url = "https://files.pythonhosted.org/packages/e5/91/c05d0e9c2432fe8b1ea0d6fae321866ee49a320ad5e494e6ec9424ca5c28/temporalio-1.24.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa71b9bfa42f951dd04ade97ce7f92ecedee8903047b4b41b122bb8cbd87a337", size = 12375155, upload-time = "2026-03-23T15:33:24.234Z" }, + { url = "https://files.pythonhosted.org/packages/c4/97/5c939e4609c164c8690a3b5a135eb828d531de8ef63ff447a2a439c0b0fb/temporalio-1.24.0-cp310-abi3-win_amd64.whl", hash = "sha256:52f6833647eceddbebcc376e2ea663a9f73b2b3a42675f503aeb27c98fd4daeb", size = 12720174, upload-time = "2026-03-23T15:33:30.826Z" }, ] [[package]] @@ -5575,10 +4733,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, - { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301, upload-time = "2026-01-05T10:40:34.858Z" }, - { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" }, - { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" }, - { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, ] [[package]] @@ -5587,15 +4741,6 @@ version = "2.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, - { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, - { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, - { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, - { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, - { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, - { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, - { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, @@ -5654,8 +4799,7 @@ dependencies = [ { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "networkx" }, { name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" }, { name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" }, @@ -5666,14 +4810,6 @@ dependencies = [ { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/f2/c1690994afe461aae2d0cac62251e6802a703dec0a6c549c02ecd0de92a9/torch-2.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2c0d7fcfbc0c4e8bb5ebc3907cbc0c6a0da1b8f82b1fc6e14e914fa0b9baf74e", size = 80526521, upload-time = "2026-03-23T18:12:06.86Z" }, - { url = "https://files.pythonhosted.org/packages/a4/f0/98ae802fa8c09d3149b0c8690741f3f5753c90e779bd28c9613257295945/torch-2.11.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:4cf8687f4aec3900f748d553483ef40e0ac38411c3c48d0a86a438f6d7a99b18", size = 419723025, upload-time = "2026-03-23T18:11:43.774Z" }, - { url = "https://files.pythonhosted.org/packages/f9/1e/18a9b10b4bd34f12d4e561c52b0ae7158707b8193c6cfc0aad2b48167090/torch-2.11.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1b32ceda909818a03b112006709b02be1877240c31750a8d9c6b7bf5f2d8a6e5", size = 530589207, upload-time = "2026-03-23T18:11:23.756Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/2d532e8c0e23705be9d1debce5bc37b68d59a39bda7584c26fe9668076fe/torch-2.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:b3c712ae6fb8e7a949051a953fc412fe0a6940337336c3b6f905e905dac5157f", size = 114518313, upload-time = "2026-03-23T18:11:58.281Z" }, - { url = "https://files.pythonhosted.org/packages/ae/0d/98b410492609e34a155fa8b121b55c7dca229f39636851c3a9ec20edea21/torch-2.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7b6a60d48062809f58595509c524b88e6ddec3ebe25833d6462eeab81e5f2ce4", size = 80529712, upload-time = "2026-03-23T18:12:02.608Z" }, - { url = "https://files.pythonhosted.org/packages/84/03/acea680005f098f79fd70c1d9d5ccc0cb4296ec2af539a0450108232fc0c/torch-2.11.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:d91aac77f24082809d2c5a93f52a5f085032740a1ebc9252a7b052ef5a4fddc6", size = 419718178, upload-time = "2026-03-23T18:10:46.675Z" }, - { url = "https://files.pythonhosted.org/packages/8c/8b/d7be22fbec9ffee6cff31a39f8750d4b3a65d349a286cf4aec74c2375662/torch-2.11.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7aa2f9bbc6d4595ba72138026b2074be1233186150e9292865e04b7a63b8c67a", size = 530604548, upload-time = "2026-03-23T18:10:03.569Z" }, - { url = "https://files.pythonhosted.org/packages/d1/bd/9912d30b68845256aabbb4a40aeefeef3c3b20db5211ccda653544ada4b6/torch-2.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:73e24aaf8f36ab90d95cd1761208b2eb70841c2a9ca1a3f9061b39fc5331b708", size = 114519675, upload-time = "2026-03-23T18:11:52.995Z" }, { url = "https://files.pythonhosted.org/packages/6f/8b/69e3008d78e5cee2b30183340cc425081b78afc5eff3d080daab0adda9aa/torch-2.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b5866312ee6e52ea625cd211dcb97d6a2cdc1131a5f15cc0d87eec948f6dd34", size = 80606338, upload-time = "2026-03-23T18:11:34.781Z" }, { url = "https://files.pythonhosted.org/packages/13/16/42e5915ebe4868caa6bac83a8ed59db57f12e9a61b7d749d584776ed53d5/torch-2.11.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f99924682ef0aa6a4ab3b1b76f40dc6e273fca09f367d15a524266db100a723f", size = 419731115, upload-time = "2026-03-23T18:11:06.944Z" }, { url = "https://files.pythonhosted.org/packages/1a/c9/82638ef24d7877510f83baf821f5619a61b45568ce21c0a87a91576510aa/torch-2.11.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:0f68f4ac6d95d12e896c3b7a912b5871619542ec54d3649cf48cc1edd4dd2756", size = 530712279, upload-time = "2026-03-23T18:10:31.481Z" }, @@ -5701,20 +4837,11 @@ name = "torchvision" version = "0.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "pillow" }, { name = "torch" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/74/b4/cdfee31e0402ea035135462cb0ab496e974d56fab6b4e7a1f0cbccb8cd28/torchvision-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a06d4772a8e13e772906ed736cc53ec6639e5e60554f8e5fa6ca165aabebc464", size = 1863503, upload-time = "2026-03-23T18:13:01.384Z" }, - { url = "https://files.pythonhosted.org/packages/e4/74/11fee109841e80ad14e5ca2d80bff6b10eb11b7838ff06f35bfeaa9f7251/torchvision-0.26.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:2adfbe438473236191ff077a4a9a0c767436879c89628aa97137e959b0c11a94", size = 7766423, upload-time = "2026-03-23T18:12:56.049Z" }, - { url = "https://files.pythonhosted.org/packages/5e/00/24d8c7845c3f270153fb81395a5135b2778e2538e81d14c6aea5106c689c/torchvision-0.26.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b6f9ad1ecc0eab52647298b379ee9426845f8903703e6127973f8f3d049a798b", size = 7518249, upload-time = "2026-03-23T18:12:51.743Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ed/e53cd7c0da7ae002e5e929c1796ebbe7ec0c700c29f7a0a6696497fb3d8b/torchvision-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:f13f12b3791a266de2d599cb8162925261622a037d87fc03132848343cf68f75", size = 3669784, upload-time = "2026-03-23T18:12:49.949Z" }, - { url = "https://files.pythonhosted.org/packages/b4/bd/d552a2521bade3295b2c6e7a4a0d1022261cab7ca7011f4e2a330dbb3caa/torchvision-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55bd6ad4ae77be01ba67a410b05b51f53b0d0ee45f146eb6a0dfb9007e70ab3c", size = 1863499, upload-time = "2026-03-23T18:12:58.696Z" }, - { url = "https://files.pythonhosted.org/packages/33/bf/21b899792b08cae7a298551c68398a79e333697479ed311b3b067aab4bdc/torchvision-0.26.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:1c55dc8affbcc0eb2060fbabbe996ae9e5839b24bb6419777f17848945a411b1", size = 7767527, upload-time = "2026-03-23T18:12:44.348Z" }, - { url = "https://files.pythonhosted.org/packages/9a/45/57bbf9e216850d065e66dd31a50f57424b607f1d878ab8956e56a1f4e36b/torchvision-0.26.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fd10b5f994c210f4f6d6761cf686f82d748554adf486cb0979770c3252868c8f", size = 7519925, upload-time = "2026-03-23T18:12:53.283Z" }, - { url = "https://files.pythonhosted.org/packages/10/58/ed8f7754299f3e91d6414b6dc09f62b3fa7c6e5d63dfe48d69ab81498a37/torchvision-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:de6424b12887ad884f39a0ee446994ae3cd3b6a00a9cafe1bead85a031132af0", size = 3983834, upload-time = "2026-03-23T18:13:00.224Z" }, { url = "https://files.pythonhosted.org/packages/ae/e7/56b47cc3b132aea90ccce22bcb8975dec688b002150012acc842846039d0/torchvision-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c409e1c3fdebec7a3834465086dbda8bf7680eff79abf7fd2f10c6b59520a7a4", size = 1863502, upload-time = "2026-03-23T18:12:57.326Z" }, { url = "https://files.pythonhosted.org/packages/f4/ec/5c31c92c08b65662fe9604a4067ae8232582805949f11ddc042cebe818ed/torchvision-0.26.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:406557718e62fdf10f5706e88d8a5ec000f872da913bf629aab9297622585547", size = 7767944, upload-time = "2026-03-23T18:12:42.805Z" }, { url = "https://files.pythonhosted.org/packages/f5/d8/cb6ccda1a1f35a6597645818641701207b3e8e13553e75fce5d86bac74b2/torchvision-0.26.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d61a5abb6b42a0c0c311996c2ac4b83a94418a97182c83b055a2a4ae985e05aa", size = 7522205, upload-time = "2026-03-23T18:12:54.654Z" }, @@ -5756,8 +4883,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "huggingface-hub" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, { name = "packaging" }, { name = "pyyaml" }, { name = "regex" }, @@ -5777,20 +4903,6 @@ version = "0.25.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/66/7c/0350cfc47faadc0d3cf7d8237a4e34032b3014ddf4a12ded9933e1648b55/tree-sitter-0.25.2.tar.gz", hash = "sha256:fe43c158555da46723b28b52e058ad444195afd1db3ca7720c59a254544e9c20", size = 177961, upload-time = "2025-09-25T17:37:59.751Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/d4/f7ffb855cb039b7568aba4911fbe42e4c39c0e4398387c8e0d8251489992/tree_sitter-0.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72a510931c3c25f134aac2daf4eb4feca99ffe37a35896d7150e50ac3eee06c7", size = 146749, upload-time = "2025-09-25T17:37:16.475Z" }, - { url = "https://files.pythonhosted.org/packages/9a/58/f8a107f9f89700c0ab2930f1315e63bdedccbb5fd1b10fcbc5ebadd54ac8/tree_sitter-0.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:44488e0e78146f87baaa009736886516779253d6d6bac3ef636ede72bc6a8234", size = 137766, upload-time = "2025-09-25T17:37:18.138Z" }, - { url = "https://files.pythonhosted.org/packages/19/fb/357158d39f01699faea466e8fd5a849f5a30252c68414bddc20357a9ac79/tree_sitter-0.25.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2f8e7d6b2f8489d4a9885e3adcaef4bc5ff0a275acd990f120e29c4ab3395c5", size = 599809, upload-time = "2025-09-25T17:37:19.169Z" }, - { url = "https://files.pythonhosted.org/packages/c5/a4/68ae301626f2393a62119481cb660eb93504a524fc741a6f1528a4568cf6/tree_sitter-0.25.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20b570690f87f1da424cd690e51cc56728d21d63f4abd4b326d382a30353acc7", size = 627676, upload-time = "2025-09-25T17:37:20.715Z" }, - { url = "https://files.pythonhosted.org/packages/69/fe/4c1bef37db5ca8b17ca0b3070f2dff509468a50b3af18f17665adcab42b9/tree_sitter-0.25.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a0ec41b895da717bc218a42a3a7a0bfcfe9a213d7afaa4255353901e0e21f696", size = 624281, upload-time = "2025-09-25T17:37:21.823Z" }, - { url = "https://files.pythonhosted.org/packages/d4/30/3283cb7fa251cae2a0bf8661658021a789810db3ab1b0569482d4a3671fd/tree_sitter-0.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:7712335855b2307a21ae86efe949c76be36c6068d76df34faa27ce9ee40ff444", size = 127295, upload-time = "2025-09-25T17:37:22.977Z" }, - { url = "https://files.pythonhosted.org/packages/88/90/ceb05e6de281aebe82b68662890619580d4ffe09283ebd2ceabcf5df7b4a/tree_sitter-0.25.2-cp310-cp310-win_arm64.whl", hash = "sha256:a925364eb7fbb9cdce55a9868f7525a1905af512a559303bd54ef468fd88cb37", size = 113991, upload-time = "2025-09-25T17:37:23.854Z" }, - { url = "https://files.pythonhosted.org/packages/7c/22/88a1e00b906d26fa8a075dd19c6c3116997cb884bf1b3c023deb065a344d/tree_sitter-0.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ca72d841215b6573ed0655b3a5cd1133f9b69a6fa561aecad40dca9029d75b", size = 146752, upload-time = "2025-09-25T17:37:24.775Z" }, - { url = "https://files.pythonhosted.org/packages/57/1c/22cc14f3910017b7a76d7358df5cd315a84fe0c7f6f7b443b49db2e2790d/tree_sitter-0.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc0351cfe5022cec5a77645f647f92a936b38850346ed3f6d6babfbeeeca4d26", size = 137765, upload-time = "2025-09-25T17:37:26.103Z" }, - { url = "https://files.pythonhosted.org/packages/1c/0c/d0de46ded7d5b34631e0f630d9866dab22d3183195bf0f3b81de406d6622/tree_sitter-0.25.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1799609636c0193e16c38f366bda5af15b1ce476df79ddaae7dd274df9e44266", size = 604643, upload-time = "2025-09-25T17:37:27.398Z" }, - { url = "https://files.pythonhosted.org/packages/34/38/b735a58c1c2f60a168a678ca27b4c1a9df725d0bf2d1a8a1c571c033111e/tree_sitter-0.25.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e65ae456ad0d210ee71a89ee112ac7e72e6c2e5aac1b95846ecc7afa68a194c", size = 632229, upload-time = "2025-09-25T17:37:28.463Z" }, - { url = "https://files.pythonhosted.org/packages/32/f6/cda1e1e6cbff5e28d8433578e2556d7ba0b0209d95a796128155b97e7693/tree_sitter-0.25.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:49ee3c348caa459244ec437ccc7ff3831f35977d143f65311572b8ba0a5f265f", size = 629861, upload-time = "2025-09-25T17:37:29.593Z" }, - { url = "https://files.pythonhosted.org/packages/f9/19/427e5943b276a0dd74c2a1f1d7a7393443f13d1ee47dedb3f8127903c080/tree_sitter-0.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:56ac6602c7d09c2c507c55e58dc7026b8988e0475bd0002f8a386cce5e8e8adc", size = 127304, upload-time = "2025-09-25T17:37:30.549Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d9/eef856dc15f784d85d1397a17f3ee0f82df7778efce9e1961203abfe376a/tree_sitter-0.25.2-cp311-cp311-win_arm64.whl", hash = "sha256:b3d11a3a3ac89bb8a2543d75597f905a9926f9c806f40fcca8242922d1cc6ad5", size = 113990, upload-time = "2025-09-25T17:37:31.852Z" }, { url = "https://files.pythonhosted.org/packages/3c/9e/20c2a00a862f1c2897a436b17edb774e831b22218083b459d0d081c9db33/tree_sitter-0.25.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ddabfff809ffc983fc9963455ba1cecc90295803e06e140a4c83e94c1fa3d960", size = 146941, upload-time = "2025-09-25T17:37:34.813Z" }, { url = "https://files.pythonhosted.org/packages/ef/04/8512e2062e652a1016e840ce36ba1cc33258b0dcc4e500d8089b4054afec/tree_sitter-0.25.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c0c0ab5f94938a23fe81928a21cc0fac44143133ccc4eb7eeb1b92f84748331c", size = 137699, upload-time = "2025-09-25T17:37:36.349Z" }, { url = "https://files.pythonhosted.org/packages/47/8a/d48c0414db19307b0fb3bb10d76a3a0cbe275bb293f145ee7fba2abd668e/tree_sitter-0.25.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dd12d80d91d4114ca097626eb82714618dcdfacd6a5e0955216c6485c350ef99", size = 607125, upload-time = "2025-09-25T17:37:37.725Z" }, @@ -5882,10 +4994,6 @@ name = "triton" version = "3.6.0" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/ba/b1b04f4b291a3205d95ebd24465de0e5bf010a2df27a4e58a9b5f039d8f2/triton-3.6.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c723cfb12f6842a0ae94ac307dba7e7a44741d720a40cf0e270ed4a4e3be781", size = 175972180, upload-time = "2026-01-20T16:15:53.664Z" }, - { url = "https://files.pythonhosted.org/packages/8c/f7/f1c9d3424ab199ac53c2da567b859bcddbb9c9e7154805119f8bd95ec36f/triton-3.6.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6550fae429e0667e397e5de64b332d1e5695b73650ee75a6146e2e902770bea", size = 188105201, upload-time = "2026-01-20T16:00:29.272Z" }, - { url = "https://files.pythonhosted.org/packages/0f/2c/96f92f3c60387e14cc45aed49487f3486f89ea27106c1b1376913c62abe4/triton-3.6.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49df5ef37379c0c2b5c0012286f80174fcf0e073e5ade1ca9a86c36814553651", size = 176081190, upload-time = "2026-01-20T16:16:00.523Z" }, - { url = "https://files.pythonhosted.org/packages/e0/12/b05ba554d2c623bffa59922b94b0775673de251f468a9609bc9e45de95e9/triton-3.6.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8e323d608e3a9bfcc2d9efcc90ceefb764a82b99dea12a86d643c72539ad5d3", size = 188214640, upload-time = "2026-01-20T16:00:35.869Z" }, { url = "https://files.pythonhosted.org/packages/17/5d/08201db32823bdf77a0e2b9039540080b2e5c23a20706ddba942924ebcd6/triton-3.6.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:374f52c11a711fd062b4bfbb201fd9ac0a5febd28a96fb41b4a0f51dde3157f4", size = 176128243, upload-time = "2026-01-20T16:16:07.857Z" }, { url = "https://files.pythonhosted.org/packages/ab/a8/cdf8b3e4c98132f965f88c2313a4b493266832ad47fb52f23d14d4f86bb5/triton-3.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74caf5e34b66d9f3a429af689c1c7128daba1d8208df60e81106b115c00d6fca", size = 188266850, upload-time = "2026-01-20T16:00:43.041Z" }, { url = "https://files.pythonhosted.org/packages/3c/12/34d71b350e89a204c2c7777a9bba0dcf2f19a5bfdd70b57c4dbc5ffd7154/triton-3.6.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448e02fe6dc898e9e5aa89cf0ee5c371e99df5aa5e8ad976a80b93334f3494fd", size = 176133521, upload-time = "2026-01-20T16:16:13.321Z" }, @@ -5933,7 +5041,6 @@ dependencies = [ { name = "botocore-stubs" }, { name = "types-aiobotocore" }, { name = "types-s3transfer" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/76/e162ea2ef8d414d4f36f28a6e0b6078ccef3f2f9d5f957859f303995c528/types_aioboto3-15.5.0.tar.gz", hash = "sha256:5769a1c3df7ca1abedf3656ddf0b970c9b0436d0f88cf4686040b55cd2a02925", size = 81059, upload-time = "2025-10-31T01:11:54.445Z" } wheels = [ @@ -5954,7 +5061,6 @@ version = "3.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore-stubs" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/e4/5dd83c879eff726931ef222d3ae27f67999c3bc33dfae1ca8237ebccdf17/types_aiobotocore-3.6.0.tar.gz", hash = "sha256:e990056ce9d19094a9d9b36008ca0b2a4d69948ff58f50868dd159a81f6ad69c", size = 87978, upload-time = "2026-05-02T03:05:30.694Z" } wheels = [ @@ -5965,9 +5071,6 @@ wheels = [ name = "types-aiobotocore-bedrock" version = "2.25.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/69/99/b986a2dcd19828b7d79d237d9c6154327bfcc4fd6126b67ea6343322a8b5/types_aiobotocore_bedrock-2.25.2.tar.gz", hash = "sha256:524043f7cf95d4670706b05d48835d8ad3e401fa4095000d107ca444ea3c4e7f", size = 59660, upload-time = "2025-11-12T01:42:00.672Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d3/1d32ce456037008fa0878832f80347d029887a7ea20922745f003def4ab9/types_aiobotocore_bedrock-2.25.2-py3-none-any.whl", hash = "sha256:d06ebd7a8e8ffe22567719136bd73b9a804f77bd83ec7ad02a8077438c5436d3", size = 67366, upload-time = "2025-11-12T01:41:59.369Z" }, @@ -5977,9 +5080,6 @@ wheels = [ name = "types-aiobotocore-bedrock-runtime" version = "2.25.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, -] sdist = { url = "https://files.pythonhosted.org/packages/54/af/47f695dd846b3898feb0a858020ac86f088c65826d0d60f9680a1177837d/types_aiobotocore_bedrock_runtime-2.25.2.tar.gz", hash = "sha256:7068ac2f4cda13852739db2dc822ef7498c6fe81fc031b496dc35bdcb7cc44f3", size = 28451, upload-time = "2025-11-12T01:42:02.961Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/01/ba/baeb40c98b0a2be60b5e6c704ed16646f6981618a543087832877aa7b170/types_aiobotocore_bedrock_runtime-2.25.2-py3-none-any.whl", hash = "sha256:8a2e881e0922c6866b5fac1835abfa8b623a2046db9125ea20e2832248ed55a0", size = 34804, upload-time = "2025-11-12T01:42:01.759Z" }, @@ -6017,8 +5117,7 @@ name = "types-networkx" version = "3.6.1.20260408" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/06/fe448df6a42cc938d36fa6e88cb0c6a269059cd4ce05347ec52da306e007/types_networkx-3.6.1.20260408.tar.gz", hash = "sha256:63f94902b2d99d6d4f448eb1bc23b8a327d4022f5098bc0d22d42b13003b106e", size = 73828, upload-time = "2026-04-08T04:34:38.471Z" } wheels = [ @@ -6118,20 +5217,12 @@ version = "6.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, - { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, - { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, - { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, - { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, - { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, - { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, - { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, @@ -6150,24 +5241,6 @@ version = "16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" }, - { url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" }, - { url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" }, - { url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" }, - { url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" }, - { url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" }, - { url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" }, - { url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" }, - { url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" }, - { url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" }, - { url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" }, - { url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" }, { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, @@ -6204,11 +5277,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, - { url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" }, - { url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" }, - { url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" }, - { url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" }, { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] @@ -6230,26 +5298,6 @@ version = "1.17.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/23/bb82321b86411eb51e5a5db3fb8f8032fd30bd7c2d74bfe936136b2fa1d6/wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04", size = 53482, upload-time = "2025-08-12T05:51:44.467Z" }, - { url = "https://files.pythonhosted.org/packages/45/69/f3c47642b79485a30a59c63f6d739ed779fb4cc8323205d047d741d55220/wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2", size = 38676, upload-time = "2025-08-12T05:51:32.636Z" }, - { url = "https://files.pythonhosted.org/packages/d1/71/e7e7f5670c1eafd9e990438e69d8fb46fa91a50785332e06b560c869454f/wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c", size = 38957, upload-time = "2025-08-12T05:51:54.655Z" }, - { url = "https://files.pythonhosted.org/packages/de/17/9f8f86755c191d6779d7ddead1a53c7a8aa18bccb7cea8e7e72dfa6a8a09/wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775", size = 81975, upload-time = "2025-08-12T05:52:30.109Z" }, - { url = "https://files.pythonhosted.org/packages/f2/15/dd576273491f9f43dd09fce517f6c2ce6eb4fe21681726068db0d0467096/wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd", size = 83149, upload-time = "2025-08-12T05:52:09.316Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c4/5eb4ce0d4814521fee7aa806264bf7a114e748ad05110441cd5b8a5c744b/wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05", size = 82209, upload-time = "2025-08-12T05:52:10.331Z" }, - { url = "https://files.pythonhosted.org/packages/31/4b/819e9e0eb5c8dc86f60dfc42aa4e2c0d6c3db8732bce93cc752e604bb5f5/wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418", size = 81551, upload-time = "2025-08-12T05:52:31.137Z" }, - { url = "https://files.pythonhosted.org/packages/f8/83/ed6baf89ba3a56694700139698cf703aac9f0f9eb03dab92f57551bd5385/wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390", size = 36464, upload-time = "2025-08-12T05:53:01.204Z" }, - { url = "https://files.pythonhosted.org/packages/2f/90/ee61d36862340ad7e9d15a02529df6b948676b9a5829fd5e16640156627d/wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6", size = 38748, upload-time = "2025-08-12T05:53:00.209Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c3/cefe0bd330d389c9983ced15d326f45373f4073c9f4a8c2f99b50bfea329/wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18", size = 36810, upload-time = "2025-08-12T05:52:51.906Z" }, - { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, - { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, - { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, - { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, - { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, - { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, - { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, - { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, @@ -6322,42 +5370,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0d/9cc638702f6fc3c7a3685bcc8cf2a9ed7d6206e932a49f5242658047ef51/yarl-1.23.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107", size = 123764, upload-time = "2026-03-01T22:04:09.7Z" }, - { url = "https://files.pythonhosted.org/packages/7a/35/5a553687c5793df5429cd1db45909d4f3af7eee90014888c208d086a44f0/yarl-1.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d", size = 86282, upload-time = "2026-03-01T22:04:11.892Z" }, - { url = "https://files.pythonhosted.org/packages/68/2e/c5a2234238f8ce37a8312b52801ee74117f576b1539eec8404a480434acc/yarl-1.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05", size = 86053, upload-time = "2026-03-01T22:04:13.292Z" }, - { url = "https://files.pythonhosted.org/packages/74/3f/bbd8ff36fb038622797ffbaf7db314918bb4d76f1cc8a4f9ca7a55fe5195/yarl-1.23.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d", size = 99395, upload-time = "2026-03-01T22:04:15.133Z" }, - { url = "https://files.pythonhosted.org/packages/77/04/9516bc4e269d2a3ec9c6779fcdeac51ce5b3a9b0156f06ac7152e5bba864/yarl-1.23.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748", size = 92143, upload-time = "2026-03-01T22:04:16.829Z" }, - { url = "https://files.pythonhosted.org/packages/c7/63/88802d1f6b1cb1fc67d67a58cd0cf8a1790de4ce7946e434240f1d60ab4a/yarl-1.23.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764", size = 107643, upload-time = "2026-03-01T22:04:18.519Z" }, - { url = "https://files.pythonhosted.org/packages/8e/db/4f9b838f4d8bdd6f0f385aed8bbf21c71ed11a0b9983305c302cbd557815/yarl-1.23.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007", size = 108700, upload-time = "2026-03-01T22:04:20.373Z" }, - { url = "https://files.pythonhosted.org/packages/50/12/95a1d33f04a79c402664070d43b8b9f72dc18914e135b345b611b0b1f8cc/yarl-1.23.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4", size = 102769, upload-time = "2026-03-01T22:04:23.055Z" }, - { url = "https://files.pythonhosted.org/packages/86/65/91a0285f51321369fd1a8308aa19207520c5f0587772cfc2e03fc2467e90/yarl-1.23.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26", size = 101114, upload-time = "2026-03-01T22:04:25.031Z" }, - { url = "https://files.pythonhosted.org/packages/58/80/c7c8244fc3e5bc483dc71a09560f43b619fab29301a0f0a8f936e42865c7/yarl-1.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769", size = 98883, upload-time = "2026-03-01T22:04:27.281Z" }, - { url = "https://files.pythonhosted.org/packages/86/e7/71ca9cc9ca79c0b7d491216177d1aed559d632947b8ffb0ee60f7d8b23e3/yarl-1.23.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716", size = 94172, upload-time = "2026-03-01T22:04:28.554Z" }, - { url = "https://files.pythonhosted.org/packages/6a/3f/6c6c8a0fe29c26fb2db2e8d32195bb84ec1bfb8f1d32e7f73b787fcf349b/yarl-1.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993", size = 107010, upload-time = "2026-03-01T22:04:30.385Z" }, - { url = "https://files.pythonhosted.org/packages/56/38/12730c05e5ad40a76374d440ed8b0899729a96c250516d91c620a6e38fc2/yarl-1.23.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0", size = 100285, upload-time = "2026-03-01T22:04:31.752Z" }, - { url = "https://files.pythonhosted.org/packages/34/92/6a7be9239f2347234e027284e7a5f74b1140cc86575e7b469d13fba1ebfe/yarl-1.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750", size = 108230, upload-time = "2026-03-01T22:04:33.844Z" }, - { url = "https://files.pythonhosted.org/packages/5e/81/4aebccfa9376bd98b9d8bfad20621a57d3e8cfc5b8631c1fa5f62cdd03f4/yarl-1.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6", size = 103008, upload-time = "2026-03-01T22:04:35.856Z" }, - { url = "https://files.pythonhosted.org/packages/38/0f/0b4e3edcec794a86b853b0c6396c0a888d72dfce19b2d88c02ac289fb6c1/yarl-1.23.0-cp310-cp310-win32.whl", hash = "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d", size = 83073, upload-time = "2026-03-01T22:04:38.268Z" }, - { url = "https://files.pythonhosted.org/packages/a0/71/ad95c33da18897e4c636528bbc24a1dd23fe16797de8bc4ec667b8db0ba4/yarl-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb", size = 87328, upload-time = "2026-03-01T22:04:39.558Z" }, - { url = "https://files.pythonhosted.org/packages/e2/14/dfa369523c79bccf9c9c746b0a63eb31f65db9418ac01275f7950962e504/yarl-1.23.0-cp310-cp310-win_arm64.whl", hash = "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220", size = 82463, upload-time = "2026-03-01T22:04:41.454Z" }, - { url = "https://files.pythonhosted.org/packages/a2/aa/60da938b8f0997ba3a911263c40d82b6f645a67902a490b46f3355e10fae/yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", size = 123641, upload-time = "2026-03-01T22:04:42.841Z" }, - { url = "https://files.pythonhosted.org/packages/24/84/e237607faf4e099dbb8a4f511cfd5efcb5f75918baad200ff7380635631b/yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", size = 86248, upload-time = "2026-03-01T22:04:44.757Z" }, - { url = "https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", size = 85988, upload-time = "2026-03-01T22:04:46.365Z" }, - { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, - { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, - { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, - { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, - { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, - { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, - { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, - { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, - { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, - { url = "https://files.pythonhosted.org/packages/e5/1c/9a1979aec4a81896d597bcb2177827f2dbee3f5b7cc48b2d0dadb644b41d/yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", size = 82602, upload-time = "2026-03-01T22:05:08.444Z" }, - { url = "https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", size = 87461, upload-time = "2026-03-01T22:05:10.145Z" }, - { url = "https://files.pythonhosted.org/packages/93/95/07e3553fe6f113e6864a20bdc53a78113cda3b9ced8784ee52a52c9f80d8/yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", size = 82336, upload-time = "2026-03-01T22:05:11.554Z" }, { url = "https://files.pythonhosted.org/packages/88/8a/94615bc31022f711add374097ad4144d569e95ff3c38d39215d07ac153a0/yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", size = 124737, upload-time = "2026-03-01T22:05:12.897Z" }, { url = "https://files.pythonhosted.org/packages/e3/6f/c6554045d59d64052698add01226bc867b52fe4a12373415d7991fdca95d/yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", size = 87029, upload-time = "2026-03-01T22:05:14.376Z" }, { url = "https://files.pythonhosted.org/packages/19/2a/725ecc166d53438bc88f76822ed4b1e3b10756e790bafd7b523fe97c322d/yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", size = 86310, upload-time = "2026-03-01T22:05:15.71Z" }, diff --git a/wip/mistral-workflows-plugin-extract.md b/wip/mistral-workflows-plugin-extract.md new file mode 100644 index 000000000..fed612968 --- /dev/null +++ b/wip/mistral-workflows-plugin-extract.md @@ -0,0 +1,215 @@ +# Mistral Workflows ↔ Pipelex — Extract as a Real Mistral Plugin + +Self-contained plan. Sibling document `mistral-workflows-sub-module.md` (the +former `TODOS.md`) records what was built in-tree under +`pipelex/plugins/mistralai_workflows/` during Phases 1.x–2.1. That work is the +*input* to this project, not background to redo. + +## 1. Why + +What we shipped is the **functional equivalent** of a Mistral Workflows plugin +but packaged as an optional extra of `pipelex` (`pipelex[mistralai-workflows]`, +imported from `pipelex.plugins.mistralai_workflows.*`). Mistral defines a +plugin as a **standalone, pip-installable package** that depends on +`mistralai-workflows>=2.0.0` and exposes activities / workflows / dependencies +under its own top-level package (the `mistralai.workflows.plugins.*` +namespace is reserved for Mistral-supported packages). + +To match that contract we need to: + +1. Stop shipping Mistral-specific code inside the `pipelex` distribution. +2. Ship a separate distribution (PyPI: `pipelex-mistralai-workflows`, + Python package: `pipelex_mistralai_workflows`) that `pip install`s + `pipelex` and `mistralai-workflows>=3.3.0` and re-exports the same + activities, with a Mistral-style "component" / dependency wrapper. +3. Keep the framework-agnostic embedding core (`bridge.py`, + `execution_mode.py`, `bootstrap.py`, `exceptions.py`) reachable from + *any* host, not just Mistral — so other durable runtimes (raw Temporal, + future plugins) can reuse it. + +## 2. Goals & non-goals + +**Goals** + +- Pure-Python `pipelex` distribution: no `mistralai-workflows` extra, no + `pipelex/plugins/mistralai_workflows/` directory. +- New repo `pipelex-mistralai-workflows` scaffolded from + `pipelex-starter-python` and adapted for a library (not an app), with + identical lint/type/test toolchain to the rest of the workspace. +- Public surface preserved: a user who today writes + `from pipelex.plugins.mistralai_workflows.activities import pipelex_run_pipe` + has a clear, mechanical migration to the new import path. +- Mistral-idiomatic ergonomics: a `pipelex_dependency` (or equivalent + component) so workers wire Pipelex the same way they wire + `mistralai_chat_complete` today. +- CI on the new repo runs the integration test layers that need the + optional dep (currently layer-2 / layer-3 in `mistral-workflows-sub-module.md` §3). +- Docs split cleanly: embedding-core docs stay in pipelex; Mistral-specific + recipes move to the new repo's docs. + +**Non-goals** + +- Re-doing Phase 1.x / Phase 2.x design. The behavior, boundary types, + execution modes, streaming semantics, and gotchas are all locked in — + see `mistral-workflows-sub-module.md` §2 and §4. Treat them as spec. +- Goal 1 from the original doc (porting Pipelex orchestration to run *on* + Mistral Workflows). Still out of scope. +- Backwards-compatibility shims in `pipelex` for the old import path. Per + project rule (CLAUDE.md "No backward compatibility"), we just change it + and note the migration in the changelog. + +## 3. Decision points to resolve before coding + +A follow-up agent should not start until these are answered. Each has a +proposed default; flag any that need a human call. + +1. **Where does the framework-agnostic core live?** + - Option A *(recommended default)*: keep `bridge.py`, + `execution_mode.py`, `bootstrap.py`, `exceptions.py` inside `pipelex`, + promoted out of `plugins/mistralai_workflows/` into something like + `pipelex/embedding/` (name TBD). The new plugin pkg imports from there. + Pros: any host (raw Temporal, future plugins) can reuse it; smaller + surface to maintain in the new repo. + - Option B: move *everything* into `pipelex-mistralai-workflows`. Pros: + `pipelex` stays leaner. Cons: any future host has to either depend on + the Mistral plugin pkg (wrong) or re-implement. + - This decision drives the rest of the file moves. + +2. **Package + distribution names.** + - PyPI: `pipelex-mistralai-workflows` (proposed). Confirm naming aligns + with other Pipelex packages on PyPI. + - Top-level Python package: `pipelex_mistralai_workflows`. The + `mistralai.workflows.plugins.*` namespace is reserved, so we cannot + squat there. + - GitHub repo: `pipelex-mistralai-workflows` under the existing org, + side-by-side with the other repos listed in the workspace `CLAUDE.md`. + +3. **Versioning & release cadence.** + - Pin a minimum `pipelex` version per release. Decide whether to track + `pipelex` major versions 1:1 or use independent SemVer. + - Decide whether the new repo follows the same release skill / version + conventions as `pipelex` (CHANGELOG.md format, `release/vX.Y.Z` + branches, etc.). Default: yes, identical. + +4. **Mistral component wrapper shape.** + - Mistral's existing plugins ship a "dependency" (e.g. + `mistralai_chat_complete`) that workers register. We should ship at + least one — likely a wrapper around `ensure_pipelex_booted()` plus a + `LibraryCrate` snapshot. Final shape needs a quick read of how + `mistralai.workflows.plugins.mistralai` exposes its dependency before + committing. + +5. **Cookbook example.** + - The deferred Phase 1.3 cookbook entry (`pipelex-cookbook/examples/c_advanced/mistral-workflows/`) + should land *after* the new package is on PyPI, importing from the new + path. Coordinate timing. + +## 4. Workstreams + +Three streams, parallelizable once §3 is resolved. Each has its own +follow-up agent / PR. + +### Stream A — Refactor inside `pipelex` + +In this repo (`_mistral/`, eventually merged back). High-level only; the +follow-up agent figures out the file moves once §3.1 is decided. + +- Lift the framework-agnostic core to its new home (Option A) or remove it + entirely (Option B). +- Delete the Mistral-specific modules (`activities.py`, `streaming.py`, + `streaming_event_forwarder.py`) and their unit + integration tests. +- Drop the `[mistralai-workflows]` extra from `pyproject.toml`. Drop the + `[[tool.mypy.overrides]]` block that exists only because Mistral's + source uses PEP 695 syntax (re-add it in the new repo). +- Move docs: `docs/under-the-hood/mistralai-workflows-{plugin,recipes}.md` + go to the new repo's docs site. Leave a stub in pipelex docs that links + out. +- CHANGELOG entry under `[Unreleased]` describing the move + migration. +- Verify: `make agent-check` and `make agent-test` green; `git grep + mistralai_workflows` returns nothing in `pipelex/` after the move. + +### Stream B — Scaffold `pipelex-mistralai-workflows` from `pipelex-starter-python` + +New repo, side-by-side with the other workspace repos. + +- Copy `pipelex-starter-python/` as the starting point. Rename the package + dir, rewrite `pyproject.toml` (`name`, `description`, dependencies, + package list, classifiers). +- Convert from "app starter" to "library": + - Drop the `my_project/hello_world.{mthds,py}` example. + - Add a real `LICENSE` (MIT, matching pipelex). + - Replace the README with one that explains: install, register the + activity on a worker, call it from a workflow, link to recipes. + - Wire `py.typed` (already present in starter — keep). +- `pyproject.toml` deltas vs starter: + - `name = "pipelex-mistralai-workflows"`. + - `dependencies = ["pipelex>=X.Y", "mistralai-workflows>=3.3.0"]` (no + `[mistralai,anthropic,...]` extras — this is a library, not an app). + - Re-add the `[[tool.mypy.overrides]]` for `mistralai.workflows.*` + (PEP 695 source) — copy from pipelex `pyproject.toml`. + - Pytest markers: copy the relevant subset; drop `inference`/`llm`/etc. + if the test suite only does layer-2 / layer-3 worker tests. +- Add a Makefile mirroring the `agent-check` / `agent-test` / `cleanderived` + targets used elsewhere in the workspace, so CLAUDE.md instructions in + this repo and the new repo overlap. +- Add `CLAUDE.md` for the new repo. Short — point at workspace `CLAUDE.md` + and call out: must not depend on internal `pipelex` paths, only the + promoted public embedding core. +- GitHub Actions: copy the matrix from `pipelex` if there is one, or wire + a minimal `uv sync && make agent-check && make agent-test` workflow. + +### Stream C — Move the plugin code into the new repo + +After A and B land (or in a coordinated PR pair). + +- Move `activities.py`, `streaming.py`, `streaming_event_forwarder.py` + into `pipelex_mistralai_workflows/`. Rewrite imports to point at the + promoted embedding core in `pipelex`. +- Move the integration tests (`test_activities_direct.py`, + `test_activities_offloaded.py`, `test_activities_streaming.py`, + `test_bridge_temporal_blocking.py`, `test_bridge_temporal_fire_and_forget.py`) + and their fixtures (`conftest.py`, `test_data/bridge_test.mthds`, + `test_data/bridge_funcs.py`). +- Layer-1 framework-agnostic tests (`test_bridge_direct.py`, the unit tests + under `tests/unit/pipelex/plugins/mistralai_workflows/`) follow the + embedding core — they stay in `pipelex` if we picked Option A, move if + Option B. +- Add the Mistral component / dependency wrapper from §3.4. +- First release to PyPI as `0.1.0`. Tag, write release notes, link from + the pipelex CHANGELOG migration entry. + +## 5. Migration story for users + +Single-paragraph note in pipelex CHANGELOG and in the new repo's README: + +> Mistral Workflows integration moved from +> `pipelex[mistralai-workflows]` / `pipelex.plugins.mistralai_workflows.*` +> into a dedicated package: `pip install pipelex-mistralai-workflows` and +> import from `pipelex_mistralai_workflows.*`. No API changes; the +> activities, boundary types, and execution modes are identical. + +Per project rule, no compat shim. The pipelex release that drops the +extra and the first `pipelex-mistralai-workflows` release ship together. + +## 6. Open risks (track but don't block) + +- **Version coupling.** The plugin pkg depends on internal-but-public + embedding APIs of `pipelex`. Decide on a stable surface (probably what + `bridge.py` already exposes) and document it as such, or breakage will + cascade on every pipelex release. +- **Test parity in CI.** Today layer-2 / layer-3 tests run on every PR in + pipelex CI because `uv sync --all-extras` pulls the optional dep. Once + extracted, those tests only run in the new repo. Make sure both repos' + CI matrices are healthy before flipping the switch. +- **OffloadableField import path drift.** Already noted in + `mistral-workflows-sub-module.md` §6. Carries over verbatim. + +## 7. Resuming a session + +1. Read `mistral-workflows-sub-module.md` §2, §4, §5 — these are the + binding design decisions and gotchas you must respect. +2. Read this file end-to-end. +3. Resolve §3 with the user before writing code. Especially §3.1 (where + the framework-agnostic core lives) — every other choice depends on it. +4. Pick a stream from §4. Streams A and B can run in parallel; Stream C + waits on both. diff --git a/wip/mistral-workflows-sub-module.md b/wip/mistral-workflows-sub-module.md new file mode 100644 index 000000000..3168bc18d --- /dev/null +++ b/wip/mistral-workflows-sub-module.md @@ -0,0 +1,301 @@ +# Mistral Workflows ↔ Pipelex Plugin — Plan & Progress + +Self-contained planning document. A fresh session can resume from this file +alone; no need to read prior conversation history. + +For anything implemented (Phases 1.0–1.5), the code is authoritative. Read +`pipelex/plugins/mistralai_workflows/` and the matching tests under +`tests/{unit,integration}/pipelex/plugins/mistralai_workflows/`. The +user-facing reference lives at +`docs/under-the-hood/mistralai-workflows-{plugin,recipes}.md`. + +--- + +## Status board + +| Phase | Scope | Status | +| ----- | ------------------------------------------------------ | ------ | +| 1.0 | Framework-agnostic core (`bridge.py`, modes, ...) | ✅ done | +| 1.1 | Tier-1 `pipelex_run_pipe` activity wrapper | ✅ done | +| 1.2 | `TEMPORAL_BLOCKING` + `TEMPORAL_FIRE_AND_FORGET` modes | ✅ done | +| 1.3 | Docs + CHANGELOG (mkdocs nav wired) | ✅ done¹ | +| 1.5 | Large-payload `pipelex_run_pipe_offloaded` variant | ✅ done | +| 2.0 | Streaming v1 — one Mistral `task()` per activity | ✅ done | +| 2.1 | Streaming v2 — per-step `task.update()` (DIRECT only) | ✅ done | + +¹ Cookbook example deferred to a follow-up PR in the sibling +`pipelex-cookbook/` repo (suggested entry: +`examples/c_advanced/mistral-workflows/` with a Tier-1 DIRECT-mode worker +plus a Tier-2 typed activity that uses `library_crate_dump`). + +### Outstanding from Phase 1 (not blocking Phase 2) + +- [ ] `make agent-check` passes with `mistralai-workflows` NOT installed — + needs a fresh venv without the extra. The guard placement + (`activities.py` only; `bridge.py` / `execution_mode.py` / + `bootstrap.py` / `exceptions.py` are import-clean) should make this + pass; not yet verified end-to-end. +- [ ] CI matrix for the optional dep — deferred. CI runs + `uv sync --all-extras`, so layer-2 and layer-3 tests already run on + every PR. Reconsider when we add an extra whose tests must NOT run + on the default lane. + +--- + +## 1. Context + +Integrate Pipelex with Mistral Workflows (`mistralai-workflows>=3.3.0`), +which wraps Temporal with a thicker DX layer. Two goals were considered: + +- **Goal 1** — Port Pipelex orchestration to run *on* Mistral Workflows as + an alternative durable runtime. Blocked on Mistral exposing extension + hooks for payload converter, codec, sandbox passthrough, and a + bare-Temporal `run_worker` mode. **Out of scope.** File issues with the + Mistral team if/when we want to revisit. +- **Goal 2** — Let users invoke Pipelex pipes from inside their own + Mistral Workflows activities. **In scope.** Phase 1.x complete; Phase 2 + pending. + +The `mistralai-workflows` dependency must remain strictly optional. + +--- + +## 2. Locked-in design decisions (still binding for Phase 2) + +- **Library crate transport** is dump-based: + `PipelexPipeRunInput.library_crate_dump: dict[str, Any] | None`. +- **Execution mode** is an exhaustive `StrEnum`, set per-call (not + per-worker): `DIRECT`, `TEMPORAL_BLOCKING`, `TEMPORAL_FIRE_AND_FORGET`. +- **Streaming** is phased. Phase 2.0 ships a single Mistral `task()` per + activity (started / completed / failed). Phase 2.1 ships per-step + `task.update()` events driven by Pipelex's `report_delegate`, + conditional on demand. +- **Plugin location**: `pipelex/plugins/mistralai_workflows/`. +- **Optional-dep guard** lives in `activities.py` (and will live in + `streaming.py`). `__init__.py` is empty per Pipelex's "no re-exports" + rule. `bridge.py`, `execution_mode.py`, `bootstrap.py`, `exceptions.py` + are framework-agnostic and importable without `mistralai-workflows`. +- **Boundary types are JSON-only.** No Pipelex internal types (`PipeJob`, + `PipeOutput`, `WorkingMemory`) cross the activity boundary. + +--- + +## 3. Module layout + +``` +pipelex/plugins/mistralai_workflows/ +├── __init__.py # empty (no re-exports) +├── exceptions.py # 4 exception classes +├── execution_mode.py # PipelexExecutionMode StrEnum +├── bridge.py # framework-agnostic core (NO mistralai imports) +├── bootstrap.py # ensure_pipelex_booted() + DI helper +├── activities.py # Tier-1 wrappers + offloaded variant +└── streaming.py # Phase 2.0 — pipelex_run_pipe_streaming sibling activity + +tests/unit/pipelex/plugins/mistralai_workflows/ +├── test_input_models.py # boundary BaseModels +├── test_execution_mode.py # StrEnum properties +├── test_validation.py # _validate_input + decode helpers +└── test_dispatch.py # mode dispatch with mocked PipeRun + +tests/integration/pipelex/plugins/mistralai_workflows/ +├── conftest.py # bridge_test_library fixture +├── test_data/ # bridge_test.mthds + bridge_funcs.py +├── test_bridge_direct.py # layer 1 (no optional dep) +├── test_activities_direct.py # layer 2 (Mistral test worker) +├── test_activities_offloaded.py # layer 2 — offloaded variant +├── test_activities_streaming.py # layer 2 — Phase 2.0 streaming variant +├── test_bridge_temporal_blocking.py # layer 3 (+ temporal extra) +└── test_bridge_temporal_fire_and_forget.py # layer 3 (+ temporal extra) +``` + +Users import from full paths (no re-exports per Pipelex rule): + +```python +from pipelex.plugins.mistralai_workflows.activities import ( + pipelex_run_pipe, + pipelex_run_pipe_offloaded, + PipelexPipeRunInputOffloaded, + PipelexPipeRunOutputOffloaded, +) +from pipelex.plugins.mistralai_workflows.bridge import ( + PipelexPipeRunInput, PipelexPipeRunOutput, run_pipe_via_bridge, +) +from pipelex.plugins.mistralai_workflows.execution_mode import PipelexExecutionMode +from pipelex.plugins.mistralai_workflows.bootstrap import ensure_pipelex_booted +from pipelex.plugins.mistralai_workflows.streaming import ( + pipelex_run_pipe_streaming, + PipelexPipeRunStreamingState, + PIPELEX_PIPE_RUN_TASK_TYPE, +) +``` + +--- + +## 4. Gotchas from Phase 1 (read before Phase 2) + +These bit during Phase 1.1–1.2 and will likely bite again when adding +`streaming.py` plus a new integration test module. Save the cycles. + +1. **Workflow sandbox rejects Pipelex imports** seen during workflow + class validation. Wrap them in + `mistralai_workflows.workflow.unsafe.imports_passed_through()` AND + pass `enforce_determinism=False` to `@workflow.define` for test + workflows. See `test_activities_direct.py:24-30` for the pattern. + Activities are unrestricted Python — this only matters inside + workflow class bodies. + +2. **`OtelTraceId` search attribute** must be pre-registered on the + test namespace. Mistral's `@workflow.define` upserts it on every + workflow run, and the dev server rejects activations against an + unknown attribute. Pass + `search_attributes=[SearchAttributeKey.for_keyword("OtelTraceId")]` + to `WorkflowEnvironment.start_local`. + +3. **Task queue mismatch.** Mistral's `@activity` wrapper schedules + activities on the *global* `mistralai_config.temporal.task_queue` + (default `"default"`), NOT the workflow's task queue. Spin a worker + on a custom test queue without overriding the global → activities + land on `"default"` and the workflow hangs forever. Fix: an autouse + module-scoped fixture pinning + `mistralai_config.temporal.task_queue = TEST_TASK_QUEUE` for the + duration of the test module. See `test_activities_direct.py:48-64`. + +4. **Result shape.** Mistral's `convert_result_to_temporal_format` + wraps non-BaseModel return values in `{"result": ...}`. Return a + BaseModel directly from the workflow entrypoint to skip the + wrapping (we return `PipelexPipeRunOutput`). + +5. **mypy + Mistral's PEP 695 type syntax.** `mistralai-workflows`'s + own source uses PEP 695 type parameters that mypy rejects under + `python_version=3.11`. The `[[tool.mypy.overrides]]` block for + `mistralai.workflows.*` (`follow_imports = "skip"`, + `ignore_errors = true`) in `pyproject.toml` is already in place. + Mypy will still flag `OffloadableField.get_value()` as returning + `Any` — assign through a typed intermediate variable. + +6. **`PipeFunc` is NOT Temporal-compatible.** `asyncio.to_thread` + inside `PipeFunc` raises `NotImplementedError` in the deterministic + workflow event loop. The bundle ships `bridge_func_pipe` (PipeFunc, + DIRECT only) for the no-Temporal layers and `bridge_compose_pipe` + (PipeCompose, Temporal-compatible) for the Temporal layers; the + `bridge_envelope_pipe` (PipeCompose with inline-structured concept) + exists to exercise dynamic-concept round-trip via + `library_crate_dump`. Pick the right one per execution mode. + +7. **`Pipelex.make()` is NOT idempotent** — it raises if a singleton + already exists. `bootstrap.ensure_pipelex_booted()` only calls it + when `Pipelex.get_optional_instance() is None`, so an externally- + booted singleton is adopted. Don't replace this guard with a + module-level boolean. + +--- + +## 5. Phase 2 — Streaming + +Goal: surface live progress events from Pipelex pipes through Mistral's +`task()` event API so users can subscribe via +`create_capturing_mock_events_client` and friends. + +### Phase 2.0 — One task per activity (started / completed / failed) ✅ + +A single Mistral task wraps the whole activity body — no per-step +granularity. Cheapest path to "the user sees something happen." + +- [x] Created `pipelex/plugins/mistralai_workflows/streaming.py`. Reuses + the same optional-dep guard pattern as `activities.py` (top-level + `try`/`except ImportError` re-raising `MistralWorkflowsNotInstalledError`). +- [x] **Decision: sibling activity** `pipelex_run_pipe_streaming`. Reasons: + - Keeps the silent path silent — Tier-1 users without observability + needs don't pay event publishing overhead. + - Mirrors the `pipelex_run_pipe_offloaded` sibling pattern. + - Workers register only the variant they actually use. +- [x] Inside the activity: `async with Task[PipelexPipeRunStreamingState](...)` + then call `run_pipe_via_bridge`, then `update_state` to `phase="completed"`. + `Task.__aexit__` automatically emits `CustomTaskFailed` on exception + and the original exception propagates — no extra `try`/`except` + needed (per Pipelex "don't catch Exception speculatively" rule). +- [x] Layer-2 integration test + `tests/integration/pipelex/plugins/mistralai_workflows/test_activities_streaming.py` + uses `create_test_worker_with_events` + `EventContext` + a + `create_capturing_mock_events_client` to assert that exactly one + `CustomTaskStarted`, ≥1 `CustomTaskInProgress`, and one + `CustomTaskCompleted` are emitted with the right `custom_task_type` + (`pipelex.pipe_run`) and payload shape. + +### Phase 2.1 — Per-step granularity (DIRECT mode only) ✅ + +- [x] Subscribe to Pipelex's trace event channel from inside the + activity. Implemented as a queue-backed `EventLogProtocol` + (`QueueEventLog` in `streaming_event_forwarder.py`) injected into a + per-call `GraphTracerManager` tracer. Note: `ReportingProtocol` + itself has no observer methods — the right abstraction is the + event log, not the reporting delegate. +- [x] Map Pipelex events to Mistral `task.update_state(...)` calls: + - `PipeStartEvent` → `in_progress` with `current_step_pipe_code`, + `current_step_node_id`, `last_event_kind="pipe_start"`, + `started_steps`. + - `PipeEndSuccessEvent` → `in_progress` with + `last_event_kind="pipe_end_success"`, `completed_steps`, + `last_output_stuff_name`. + - `PipeEndErrorEvent` → `in_progress` with + `last_event_kind="pipe_end_error"`. The activity's + `Task.__aexit__` then emits `CustomTaskFailed` with the + propagated exception. + - Other `TraceEventKind`s (edges, batch fan-out, controller + outputs, execution data, usage reports) intentionally suppressed + — too noisy for state updates, already captured by Pipelex's + own reporting / graph infrastructure. +- [x] Forwarder side-task drains the event log and terminates cleanly + on both success and failure. Uses `try` / `finally` (no + `except Exception`); the forwarder is fully drained *before* + writing the final `phase="completed"` state so the snapshot + reflects the right phase. +- [x] Multi-step test fixture: `bridge_sequence_pipe` (PipeSequence) + chaining `bridge_seq_step_one` and `bridge_seq_step_two` + (PipeCompose). Test asserts ≥3 pipe_start + ≥3 pipe_end_success + `CustomTaskInProgress` events with `started_steps` monotonic + `[1, 2, 3]` and per-step pipe codes in declaration order. + +Scope: DIRECT mode only. TEMPORAL_BLOCKING / TEMPORAL_FIRE_AND_FORGET +keep Phase 2.0 single-pair semantics — per-step streaming across the +Temporal worker boundary would need cross-process tee logic on top of +the existing `pipeline_run_setup` event log infra, deferred until demand +surfaces. + +--- + +## 6. Open risks (track but don't block) + +- [ ] Concurrent activities sharing process-global Pipelex state — already + mitigated by per-call library scoping in + `bridge.py::_scoped_library_for_crate`. Verify no leakage under + concurrent load when we get there. +- [ ] If Mistral upgrades change the `OffloadableField` import path + (currently `mistralai.workflows.core.encoding.fields_offloader`), + revisit the imports in `activities.py`. + +--- + +## 7. Resuming a session + +1. Read this file end-to-end — it's short by design. +2. **For anything in Phase 1.x: the code is authoritative.** Read + `pipelex/plugins/mistralai_workflows/*.py` and its tests; do not + re-derive from this doc. +3. For Phase 2 work: start at §5, pick the first unchecked box, re-read + §4 (gotchas) before scaffolding the new test module. +4. After each phase, run: + ``` + make agent-check + .venv/bin/pytest tests/unit/pipelex/plugins/mistralai_workflows/ \ + tests/integration/pipelex/plugins/mistralai_workflows/ + ``` + Before declaring Phase 2 done, run the broader sweep: + ``` + .venv/bin/pytest -n auto \ + -m "(dry_runnable or not (inference or llm or img_gen or extract or search)) and not pipelex_api" \ + tests/unit/pipelex/plugins/ tests/integration/pipelex/plugins/ \ + tests/unit/pipelex/builder/ tests/integration/pipelex/builder/ + ``` +5. Update the status board and the §5 boxes as you go.